pax_global_header00006660000000000000000000000064123440433410014510gustar00rootroot0000000000000052 comment=1761b8f94f7d14521365739419fd81352aae9e5a yao-5.4.0/000077500000000000000000000000001234404334100123065ustar00rootroot00000000000000yao-5.4.0/BUGS000066400000000000000000000001731234404334100127720ustar00rootroot00000000000000- 4.6.1 (still in 4.7.0): - improper cleaning of svipc demonstrated when running test-all.i with sim.svipc or wfs.svipc on yao-5.4.0/INSTALL000066400000000000000000000031141234404334100133360ustar00rootroot00000000000000YAO PACKAGE INSTALLATION: Notes updated for V4.0 (2007jun03) There are two methods of installation: from source or using the yorick package manager (pkg_mngr). Soon to come: debian package. 1) From source: - get the latest version from the sourceforge cvs $ cvs -z3 -d:pserver:anonymous@yorick.cvs.sourceforge.net:/cvsroot/yorick checkout -r HEAD -d yao yorick-yao or untar whatever yorick-yao tar file you've got. $ untar yorick-yao.tgz - cd yao - follow instructions in README - dependencies: - fftw3 - if you want the fancy (but useful) GUI, you will need python, pygtk, libglade 2) Using pkg_mngr: - start yorick > #include "pkg_mngr.i" > pkg_setup > pkg_sync > pkg_install,"yao" - pkg_mngr does not take care of the dependencies for the GUI, hence you will have to make sure python, pygtk and libglade are installed. - the from-source or pkg_mngr installer puts the gui executable (yao) in Y_BIN (same place as the yorick executable). You'll have to create a softlink or put Y_BIN in your path if yu want to be able to start the GUI with the command "yao" TO RUN: You'll have to have a parameter file (yao_par_file). Look in Y_SITE/share/yao/examples GUI: $ yao or $yao someparfile.par or $ yorick -i yaopy.i someparfile.par to start the GUI (see above for the path definition) Regular session: Start a regular yorick session and type #include "yao.i" 1) aoread,parfile 2) aoinit,disp=1 (other parameters, help,aoinit for more info) 3) aoloop,disp=1 (other parameters, help,aoloop for more info) This preps everything. Now you can start the loop typing "go" and pause it with "stop" yao-5.4.0/LICENSE000066400000000000000000000431311234404334100133150ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. yao-5.4.0/Makefile000066400000000000000000000155101234404334100137500ustar00rootroot00000000000000# these values filled in by yorick -batch make.i Y_MAKEDIR=/usr/lib/yorick/2.2 Y_EXE=/usr/lib/yorick/2.2/bin/yorick Y_EXE_PKGS= Y_EXE_HOME=/usr/lib/yorick/2.2 Y_EXE_SITE=/usr/share/yorick/2.2 Y_HOME_PKG= # ----------------------------------------------------- optimization flags # options for make command line, e.g.- make COPT=-g TGT=exe COPT=$(COPT_DEFAULT) TGT=$(DEFAULT_TGT) # ------------------------------------------------ macros for this package PKG_NAME=yao PKG_I=yao_fast.i yao_utils.i OBJS=aoSimulUtils.o utils.o yao_fast.o # change to give the executable a name other than yorick PKG_EXENAME=yorick # PKG_DEPLIBS=-Lsomedir -lsomelib for dependencies of this package # PKG_DEPLIBS=-lfftw3f_threads -lfftw3f -lpthread -lm PKG_DEPLIBS=-lfftw3f # on OSX, use the next command to link to the static version of imutil: # PKG_DEPLIBS=-L$(Y_EXE_HOME)/lib -limutil -L/path/to/fftw3_libs -lfftw3f # set compiler (or rarely loader) flags specific to this package PKG_CFLAGS=-Wall # on OSX (or other platforms), you may need to add the path to the # fftw3 include files: # PKG_CFLAGS=-Wall -I/path/to/fftw3/include PKG_LDFLAGS= # list of additional package names you want in PKG_EXENAME # (typically Y_EXE_PKGS should be first here) EXTRA_PKGS=$(Y_EXE_PKGS) # list of additional files for clean PKG_CLEAN= # autoload file for this package, if any PKG_I_START= # non-pkg.i include files for this package, if any PKG_I_EXTRA=yao.i aoutil.i yaokl.i yao_newfits.i yao_util.i turbulence.i yao_gui.i yaopy.i yao_wfs.i yao_structures.i yao_dm.i yao_svipc.i yao_setnsync.i yaodh.i yao_disp.i yao_lgs.i # -------------------------------- standard targets and rules (in Makepkg) # set macros Makepkg uses in target and dependency names # DLL_TARGETS, LIB_TARGETS, EXE_TARGETS # are any additional targets (defined below) prerequisite to # the plugin library, archive library, and executable, respectively PKG_I_DEPS=$(PKG_I) Y_DISTMAKE=distmake include $(Y_MAKEDIR)/Make.cfg include $(Y_MAKEDIR)/Makepkg include $(Y_MAKEDIR)/Make$(TGT) # override macros Makepkg sets for rules and other macros # Y_HOME and Y_SITE in Make.cfg may not be correct (e.g.- relocatable) Y_HOME=$(Y_EXE_HOME) Y_SITE=$(Y_EXE_SITE) # reduce chance of yorick-1.5 corrupting this Makefile MAKE_TEMPLATE = protect-against-1.5 # ------------------------------------- targets and rules for this package # simple example: #myfunc.o: myapi.h # more complex example (also consider using PKG_CFLAGS above): #myfunc.o: myapi.h myfunc.c # $(CC) $(CPPFLAGS) $(CFLAGS) -DMY_SWITCH -o $@ -c myfunc.c clean:: -rm -rf binaries install:: mkdir -p $(DEST_Y_SITE)/python mkdir -p $(DEST_Y_SITE)/glade mkdir -p $(DEST_Y_SITE)/data mkdir -p $(DEST_Y_SITE)/g mkdir -p $(DEST_Y_SITE)/gist mkdir -p $(DEST_Y_SITE)/share/yao mkdir -p $(DEST_Y_BINDIR) # mkdir -p /usr/local/man/man1 cp -p yao.py $(DEST_Y_SITE)/python/ cp -p yao.glade $(DEST_Y_SITE)/glade/ cp -p besseljprimezeros200.fits $(DEST_Y_SITE)/data/ cp -p yao.gs $(DEST_Y_SITE)/g/ cp -p letter.gs $(DEST_Y_SITE)/g/ cp -p yao.gs $(DEST_Y_SITE)/gist/ cp -p letter.gs $(DEST_Y_SITE)/gist/ cp -p yao $(DEST_Y_BINDIR)/ cp -pr examples $(DEST_Y_SITE)/share/yao/ cp -pr doc $(DEST_Y_SITE)/share/yao/ -rm -rf $(DEST_Y_SITE)/share/yao/examples/CVS -rm -rf $(DEST_Y_SITE)/share/yao/doc/CVS # gzip -9 doc/yao.1 # cp -p doc/yao.1 /usr/local/man/man1/ uninstall:: -rm $(DEST_Y_BINDIR)/yao -rm $(DEST_Y_SITE)/g/yao.gs -rm $(DEST_Y_SITE)/g/letter.gs -rm $(DEST_Y_SITE)/gist/yao.gs -rm $(DEST_Y_SITE)/gist/letter.gs -rm $(DEST_Y_SITE)/python/yao.py -rm $(DEST_Y_SITE)/glade/yao.glade -rm -rf $(DEST_Y_SITE)/share/yao/ # -rm -rf /usr/local/man/man1/yao.1 # -------------------------------------------------------- end of Makefile # for the binary package production (add full path to lib*.a below): PKG_DEPLIBS_STATIC=-lm /usr/lib/libfftw3f.a PKG_ARCH = $(OSTYPE)-$(MACHTYPE) # The above usually don t work. Edit manually and change the PKG_ARCH below: # PKG_ARCH = linux-x86 PKG_VERSION = $(shell (awk '{if ($$1=="Version:") print $$2}' $(PKG_NAME).info)) # .info might not exist, in which case he line above will exit in error. # packages or devel_pkgs: PKG_DEST_URL = packages package: $(MAKE) $(LD_DLL) -o $(PKG_NAME).so $(OBJS) ywrap.o $(PKG_DEPLIBS_STATIC) $(DLL_DEF) mkdir -p binaries/$(PKG_NAME)/dist/y_home/lib mkdir -p binaries/$(PKG_NAME)/dist/y_home/bin mkdir -p binaries/$(PKG_NAME)/dist/y_home/i-start mkdir -p binaries/$(PKG_NAME)/dist/y_site/i0 mkdir -p binaries/$(PKG_NAME)/dist/y_site/g mkdir -p binaries/$(PKG_NAME)/dist/y_site/gist mkdir -p binaries/$(PKG_NAME)/dist/y_site/python mkdir -p binaries/$(PKG_NAME)/dist/y_site/glade mkdir -p binaries/$(PKG_NAME)/dist/y_site/share/yao/examples mkdir -p binaries/$(PKG_NAME)/dist/y_site/share/yao/doc cp -p *.i binaries/$(PKG_NAME)/dist/y_site/i0/ rm binaries/$(PKG_NAME)/dist/y_site/i0/check.i if test -n "$(PKG_I_START)"; then rm binaries/$(PKG_NAME)/dist/y_site/i0/$(PKG_I_START); fi cp -p $(PKG_NAME).so binaries/$(PKG_NAME)/dist/y_home/lib/ if test -f "check.i"; then cp -p check.i binaries/$(PKG_NAME)/.; fi if test -n "$(PKG_I_START)"; then cp -p $(PKG_I_START) \ binaries/$(PKG_NAME)/dist/y_home/i-start/; fi cat $(PKG_NAME).info | sed -e 's/OS:/OS: $(PKG_ARCH)/' > tmp.info mv tmp.info binaries/$(PKG_NAME)/$(PKG_NAME).info cp -p *.i binaries/$(PKG_NAME)/dist/y_site/i0/. cp -p README binaries/$(PKG_NAME)/dist/y_site/share/yao/. cp -p INSTALL binaries/$(PKG_NAME)/dist/y_site/share/yao/. cp -p LICENSE binaries/$(PKG_NAME)/dist/y_site/share/yao/. cp -p yao binaries/$(PKG_NAME)/dist/y_home/bin/. cp -p yao.py binaries/$(PKG_NAME)/dist/y_site/python/. cp -p yao.glade binaries/$(PKG_NAME)/dist/y_site/glade/. cp -p *.gs binaries/$(PKG_NAME)/dist/y_site/g/. cp -p *.gs binaries/$(PKG_NAME)/dist/y_site/gist/. -cp -p examples/* binaries/$(PKG_NAME)/dist/y_site/share/yao/examples/. -cp -p doc/* binaries/$(PKG_NAME)/dist/y_site/share/yao/doc/. cd binaries; tar zcvf $(PKG_NAME)-$(PKG_VERSION)-$(PKG_ARCH).tgz $(PKG_NAME) distbin: package if test -f "binaries/$(PKG_NAME)-$(PKG_VERSION)-$(PKG_ARCH).tgz" ; then \ ncftpput -f $(HOME)/.ncftp/maumae www/yorick/$(PKG_DEST_URL)/$(PKG_ARCH)/tarballs/ \ binaries/$(PKG_NAME)-$(PKG_VERSION)-$(PKG_ARCH).tgz; fi if test -f "binaries/$(PKG_NAME)/$(PKG_NAME).info" ; then \ ncftpput -f $(HOME)/.ncftp/maumae www/yorick/$(PKG_DEST_URL)/$(PKG_ARCH)/info/ \ binaries/$(PKG_NAME)/$(PKG_NAME).info; fi distsrc: make clean; rm -rf binaries cd ..; tar --exclude binaries --exclude CVS --exclude .svn --exclude *.spec -zcvf \ $(PKG_NAME)-$(PKG_VERSION)-src.tgz yorick-$(PKG_NAME)-$(PKG_VERSION);\ ncftpput -f $(HOME)/.ncftp/maumae www/yorick/$(PKG_DEST_URL)/src/ \ $(PKG_NAME)-$(PKG_VERSION)-src.tgz ncftpput -f $(HOME)/.ncftp/maumae www/yorick/contrib/ \ ../$(PKG_NAME)-$(PKG_VERSION)-src.tgz # -------------------------------------------------------- end of Makefile yao-5.4.0/NOTES000066400000000000000000000136361234404334100131320ustar00rootroot00000000000000//============================================================================== yao 4.9.1 (2012sep06), before extended field and various optimizations: Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 121.7 ON 0.43@1.65mic test Simple SH6x6 w/ TT mirror, full... 139.0 OFF 0.43@1.65mic test1 Simili Altair LGS, full diffrac... 35.8 ON 0.53@1.65mic test1 Simili Altair LGS, full diffrac... 38.9 OFF 0.56@1.65mic test2 SH 12x12, quick method, with se... 233.3 ON 0.78@1.65mic test2 SH 12x12, quick method, with se... 293.9 OFF 0.78@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 22.8 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 25.5 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 313.2 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 419.8 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 59.8 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.2 OFF 0.84@2.20mic test6 DH WFS & DM 380.4 ON 0.50@1.65mic test6 DH WFS & DM 798.8 OFF 0.50@1.65mic //============================================================================== yao 4.9.5 (2012oct07, first extended field method), october 12: (faster than next, but remember this had a number of things commented in yao_fast.c) Performance Summary: Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 142.6 ON 0.42@1.65mic test Simple SH6x6 w/ TT mirror, full... 168.1 OFF 0.43@1.65mic test1 Simili Altair LGS, full diffrac... 57.1 ON 0.52@1.65mic test1 Simili Altair LGS, full diffrac... 65.2 OFF 0.53@1.65mic test2 SH 12x12, quick method, with se... 327.8 ON 0.78@1.65mic test2 SH 12x12, quick method, with se... 479.5 OFF 0.78@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 45.4 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 56.3 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 526.5 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 881.4 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 60.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.5 OFF 0.84@2.20mic test6 DH WFS & DM 406.2 ON 0.49@1.65mic test6 DH WFS & DM 1016.9 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 33.5 ON 0.19@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 34.8 OFF 0.19@1.65mic //============================================================================== yao 4.10.0 (2012oct12, new extended field method): Performance Summary: Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 125.2 ON 0.32@1.65mic test Simple SH6x6 w/ TT mirror, full... 144.3 OFF 0.32@1.65mic test1 Simili Altair LGS, full diffrac... 58.5 ON 0.47@1.65mic test1 Simili Altair LGS, full diffrac... 68.3 OFF 0.48@1.65mic test2 SH 12x12, quick method, with se... 318.5 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 424.9 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 43.7 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 54.6 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 518.1 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 897.5 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.2 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.8 OFF 0.84@2.20mic test6 DH WFS & DM 432.3 ON 0.49@1.65mic test6 DH WFS & DM 1064.1 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.0 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.9 OFF 0.50@1.65mic //============================================================================== yao 4.10.4 (2012oct13, new extended field method + optimize fft size and fftw): test now w/ extfield w.r.t. before. test Simple SH6x6 w/ TT mirror, full... 118.7 ON 0.34@1.65mic test Simple SH6x6 w/ TT mirror, full... 129.6 OFF 0.34@1.65mic test1 Simili Altair LGS, full diffrac... 69.9 ON 0.58@1.65mic test1 Simili Altair LGS, full diffrac... 82.2 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 368.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 524.9 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 49.4 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.9 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 590.8 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 903.4 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.2 OFF 0.84@2.20mic test6 DH WFS & DM 547.9 ON 0.49@1.65mic test6 DH WFS & DM 1035.9 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.2 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 28.2 OFF 0.50@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 986.1 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1955.7 OFF 0.47@1.65mic yao-5.4.0/README000066400000000000000000000730561234404334100132010ustar00rootroot00000000000000=========== YAO package =========== Copyright (c) Francois Rigaut (frigaut) 2002-2011. Initial release June 2002. Developers: ------------ Francois Rigaut frigaut@gemini.edu | frigaut@gmail.com Marcos van Dam marcos@flatwavefronts.com Ralf Flicker + July 2009 Damien Gratadour damien.gratadour@obspm.fr Aurea Garcia-Rissmann agrissmann@gmail.com Synopsis: --------- Yao is a Monte-Carlo simulation tool for Adaptive optics (AO) systems, written as a yorick plugin. It uses a number of custom developed functions to simulate wavefront sensors (WFS), deformable mirrors (DM) and many other aspects of an AO loop. The core functions are written in C, hence are very fast. Help pages: ----------- http://frigaut.github.com/yao/index.html RELEASE NOTES: -------------- version 4.8.3, 2011feb11: - move all calls to fitsread and fitswrite to new yao_fitsread and yao_fitswrite - changed graphic style to display residual phase - implemented forks over WFSs (sim.svipc) - some changes to be compatible with xft - changes to test sim.svipc version 4.8.2, 2010dec17: - Added parallelization of WFS (i.e. one thread/WFS in a multi WFS system) - Tried implementing FFTW parallelization, but the gains were really marginal and often it would be more detrimental than good. Reverted, but left the code commented in Makefile, yao_fast.i and yao_fast.c - yao now looks for and includes yao.conf, if any (before was only in yao GUI) - changed all calls to fitsRead and fitsWrite to new function names yao_fitsread and yao_fitswrite. This way, I work around any conflict with fits.i function checks. Renamed newfits.i to yao_newfits.i - fixed a number of bugs in svipc implementation (mostly how it recovers from a previous svipc run within the same session). test-all.i now runs good with sim.svipc = 1, 5, with wfs.svipc>1, as well as sim.svipc=1 *and* wfs.svipc>1 within the same run. - added items in check_parameters() to check for the svipc bad settings - re-introduced sim.name in graphic and nudged some labels in graphics a bit - introduced some changes to make the graphic look better when using xftfonts. also resized controlscreen - better handling of window closing/opening when using svipc - push to get reference tip is now 0.005 instead of 0.05 (there's no noise) - fixed a bug that animate would not be ON for display in close loop when using svipc - switched the Makefile to -Wall - 2 new sim structure members: sim.svipc_wfs_nfork and sim.svipc_wfs_forknb - fixed a bug in pyramid wfs, hopefully once and for all (bad sinc() function used). - added test3.par (same as glao.par) - fix a bug in test5.par (phase screen referred in parfile may not have existed) - fixed issue with animate being ON and preventing further plot - fixed bug in which background calib was not passed to wfs.svipc child (since 4.7.1) - fixed nitegcycle for shwfs when no svipc - written test routine (examples/test-fr.i) to check correctness of main modes of svipc (wfs and sim). version 4.8.1, 2010dec06: - changed layout of graphic window to add residual phase - display of residual phase (Marcos) - nintegcycle in pyramid wfs (Marcos) - "extended" object in pyramid wfs (Marcos) - a couple of bugfix (Marcos and I) version 4.8.0, 2010nov09: - XFT related: * increased size of axis labels fonts on plsys(4) - newfits: * fixed error handling. Now error in place, instead of calling error handling function (exitInError). Allows much clearer debugging. - Pyramid: * merged pyramid_wfs() changes from marcos, upgraded my francois * changes in yao main routines to make re-introduced obsolete "pyramid" wfs type * upgraded GUI to include pyramid modulation amplitude control * added 4 new structure members to wfs structure - MISC: * added "--dpi ##" command line call option (for GUI call). Example: yao --dpi 75 sh6x6.par * added default animate() to iMat acquisition display. * cleanup of yao.py (dictionary autoconnect) + dpi stuff * shortened get_style() calls to viewport() call * gotten rid of get_processor_number() (use nprocs() function in svipc) * added a bunch of extern wfs, dm, ... in functions called by python to set values of parameters (how could it have worked before is a mystery). - BUG FIXES: * fixed a bug in which the graphic would get stuck (animate call was done without ensuring a plsys,1) version 4.7.3, 2010 oct12: - merged SH threshold methods #2 and #3, patches from Yann Clenet Credits for original idea of method #3 (compute centroid on N brightest pixels instead of using a flux threshold) go to E.Gendron. - added some safety for the choice of shthreshold when using shmethod=3 to avoid getting segfaults in yao_fast. version 4.7.2, 2010 oct12: - added smooth animate=1 for iMat recording/display - added ETA when taking iMat - added option to findfwhm() to save RAM requirements (help,findfwhm) - merged patch from Marcos van Dam: * implemented virtual DMs for tomography * implemented save of residual phase in go() (help,go) version 4.7.1, 2010sep16: - fixed nasty bug that was not switching noise off for background calib (SHWFS) Thanks Yann Clenet for noticing and pointing me to the right direction - make screen now can drop the imaginary part (no_ipart=1) to produce larger screens by saving some RAM. - Gotten rid of hdf5 call in yaodh (and thus of hdf5 dependency) - switched the default mode in test-all.i to non svipc Version 4.7.0, 2010aug14: - Merged a bunch of changes from Marcos van Dam. From his changelog: 1. There is a new version of soy.i. I found more bugs and since it had to be modified, I added new functions. FR: I merged these changes in soy 1.3 2. filtertilt set to 0 for interaction matrix generation. I need this to generate sparse matrices. 3. filtertilt for zernike and stackarray DMs. I need to filter tilt from DMs when doing tomography with LGSs. 4. WFS measurements set to 0 if not from same subsystem as DM. 5. minimum zernike (to exclude piston/tip/tilt if desired). I need this feature for tip-tilt tomography. 6. I remove the reporting of the number of corrected modes... do we really need this? it makes no sense for anything other than classical AO. 7. pupil (real = 0). We discussed this earlier. 8. Introduced virtual DMs needed for tomographic reconstruction 9. mmse and mmse-sparse works fine with MCAO 10. Have loop.method set to closed-loop, open-loop and pseudo open-loop. Open loop means WFS sees uncorrected WF, not corrected WF. 11. Tomographic reconstruction! - Fixed a broken re-opening of graphic window because of undefined dpi. Version 4.6, 2010jun17: - Merged Aurea Garcia-Rissmann additions for diskharmonic DMs Part of the code from Mark Milton (at the time at UofA). Used with authorization. - Merged parallelization code (svipc). Can lead to 3x gains on multicore machines. Tweak with sim.svipc = value (see yao_structures) - Gotten rid of redondant code in utils.c. poidev was in there, as well as other routines. These are already in imutil and imutil is definitely a dependency. This, combine with using the latest imutil v 0.5.6, solves a bug in which poidev would SIGFPE when using too brights GS in with CWFS mode. - solved a bug in which not specifying skymag would means skymag=0 and thus lots of photons in the sky in CWFS mode. Now skymag=0 (default) is interpreted as "no sky". - upgraded all the PROTOTYPES to new recommended syntax "type array" instead of "pointer". V 4.5.6 - changed "least-squares" -> "mmse" - changed "sparse" -> "mmse-sparse" - updated documentation with input from Marcos Van Dam // sorry for inconsistency. Below are cvs revision number of yao.i * Revision 1.16 2010/06/09 15:03:42 frigaut * - Merged changes of Marcos Van Dam: This implements new reconstructors * methods "least-squares" (in fact a MMSE-like) and "sparse" (same but * using sparse matrices, very fast). This adds a dependency on soy. * There's now a few more elements in the dm and mat structures * * - added thback and cleaned up indentation in yao_fast.c * * Revision 1.15 2010/04/15 18:11:24 frigaut * * - strlower -> strcase * * Revision 1.14 2010/04/15 02:36:53 frigaut * * * final commit to upgrade this repo to yao 4.5.1 * * Revision 1.13 2008/11/19 00:53:19 frigaut * - fixed memory leak in yao_fast.c (thanks Damien for reporting that) * - fixed comments in newfits.i * - upped version to 4.2.6 * * Revision 1.12 2008/05/12 18:23:48 frigaut * version change * * Revision 1.11 2008/05/11 14:03:56 frigaut * - implemented zernike wfs * - gotten rid of faulty round function in yao_util * * Revision 1.10 2007/12/27 09:06:28 frigaut * - bumped to version 4.2.3 * - corrected problem with glade path (python does not like ~, so * replaced by expansion) * * Revision 1.9 2007/12/20 13:35:55 frigaut * bumped to v4.2.2 * * Revision 1.8 2007/12/20 13:34:53 frigaut * - various bug fixes * - better handlng of default parfile path * - better handling of options menu (WFS and DM) * * Revision 1.7 2007/12/19 20:00:08 frigaut * - statusbar updated to indicates where the results are saved when done * - bumped to 4.2.1 * * Revision 1.6 2007/12/19 19:44:19 frigaut * - solved a number of bugs and inconsistencies between regular yao call and * GUI calls. * - fixed misregistration for curvature systems * - change: misregistration entry from the GUI is now in pupil diameter unit, * not in subaperture unit! * - changed default efd in c188-bench.par * * Revision 1.5 2007/12/19 15:45:32 frigaut * - implemented yao.conf which defines the YAO_SAVEPATH directory where * all temporary files and result files will be saved * - modified yao.i and aoutil.i to save in YAO_SAVEPATH * - bumped version to 4.2.0 * - slight changes to GUI (edit conf file) * version 4.1.1: 2007dec13: - upgrade/update of Makefile version 4.1: 2007dec12: - cleaned up all things for the debian release and a fresh pkg_mngr release - cleaned up the LICENSE issue (GPLv2) - suppressed warning message if fftw_wisdom.dat not found. In my experience, on modern hardware and for fftw3, this does not improve speed. One can still generate and use one if wanted (run init_fftw_wisdom) - produced man page (doc/yao.1) version 4.0: 2007jun03: - Added all GTK GUI. No further modifs in yao, hence yao can still be used safely without a gui (scripts, scripts). - migrated to a flat directory structure for yao. There is no more yao_fftw subdirectory - This is now meant to be installed in i0, so the path to the yao required functions has been changed from yao/file.i to file.i version 3.81, 2007jun02: added gui_message version 3.80, 2007apr19: now 64 bits safe ! version 3.75, 2007feb22: added angle offset for curvature wfs and dms 2006mar01: corrected bug. reset put command to 0, while it needed to zero dm._command v3.6 2005dec01 - renamed aosimul -> yao - reworked files and directory structure to accommodate new yorick plugin binary distribution scheme. - aoloop now -> aoloop + go structure to have prompt active while the loop is running. type "stop" to stopo the loop and "cont" to resume it. - simple principle demo of tyk control v3.4.0 2004sep10 - Makefiles completely reworked. Install more easy. See README in distribution directory (yao_veclib or yao_fftw) for more info. - added a printout of the yao versoin used in yao_fast.i's - modified to include yao and yao_fast.i at parse - This is the first version compatible with plugins. - modified tic and tac to accomodate multiple counters - now the "Time Left" functionality works again. v3.3.2 2004aug02 - fixed a few bugs: - a division by zero was causing a SIGFPE for odd number of subaperture shack hartmann systems in the angle/elongation calculations in shwfs_init (bug noted by Miska) - Added a check of indices overflow when determining the Y interpolation points in get_turb_phase_init v3.3 2004July28 - semi major changes in this version. Watch out, as some parameters meaning has changed (I know this is silly, but it's more logical now) - Implemented zenith dependance. Now one can change one parameter (gs.zenithangle) and everything change as needed (r0, lgs altitude and thickness of Na layer, atm layer altitude, LGS brightness) - Imlemented Rayleigh fratricide effect for multiple LGS systems! This was quite an endeavour. I had to modify the _shwfs routine to include several new lines and parameters relative to Rayleigh and calibration (a side effect is that we can now do and use calibration frame in this routine). To enable Rayleigh calculations set wfs.rayleighflag to 1 (it will *not* be calculated for NGS WFS as it is assumed that you can easily block the light from the laser wavelength). - The way to specify the photometry has also changed. Now, if you deal with a LGS, you specify a power and a return per watt, not anymore a magnitude (magnitude are still ok for a NGS). Also, everything -in term of zeropoints- is now specified at the entrance of the telescope: gs.zeropoint is now the number of photons for a zero mag star per sec per pupil at M1 (it used to be detected by the WFS). gs.lgsreturnperwatt is also in photons at M1. Instead, I have added a wfs.optthroughput parameter to specify the optical throughput of each WFS. Please set it, as it defaults to 1. - In summary, the following keywords were added in the parfile: - gs.lgsreturnperwatt - gs.zenithangle - wfs.laserpower - wfs.rayleighflag - wfs.optthroughput v3.2.3 2004jun07 - fixed a bug that yao_fftw could not write the file fftw_wisdom.dat in ~/Yorick. Made use of get_end("HOME") to get correct path. - fixed screen names in all example parfiles to 1,2,3,4 - changed several other minor inaccuracies v3.2.2 2004jun07 - Yao is now under CVS! - several cosmetic modifications (this NOTES file, ...) - changed convVE -> convol for compat with yao_fftw in aoutil.i v3.2.1 2004apr29 - implemented sky and dark current in WFS structure and in yao_fast.c, both veclib and fftw. checked by printing _fimage, (sum) and (rms). for a 4cell. the level is OK and the noise is OK. - implemented the same for the CWFS. Note that the dark current is per channel and per sample, i.e. for 2 reads (each extra-focal image). Per read, the dark current is taken as wfs.darkcurrent/2 v3.2.0 2004apr07 - reworked the distribution tree - implemented a faster computation of the DM shape for PZT DMs where only the relevant subarray is used in the summation. Instead of precomputing the Influence function (IF) on the whole pupil, I compute it on a fraction of it and store the indices. The branch is done in the new function comp_dm_shape. if dm.elt == 1, then we use the new and faster method. To date, dm.elt is set to 1 in check_parameters (aoutil.i) for any strackarray DM. This is just a patch for now as there is a problem with the computation of the anisoplanatism modes. v2.5.3 2004mar11 - found and fixed a bug in the determination of wfs._tiprefv and wfs._tiltrefv. - implemented dithering for LGS (using uplink, so only for LGS) v2.5.2 2004mar10 - added capability to have extrapolated actuators. I have done that with only a few lines of codes, which tends to prove that the code is easy to upgrade and relatively well structured (allright, subjective judgement!). v2.5.1 2004mar02 - fined tuned the spot elongation - changed wfs.imatkernel into wfs.kernel (serves also for LGS spot FWHM in aoloop) v2.5 2004feb13 - implemented the LGS spot elongation: - added a number of _entries in wfs structures (_kernels, _kerfftr, _kerffti, _x, _y) - modified shwfs_init accordingly - added the element wfs.LLTxy - added wfs.gsdepth v2.4.1 2004jan30 - Strehl, fwhm and e50 are now extern variables so one can access them after completion of aoloop. - added wfs.fracIllum = fraction of subaper. illuminated for sub to be valid - reworked configuration graphical display ( graphic_config() ). - added the possibility to interactively select the threshold for valid/not valid actuators (put dm.thresholdresp = -1 in parfile) v2.4 2004jan22 - written and implemented parameterCheck, to check parameters in aoread. - rather big change, at least in matter of compatibility: I have changed the normalization of the phase, IFs and phase screens. Previously, the problem was that I could not have different lambda per sensor, as the input phase screens are normalized at one single given dr0. Now the input dr0 is given at 0.5 microns, and everything is normalized in microns (IF, phase screens, phase). New keyword: atm.dr0at05mic, instead of atm.dr0 v2.3.2 2004jan21 - I got the MCAO LGS working nicely !! with the anisoplanatism modes as they are handled in MCAO, and implemented in a simple, non obstrusive way. Great. I had to think a long time about the best way to implement it, but now it's done. - worked out the output to the file parprefix+".res" - debugged quite a bit with different parfiles - implemented a new input "sim.name" that contains a comment string to put on all graphics. - reworked the format of some output (e.g. WFS parameters) v2.3.1 2004jan20 - implemented different subsystem, i.e. each dm and wfs is specified to belong to a given subsystem. The cMat for each subsystem is then computed separately. This allow a good separation of e.g. the TT NGS WFS and the HO LGS WFS in a LGS system. I have added the following keywords: - wfs.subsystem - dm.subsystem - mat.condition is now a pointer to a vector of condition numbers v2.3.0 2004jan18 - implemented ShWFS method 1, i.e. straight gradient average, method 2 being the full propagation calculations. - implemented bias and flat in ShWFS, method 2 (new keywords wfs.biasrmserror and wfs.flatrmserror) - implemented target multi-lambda PSF. Changed target.lambda, now a pointer, use to be a float. e.g. target.lambda = &([1.25,2.2]*1e-6) note 2004jan22: now lambda in microns - implemented hysteresis on DMs. Adapted routine from idl routine new parameter dm.hyst - passed thresholdresp from hardcoded to parameter, dm.thresholdresp, separate for each DM. - implemented central obstruction. v2.2.4 2004jan12 - implemented gaussian and poisson noise in shwfs and cwfs ! - implemented the correction of the uplink TT for LGS. v2.2.3 2004jan11 - added proper reference measurement subtraction - added tip-tilt filtering of WFS measurements v2.2.2 2004jan11 - fixed a rather major bug in the computation of the DM shapes. In my haste of implementing the get2dphase, I had used only one interpolation x coordinate vector (see get_turb_phase_init). I was using the vector precomputed for the screens, for the DM... I have fixed it by computing dmxposcub (and y). - Got back to using *dm._def instead of the def variable to stock the influence functions. This is because I can save much more space by allowing different n1 and n2 per mirror. v2.2 2003dec28 - coded _shwfs, shwfs routine in C, using veclib FFT call. - Got rid of wfs.shmethod in parfile - added wfs.npixels in parfile - changed wfs.subsize into wfs.pixsize in parfile - added the routine wfs_check_pixel_size - also, I have moved the influence function setup functions in aoutil.i to reduce the size of yao.i v2.0 2003dec12 - written and included "optimized" C routines in aoloop. - _fftVE to compute set of image from set of phases - _dmsum to compute mirror shape(s) from set of command - _get2dPhase to integrate a set of phase screens along a given direction and return an integrated phase. all in all, this has resulted in a rather large reduction of execution time in this routine (the most critical). When I started the optimization, I was at 10 iteration/sec for sh6.par, a 6x6 SH, 30 pixel pupil, 1 DM, 1 GS, 4 targets case. In the intermediate stage I am right now, with the 3D phase integral, the tagret FFTs and the DM shape computation optimized, I am now running at about 95 iterations per seconds on the G4. I am left with some optimization to do, namely the SH WFS and grouping the integrated phase and target image computation in one subroutine call. v1.2.5 2003Jun15 - added multi viewport display in aoloop v1.2.4 2003May8 - debugged and fixed the method 2 for SHWFS v1.2.3 2003mar16 - modified support of IFs to reduce RAM consumption. before: with tests/mcao.par (5wfs, 3dm, 16x16, 64x64 pupil), the ram (RSIZE) was 37M at the complexion of the IF calculation. v1.2.2 2003mar03 - added some graphics output at the end of aoinit - added some comment and general explanation of calling sequences below v1.2.1 Feb 2003. - Modified the selection of valid actuators to cope with altitude DMs. v1.2 February 2003. - a whole lot of changes in this version, which is basically made to handle MCAO, i.e. one or more DM, one or more WFS. Should be able to deal with Classical AO, altitude conjugated AO, ground conjugated wide field AO, MCAO. - The input parameter file has been changed, together with the code. Now each DM and each WFS has its own parameter set stored in a structure. The idea is that the structure is loaded into a working structure before one calls the WFS routine. feb 24, 00:35. This version seems now stable enough that I can freeze it and go on subversion for improvements - the basic layout of the software is now as follow: - in aoloop: - aoloop calls mult_wfs(iter). - for each WFSs, mult_wfs calls get_phase2d_from_dms(offsets,gsalt), which returns the integrated phase along the line of sight for the given WFS (offset,gsalt). The core shifting routine of get_phase2d_from_dms is interp2dmir. - for each WFS, multWFS calls get_turb_phase(iter,#star,starType (wfs|target)), which returns the integrated phase accross the phase screens for the given star and iteration #. The core shifting routine of get_turb_phase is interp2dturb. - mult_wfs then execute the given WFS routine on the total phase and returns the cummulative measurement vector. - aoloop then manages the WFS measurement vector history to pass the vector with correct delay to the matrix multiplication - multiplication by command matrix. - for each mirror, the mirror shape is constructed from the command vector and stored in "mircube(size,size,ndm)". - if certain conditions are met, the PSFs are computed at all needed points in the FoV, and statistics are accumulated. - To summarize: 1) aoloop 1.1) multWFS(iter,ok), for each sensor: 1.1.1) get_phase2d_from_dms(offsets,gsalt) 1.1.1.1) interp2dmir(shifts) 1.1.2) get_turb_phase(iter,gsalt,ok) 1.1.2.1) interp2dturb(shifts) 1.1.3) Get and accumulate sensor measurements 1.2) delay management 1.3) multiply by cMat 1.4) compute PSFs and accumulate statistics if ok to do so. v1.0.8 February 7, 2003 - upgraded all calls to fits_read and fits_write (from fitsRead and fitsWrite, to conform to fits2.i) - fixed one problem in make_pzt_dm (wrong pitch) - also IF back to log form (laserdot form) as sinc is no good. - SVdec broken in last yorick versions. Works with 1.5.13 - implemented debug printout and displays - This version is fully functional. v1.0.7 June 17, 2002, FR - added some parameters (LoopFrameDelay, LoopModalGainFile) - implemented modal gain optimization routine. v1.0.6 - Remove ao.Size from accesible structure. Set in aoinit. - Cleaned up par file - Trim ActIF at the end of aoinit (therefore for use in aoloop). This saves a lot of computation time in the mirror surface calculation. v1.0.5 First Release, June 11, 2002, FR BUGS: ----- - dm.elt is not compatible with MCAO systems, or more generally "aniso" DMs. This is because one has to project on modes and this is not possible with the localized version of dm shape computation (with dm.elt=1). TO DO: ------ - implement NCPAs - add a red light when actuators are saturating in the controlscreen (and the number of saturated actuators) ---------------------------------------------------------------------- YAO_FFTW: Note: updated 2007jun03 This directory includes all the files necessary for the production of the executable "yao" (Yorick Adaptive Optics). This package makes use of dedicated C routines to compute wavefront sensor images/signal, deformable mirror shape, etc... It uses fast FFT routines from FFTW. FFTW HAS TO BE INSTALLED ON YOUR SYSTEM (see below). //============================================================= INSTRUCTION FOR THE COMPILATION OF YAO_FFTW: 1. First Update the Makefile: yorick -batch make.i NOTE: if you don't have yorick in your path, or don't have a symlink to it, you can specify the path by hand: e.g.: ../../../Darwin-Power_Macintosh/bin/yorick -batch make.i or ../../../Linux-i686/bin/yorick -batch make.i 2. If you have installed FFTW3 locally (i.e. not system wide install, that is you used the -prefix="/some/path/in/your/home/directory/fftw3/" when compiling FFTW3), then you have to edit manually the Makefile and update the path to the libraries and include files. I have put a FFTW3_PATH variable that you need to update to reflect your installation, e.g.: FFTW3_PATH=/home/frigaut/fftw3 3. Update the path to the yorick executable (search for YORICK_EXE at the end of the Makefile). 4. Compile, test and install the plugin: make make check make install You may want to specify optimization flags when building the plugin. Here is the one I use: On a Apple G4: make plugin COPTIONS="-O3 -fomit-frame-pointer -mcpu=7450" On a Apple G5: make plugin COPTIONS="-O3 -fomit-frame-pointer -fstrict-aliasing -mcpu=970 -mtune=970 -mpowerpc-gpopt" for a Linux system: make COPTIONS="your favorite options, if any" 5. yao should be installed. Now you can start a regular yorick session and type #include "path_to_include_file/yao.i" e.g. #include "yao/yao.i" if the yao tree is installed in Y_SITE/contrib This will include all the necessary files and load the plugin you just built. //============================================================= HOW TO INSTALL FFTW3: Obviously, if you are on a debian or fedora type system, you can easily install fftw3 fro the repositories. If not: 1. Download fftw3 from http://www.fftw.org/ 2. gunzip and untar the package 3. configure and compile. You have to use special compilation flags to enable the use of the vectorial processor on your machine (if you have any). Also, you have to enable fftw3f, i.e. float operation (yao uses floats for FFTs). --enable-float enables float operations. If you don't have root privilege, you can install fftw3 locally. Use the --prefix to do that (see an example below) Each machine takes different flags. A good resource to find out which one you should use is the speed benchmark pages at fftw.org (http://www.fftw.org/speed/), i.e. http://www.fftw.org/speed/g5-2GHz/ for the G5. For an Dual Ahtlon, I used: ./configure --enable-float --enable-k7 CFLAGS="-O2 -fomit-frame-pointer -Wall -W -Wcast-qual -Wpointer-arith -Wcast-align -pedantic -malign-double -fstrict-aliasing -mpreferred-stack-boundary=4 -mcpu=pentiumpro" -prefix="/home/frigaut/fftw3/" The -prefix="/home/frigaut/fftw3/" points to the local installation directory. For a G5, I use: ./configure --enable-float --enable-altivec CFLAGS="-O3 -fomit-frame-pointer -fstrict-aliasing -mcpu=970 -mtune=970 -mpowerpc-gpopt" For a G4: ./configure --enable-float --enable-altivec CFLAGS="-O3 -fomit-frame-pointer -mcpu=7450 -faltivec" then: make make install //============================================================== yao-5.4.0/TODO000066400000000000000000000132741234404334100130050ustar00rootroot00000000000000- is there a bug in the fact that the disk harmonic are not defined on a support larger than the pupil (for shmethod=1, don't we need one more pixel outside of pupil?) ??? same for KL. BUG: > dm(1).type="zernike" > dm(1).nzer=50 > dm(1).alt = 1000 > aoinit,disp=1,clean=1 Checking parameters ... Check parameters: OK nbigpixels = 16, wfsnpix = 18, npb=2 *** glibc detected *** /usr/lib/yorick/2.2/bin/yorick: malloc(): memory corruption: 0x0000000001f6cc70 *** dynamical range increase and lgs elongation plan B, 2012sep27: Not finished, to do: - fix normalization of wfs._lgs_defocuses - fix amplitude normalization - fix field stop. right now not shifted properly following shift of image To do, 5/8/2011: - LLTxy in mcao_rayleigh - solve issue with GMT pupil and LLT location (both elongation and fratricide) Upgrades: - add KL DM (done in 4.3.0) - add vibration spectrum (done) - slow down imat display (done in 4.3.0, use sleep=ms) - accept an odd # of pixels / subaperture (on CCD) (upgraded in 4.3.1) - add neighbor overlap between SH subapertures (done in 4.3.2) - implement field stops (done in 4.3.2) - leaky integrator (done in 4.3.2) - up to tenth order filter (done in 4.3.2) - all SH possible config work (odd/even # subap and odd/even # of pixel/subap) - add non contiguous/arbitrary pupil (done) - add different pupil for WFS and imager (already exist) - segmented pupil (done) - segmented DM (done) - added a number of user functions, that are called if they are defined (user_pupil, user_loop_err, user_loop_command) - cleanup the code somewhat: - created yao_wfs.i and relocated all wfs related functions - created yao_dm.i and relocated all dm related functions - created yao_structures.i and relocated all struct definitions - changed all function names from old style (with capitals, e.g. checkParameters) to new style (no capital, but underscores, e.g. check_parameters). To keep the API compatibility with existing user code, I have copied the function names into the old names (see API compat section at the end of yao.i). future plans (not done): - hexagonal stackarray configuration - POLC - User cmat - separate display routines (e.g. that can be called by the user, like display wfs 1 config, or display filtered modes in svd, etc...) - clean up and fine tune the rayleigh calculatio. Right now I have a feeling it's only one number per subaperture. I mean, the subap is assumed to be punctual, located at the center of the subap. a better approach would be to compute the thing for a number of point in the subaperture entrance pupil. bug to fix / fixed: - desired pixel size is wrong (done 4.3.0) - bug with extrapolated counted several time (clean=1) (done 4.3.0) - solved zernike IF for altitude DM (radius was not good 4.3.0) - merged many new things from yao_mcao (done in 4.3.0) - added dm.xflip and yflip (done in 4.3.0) - added dm.irexp (done in 4.3.0) - can now use dm.elt with aniso modes. (done in 4.3.0) - skymag not set to zero when doing imat (done) - bad normalization of sky with field stop (done) - bad normalization of star with field stop (done) - fix mesvec length in shwfs_simple (done) - fixed bug in which user would be stuck at prompt when doing interactive SVD (fixed) - dispImImav reverse behavior to expected. (fixed) - setting npixpersub is not taken into account system wide (fixed) - fixed a small bug in phase screen generation (max offseted (1,1)) - fixed mess in actuator/subaperture order. now both go from bottom left to top right, in line (i.e. subap/act#2 is at right of subap/act#1) Other for changelog: - updated many help document section (yao.i, yao_wfs.i) TO SOLVE for GMT: - bug with extraps - when makepztif and displayed, IF are not offseted - find a simple way to select between gspos-based and pupoffset based for display of wfs._fimage (done, wfs_display_mode="spatial") - one DM overlap on neighbor primary (solved) - there is a tilt in the corrected phase (on the dms) while the image is centered (not sure) no, was not a problem. it's the DM shape that are displayed, stupid. - does not seem to play well with the gtk GUI (solved) --------------------------------------------------------------- for GMT: see gmt.par need a special pupil definition func(), user_pupil need to redefine ipupil (wfs) and pupil (image) but also to define disjointpup a datacube of which each plan is dimsof(ipupil) and represent the pupil to apply for a particular primary (up to 7 in th ecase of the GMT) set keywords: dm.disjointpup = 1 wfs.disjointpup = 1 for the dm and wfs (resp) to take into account the disjoint pupils, i.e. to *not* see the part fo the phase that it should not see because it goes through different optics. wfs_display_mode = "spatial" set if any wfs.pupoffset is non-zero. sorry, for now can't have both the spatial AND angular display Compatibility: new yao is fully compatible with old parfile and user code. However, it is *not* compatible with binary configs saved with previous version. This means that you will have to remember to re-run aoinit with option clean=1 for doc: new go,all=1 api describe API to user_pupil, user_wfs and user_dm user_loop_err user_loop_command,nm ------------------------------------------------------------------ RAM requirement: teldiam = 42; pupd = 84*10; nxsub = 84; seeing = 0.7; shmethod = 2 1350MB peak @ imat taking 1.1 actuator/seconds -> 85mn for imat teldiam = 16; pupd = 240; nxsub = 40; seeing = 0.7; 166MB peak @ imat taking 9.501409 iterations/second in average 400MB peak at inversion 280MB peak in aoloop teldiam = 30; pupd = 500; nxsub = 50; seeing = 0.7; 340MB while taking imat imat 50 act in 15 sec -> 3.2 act/sec RAM 830MB peak during inverse RAM 650MB during loop it/sec loop: 2.7 yao-5.4.0/aoSimulUtils.c000066400000000000000000000172161234404334100151130ustar00rootroot00000000000000/* * aoSimulUtils.c * * C utility functions for yao * * This file contains a number or C routines used in conjunction with * yao.i, the AO simulation tool written in Yorick. This codes * efficiently, in C, the most critical elements of the AO loop (func- * tion aoloop in yao.i, for yao versions > 2.0. * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ /************************************************************************ * Function int _get2dPhase * * Computes the integrated phase along one given direction (angle) * * All init data are pre-computed to accelerate execution time within * * the time critical aoloop() in yao.i. * * Last modified: Dec 12, 2003. * * Author: F.Rigaut * ************************************************************************/ int _get2dPhase(float *pscreens, /* dimension [psnx,psny,nscreens] */ int psnx, int psny, int nscreens, float *outphase, /* dimension [phnx,phny] */ int phnx, int phny, int *ishifts, /* array of X integer shifts dimension [phnx,nscreens] */ float *xshifts, /* array of X fractional shifts dimension [phnx,nscreens] */ int *jshifts, /* array of Y integer shifts dimension [phnx,nscreens] */ float *yshifts) /* array of Y fractional shifts dimension [phnx,nscreens] */ /* ishifts[k,nscreens] and jshifts[k,nscreens] are the integer shifts for screen[k] xshifts[k,nscreens] and yshifts[k,nscreens] are the fractional shifts for screen[k], */ { int i,j,k,ips,jps; int firstel; float wx1,wx2,wy1,wy2; /* Loop on phase screens */ for (k=0;k= (psnx*psny*nscreens) ) {return (1);} /* Finaly, compute and integrate outphase */ outphase[i+j*phnx] += ( wx1*wy1*pscreens[firstel+ips+jps*psnx] + wx2*wy1*pscreens[firstel+ips+1+jps*psnx] + wx1*wy2*pscreens[firstel+ips+(jps+1)*psnx] + wx2*wy2*pscreens[firstel+ips+1+(jps+1)*psnx]); } } } return(0); } /************************************************************************ * Function void _dmsum * * This routine simply loop on the number of actuator and computes the * * DM global shape, given a serie of influence functions and a command * * vector. It can also accomodate more than one DM. * * It saves a bunch of time in aoloop() for such a simple function. * * Last modified: Dec 14, 2003. * * Author: F.Rigaut * ************************************************************************/ void _dmsum(float *def, // pointer to dm influence functions int nxdef, // X dim int nydef, // Y dim int nzdef, // Z (3rd) dim = # IFs float *coefs, // command coefficients float *dmshape) // pointer to output phase. { /* Declarations */ int i, k; int n = (nxdef*nydef); float co; /* Zero out dmshape */ for ( i=0 ; i (outnx-1)) ) continue; for ( j=0 ; j (outny-1)) ) continue; // now we map the def indices into the output array indices ioff = (i1[k]+i) + outnx*(j1[k]+j); dmshape[ioff] += co * def[i+nxdef*j+n*k]; } } } } yao-5.4.0/aoutil.i000066400000000000000000002042361234404334100137640ustar00rootroot00000000000000/* AOUTIL.I * * A collection of utility routines to go with yao.i * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ func create_yao_window(dpi) /* DOCUMENT create_yao_window(dpi) Open or re-open (e.g. after a fork() ) the main and only yao graphical window. SEE ALSO: */ { // dpi is in fact already stored in extern (sigh) if (!dpi) dpi=default_dpi; if (window_exists(0)) winkill,0; if (window_exists(2)) winkill,2; if (yao_pyk_parent_id) { // there's a GUI, re-parent within GUI drawingarea: yao_win_init,yao_pyk_parent_id; } else { // there's no GUI, re-open normal graphical window:width=635,height=650 window,0,style="yao.gs",dpi=dpi,width=long(635*(dpi/75.)), \ height=long(650*(dpi/75.)),wait=1; if ( (xft!=[]) && (xft()) ) { get_style, landscape, systems, legends, clegends; systems.ticks.vert.textStyle.height(4)*=1.5; systems.ticks.horiz.textStyle.height(4)*=1.5; set_style, landscape, systems, legends, clegends; } } plsys,1; limits,square=1; plsys,2; limits,square=1; } //---------------------------------------------------- //func xyxy2xxyy(void) func xxyy2xyxy(void) { offset=0; for (n=1;n<=nwfs;n++) { grow,reordered,transpose(reform(indgen(wfs(n)._nmes), [2,wfs(n)._nsub,2]))(*)+offset; offset+=wfs(n)._nmes; } return reordered; } //---------------------------------------------------- func get_turb_phase_initCheckOverflow(void) /* DOCUMENT func get_turb_phase_initCheckOverflow This routine has the sole purpose of checking the possible "overflow" of the Y index in the future calls to get_turb_phase. In any of the Y index at which the interpolation is to be done is larger than the phase screen(s) Y dimension, then an error is flagged. SEE ALSO: get_turb_phase_init, get_turb_phase */ { extern screendim; dimy = screendim(2); if (max(wfsyposcub(max,,)+yposvec(max,)(,-)) > dimy) { write,"\nSome of the phase screens are too small (Y dimension) "+ "for the specified system."; write,format="The following WFS/screens will cause a "+ "index overflow (current Ydim is %d):\n",dimy; maxind = wfsyposcub(max,,)+yposvec(max,)(,-); w2 = where2(maxind > dimy); for (i=1;i<=dimsof(w2)(3);i++) { write,format="WFS#%d, screen#%d, Ymax=%f\n",w2(2,i),w2(1,i), maxind(w2(1,i),w2(2,i)); } write,"To remedy this situation, you can either:"; write," - use larger phase screens (Y axis) using 'create_phase_screens'"; write," - Modify the extremum Y offsets of your WFSs"; write," - Lower the altitude of the offending atmospheric layer"; exit; } if (max(gsyposcub(max,,)+yposvec(max,)(,-)) > dimy) { write,"\nSome of the phase screens are too small (Y dimension) "+ "for the specified system."; write,format="The following Perf Star/screens will cause a "+ "index overflow (current Ydim is %d):\n",dimy; maxind = gsyposcub(max,,)+yposvec(max,)(,-); w2 = where2(maxind > dimy); for (i=1;i<=dimsof(w2)(3);i++) { write,format="Perf.Star#%d, screen#%d, Ymax=%f\n",w2(2,i),w2(1,i), maxind(w2(1,i),w2(2,i)); } write,"To remedy this situation, you can either:"; write," - use larger phase screens (Y axis) using 'create_phase_screens'"; write," - Modify the Y position of your Perf. Star"; write," - Lower the altitude of the offending atmospheric layer"; exit; } } //---------------------------------------------------- func graphic_config(subsystemnum,dmnum) /* DOCUMENT func configGraphic(void) Plots a graphical representation of the system config, per subsystem and per level (altitude) subsystemnum and dmnum optional. If not set all subsystems and dms are displayed SEE ALSO: */ { t = span(0.,2*pi,100); col = ["red","blue","green","cyan","magenta","yellow"]; markers = ['1','2','3','4','5','6','7','8','9']; markers = char(indgen(36)+48); // 1,2,...A,B... maxcol = numberof(col); plsys,1; limits,square=1; psize = tel.diam/sim.pupildiam; for (nss=1;nss<=max(dm.subsystem);nss++) { if ( (subsystemnum != [] ) && (subsystemnum != nss) ) continue; fma; // one level by one level for (i=1;i<=ndm;i++) { if ( (dmnum != [] ) && (dmnum != i) ) continue; if ( dm(i).subsystem != nss ) continue; if ( dm(i).type == "aniso" ) continue; for (j=1;j<=nwfs;j++) { if ( wfs(j).subsystem != nss ) continue; // overplot subaperture position and size for first wfs in this subsystem first_wfs_plotted = 0; if ( (first_wfs_plotted==0) && (dm(i).alt==0.) && (dm(i).type!="tiptilt") ) { for (jj=1;jj<=wfs(j)._nsub4disp;jj++) { if ((*wfs(j)._validsubs)(jj)==0) continue; x1 = (*wfs(j)._istart)(jj); y1 = (*wfs(j)._jstart)(jj); subsize = sim.pupildiam/wfs(j).shnxsub; if (wfs(j).npixpersub) subsize = wfs(j).npixpersub; l1 = subsize; // convert pixels in meters x1 = (x1-sim._cent)*tel.diam/sim.pupildiam; y1 = (y1-sim._cent)*tel.diam/sim.pupildiam; l1 = l1*tel.diam/sim.pupildiam; plg,_(y1,y1,y1+l1,y1+l1,y1),_(x1,x1+l1,x1+l1,x1,x1),color=[50,50,50]; } first_wfs_plotted = 1; } } // radius of outmost actuator in meters: // rad = (dm(i).nxact-1)/2.*dm(i).pitch*psize; // plots circle containing all actuators // plg,rad*sin(t),rad*cos(t),type=2; // radius of outmost object beam in meter: tmp = sqrt((*target.xposition)^2.+(*target.yposition)^2.); maxobjrad = max(tmp); rad = max(tmp)*4.848e-6*dm(i).alt+tel.diam/2.; // plots circle containing all rays from objects: plg,rad*sin(t),rad*cos(t),type=3; if ( dm(i).type == "stackarray" ) { // build array containing (x,y) location of valid/controlled actuators: loc = ([*(dm(i)._x),*(dm(i)._y)]-sim._cent)*psize; // and plot: plg,loc(,2),loc(,1),type=0,marker=markers(i),color=col(i%maxcol); if (numberof(*dm(i)._ex) != 0) { // build array containing (x,y) location of extrapolated actuators: loc = ([*(dm(i)._ex),*(dm(i)._ey)]-sim._cent)*psize; // and plot: plg,loc(,2),loc(,1),type=0,marker=markers(i); } } // loop on sensor: for (j=1;j<=nwfs;j++) { if ( wfs(j).subsystem != nss ) continue; // computes scaling factor due to limited altitude: if (wfs(j)._gsalt != 0) { fact = (wfs(j)._gsalt-dm(i).alt)/wfs(j)._gsalt; } else { fact=1; } offsets = wfs(j).gspos*4.848e-6*dm(i).alt; rad=tel.diam/2.*fact; // plotting beam shape for this wfs at this dm altitude: plg,offsets(2)+rad*sin(t),offsets(1)+rad*cos(t),color=col(i%maxcol),width=3; } myxytitles,"Beam outline [m]","Beam outline [m]",[0.02,0.02]; mypltitle,swrite(format="Patches of guide star beams on DM#%d, Subsystem %d",i,nss); comment = swrite(format="Configuration actuator/beams in a plane at altitude %.0f\n"+ "Solid lines: Outline of this subsystem GS beams\n"+ "Dotted line: Circle including outermost ray to specified science \n"+ " objects (at %.1f arcsec off-center)\n"+ "Numbers for stackarrays actuators: colored:controlled, BW: extrapolated\n"+ "# of active actuators= %d, # of extrapolated actuators=%d", dm(i).alt,maxobjrad,dm(i)._nact,dm(i)._enact); plt,comment,0.06,0.22,tosys=0,justify="LT"; plt,sim.name,0.01,0.227,tosys=0; limits; lim=limits(); limits,lim(1)*1.1,lim(2)*1.1,lim(3)*1.1,lim(4)*1.1; hcp; if (sim.debug >=1) typeReturn; fma; } if ( subsystemnum != [] ) continue; // all levels for (i=1;i<=ndm;i++) { if ( dm(i).subsystem != nss ) continue; if ( dm(i).type == "aniso" ) continue; // radius of outmost actuator in meters: rad = (dm(i).nxact-1)/2.*dm(i).pitch*psize; // plots circle containing all actuators plg,rad*sin(t),rad*cos(t),type=i; if ( dm(i).type == "stackarray" ) { // build array containing (x,y) location of valid actuators: loc = ([*(dm(i)._x),*(dm(i)._y)]-sim._cent)*psize; // and plot: plg,loc(,2),loc(,1),type=0,marker=markers(i),color=col(i%maxcol); } // loop on sensor: for (j=1;j<=nwfs;j++) { if ( wfs(j).subsystem != nss ) continue; // computes scaling factor due to limited altitude: if (wfs(j)._gsalt != 0) { fact = (wfs(j)._gsalt-dm(i).alt)/wfs(j)._gsalt; } else { fact=1; } offsets = wfs(j).gspos*4.848e-6*dm(i).alt; rad=tel.diam/2.*fact; // plotting beam shape for this wfs at this dm altitude: plg,offsets(2)+rad*sin(t),offsets(1)+rad*cos(t),color=col(i%maxcol),width=3; } } myxytitles,"Beam outline [m]","Beam outline [m]",[0.02,0.02]; mypltitle,swrite(format="Patches of guide star beams on DMs, Subsystem %d",nss); plt,sim.name,0.01,0.227,tosys=0; limits; lim=limits(); limits,lim(1)*1.1,lim(2)*1.1,lim(3)*1.1,lim(4)*1.1; hcp; if (sim.debug >=1) typeReturn; } } //---------------------------------------------------- func check_parameters(void) /* DOCUMENT func check_parameters(void) Check the parameters in yao parfile - set defaults - value valid? - compatibility with other parameters SEE ALSO: */ { extern sim,atm,wfs,dm,mat,tel,target,gs,loop; if (sim.verbose) write,format="Checking parameters ... %s\n",""; //================================================================== // BASIC EXISTENCE AND CONSISTENCY CHECKINGS AND DEFAULT ASSIGNMENTS //================================================================== extern nwfs,ndm,ntarget,noptics; nwfs = numberof(wfs); ndm = numberof(dm); ntarget = numberof(*target.lambda); noptics = numberof(opt); // SIM STRUCTURE if (sim.pupildiam == 0) {exit,"sim.pupildiam has not been set";} if ( ((sim.svipc>>2)&1) && (!((sim.svipc>>0)&1)) ) { write,"If you have (sim.svipc>>2)&1, you should have (sim.svipc>>0)&1"; write,"Setting sim.svipc first bit to 1" sim.svipc++; pause,2000; } if (sim.svipc_wfs_nfork>nwfs) { write,"sim.svipc_wfs_nfork > nwfs, setting sim.svipc_wfs_nfork = nwfs" sim.svipc_wfs_nfork = nwfs; pause,2000; } // ATM STRUCTURE if ((*atm.screen) == []) {exit,"atm.screen has not been set";} if (typeof(*atm.screen) != "string") {exit,"*atm.screen is not a string";} ftmp = *atm.screen; for (i=1;i<=numberof(ftmp);i++) { if (!open(ftmp(i),"r",1)) { // file does not exist msg = swrite(format="Phase screen %s not found!\\n"+ "You need to generate phase screens for yao.\\n"+ "Go to \"Phase Screen -> Create phase Screen\"\\n"+ "If you already have phase screens, you can modify\\n"+ "the path in the parfile atm.screen definition",ftmp(i)); if (_pyk_proc) pyk,"set_cursor_busy(0)"; pyk_warning,msg; msg = swrite(format="\nWARNING: %s not found!\nEdit the par file and change the "+ "path,\nand/or run \"Phase Screen -> Create phase Screen\"\n",ftmp(i)); write,msg; break; } } if ((*atm.layerfrac) == []) {exit,"atm.layerfrac has not been set";} if ((*atm.layerspeed) == []) {exit,"atm.layerspeed has not been set";} if ((*atm.layeralt) == []) {exit,"atm.layeralt has not been set";} if ((*atm.winddir) == []) {exit,"atm.winddir has not been set";} if (nallof(_(numberof(*atm.screen),numberof(*atm.layerfrac),numberof(*atm.layerspeed), \ numberof(*atm.layeralt)) == numberof(*atm.winddir))) { exit,"Some elements within atm.screen, layerfrac, layerspeed, layeralt \n"+\ "or winddir do not have the same number of elements."; } // WFS STRUCTURE for (ns=1;ns<=nwfs;ns++) { if (wfs(ns).type == string()) { exit,swrite(format="wfs(%d).type has not been set",ns); } // if (wfs(ns).subsystem == 0) {wfs(ns).subsystem = 1;} if (wfs(ns).lambda == 0) { exit,swrite(format="wfs(%d).lambda has not been set",ns); } //~ if (wfs(ns).dispzoom == 0) {wfs(ns).dispzoom = 1;} if ((wfs(ns).type == "curvature") && ((*wfs(ns).nsubperring) == [])) { write,format="wfs(%d).nsubperring has not been set.\n",ns; write,"Valid values are, for example:"; exit,"wfs(n).nsubperring = &([6,12,18]);"; } if ((wfs(ns).type == "curvature") && (wfs(ns).l == 0)) { exit,swrite(format="wfs(%d).l has not been set",ns); } if ((wfs(ns).type == "curvature") && (wfs(ns).gsdepth > 0)) { exit,swrite(format="wfs(%d): gsdepth not implemented for CWFS, sorry",ns); } if ((wfs(ns).type == "curvature") && (wfs(ns).rayleighflag == 1)) { exit,swrite(format="wfs(%d): Rayleigh not implemented for CWFS, sorry",ns); } if ((wfs(ns).gsalt == 0) && (wfs(ns).rayleighflag == 1)) { write,swrite(format="wfs(%d): gsalt = 0 and Rayleigh flag is set !",ns); exit,"Rayleigh is not computed for NGS sensors, sorry."; } if ((wfs(ns).gsalt > 0) && (wfs(ns).laserpower == 0)) { exit,swrite(format="wfs(%d): this is a LGS and you haven't set wfs.laserpower",ns); } if ((wfs(ns).type == "curvature") && (wfs(ns).fieldstopdiam == 0)) { wfs(ns).fieldstopdiam = 1.f; } if ((wfs(ns).type == "hartmann") && (wfs(ns).shmethod == 0)) { exit,swrite(format="wfs(%d).shmethod has not been set",ns); } if ((wfs(ns).type == "hartmann") && (wfs(ns).shnxsub == 0)) { exit,swrite(format="wfs(%d).shnxsub has not been set",ns); } if ((wfs(ns).type == "hartmann") && (wfs(ns).shmethod == 2)) { if ((wfs(ns).type == "hartmann") && (wfs(ns).pixsize == 0)) { exit,swrite(format="wfs(%d).pixsize has not been set",ns); } if ((wfs(ns).type == "hartmann") && (wfs(ns).npixels == 0)) { exit,swrite(format="wfs(%d).npixels has not been set",ns); } if ((wfs(ns).type == "hartmann") && (wfs(ns).shthmethod == 0)) { wfs(ns).shthmethod = 1; } if ((wfs(ns).type == "hartmann") && (wfs(ns).shthmethod == 3) && ((wfs(ns).shthreshold > (wfs(ns).npixels)^2) || (wfs(ns).shthreshold <= 0))) { exit,swrite(format="Wrong wfs(%d).shthreshold value for wfs(%d).shthmethod = %d",ns,ns,wfs(ns).shthmethod); } } if ((wfs(ns).type == "hartmann") && (wfs(ns).shmethod == 2)) { if ((strlen(wfs(ns).fsname)>0) && (strlen(wfs(ns).fstop)>0)) { write,format="You have set both wfs(%d).fsname and wfs(%d).fstop\n",ns,ns; write,format="I will ignore wfs(%d).fstop and use wfs(%d).fsname !\n",ns,ns; } if ((strlen(wfs(ns).fsname)==0) && (strlen(wfs(ns).fstop)==0)) { write,format="No field stop defined for wfs %d. Setting to 'square'\n",ns; wfs(ns).fstop = "square"; } if (wfs(ns).fssize==0) { write,format="wfs(%d).fssize has not been set, will be forced to subap FoV\n",ns; } } if ((wfs(ns).type != "hartmann")&&(wfs(ns).LLT_uplink_turb)) { write,format="WARNING, wfs#%d: LLT_uplink_turb only implemented for SHWFS, ignoring.\n",ns; } if (wfs(ns).LLT_uplink_turb) { if ((wfs(ns).LLTr0==0)) { write,format="WARNING, wfs(%d).LLTr0 undefined, Using atm-defined r0\n",ns; wfs(ns).LLTr0 = tel.diam/atm.dr0at05mic * (wfs(ns).lambda/0.5)^1.2; } if ((wfs(ns).LLTdiam==0)) \ error,swrite(format="wfs#%d: LLT_uplink_turb set but LLTdiam not defined",ns); if ((wfs(ns).LLT1overe2diam==0)) \ error,swrite(format="wfs#%d: LLT_uplink_turb set but LLT1overe2diam not defined",ns); } if (wfs(ns).nintegcycles == 0) {wfs(ns).nintegcycles = 1;} if (wfs(ns).fracIllum == 0) {wfs(ns).fracIllum = 0.5;} if (wfs(ns).optthroughput == 0) {wfs(ns).optthroughput = 1.0;} if (wfs(ns).svipc>1) { if (wfs(ns).type!="hartmann") { write,format="wfs(%d).svipc >1 only for SHWFS, will have no effect\n",ns; wfs(ns).svipc = 0; } else if (wfs(ns).shnxsub < 2) { write,format="wfs(%d).svipc >1 but SH 1x1 sub. Disabling ||.\n",ns; wfs(ns).svipc = 0; } } if (wfs(ns).type == "pyramid") { if ((wfs(ns).pyr_mod_loc!="after") && (wfs(ns).pyr_mod_loc!="before")) { write,format="wfs(%d).pyr_mod_loc is not set, setting to \"after\"\n",ns; } } wfs.ron = float(wfs.ron); if (!wfs(ns).lgs_prof_amp) wfs(ns).lgs_prof_amp = &float([0.]); if (!wfs(ns).lgs_prof_alt) wfs(ns).lgs_prof_alt = &float([0.]); if (numberof(*wfs(ns).lgs_prof_amp)!=numberof(*wfs(ns).lgs_prof_alt)) { error,"numberof(*wfs(ns).lgs_prof_amp)!=numberof(*wfs(ns).lgs_prof_alt)"; } } // DM STRUCTURE for (nm=1;nm<=ndm;nm++) { if (dm(nm).type == string()) { exit,swrite(format="dm(%d).type has not been set",nm); } // disk harmonic type string has changed. for compatibility // with old API: if (dm(nm).type == "diskharmonic") dm(nm).type = "dh"; if (dm(nm).subsystem == 0) {dm(nm).subsystem = 1;} if (dm(nm).iffile == string()) {dm(nm).iffile = "";} if (dm(nm).ecmatfile == string()) {dm(nm).ecmatfile = "";} if (dm(nm).push4imat == 0) {dm(nm).push4imat = 20;} if (dm(nm).thresholdresp == 0) {dm(nm).thresholdresp = 0.3;} if (dm(nm).gain == 0) {write,format=" WARNING: dm(%d).gain set to 0\n",nm;} if (dm(nm).unitpervolt == 0) { write,format=" WARNING: dm(%d).unitpervolt set to 0\n",nm; // below: this is stupid. but I don't dare to change it now (2011mar16) if ( (dm(nm).type == "tiptilt") || (dm(nm).type == "zernike")) { dm(nm).unitpervolt = 0.0005; } else if ( (dm(nm).type == "bimorph") || (dm(nm).type == "dh")) { dm(nm).unitpervolt = 1.0; } else { dm(nm).unitpervolt = 0.01; } write,format=" WARNING: dm(%d).unitpervolt overwritten to %f\n",nm,dm(nm).unitpervolt; } if ( (dm(nm).type == "bimorph") && ((*dm(nm).nelperring) == []) ) { write,format="dm(%d).nelperring has not been set.\n",nm; write,"Valid values are, for example:"; exit,"dm(n).nelperring = &([6,12,18]);"; } if ( (dm(nm).type == "stackarray") && (dm(nm).nxact == 0) ) { exit,swrite(format="dm(%d).nxact has not been set",nm); } if ( (dm(nm).type == "stackarray") && (dm(nm).pitch == 0) ) { exit,swrite(format="dm(%d).pitch has not been set",nm); } if (dm(nm).type=="stackarray") { if ((dm(nm).coupling<0.0) || (dm(nm).coupling>0.8)) { write,format="Invalid value for dm(%d).coupling -> %f\n",nm,dm(nm).coupling; exit,"Valid values from 0 to 0.80"; } } if ( (dm(nm).type == "zernike") && (dm(nm).nzer == 0) ) { exit,swrite(format="dm(%d).nzer has not been set",nm); } if ( (dm(nm).type == "dh") && (dm(nm).ndh == 0) ) { exit,swrite(format="dm(%d).ndh has not been set",nm); } if (dm(nm).minzer == 0) { dm(nm).minzer = 1; } if ( (dm(nm).filtertilt) && (noneof(dm(nm).type == ["zernike","stackarray"]) )) {write, "WARNING: filtertilt only defined for zernike and stackarray DMs";} if ( (dm(nm).type == "kl") && (dm(nm).nkl == 0) ) { exit,swrite(format="dm(%d).nkl has not been set",nm); } if (dm(nm).irexp==1) { if (dm(nm).irfact == 0.) { dm(nm).irfact = 1.; write,format="dm(%d).irfact set to %f\n",nm,dm(nm).irfact; } } // check that laplacian only applies to stackarrays if ((dm(nm).regtype == "laplacian") && (dm(nm).type != "stackarray")){ exit, "regtype can only be set to laplacian for stackarray DMs"; } // set the regparam for stack arrays to something other than 0 if ((dm(nm).type == "stackarray") && (dm(nm).regparam == 0)){ write,"Setting regparam to 1e-5"; dm(nm).regparam = 1e-5; } // check that any virtual DMs have a lower DM number than a DM that uses it if (*dm(nm).dmfit_which != []){ if (max(*dm(nm).dmfit_which) > nm){ write,format="Virtual DMs (%d) must have a lower numbering than the DM (%d) that fits to them\n",max(*dm(nm).dmfit_which),nm; exit, "Exiting"; } } if ((dm(nm).hyst < 0.)+(dm(nm).hyst > 0.25)){exit,"DM hysteresis must be between 0 and 0.25";} if (dm(nm).hyst > 0.){write,"WARNING: DM hysteresis implementation assumes that voltages are of the order of 0.1 to 10. If not, do not use hysteresis.";} } // MAT STRUCTURE if (mat.method == string()) {mat.method = "svd";}; if (mat.method == "svd"){ if ((*mat.condition) == []) {exit,"mat.condition has not been set";} if (numberof(*mat.condition) != max(_(wfs.subsystem,dm.subsystem)) ) { exit,"dimension of *mat.condition is not equal to the number of subsystems"; } } if (mat.file == string()) {mat.file = "";} if (mat.sparse_MR == long()){mat.sparse_MR = 10000;} if (mat.sparse_MN == long()){mat.sparse_MN = 200000;} if (mat.sparse_thresh == float()){mat.sparse_thresh = 1e-8;} if (mat.sparse_pcgtol == float()){mat.sparse_pcgtol = 1e-6;} if (mat.fit_subsamp == long()){mat.fit_subsamp = 1;} if (mat.fit_minval == float()){mat.fit_minval = 1e-2;} // TEL STRUCTURE if (tel.diam == 0) exit,"tel.diam has not been set"; // TARGET STRUCTURE if ((*target.lambda) == []) exit,"target.lambda has not been set"; if ((*target.xposition) == []) exit,"target.xposition has not been set"; if ((*target.yposition) == []) exit,"target.yposition has not been set"; if ((*target.dispzoom) == []) { target.dispzoom = &(array(1.,numberof(*target.xposition))); } if (nallof(_(numberof(*target.xposition), \ numberof(*target.yposition)) == numberof(*target.dispzoom) )) { exit,"Some elements within target.xposition, yposition, dispzoom "+\ "do not have the same number of elements."; } // GS STRUCTURE if (gs.zenithangle > 0 && anyof(wfs.gsalt > 0)){write,"WARNING: The return from the LGS is assumed to vary as cos(gs.zenithangle).";} if (anyof(wfs.gsalt != 0) && (gs.lgsreturnperwatt == 0)) { gs.lgsreturnperwatt = 22.; write,format="gs.lgsreturnperwatt set to %f\n",gs.lgsreturnperwatt; } if (anyof((wfs.gsalt == 0)*(wfs.zeropoint == 0)) && (gs.zeropoint == 0)) { exit,"You have some NGS and gs.zeropoint has not been set"; } if (anyof((wfs.gsalt != 0)*(wfs.zeropoint == 0)*(wfs.skymag != 0)) && (gs.zeropoint == 0)) { exit,"You have some LGS with sky background and gs.zeropoint has not been set"; } // LOOP STRUCTURE if (loop.method == string()) loop.method = "closed-loop"; loop_method_options = ["closed-loop","open-loop","pseudo open-loop"]; if (noneof(loop_method_options == loop.method)) exit,"ERROR: loop.method should be set to closed-loop, open-loop or pseudo open-loop"; if ((loop.method == "open-loop") && (loop.gain != 1 || loop.leak != 1)){ write, "Warning: For open-loop simulations the recommended settings are"; write, "loop.gain = 1. and loop.leak = 1."; } if (loop.gain == 0) write,format="%s\n","Warning: loop.gain = 0"; if ( (numberof(*loop.gainho)) != (numberof(*loop.leakho)) ) \ exit,"*loop.gainho should have same number of elements as *loop.leakho"; if (loop.niter == 0) exit,"loop.niter has not been set"; if (loop.ittime == 0) exit,"loop.ittime has not been set"; if (loop.startskip == 0) loop.startskip = 10; if (loop.skipevery == 0) loop.skipevery = loop.niter; if (loop.skipby == 0) loop.skipby = 10000; if (loop.modalgainfile == string()) loop.modalgainfile = ""; if (loop.stats_every==0) loop.stats_every=4; //============================================================================ // DONE WITH BASIC EXISTENCE AND CONSISTENCY CHECKINGS AND DEFAULT ASSIGNMENTS //============================================================================ // NOW GOING INTO MORE ELABORATE CHECKINGS // WFSs: for (ns=1;ns<=nwfs;ns++) { if (wfs(ns).zeropoint == 0){ wfs(ns)._zeropoint = gs.zeropoint; } else { wfs(ns)._zeropoint = wfs(ns).zeropoint; } if (wfs(ns).lambda < 0.1) { write,format="WFS#%d: wfs.lambda < 0.1. That seems weird.\n",ns; write,"Remember: lambda should be in microns"; exit; } if (wfs(ns).shthreshold < 0.) { write,format="WFS#%d: wfs.shthreshold < 0 does not make sense\n",ns; exit; } if ((wfs(ns).filtertilt == 1) && (wfs(ns).correctUpTT == 0)) { write,format="WARNING! WFS#%d: wfs.correctUpTT = 0 with wfs.filtertilt = 1\n",ns; } if ((wfs(ns).correctUpTT == 1) && (wfs(ns).uplinkgain == 0)) { write,format="WARNING! WFS#%d: wfs.correctUpTT = 1 but wfs.uplinkgain = 0\n",ns; } // for shmethod = 1, we still need to set npixels and pixsize to avoid crashing the // WFS initialization routine that is still used to set other parameters used with // method 1. So we put DUMMY VALUES. if (wfs(ns).shmethod == 1) { if (wfs(ns).pixsize == 0){wfs(ns).pixsize = 0.1;} if (wfs(ns).npixels == 0){wfs(ns).npixels = 2;} } if ( (wfs(ns).type=="curvature") && (wfs(ns).nintegcycles != 1) ) { write,"\n I have not implemented yet nintegcycle > 1 for curvature WFS."; write,"I can see no reason to do it, as curvature sensors are usually"; write,"read-out noise free, therefore reducing the gain should be"; write,"prefered. If you have a compelling reason and want it, drop"; write,"me an email."; exit; } // Are we using a WFS we know? wfs_type = strtolower(wfs(ns).type); if ( (wfs_type != "curvature") && (wfs_type != "hartmann") && (wfs_type != "zernike") && (wfs_type !="kl") && (wfs_type != "pyramid") && (wfs_type !="dh")) { // check if this is a user supplied function cmd = swrite(format="totype = typeof(%s)",wfs(ns).type); include,[cmd],1; if ( totype != "function") { error,swrite(format="wfs(%d).type : Unknown value or non-existing function \"%s\"", ns,wfs(ns).type) } } else wfs(ns).type = wfs_type; } // Sets the Influence function file name if not set: for (nm=1;nm<=ndm;nm++) { if (dm(nm).iffile == "") { dm(nm).iffile = parprefix+swrite(format="-if%d",nm)+".fits"; write,format="dm(%d).iffile set to %s\n",nm,dm(nm).iffile; } if (dm(nm).ecmatfile == "") { dm(nm).ecmatfile = parprefix+swrite(format="-ecmat%d",nm)+".fits"; } if ((dm(nm).type != "stackarray") && (dm(nm).elt == 1)) { exit,swrite(format="DM %d: parameter dm.elt only used with stackarray mirrors\n",nm); } // Are we using a DM we know? dm_type = strtolower(dm(nm).type); if ( (dm_type != "bimorph") && (dm_type != "stackarray") && (dm_type != "zernike") && (dm_type != "kl") && (dm_type != "segmented") && (dm_type != "dh") && (dm_type != "tiptilt") && (dm_type != "aniso") ) { // check if this is a user supplied function cmd = swrite(format="totype = typeof(%s)",dm(nm).type); include,[cmd],1; if ( totype != "function") { error,swrite(format="dm(%d).type : Unknown value or non-existing function \"%s\"", nm,dm(nm).type) } } else dm(nm).type = dm_type; dm(nm)._eiffile = parprefix+swrite(format="-if%d",nm)+"-ext.fits"; } // now possible (2009oct6, v4.3.0) // if (anyof(dm.elt == 1) && anyof(dm.type == "aniso")) { // exit,"You can not use currently dm.elt=1 with anisoplanatism modes"; // } for (i=1;i<=max(_(wfs.subsystem,dm.subsystem));i++) { if (noneof(wfs.subsystem == i)) { exit,swrite(format="There is no WFS in subsystem %d\n",i); } if (noneof(dm.subsystem == i)) { exit,swrite(format="There is no DM in subsystem %d\n",i); } } // Sets the interaction/command matrix file name if not set: if (mat.file == "") {mat.file = parprefix+"-mat.fits";} // # of targets (stars at which the performance are evaluated): target.xposition = &(float(*target.xposition)); target.yposition = &(float(*target.yposition)); target._ntarget = numberof(*target.xposition); target._nlambda = numberof(*target.lambda); if (anyof((*target.lambda) < 0.1)) { write,"Some or all target.lambda < 0.1. That seems weird."; write,"Remember: lambda should be in microns"; exit; } if (opt!=[]) { for (no=1;no<=noptics;no++) { if (opt(no).misreg==[]) { noptics = numberof(opt(no).phasemaps); for (i=1;i<=noptics;i++) opt(no).misreg = [0.,0.]; } opt(no).misreg= float(opt(no).misreg); if ((opt(no).path_type=="wfs")&&(opt.path_which==[])) opt.path_which = &indgen(nwfs); if ((opt(no).path_type=="target")&&(opt.path_which==[])) opt.path_which = &indgen(ntarget); if ((opt(no).path_type)&&(opt(no).path_type=="")) opt(no).path_type="common"; if ((opt(no).path_type)&&(opt(no).path_type!="wfs")&&\ (opt(no).path_type!="target")&&(opt(no).path_type!="common")) \ error,swrite(format="Unknown optics path \"%s\".\n It should be \"common\", \"wfs\" or \"target\" (default=\"common\")",opt(no).path_type); } } if (sim.verbose) write,format="%s\n","Check parameters: OK"; } //---------------------------------------------------- func disp2d(ar,xpos,ypos,area,zoom=,power=,init=,nolimits=) /* DOCUMENT func disp2d(arrayptr,xpos,ypos,area,zoom=,power=,init=) display several images in the same plsys, at position given by xpos and ypos. ar: ar can be either an array of pointers or an image cube xpos,ypos: the (X,Y) positions, in arbitrary coordinates area: plsys number zoom: keyword (vector, dim nim), additional zooming factor (on top of default) power: *arrayptr^power is displayed init: initialize, precompute stuff SEE ALSO: */ { extern basezoomptr; plsys,area; if (typeof(ar) == "pointer") { cas = "ptr"; nim = numberof(ar); earlyExit = (*ar(1) == []); // in case we call init with ar undefined (legitimate) } else { cas = "cube"; tmp = dimsof(ar); if (tmp(1) == 2) {nim=1;} else {nim=tmp(4);} } if (is_set(init)) { if (basezoomptr == []) { basezoomptr=array(pointer,10); } if ((zoom != []) && (numberof(zoom) != nim)) {zoom = array(zoom,nim);} if (zoom == []) {zoom = array(1.,nim);} xd = abs(xpos-xpos(-,)); yd = abs(ypos-ypos(-,)); di = sqrt(xd^2.+yd^2.); di = di+unit(nim)*max(di); w = where(zoom!=0); basezoom = (1.+0.9*min(di(w))/2.)*zoom; basezoomptr(area) = &basezoom; if (!is_set(nolimits)) { limits,min(xpos(w)-basezoom(w)),max(xpos(w)+basezoom(w)), min(ypos(w)-basezoom(w)),max(ypos(w)+basezoom(w)),square=1; } if (earlyExit) return; } basezoom = *basezoomptr(area); if ( cas=="ptr") { if (!is_set(power)) { for (i=1;i<=nim;i++) { if (basezoom(i)==0) continue; off = basezoom(i)/(dimsof(*ar(1))(2)); pli,bytscl(*ar(i),cmin=0),xpos(i)-basezoom(i)-off,ypos(i)-basezoom(i)-off, xpos(i)+basezoom(i)-off,ypos(i)+basezoom(i)-off; } } else { for (i=1;i<=nim;i++) { if (basezoom(i)==0) continue; off = basezoom(i)/(dimsof(*ar(1))(2)); pli,bytscl(*ar(i)^power,cmin=0),xpos(i)-basezoom(i)-off,ypos(i)-basezoom(i)-off, xpos(i)+basezoom(i)-off,ypos(i)+basezoom(i)-off; } } } else { if (!is_set(power)) { for (i=1;i<=nim;i++) { if (basezoom(i)==0) continue; off = basezoom(i)/(dimsof(ar(,,1))(2)); pli,bytscl(ar(,,i),cmin=0),xpos(i)-basezoom(i)-off,ypos(i)-basezoom(i)-off, xpos(i)+basezoom(i)-off,ypos(i)+basezoom(i)-off; } } else { for (i=1;i<=nim;i++) { if (basezoom(i)==0) continue; off = basezoom(i)/(dimsof(ar(,,1))(2)); pli,bytscl(ar(,,i)^power,cmin=0),xpos(i)-basezoom(i)-off,ypos(i)-basezoom(i)-off, xpos(i)+basezoom(i)-off,ypos(i)+basezoom(i)-off; } } } if ((is_set(init)) && (!is_set(nolimits))) { limits,square=1; limits; } } //-------------------------------------------------------------------------- func modal_gain_optimization(disp=,update=) /* DOCUMENT func modal_gain_optimization(disp=,update=) NOT UPGRADED TO VERSION 2. DO NOT USE. This routine optimizes the modal gains. Keywords: disp: set to display stuff update: set if this is a gain update (opposite to the first time run) This routine uses: - the saved error circular buffer (cberr.fits) This routine calls: ... This routine sets: ... SEE ALSO: */ { cberr = yao_fitsread("cberr.fits"); // CB of actuator error nGoodSamples = long(2^floor(log(ao.LoopNIter-ao.LoopStartSkip)/log(2))); cbmoderr = atm(,+)*cberr(+,1-nGoodSamples:);// CB of mode coef errors modgains = modalgain*ao.LoopGain; // overall mode gains bestGains = modgains*0.; length = 2048; gainNpt = 30; toGains = spanl(1e-2,0.9,gainNpt); errvect = array(float,gainNpt); errTF = array(float,length/2-1,gainNpt); fudgeFactor = 0.85; // initialize Error Transfer functions: for (n=1;n<=gainNpt;n++) {errTF(,n) = ft_cb_ao_simul(ao.LoopFrameDelay,toGains(n),length/2)(,1);} // Loop over controlled modes: for (i=1;i<=NModesControlled;i++) { // Build PSD of the error psderr = psd(cbmoderr(i,),length,samp=ao.LoopItTime,filter=6,silent=1)(2:,2); pause,10; // ^^ psderr is in fact length/2 long // Build current gain transfer function curErrTF = ft_cb_ao_simul(ao.LoopFrameDelay,modgains(i),length/2)(,1); // Reconstruct open loop PSD OLmodPsd = psderr/curErrTF; // Loop over possible gains for (n=1;n<=gainNpt;n++) {errvect(n) = sum(OLmodPsd*errTF(,n));} if (is_set(disp)) {logxy,0,0; plot,errvect,toGains; pause,500;} // Determine best gain bestGains(i) = fudgeFactor*toGains(errvect(mnx)); if (ao.verbose>=1) {write,format="Mode %i, gain to be updated from %f to %f\n", i,modgains(i),bestGains(i);} } // Update modalgain if (is_set(update)) { modalgain = bestGains/ao.LoopGain; yao_fitswrite,YAO_SAVEPATH+ao.LoopModalGainFile,modalgain; if (ao.verbose>=1) {write,format="Gains updated and saved in !",ao.LoopModalGainFile;} } } //---------------------------------------------------- func ft_cb_ao_simul(FrameDelay,gain,dim) /* DOCUMENT func ft_cb_ao_simul(FrameDelay,gain,dim) NOT UPGRADED TO VERSION 2. DO NOT USE UNTIL UPGRADED. This routine simulates the time aspect of the numerical loop and compute the associated transfer functions (error, closeloop) for further use in modal_gain_optimization(). Inputs: FrameDelay: frame delay in close loop. gain: AO loop gain dim: desired linear size of the output transfer functions SEE ALSO: modal_gain_optimization */ { input = array(float,2*dim); mirvect = array(float,2*dim); output = array(float,2*dim); input(2) = 1.; mir = 0.; command = 0.; wfsMesHistory = array(float,FrameDelay+1); for (i=1;i<=2*dim;i++) { in = input(i); // Subtract the mirror shape: out = in - mir; // Do the WFS: mes = out; // Handling frame delay (0 -> no frame delay at all, 1 -> regular // one frame delay of integrator, 2 -> integrator + one frame // computation, etc...) wfsMesHistory = roll(wfsMesHistory,-1); wfsMesHistory(FrameDelay+1) = mes; usedMes = wfsMesHistory(1); // computes the command vector (integrator with gain): err = usedMes; command += gain*err; // Computes the mirror shape using influence functions: mir = command; // Subtract the mirror shape: out = in - mir; mirvect(i) = command; output(i) = err; // write,input(i),command,err,out; pause,500; } errTF = abs((fft(output+1e-12,1))^2.)/abs((fft(input,1))^2.); errTF = errTF(2:dim); clTF = abs((fft(mirvect,1))^2.)/abs((fft(input,1))^2.); clTF = clTF(2:dim); return [errTF,clTF]; } //---------------------------------------------------- func ss_noise(nss) { write,format="Computing propagated noise for subsystem %d\n",nss; write,"Extracting cmat"; sswfs = ssdm = []; for (ns=1;ns<=nwfs;ns++) {grow,sswfs,array(wfs(ns).subsystem,wfs(ns)._nmes);} for (nm=1;nm<=ndm;nm++) {grow,ssdm,array(dm(nm).subsystem,dm(nm)._nact);} wsswfs = where(sswfs == nss); wssdm = where(ssdm == nss); cmat = cMat(wssdm,wsswfs); write,"Computing subsystem modes"; nmv = where(dm.subsystem == nss); if (numberof(nmv)==0) error,"No DM found in subsystems"; modes = build_dm_modes(nmv,actmodes,modvar); tmp = actmodes(+,)*cmat(+,); modcov = trace(tmp(,+)*tmp(,+)); // now the measurements are in arcsec, so we got to convert to rd of // phase difference at the edge of the subaperture, which is what // the SH measure: nsv = where(wfs.subsystem == nss); if (numberof(nsv) != 1) error,"zero or more than one wfs in subsystem"; ns = nsv(1); // subsize in pixel: subsize = sim.pupildiam/wfs(ns).shnxsub(0); if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; // subsize in meters: subsize_m = subsize * tel.diam/sim.pupildiam; //subsize = tel.diam/wfs(ns).shnxsub; arcsectord = 4.848e-6*subsize_m*2*pi/wfs(ns).lambda/1e-6; noise = modcov*modvar/arcsectord^2.; write,format="Total noise on phase for 1rd2 per subaperture = %f rd2\n",sum(noise); fma;plh,noise; limits,square=0; limits; return noise; } //---------------------------------------------------- func build_dm_modes(nm,&u,&modvar,&eigenvalues,disp=) /* DOCUMENT unfinished, I think. NOT FINISHED, NOT UPGRADED TO VERSION 2. DO NOT USE. */ { if (anyof(dm(nm).elt)) exit,"Not implemented for dm.elt=1"; def = []; for (i=1;i<=numberof(nm);i++) { grow,def,*dm(nm(i))._def; } defpup = ipupil(dm(nm(1))._n1:dm(nm(1))._n2,dm(nm(1))._n1:dm(nm(1))._n2); wpup = where(defpup); tmp = def(*,)(wpup,); // not really saving RAM, but... tpup = sum(defpup); /* p = (def*ipupil)(sum,sum,)/tpup; def = def-p(-,-,); def = reform(def,long(ao._size)*ao._size,ao._DmNAct); def = def(where(ipupil),); */ dd = tmp(+,)*tmp(+,); eigenvalues = SVdec(dd,u,vt); modes = def(,,+)*u(+,); // mask with ipupil modes = modes*defpup(,,-); // compute mode variance: modvar = (modes(*,)(wpup,)(rms,))^2.; return modes; if (disp == 1) {for (i=1;i<=ao._DmNAct;i++) {fma; pli,modes(,,i)*ipupil;pause,100;}} //normalize the modes: norm = sqrt((modes^2.*ipupil)(avg,avg,)); modes = modes/norm(-,-,); ActIF = modes(,,1:-1) //*(1./indgen(ao._DmNAct-1))(-,-,); ao._DmNAct = ao._DmNAct-1; do_imat,disp=1; build_cmat,all=1,nomodalgain=1; mn = cMat(,+)*cMat(,+); mn = diag(mn)*indgen(ao._DmNAct-1)^2. if (disp == 1) {fma;plg,mn;} return modes; } //---------------------------------------------------- func make_curv_wfs_subs(ns,dim,pupd,disp=,cobs=) /* DOCUMENT func make_curv_wfs_subs(ns,dim,pupd,disp=) */ { local WhichRing,SubThetaIn,SubThetaOut,SubRadiusIn,SubRadiusOut; NRing = sum(*(wfs(ns).nsubperring) != 0); // Number of Rings NSubPerRing = (*(wfs(ns).nsubperring))(1:NRing); NSub = sum(NSubPerRing); // Compute the internal and external radius of each rings // given the number of subapertures per rings: SurfOneSub = pi/sum(NSubPerRing); // Surface of one actuator RInRing = array(float,NRing); // Internal Radius ROutRing = array(float,NRing); // External Radius if (is_set(cobs)) {RInRing(1) = cobs;} // loop on ring number for (i=1;i<=NRing;i++) { ROutRing(i) = sqrt(NSubPerRing(i)*SurfOneSub/pi+RInRing(i)^2.); if (i != NRing) RInRing(i+1) = ROutRing(i); } if (is_set(cobs)) {RInRing(1) = 0.;} ROutRing(NRing) = 1.6; // now we got to determine the inner and outer radius and angle for // each actuators: WhichRing = array(1,NSubPerRing(1)); // Ring index per actuator for (i=2;i<=NRing;i++) {grow,WhichRing,array(i,NSubPerRing(i));} // offset angle of first subaperture in rings: if (*wfs(ns).angleoffset==[]) angleoffset=array(0.,NRing); else angleoffset=(*wfs(ns).angleoffset)*pi/180.; // if rint and rout are specified, use it instead: if ((*wfs(ns).rint)!=[]) RInRing=*wfs(ns).rint; if ((*wfs(ns).rout)!=[]) ROutRing=*wfs(ns).rout; // loop to determine radiuses and angle: for (i=1;i<=NRing;i++) { dtheta = 2*pi/NSubPerRing(i); for (j=1;j<=NSubPerRing(i);j++) { t1 = (j-1.)*dtheta + angleoffset(i); t2 = t1+dtheta; grow,SubThetaIn,t1 ; grow,SubThetaOut,t2 ; grow,SubRadiusIn,RInRing(i) ; grow,SubRadiusOut,ROutRing(i) ; } } // Now build the subapertures images: x = span(1,dim,dim)(,-:1:dim)-dim/2.-1; y = transpose(x); ang = atan(y,x); ang1 = ang + (ang < 0)*2*pi; ang2 = (ang1+pi)%(2*pi)+pi; rad = dist(dim)/(pupd/2.); d2 = eclat(dist(dim)^2.); Subs = array(short,dim,dim,NSub); for (i=1;i<=NSub;i++) { // the following to avoid issues due to discontinuity of ang array at 0=2pi if (SubThetaOut(i)>(2*pi)) ang=ang2; else ang=ang1; tmp = (rad >= SubRadiusIn(i)) * (rad < SubRadiusOut(i)) * \ (ang >= SubThetaIn(i)) * (ang < SubThetaOut(i)); if (i>1) tmp = tmp-Subs(,,i-1); // avoid double points Subs(,,i) = (tmp==1); if (disp == 1) {fma; pli,tmp;} } // ok, in the following, I have changed the way one sums // the signal over the subaperture area in CurvWFS: // now I am passing a vector of indices for each subaperture // and using them for the sum. // sind is the ensemble of indice vectors // nsind is the number of actual indices for a given subaperture tmp = Subs(sum,sum,); sind = array(long,max(tmp),NSub)*0+1; nsind = array(long,NSub); for (i=1;i<=NSub;i++) { sind(1:tmp(i),i) = where(Subs(,,i) == 1); nsind(i) = sum(Subs(,,i)); } wfs(ns)._sind = &(int(sind)); wfs(ns)._nsind = &(int(nsind)); return Subs; } //---------------------------------------------------- func _map2d(t,dim,cent) { // assumes XY square array as input curdim = dimsof(t); if (curdim(2) != curdim(3)) {exit,"_map2d only takes square arrays";} cdim = curdim(2); if (cdim == dim) {return t;} if (cdim > dim) { if (is_void(cent)) {cent = cdim/2+1.;} _p1 = long(ceil(cent-dim/2.)); _p2 = _p1+dim-1; return t(_p1:_p2,_p1:_p2,..); } if (cdim < dim) { if (is_void(cent)) {cent = dim/2+1.;} curdim(2:3) = [dim,dim]; tmp = array(structof(t),curdim); _p1 = long(ceil(cent-cdim/2.)); _p2 = _p1+cdim-1; if (_p2 != long(floor(cent+cdim/2.-1))) {exit,"Problem in _map2d";} tmp(_p1:_p2,_p1:_p2,..) = t; return tmp; } } //---------------------------------------------------- func noll(ord) { /* DOCUMENT func noll(ord) Noll variance of zernike for D/r0 = 1 SEE ALSO: */ innp = 0.; cov = array(double,ord); for (j=2;j<=ord+1;j++) { tmp = zernumero(j); n = tmp(1); m = tmp(2); innp = gamma(14./3.)*gamma((2*n-14./3.+3.)/2.)/ (2.^(14./3.)*gamma((14./3.+1.)/2.)*gamma((14./3.+1.)/2.)* gamma((2*n+14./3.+3.)/2.)); cov(j-1) = (0.046/pi*(n+1.)*innp*(-1.)^((2*n-2*m)/2.)); } return cov*(2.*pi)^(11./3.)/pi; } //---------------------------------------------------- func nollmat(ord) { /* DOCUMENT func nollmat(ord) Noll covariance matrix for D/r0 = 1 SEE ALSO: */ innp = 0.; cov = array(double,[2,ord,ord]); for (j=2;j<=ord+1;j++) { for (jp=2;jp<=ord+1;jp++) { tmp = zernumero(j); tmpp = zernumero(jp); n = tmp(1); m = tmp(2); np = tmpp(1); mp = tmpp(2); //print,(n+np-14./3.+3.)/2.,(np-n+14./3.+1.)/2., // (n-np+14./3.+1.)/2.,(n+np+14./3.+3.)/2.; innp = gamma(14./3.)*gamma((n+np-14./3.+3.)/2.)/ (2.^(14./3.)*gamma((np-n+14./3.+1.)/2.)*gamma((n-np+14./3.+1.)/2.)* gamma((n+np+14./3.+3.)/2.)); cov(j-1,jp-1) = (0.046/pi*sqrt((n+1.)*(np+1.))*innp*float(m == mp)* (-1.)^(float(m == mp)*(n+np-2*m)/2.))*long((abs(j-jp)%2) == 0); } } cov = (cov+transpose(cov))/2.; return cov*(2.*pi)^(11./3.)/pi; } //---------------------------------------------------- func rotby90(image,rot) /* DOCUMENT rotby90(image,rot) with: rot = 0 -> no rotation rot = 1 -> 90 deg anticlockwise rot = 2 -> 180 deg anticlockwise rot = 3 -> 270 deg anticlockwise AUTHOR: F.Rigaut, June 11, 2002. SEE ALSO: rotate */ { if (rot == 0) {return image;} if (rot == 1) {return transpose(image)(::-1,);} if (rot == 2) {return image(::-1,::-1);} if (rot == 3) {return transpose(image)(,::-1);} } //---------------------------------------------------- func make_pupil(dim,pupd,xc=,yc=,real=,cobs=) /* DOCUMENT func make_pupil(dim,pupd,xc=,yc=,real=) */ { if (real == 1) { pup = exp(-clip(dist(dim,xc=xc,yc=yc)/(pupd/2.),0.,2.)^60.)^0.69314; } else { // xc;yc;info,xc; // tv,dist(dim,xc=xc,yc=yc);pause,2000; pup = dist(dim,xc=xc,yc=yc) < (pupd+1.)/2.; } if (is_set(cobs)) { if (real == 1) { pup -= exp(-clip(dist(dim,xc=xc,yc=yc)/(pupd*cobs/2.),0.,2.)^60.)^0.69314; } else { pup -= dist(dim,xc=xc,yc=yc) < (pupd*cobs+1.)/2.; } } return pup; } //---------------------------------------------------- func fwhmStrehl(image,ps,lambda,teldiam,cobs,&strehl,&fwhm,&strehlab,&airy,&psf0, fibre=,source=,rmask=,dlambda=,psfcomp=,autoback=,silent=) { /* DOCUMENT function fwhmStrehl Syntax: fwhmStrehl(image,ps,lambda,teldiam,cobs,strehl,fwhm,strehlab,&airy, fibre=,source=,rmask=,dlambda=,psf0=,psfcomp=,autoback=) Cette routine calcule le strehl et la fwhm de l'image. Le strehl est calcule de la facon suivante : 1) on calcule la fto et on filtre les frequences > coupure du telescope 2) On corrige de l'effet de filtrage par la taille finie du pixel 3) Le cas echeant ("source" is set), on divise par la fto de la source 4) On synthetise une tache d'airy pour la longueur d'onde en question 5) On rebinne par 4, normalise, et on compare les maxima -> Strehl La FWHM est simplement calcule a partir du nombre de pixel de valeur > au max de l'image/2. ps = pixel size en arcsec lambda = en um teldiam = telescope diameter en m cobs = fraction obstruction central/telescope diameter fibre = cf ci-dessus source = source dimension in arcsec. autoback = automatic normalization of background by interpolation of zero point in MTF By convention, real plane coordinate (0,0) -> [dim/2,dim/2] fourier plane coordinates (0,0) -> [0,0] */ if (!is_set(dlambda)) {dlambda=0.;} if (!is_set(fibre)) {fibre = "disk";} // valeur autorisee pour fibre = 'disk' ou 'gaussian' dim = dimsof(image)(2); // CALCUL DU STREHL : // Image theorique : tfto = telfto(lambda,dlambda,teldiam,cobs,ps,dim,silent=1); tfto = roll(tfto,[1,1]); // bug fixed 2007jul28 (no impact) mask = (tfto > 1e-4); airy = roll(abs(fft(tfto,1))); // was fftrebin, caused ripples in ima below, 2007jul28 airy = spline2(airy,4); // Image experimentale : fcoup = dim/2/(lambda*1e-6/2./teldiam/4.848e-6/ps); ifto = fft(roll(image),1); mask = roll((dist(dim) < fcoup)); // on soustrait le bruit moyen : what's that? 2007jul28 /* if (sum(1.-mask) != 0) { mfl = sum(ifto.re*(1.-mask))/sum(1.-mask); mim = sum(ifto.im*(1.-mask))/sum(1.-mask); // print,max(ifto.re)/mfl,max(ifto.im)/mim; ifto.re = (ifto.re-mfl)*mask; ifto.im = (ifto.im-mim)*mask; } */ // calcul de l'attenuation de la FTM par le moyennage du pixel : tmp = roll(dist(dim))/(dim/2.)*pi/2.; ifto = ifto/sinc(tmp); if (is_set(source)) { // Calcul de la FTM de la source (etoile artificielle ) : if (fibre == "gaussian") { // fibre = gaussian imfib = exp(-(clip((dist(dim)/(source/ps/1.66))^2.,,20))); fibfto = abs(fft(imfib,-1)); } else { // fibre = camember tmp = roll(dist(dim))/(dim/2.)*pi/2.*source/ps; fibfto = sinc(tmp); } } else { fibfto = ifto.re*0.+1.; } ima = roll(float(fft((ifto/fibfto)*(tfto > 1e-8),-1))); psf0 = ima/sum(ima); // was fftrebin, caused ripples, 2007jul28 ima = spline2(ima,4); if (is_set(rmask)) // diaphragme les deux images { diap = roll(dist(4*dim)) <= 4*rmask; wm = (where2(ima == max(ima)))(,1); ima = ima*roll(diap,wm); airy = airy*roll(diap); } airy = airy/sum(airy); ima = ima/sum(ima); strehl = max(ima)/max(airy); // Calcul de la largeur a mi-hauteur : fwhm = sqrt(4./pi*sum(ima >= max(ima)/2.))*ps/4.; if (!is_set(silent)) write,format="fwhm = %f, Strehl = %f\n",fwhm,strehl; if (is_set(autoback)) { tmp = ifto.re; t1 = (tmp(2,1)+tmp(1,2)+tmp(1,0)+tmp(0,1))/4.; t12 = (tmp(2,1)-tmp(3,1)+tmp(1,2)-tmp(1,3)+ tmp(1,0)-tmp(1,-1)+tmp(0,1)-tmp(-1,1))/4.; ifto.re(1,1) = t1+t12; ifto = ifto/(t1+t12); ima = roll(float(fft((ifto/fibfto)*(tfto > 1e-8),-1))); psf0 = ima/sum(ima); ima = fftrebin(ima,4); if (is_set(rmask)) // diaphragme les deux images { diap = dist(4*dim) <= 4*rmask; ima = ima*roll(diap,[ima(mxx,),ima(,mxx)]); } airy = airy/sum(airy); ima = ima/sum(ima); strehlab = max(ima)/max(airy); // Calcul de la largeur a mi-hauteur : fwhm = sqrt(4./pi*sum(ima >= max(ima)/2.))*ps/4.; write,format="%s\n","With automatic determination of background from points 0,1,2 of MTF :"; write,format="fwhm = %f, Strehl = %f\n",fwhm,strehlab; } } //------------------------------------------------ func telftoh1(f,u,v) { e = -1; if (abs(1-v) < 1e-12) {e = 1.;} tmp= (v^2/pi)*acos((f/v)*(1.+e*(1-u^2.)/(4.*f^2.))); return tmp; } //------------------------------------------------ func telftoh2(f,u) {return -1.*(f/pi)*(1.+u)*sqrt((1.-(2*f/(1+u))^2.)* (1-((1-u)/(2*f))^2));} //------------------------------------------------ func telftog(f,u) { tmp = f*0.; z1 = where(f <= (1-u)/2.); z2 = where(f >= (1+u)/2.); z3 = where( f > (1-u)/2. & f < (1+u)/2. ); if (exist(z3)) {tmp(z3) = telftoh1(f(z3),u,1.) + telftoh1(f(z3),u,u) + telftoh2(f(z3),u);} if (exist(z1)) {tmp(z1) = u^2.;} if (exist(z2)) {tmp(z2) = 0.;} return tmp; } //------------------------------------------------ func telftot0(f,cobs) {return (telftog(f,1.)+cobs^2*telftog(f/cobs,1.)-2.*telftog(f,cobs))/(1.-cobs^2.);} //------------------------------------------------ func telfto(lambda,dlambda,teldiam,cobs,pixsize,dim,freqc=,npt=,silent=,returnpsf=) { /* DOCUMENT func telfto Syntax: telfto(lambda,dlambda,teldiam,cobs,pixsize,dim,freqc=, npt=,silent=,returnpsf=) Computes and returns the Modulation transfer function (FTO is the french equivalent...) of a telescope with central obstruction and perfect optics. Parameters and keywords: lambda in microns dlambda in microns teldiam in meters cobs in fraction of teldiam pixsize in arcsec dim is output array dimension freqc is the cut-off frequency ? npt the number of point in dlambda (for calculations in this routine) silent has to be set to one for suppressing printout comments setting returnpsf has the effect of returning the PSF, not the MTF */ if (is_void(dim)) {exit,"function telfto,lambda,dlambda,teldiam,cobs,pixsize,dim,freqc=,npt=,silent=";} if (is_set(freqc)) { dlamb = 0.; lamb = 1.; teld = 1.; pixs = freqc*lamb/teld/4.848/dim; } else { dlamb = dlambda; lamb = lambda; teld = teldiam; pixs = pixsize; } if (!is_set(npt)) npt = 5; if (dlambda == 0.) npt = 1; if (!is_set(silent)) { write,format="Cut-off frequency in pixels : %7.4f\n",teld*4.848/lamb*dim*pixs; } mtf = array(float,dim,dim); dd = clip(roll(dist(dim)),1e-10,); for (i=0;i<=npt-1;i++) { if (npt > 1) {l = lamb - dlamb*(i-(npt-1)/2.)/(npt-1);} else {l=lamb;} fc = teld*4.848/l; fc = fc*dim*pixs; f = dd/fc; mask = (f <= 1.); f = f * mask + f(dim/2+1,dim/2+1) * (1-mask); mtf = mtf + telftot0(f,cobs)*mask/npt; } mtf = mtf*sin(pi*dd/2./dim)/(pi*dd/2./dim); // big bug detected on 2007feb13: was returning fft(mtf)^2. for PSF // fortunately, I was not using the flag in any other routine, so no harm done if (is_set(returnpsf)) return abs(fft(mtf,1)); return mtf; } //------------------------------------------------------- func ftcb(te,tcal,tmir,gain,dim,x=) { /* DOCUMENT ftcb(te,tcal,tmir,gain,dim,x=) returns [f,hbo,hcor,hbf] AUTHOR: F.Rigaut, way back in 1996? SEE ALSO: */ f = indgen(dim)/te/2./dim; if (!is_void(x)) { f = x;} p = 2i*pi*f; hzoh = (1.-exp(-te*p))/(te*p); //hzoh = 1.; hmir = 1./(1.+tmir*p); hwfs = (1.-exp(-te*p))/(te*p); hcal = gain*exp(-tcal*p); hbo = hzoh*hmir*hwfs*hcal/(1-exp(-p*te)); hcor = float((1./(1.+hbo))*conj(1./(1.+hbo))); hbf = float((hbo/(1.+hbo))*conj(hbo/(1.+hbo))); hbo = float(hbo*conj(hbo)); return ([f,hbo,hcor,hbf]); } //--------------------------------------------------------- func encircled_energy(image,&ee50,xc=,yc=) /* DOCUMENT encircled_energy(image,ee50,xc=,yc=) * Computes encircled energy function for a 2D array. * Keywords xc and yc optionaly specify center about which the encircled * energy profile is to be computed. Returns optionally the value of the * 50% encircled energy *diameter* (output). * F.Rigaut, Nov 2001. * SEE ALSO: findfwhm */ { im = float(image); dim = (dimsof(image))(2); if (xc == []) {xc = dim/2+1;} if (yc == []) {yc = dim/2+1;} e = 1.9; npt = 20; rv = span(1.,(dim/2.)^(1./e),npt)^e; ee = rv*0.; for (i=1;i<=npt;i++) { fil = make_pupil(dim,rv(i),xc=xc,yc=yc,real=0); rv(i) = sqrt(sum(fil)*4/pi); // that's a diameter ee(i) = sum(fil*im); } rv = grow(0.,rv); ee = grow(0.,ee); ee = ee/sum(im); //fma;plg,ee,rv; xp = span(0.,dim/2.,2*dim); yp = interp(ee,rv,xp); ayp = abs(yp-0.5); ee50 = xp(ayp(mnx)); return yp; } //--------------------------------------------------------- func findfwhm(image,psize,nreb=,saveram=) /* DOCUMENT findfwhm(image,psize) * Determine the FWHM of an image. It simply rebins the image by * a factor of 4 and counts the number of pixels above the maximum * of the image divided by 2. Not the best accurate method but it's * robust * image = image for which to compute FWHM * psize = pixel size (in whatever units FWHM has to be computed, e.g. arcsec) * nreb = rebin factor to compute FWHM (default 4). not used when * saveram is set * saveram = in that case, we don't use the brutal rebin + number of * pixels above 1/2 max method. Instead, we iteratively determined * if the FWHM is above 8 pixels, and zoom on the peak if not. * when this condition is verified, we use the above rebin method. * This saves RAM when dealing with very large images and small cores. * Modified 2010Oct05 to save RAM for ELT applications. Do a first pass * at lower rebin factor to avoid generating too large images. Isolate * a subimage for rebinning if necessary. * F.Rigaut, 2001/11/10. * SEE ALSO: */ { if (psize == []) psize=1; if (nreb==[]) nreb=4; if (!saveram) { if (nreb==1) eq_nocopy,imreb,image; else imreb = fftrebin(image,nreb); fwhm = sum(imreb >= (max(imreb)/2.))/nreb^2.; fwhm = sqrt(4.*fwhm/pi)*psize; return fwhm; } // saveram: nreb = 1; fwhm = compfwhm(image); while (fwhm < 8.) { nreb *= 2; dim = dimsof(image)(2); hdim = dimsof(image)(2)/4; // identify max wmax = where2(image==max(image))(,1); // compute sub image (1/2 the initial size): i1 = clip(wmax(1)-hdim+1,1,); i2 = clip(wmax(1)+hdim,,dim); j1 = clip(wmax(2)-hdim+1,1,); j2 = clip(wmax(2)+hdim,,dim); image = image(i1:i2,j1:j2); // rebin image: imreb = fftrebin(image,nreb); fwhm = compfwhm(imreb); } fwhm = fwhm*psize/nreb; return fwhm; } func compfwhm(image) { fwhm = sum(image >= (max(image)/2.)); fwhm = sqrt(4.*fwhm/pi); return fwhm; } func phi2zer(i_num, phase,pup, nzer=, kl=) /* DOCUMENT phi2zer(phase,nzer=,&zcoeff) * Do the decomposition of a phase screen on N zernike (or KL) * coefficients. To be used in yao_mcao.i, to save a circular buffer * with the Z (or KL) coefficients of the residual phase. * B.Neichel, 2009/05/13. * SEE ALSO: */ { //require,mcao_i_dir+"lib/libkl.i"; //no need anymore, they are include in myst_init.i extern conv, w_def; //first, find the dimension of the phase dim_phi = dimsof(phase)(2); //in x and y if (dimsof(phase)(1) == 3) {ndir = dimsof(phase)(4);}; //we are dealing with multiple directions //This should be computed only once (for the first iteration) //then, we only need "conv" if (i_num == 1) { if (kl) { kl_tab = array(float,[3,dim_phi,dim_phi,nzer]); kl_tab = make_kl(nzer,dim_phi,var,outbas,pup); w_def = where(kl_tab(,,1)); def_kl =kl_tab(*,)(w_def,); conv = generalized_inverse(def_kl); } else { prepzernike,dim_phi,sim.pupildiam; tmp = zernike(1); w_def = where(tmp); zer_tab = array(float,[3,dimsof(tmp)(2),dimsof(tmp)(2),nzer]); for (z=1;z<=nzer;z++) { zer_tab(,,z) = zernike(z); }; def_zer =zer_tab(*,)(w_def,);///norm; conv = generalized_inverse(def_zer); }; }; //do the loop on each directions here. if (ndir) ztmp = array(float,[2,ndir,nzer]); else { ztmp = array(float,[2,1,nzer]); ndir = 1; } for (nnn=1;nnn<=ndir;nnn++){ ztmp(nnn,) = conv(,+)*(phase(,,nnn)(w_def))(+); } return ztmp; } func make_fieldstop(ns) { extern wfs; // build field stop for WFS ns subsize = sim.pupildiam/wfs(ns).shnxsub(0); if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; sdim = long(2^ceil(log(subsize)/log(2)+1)); if (no_pad_simage) sdim = long(2^ceil(log(subsize)/log(2))); fftpixsize = wfs(ns).pixsize/wfs(ns)._rebinfactor; // fft pixel size in arcsec // if field stop size has not been set, set it to the subap fov (which seems // the best thing to do) if (wfs(ns).fssize==0) wfs(ns).fssize = wfs(ns)._npixels * wfs(ns).pixsize; if (sim.verbose>=1) { write,format="WFS#%d Field stop size = %f\n",ns,wfs(ns).fssize; } fs_size_fftpix = wfs(ns).fssize/fftpixsize; if (wfs(ns).fstop=="none") { fs = array(1n,[2,wfs(ns)._nx4fft,wfs(ns)._nx4fft]); } else if (wfs(ns).fstop=="round") { fs = dist(wfs(ns)._nx4fft,xc=wfs(ns)._nx/2+0.5, \ yc=wfs(ns)._nx/2+0.5)<=(fs_size_fftpix/2.); } else { // anything else -> square FS fs = array(0n,[2,wfs(ns)._nx4fft,wfs(ns)._nx4fft]); hsize = long(round(fs_size_fftpix/2.)); hsize = clip(hsize,,wfs(ns)._nx/2); fs(wfs(ns)._nx/2-hsize+1:wfs(ns)._nx/2+hsize, \ wfs(ns)._nx/2-hsize+1:wfs(ns)._nx/2+hsize) = 1n; } if (wfs(ns).fsoffset!=[]) { // only roll by an integer # of fft pixel: fsoffset = long(round(wfs(ns).fsoffset/fftpixsize)); fs = roll(fs,fsoffset); // refresh value of fsoffset to actual value: wfs(ns).fsoffset = fsoffset * fftpixsize; if (sim.verbose>=2) { write,format="WFS#%d Field Stop offsets actual values: (%f,%f) arcsec\n", ns,(wfs(ns).fsoffset)(1),(wfs(ns).fsoffset)(2); } } wfs(ns)._submask = &(float(fs)); wfs(ns)._domask = 1l; } func generate_vib_time_serie(sampling_time,length,white_rms,one_over_f_rms,peak,peak_rms,peak_width=) /* DOCUMENT generate_vib_time_serie sampling_time = loop sampling time [seconds] length = number of point desired in generated time serie white_rms = rms of white noise [arcsec] one_over_f_rms = rms of 1/f noise (from 1 Hz included up to cutoff frequency) peak = vector containing the frequency [Hz] at which vibration peaks are to be generated peak_rms = vector (same number of elements as peak) containing the rms of each peaks (arcsec) peak_width = keyword optionaly containing a vector (same number of elements as peak) of width of each peaks [FWHM in Hz, default one Hz]. SEE ALSO: */ { local psd; // construct power spectrum: npt = long(ceil(length/2.))+1; //+1 to include both 0 and freqmax freq = span(0.,1./sampling_time/2.,npt); psdall = array(0.,npt); // white noise: psd = array(1.,npt); // normalize (power theorem) psd = psd/sum(psd)*white_rms^2.; psdall = psd; // one over f noise: psd = 1./clip(freq,freq(2),); onehz = long(ceil(1./freq(2))); psd = psd/sum(psd(onehz:))*one_over_f_rms^2.; psdall += psd; // peaks: if (peak!=[]) { if (peak_width==[]) peak_width=array(freq(2)/10.,numberof(peak)); if ( (numberof(peak_rms) != numberof(peak)) ) \ error,"numberof(peak_rms) != numberof(peak)"; if ( (numberof(peak_width) != numberof(peak)) ) \ error,"numberof(peak_width) != numberof(peak)"; for (i=1;i<=numberof(peak);i++) { if ( (peak(i)<0) || (peak(i)>max(freq)) ) continue; peak_width(i) = clip(peak_width(i),freq(2)/10.,); sigma = peak_width(i)/2.35; psd = exp( - (freq-peak(i))^2./(2*sigma^2.)); psd = psd/sum(psd)*peak_rms(i)^2.; psdall += psd; } } psdall(1) = 0.; // null zero freq component // add negative part: psdtot = _(psdall,psdall(2:-1)(::-1)); norm = sum(psdtot); // amplitude amp = sqrt(psdtot); // generate random phase: pha = random(numberof(amp))*2*pi; // do the fourier transform: tmp = array(complex,numberof(amp)); tmp.re = amp*cos(pha); tmp.im = amp*sin(pha); ts = float(fft(tmp,1)); // post normalize: if ((normts=sum(ts^2))!=0.) ts = ts * sqrt(norm/normts); ts = ts*sqrt(length)/sqrt(2.); // don't ask, but it works and kinda make sense write,format="rms of time series = %.3f milliarcsec\n",ts(rms)*1000.; if (sim.debug>=2) { fma; plsys,2; logxy,0,0; plh,sqrt(psdall(2:)),freq(2:); xytitles,"Frequency [Hz]","sqrt(PSD) (one axis)"; pltitle,swrite(format="Vibrations PSD (rms=%.1fmas)",ts(rms)*1000); limits,square=0; limits; limits,-10,freq(0)+10; hitReturn; logxy,0,0; limits; } return ts; } func find_examples_path(void) { parpath="./:"+pathform(_(Y_USER,Y_SITES,Y_SITE)); tmp = find_in_path("sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("data/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("share/yao/examples/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) { parpath="/usr/share/doc/yorick-yao/examples/"; tmp = find_in_path("sh6x6.par",takefirst=1,path=parpath); } if (tmp==[]) { write,"Couldn't find the examples directory"; return []; } else write,format="Found examples directory: %s\n",dirname(tmp); return dirname(tmp); } func find_doc_path(silent=) { parpath="./:"+pathform(_(Y_USER,Y_SITES,Y_SITE)); tmp = find_in_path("aosimul.html",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("doc/aosimul.html",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("share/yao/doc/aosimul.html",takefirst=1,path=parpath); if (tmp==[]) { parpath="/usr/share/doc/yorick-yao/doc/"; tmp = find_in_path("aosimul.html",takefirst=1,path=parpath); } if (tmp==[]) { if (!silent) write,"Couldn't find the doc directory"; return []; } else { if (!silent) write,format="Found doc directory: %s\n",dirname(tmp); return dirname(tmp); } } func yaodoc(void) /* DOCUMENT will find the location of the documentation directory and open the manual in a browser (default browser for osx, firefox for linux). SEE ALSO: */ { docpath = find_doc_path(silent=1); if (os_env=="darwin") { system,"open "+docpath+"/manual.html"; } else if (os_env=="linux") { system,"firefox "+docpath+"/manual.html"; } } func expand_path(_path) /* DOCUMENT expand_file_name(path) Expand leading "~" in file name PATH which must be an array of strings (or a scalar string). SEE ALSO: strpart, cd, get_cwd, get_file_name, protect_file_name. */ { result = array(string, dimsof(_path)); n = numberof(_path); cwd = get_cwd(); /* memorize current working directory */ head = string(0); local path; for (i=1 ; i<=n ; ++i) { /* Expand leading "~" in file name(s). */ eq_nocopy, path, _path(i); if (strpart(path, 1:1) == "~") { sread, path, format="%[^/]", head; home = cd(head); if (home) { cd, cwd; /* restore working directory */ tail = strpart(path, strlen(head)+1:0); if (strlen(tail)) { /* remove trailing '/' in HOME to avoid two '/' in result */ path = strpart(home, 1:-1) + tail; } else { path = strpart(home, 1:-1); } //~ else { //~ eq_nocopy, path, home; //~ } } } result(i) = path; } return result; } func prime_factors(n,upper_limit=) { if (!upper_limit) upper_limit=7; // up to or equal // prime up to 1000: prime = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,\ 97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,\ 181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,\ 277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,\ 383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,\ 487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,\ 601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,\ 709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,\ 827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,\ 947,953,967,971,977,983,991,997]; prime = prime(where(prime<=upper_limit)); factors = []; while (n>upper_limit) { m = float(n)/prime-n/prime; w = where(m==0); if (numberof(w)==0) { grow,factors,n; return factors; } grow,factors,prime(w(1)); n /= prime(w(1)); } grow,factors,n; return factors; } yao-5.4.0/besseljprimezeros200.fits000066400000000000000000011735001234404334100171750ustar00rootroot00000000000000SIMPLE = T / true FITS file created by Yorick BITPIX = -64 / IEEE double precision floating point NAXIS = 2 / number of dimensions NAXIS1 = 201 / length of 1st dimension NAXIS2 = 200 / length of 2nd dimension END ?ēn|?AF?60<4?e??VT=?5ϒ?G6?$ dp?F ?k'y@T@WE@̬@m@W.$@J@I@S'@%@ ;}@ XJ@ JPB@ s?@@ @G c@ok@m9@NQ@g}P@JQu@A M @];N@ 7y@M2@"*@"}ݸ< @"d @##Ӆy@#vw@#ɷq@$4@$oO@$o'@%O,0@%h+x7@%#r@& Eg}9@&`܂4@&yG'@'DR@'Y *Q^O@'P@'j_@(QQ92@( x-@(!@)I|,@)/o^@)+=E&@*AJ @*9ۗr@*-~@+9t@+-@+ϗ*>@,1o"h@, j0v@,֧y@-)@[H@-{@-k@. X @.s!@.˱n@/"@/k4cs@/uP@0"X@01d\@0ZO@0p@0'd<%@0f~Rc@0pV@1(4h@1Rt_@1{Z@1 A@1@1 @2 BNv@2IzX}6@2rk@2?i+@2#|@2SUs@3$@3@@3i٫Kn@3!]X@3S;p_@3v;@4M@47 %=@4ah@4C,| @4qWi@4ܞo@5XT@5.X3@5X$4^z@5O;B@5zBq@5ӤwJp@5"@6%E8@6Od@6xGU@6on@6ʖI@68Q@7Nw@7F痛@7o.@7RZ@7vm~@7ꚇh@8@8@>-^@>V䅬b@>4@> ȩ@> u^@>3 @?$Fl@?MY`s@?vl1Nh@?~e7@?ȐPy @?]u@@ Y@@!/`@@6j7@@J?s?'㖌2??i4b?.{~?K4?&H@wMs"@aoI@v1k@*%G'@h˃@^@ Pl]@ K@ 1@# @ Dڭ@ D@;!KSS@#n@_.@X6  M@ 9Q@~|/P@qlR/@#! @я@O2@7hW@3@Bjm[@Hc Z@@2@X8Pk@aL@mxo@eDe*@]m@^N@p @ _U@ fVZf9@ 8& @!r@!j @!kG@"s@@"n @"o@#bqy @#q@#dmj@$4@'@$t]Z5o@$xLx@% =@%v/@%y_@&"`&@&x<*GX@& l@'#ϟȲo@'y],@'6@($m7@(zstW@@(=@)%K_@){.@)u@*%@*{>2/`@*Е@+%<]@+{*R@+h~@,% @,z ;@,󔂙@-%@@-z*!ƀ)@-:t$3@.$C@.yE3{@.ANVx@/#5yɕ@/x$ѻ@/ *@0‰@0;d f)@0e΃Y@05!i@0}@062@1Z۾n@19ϲnj@1d@1f}R@1OW{@1 6l@2 Z]9@271Z@2au@26ᴸ^@2{Ur@2}x@3 kP@35;|&R@3_vHQ@3(`@3% @3(k @4N2>)@42~E4@4\ @4[E@4@4+@5R@Z@5/v@5Y@50X@5N@5$~|@6(A@6,)`d@6V@N}@6VE;@6jz@6|@6NR@7(5@7Rx@7|C@7!9@7ǒΆ@7r05@8$ƅ@8Nגff@8x4@8ڥ @80@8΃(@9 6A@9J1 @9tt@9I@9ȷբ@9$f#@:72@:F@:p^h@:uz@:dJ@:QӔ@;>@@;B)@;li@;n}@;Êe@;@<,. @<=ʞ@ k*5@>3_@>][5@>V@>d,c@>6@?˪@?.Wx@?X$,@?v0@?CBf@?-1[t@?۽l#@@.{Y@@)m@@>i>/@@SVr@@hc@@}Fb*@@)hP@@ G@@<2 ,@@~[d@@Rp@@f@AoΤ@A$O?#\E??&?c$=mt?dbG/@%{k@[@pF` @ R@mc탿@2ߒ@ @ I_X8@ Ok@S$@`-@P@<@hZZ~@&)@{sz@v؝@Zɽk@@ϣw^@@B伷X@l(@W_@i(9g@ @o@@C\J@ @*@cM@E@6W@ ?5@ *@ j;V@!MH $@!w5m@!@"Y@"/u^@# 66,@#d#;-+@#_V@$q@$nX5P@$fS@%^Fg@%wR)@%J?@&(J@&qU3@&؆ }@'0|"$@'w@'Vg@(8$ + @(4%@(IXh<@)?+B@) @)9 @*E 6@* %Ӣ@*`"{M@+K@+x1@+B޸9@,Q.`@,Bk@,I,@-VEci@-5x?@.*Z@.Z#@.O;N@/3@/_?դ@/'N@0I>$@01`q[@0\ }+@0#@0c.x@0ޝT@1 A@15@1`2/@1[N@1R@1h6@2 }@27֡A@2bMDw@2M@2 %@2[< @3_|@3:bX@3e6J@3@3 ov]@3gu@4J7o@4;Ny@4fV@4(@4ρD5@4qW@5Nʻ@5=)5@5hS@5@5/P@5u]@6A:wq@6> K@6hЛ,@63=n@6Up@6]P@7@7>*}@7i>so@7@7k@7S 0@8G@8>@8iQMz@8a@8g6@8;y@97@=@9>vt@9idO@9p@9>[[@9ұj@:d`\@:=t(e@:hin@: x5@:[;@: @;@;='.[@;g@@;(@;{gL@;"}J@<f5-@<<N(@2@>90u@>c)EC@>~@>R@>:d@? $@?7f"@?ac@?.@?l@?}@@=@@'@@/ڿzm@@E@@Z(L@@oNr@@s[7@@T"@@-=@@ZT@@ۼ @@#MW@ADz9m@Aej`@A-MT@AB̬@AW'u@Al!@A{G@A7 @A7T]@ARC@.# ? 2;@ߛ{@?TY@S}iT@  @ܨE@ d@ =(@ P,2@@ @ׂ ɺ@p}X@}@Dpk\@ =\@um|A@es@TJށ@6\@֋!]@zaq@U @8\@iWe@f${@LK;@L) c@pT)@&^@9߁@'En@@ 3z@ H{@ Z4]@!HѠB@!ԴD@"Gd@"\_CL(@"4(< @#Qu$'@#n l@#ɴ2u@$$1@$Cɮ@$QU?@%4Oܱ@%wߓ8n@%:@&D->2@&_HZ@&xx(@'Rx4@'_@(/x-2@(_SNO@(b@)ۺ@)l"M@) @*@q>>@*x{Os@*Ѥf@+*]@+z,N@+ܭ$Dp@,5:+_@,\]@,n@-?@-gbT@-4@.Iu"M3@.壔@.GX@/R1/@/He@0`@0-Oc@0YB@0qpQ-@0I0s,@0ݵmd@1 lz6@15RYQ@1a@1hue%$@1F@1De@2i\_@2<, .@2h @2K2@2 \@24W@3wc4$@3C&@3n=@3w] @3>@3ݳZ@4Lj@4H@4tp +I@47͇@4ˁ H@4W@5"%.@5MF#@5yt0~F@5;2@5U@5k@6''^2*@6Rc@6}꿔@6F嬉@6ԟ{%@6O@7+F$x@7VO@7^@7&T@7j?@8$@8.O@8Z#@8[:1 @8@8*h@9g@92= b@9]B)f@9g[@9p)@9ު!@: u@:4 J@:_ca@: @:`7@:.>S @; :Is@;7D[@;bL{%Y@;QsSӀ@;Sz@;S @<Qf '@<9L}@}'@><\l}@>g:@>AE@>{1@>1@?@?=ov@?hAOq@?ͯ@?3@?詉h@@ b@@@TI%@@4/{*@@IA@@_C@@t$vH@@I?@@`J@@|@@Qw@@uJ@@Г@A *fF@A]@A4z*@AJ2 @A_,q@At@%@A3@Aۂ@Aڧ@A,^a@A~@AMϢ@B G ʔ@BnyAa@B4"@BJ Y@9*>@$@v4@: ѱ@pm@ 25u@ 젯 @ 4Öha@N.-Z@{E@MO@f @ @(@&.I@P#K@A.@?BF@4-Y@n0)1@3F;@ʿO@_G@}<Ó@?a@9@a˥_@RB>@̆w@AV?UU@ +V:`@ _iQ@ i@!,R@!{;@! @"8(k@"Vd@"Ϩp@#Q\;V@# l@$ @$hnit@$|@%"p !@%,@%۝u'@&7L@&9@&!ew@'L {+@'Kb@(MJ@(_e7@(R@)uP@)q@)=l@*'E+m@*5Bg@* u@+7o.@+u!{x@+R&[@,G0 @,UQ@,<-@-VynpS@-Lix@. BY@.d@.9@/Jt@/rU@/i@0E4S@0?lK@0llVZt@0(-ɟ@0_@0CÃ@1,/y@1KΣ$@1x_?@15!_@1u|@1Gg@2*p @2V|K@2O@2@2d@3nދ+@347@3aʣ@3V@w@3{'X@3M^I@4 zn@4>;G0@4jf@C@4-g-@4¬}F҄@4ǽJK@5pQ@5Fuc@5rA@5@5g@5.-@6",@6Nwp @6zސ_g@6ɬ@^@6ҰV@62C@7*p@7VJB 1C@76@773I@7پJtK@8yo$@81LT2@8] a@8F|K@8D}@8:@9 @97%S@9cEh@9m4@9@9/ZK@:C'y@:=eF˿@:h@:%=&}@:Hs@:맻@;0$]@;BX;|@;n7`$q@;E]8@;2@;R@< }s[@$Ȩ@>P`@@>{cV b@>6^4~@>@>?K$@?(ts@?SP@?M[@?Aw@?{z@@Y,@@B@@+uZ@K@@A&D|@@VIǐ@@lT{@@|4@@}|@@Op@@¢ @@2>C@@8C@APa@A.@A.jy;@AC~9@AYRC@Ao SVb@A@Aѓ@AK<@A$@'@Aڨ}@A+&@B:i@B/o;@B0@BF/Ja@B[mf@Bq+f:@B¦@B#@B#y9@Be@ƛ@&,+@8@ (r@ 1@N @W}J@*2C@>8@K @pY @D@N@; 4@핖@Tsj@dG@S۔q\@n[*@-i@up@|q@DB@ Y@)N$@[_R@\%f@ !@ qg@ M0|@!4r4@!P>@!A]O@"VD`g@"`%(:V@#?W@#uxj@#V`@$4<%@$3*T@$pm@%Q @% @& ߈@&l7\@&C@''ν{@'z@'`@(@a‡@(/ @(y@)W@)NB@*K=j@*mWa@*f}]@+&ȟW@+ }!$@+7U@,;G@,;a@,R9-@-N8@-@.S? @.a~“@.|q@/DET9;@/s|@/Π?6T@0m5 @0BTNS@0oǿp@01/@0ʑO0@0?@1%4Q@1RyU@1q@1!@15 @24LM @24N8@2a`/p@2j%>@2ln@2gd@3ZWj@3BF:.@3o*(@3~P@3&X@3}4@4"w>(@4O:K66@4{*2@4o)@4Z;{@5옞@5.s6@5[C61"@5 [i@5k@5;g@6 {Ɓ{@69Bw@6fv+}ן@6.@6ZGE@69 V@7*g{@7Ds@7pp@7;p@7ɌWl@7ؽ%/@8" +:j@8NbΏk@8z@8VƊ@89@8?b@9+k*a@9W0͍@9wΏ@9zr@9Gt@:O@:4rz@:`'gx@:2_~@:8ݐ@:;pӊ@;:% 6@;<5*@;h,I@;yśu@;#1@;% @<@%yc_^@>QyT8@>}3N@> @>ԝ_wZ@?MC@?+6@?WI@?N f@?c@?ڔ|@@:0@@-@@.j@@DX2@@ZJ`Hp@@p ̲.@@bHd@@c@@eN\@@(w @@2@@_@AjD6@A)5'@A3@"@AI@A_\@AueD@A/X3u@A)or@A:@AU@A :@AU\׉@B ܦ@B",Q@B8e~7@BNLe@Bc@Byka@B!X0@B@Bg\@BF$>@B嵋,@BZ3z@C_@C&!仠@C@,(@,tXE@,9X@-/8`@-`W @-ldE@.F\O@.1@. )@/\H@/ a@0 »wW@08j@0gS3@0"FA@0+L@0)$@1*\*@1MO@1ze{@16*#@1ւVyu@2B9@21lF@2_@2Jp@2BM@2w󿪖@3PI@3C8@3pl՜@3jx̑P@3_6@32C5@4&Idk@4Sڐ@4#;)@4djk=!@4۞;P@5,O@55*."@5T梧@5d@6nIZ@6Dq3ǝ@6qm;@6cۗ@6S@6=h@7%!@7Q`@7~ׄ @7D?@7vH`@8=0q@81@8^o.2@8p축@8"1@8!@9tawa@9>LΞ@9jRK@9Jd|]@9@9jS@:xZ@:Iw6.V@:uzb@:ra U@:(@:Zӹ@;'R}L@;T0οU@;cIY@;ͽ@;QSI@<}1@<1$# =@<^L@<&Kd@<ߚ@<#c"@=bG@=;H@=gT^@= H@=:Xd@=fމ%^@>G%@>DH+@>p}$@> @>=V@>% @?!9^|@?MI&@?yV\8=@?_W@?e@?hm@@ T@@*&@@@Fě@@V@@l ,^@@s@@2o|k@@@@yBP@@k @@[Zp@AJ10@A7C@A2#B@AH@A]+o>@As@A4WX@A'أ@Ab@Ao@AP߂@A0q $@B @B"뤠H@B8LGx@BN@BdzŁ4@BzRM@B)3@Be|@BҬ``x@Bѥ;@BwD*#@BG@C@C(0P@C>$m[w@CT}VM@CjHlA@C%k@Cpt@C&@}f@B9R@pZ|@bF@Pmw@:LxK@ 3@7q@f2g@ė(@K&@|-@U*@,u'F@Vڳ@S?@E@{T_@LHs@K@P@ \czD@ A@@!) A}@!0$S@!X@"X/@"P6>J@#!X@#c @# ʦ8@$L>Xd@$? @%AH@%tttT@%֯+M%w@&82o֊@&n/VS@&7@']I@t@'f( 0@(O& @(@(2@)@B@)H@*@*`d@*@+ ,=@+v@+ޭ@,=@@,z@,x ]c@-Z!U@-D@.\@.uX@.ӁV@/1I@/yF;@/I@0%'@0TK}@0 @0@0a@12V!@1=hD@1l@1z/@1㱇n[@1A# @2%y1@2SQ3@2@2Il@2q@3 %t@3:t@3hq@3rk@3ĦA@39@4 yGVHf@4NUnZ@4|(D{@4J @4׵2@5p8@53!ܠVa@5`˨5@5miM@5/X@5x@6$@6DP\c@6r$jQ@6N4@6[@6mj@7'tg@7U&#@7yI"@7k@7 d 1@8 IG@87@8d+w@8XD@8tA@8&@9@zta@9FU/o@9scӭf@9lR@9p(p@9m,@:'f`>@:TY]N@:GD@:/q@:X@;ä@;4D@;ã@;lT3@;7v@;[@<Q@ @<% @<ǐZ @<:{'@= ߫s@=Mg(@=z)@=۱q!@=H@=J@>,c\~@>X's@>nPO@>:@>h5@? K&@?7Slz@?c|:@?.-@?%B@?@@ G@@ 턦@@7}b"@@M3@F@@c\:]@@yq5$@@n"@@̣"t@@o@@O@@-#@@J$Ul@Ae,@A*#N@A@4@AVx@Al{@AG~@A-@A2* @Al@A?@AX@B)S@B2bt@B39_@BI?LB@B_CL@BuFr0@BGMBq@BG @BF@BCԫ@B?'Q@B:A@C3qè@C%+K@C;!H@CQR"@Cg i@C|@C4J@CD@CͿ@@CԻK@C꧙c @DG@D| }@}`^@zʹ}@r\S@eu@U,2x{@@>@)q$?_@=@+@Ri-n@v[@i f@l6c@F@ԔC@Kp@2Kt@wu@ 9gO@ Svq@! =׍ @!s_Y@! @"BKN (@" @#iu͉@#u@#V<˫@$@*6@$qM@% wi@%n&{@%d@&6@&y}@&^@'`@L@'ýش@(&[>d-@(vMT@(a@)L;@)_6 @*8c@*qtvW@*F@+3Ζ?@+@+Q@,Uwt@,,k(؏@-]c@-vgaX@-L ^@.6 @.q@.!7)@/Tx3$@/@0 am@0873@0hH @09@0񓳀@00tB@1%a,3@1T 3']@1Vg@1^%4+@1e@2$@2?l;@2nBC\@2 o@2ɅWE@2{Q@3)"Վ(@3WP@3OV @3;(@3Qh>@4fS@4@*0@4n8i'@4U5@4%@4f@5'K5@5U  )@5BZ@5 @5!R$@6,tɹ@6@ J @>76 @>dZZ@>^@>_#@>,~E @?@?D^Y@?q+R I@?Ŵ9@?ʷ0lN@?x (+}@@(@@(u#@@>l@@U'@@k}@@jЁ@@#b8Y@@sk@7@@@@ A@@X&N@Ao@AT,{}@A4,-\@AJo:>@A`}KƟ@Avd@A-#@Aiu?@A@AܕE@AxU@@AH@B|k@BU t@Bk:$:@BeD@B:r@Bjh@Bޥ^@BX@B'J@CIx @Cjy@C2@CH8@C^@Ct@CIF@CN@C&@C< KY@CO@CbdS@Dsx@D%2 2h@D;@DQ&@DgVo@D}@~)l?@{V@sq @hW6x@Y sV@FzH@05u@ @H@t!@9;@2vdz@u@[T@6x@ &a@ sq@ 91*@!JN@!G}@$~{@$X`y;@%\3@%/CS@&'wn@&l{=4@&@'Wy)Ǯ@'x@( nE@(+C@(\jR@)Kч@)Wx9@*~#@*um&@*'Ry@+:-:@+@+#,N@,a3+>w@,@-$s^8@-S"@-!$n/@.H9A@.)\y@@/ @/jB51@/T@0P@0Ea@@0uٳ@0@0չׯ@1XQf@15Y]}e@1e;p@14|@1U^8@1LJ@2#_ X@2R@21@2@2п1@3t@3?7?x|@3nYZs@3o]@3y@3xm@4*k @4YRT@4/\h@4@4 1;@5%@5C8g@5q L@5T`@5l@5j2@6,!^s@6ZB@6 *@6oh~@6!@7!}@7Bmf$3@7pJΨ]@7욊1@7u@7J@8)mˆ@@8Wd@8e"@86! P@8ᬁSR]@9a@9=<:@9kKN+@9t"[@9T'@9. Z0@:#?@:P9@:~KHH@:O3i@:{ @;qoI@;5d@;c @;@;A o}@;c@<aG$@ .@>:E@>gsx@>̝^@>k &@>?K?@?qJQ@?IwQ@?v@?ꋗ)@? F5@?#xD@@C@@,%J3@@Bð@@Y0b7@@of@@1N@@mF}@@+lF@@ɤɂ@@ݙY@@#X*|@A ]i@A#uQO@A9c@APQ%@Af0@A}&x@AҜr@AB@l@AVe]@Aָu@ABV@Bv6jE@BVτ@B0,@BF,Y@B\m(K@Bs0S@B@B՟d@B%gi@Bs{@B @B %a@CS_@C%H:@C;ۀ)@CR%@Chg3@C~'=@C[ɯ@C%Ε!@Cbp@Cלt@C\1@D Rh3@DC93@D0xTy@DFHX@D\ݹb,@Ds *S8@D<)@DjbZG@Dk#D@D  @DD=?@~EW@{s@uX@j_d@\F}1@KpV@7V@ 1@ƪ8I@@$1@9ϏG@Vu@ 7pNgB@ `@!V$K@!K@! @"Xm@"ê@#.c߆@#0|4@$duѭ@$k2@$Ԡm@%=! @%@Z@& ra+e@&tf Cx@&tǑI@'B0V@'$z@()@(td'@(x@)?^u(@)bB@* % _@*m @*{@+5k@+}=@+qa@,`9s @, W@-'~@-["@-@.N/$@.;1@/Uo@/uD^~@/  @0TF@0M-@0}yA@0K,*.@0x}^@1=˶د@1?w@1o)Ɠ@1&@1Se/D@2oB@20|fQ@2`yDPx@2g^@2GXzV@2]/@3:X@3O77@37^~@3ѥWfF@3^ @4 ޺q@4=R@~g@4lj@@4p>@4c@4l@5)e@5Y p@5,K^@5CS@5O`T@6P,@6DG ݨ@6s4Y>O@6 ߏ@6H.@6N@7.~]M@7]@ֻ @7vY@7.n@7=鍵@8~@8Fd @8t1@@8i@8XY]@9L2@9.IHZa@9]@9e@"@@9)U7@9e@:7^~@:Dn @:r|G@:)@:B"@:~3`@;+ь@;Y"@;'S@;&܊@;?ԇ@<pE@<>@FA=@>6[M@>d%Z/@>8t@>[$2@>9k@?|/-@?H~S@?u@?oG@?~/^@?tї@@@C;@@,e@BT@BцḚi@B&E@Bj4j@Cr1G@C+FPX@CA@CXuYr@CnB@C~J@CO6C@C@C|@Cs[@CѕQ@D -$@D!7[@D7@DN9 \W@Dd'@Dz!Ó@D59v@Du@DւY @D$|@Dq!3@EwK@E,O@E-M҂@EC#@~iy @|"@uN~@lN@_C@Oo@dd @*1i@+&魌X@+ a|@+6rw@,V a;`@,äG@-4Z@-og_4@-uE@.KGP,@.48y@/VNo@/uy@/اQaI@0@0O"1@0h䗫@0^@1uB@1lZ@1+{ e@2؇ņ@28tE@2hm_@2yOﲽ@2R @2=sJ@3*B@3ZY@367@3 }az@3GR@44@4K{e@4z?@4Zoh@4ڛ @5 Zɓk@5: @5i@5L2@5p26@5\J@6'^@6W>X@6tH@6@e@6={@7}8@7C%Gޅ@7r>@7>&L@7Lk@8#>@8/'1b@8^!T&r@8T@8@8.S|@9,@9Hzz2#@9w>Y0@9M@9ԭr@:WɟE@:1L@:`z@:'$3A@:U@:4x@;8CT@;I#4x\@;w/@;Hi@;QMv @<GC@<0=u@<_>ωr@<*@,H ]@>Z3@>0nc@>xگ@>@?g?@?@Jy@?n'@?5;@?#@?a .@@m@@)c@@@p^ @@WL3mո@@n$"/@@9@@Χ}lq@@ۿ@@n/OQ@@:2k@@G@A f!=@A$S@A;QNTg@ARqq@AhK x@A5׹@ACyg%@A# @Aî0@A`\@A|[@Bhk@Bi@B5kX3@BK@Bb_j@ByCh@B@BBk@B@Bz@B%@C @C?~@C-|V@CDc[y=@CZ4M/@Cq۱@C K@CA@Co*'8@Cˢ>>Y@C&;q@Cj@D(ϻ^@D%nws@D<$J~@DRg@Di @Dt5@DjC#W@Dz @DHB8@D^6*?@DF@E;$@E*^@E3&@EIzb@E_~@EvGC>@EYð.@E \@~'i`@|obh@vCO@m1#@aYX@Ra @@@ @- 1j !@ @ _6@ "@!dD$O(@!P@"Fyo@"l@#&B;@#I4"@*a @+ rZ@+t@+2gw@,A@,8@- A @-sTU-D@-ĥX@.=$F@.k@/C2 p@/lX脺@/к`(S@0uѿ@0Lt@0~\FB@0-tع@09@1N@1E b'@1v _p@1 @1N F@2 }@2;m@2lрw@2h\3@2͈#@2Ci@30d9@3aEJ@3x@3™Z`@3+Z>,j@4#@@4T!f@4Mr@4ܒ+@4$@5^fe@5EF3@5uv@5H@5mRB@6gp@65@6e`&@6V@6+S@6؛K@7$_@7T-(2g@7ƣG@@7U)`@7箈@8R^@8Av@8q%y@8a`@8ϫfS@8"@9.R@9]);*@9n"@9Жժ@9 r@:}׉F@:HiŎ@:w`@:,e@:ƦV@;@;3@;bi3f@;4N]@;w@;wE@<er@_@=ݸ&@=e/<@=k=s@>4&@>K}@>yl@>9\F@>ւ;@?U|y@?3?Z@?a:mB/a@?k1@?ٗ@?뺅@@ \@@#p%@@;} @@R 91@@i E6@@ đ@@ g@@FQ}2@@@@l;@@AG@A ٴ1@A ǯa@A7S|@ANͫ@Ae'm@A|e@AG)!x_@A%@AH@A3@A@B9@B[3'@B3,S@BI@@B`@Bw@BW[@B.!@B @Bҟ@B^h.q@CPp@C"A@C-Sز@CDCnݯ@CZx@Cqs@CYg9@CV]-@CE̾@C]9]@C7*@CA,@DO]G=@D&#Ek@D=}s@DT0CXB@Dj΋@Dg+@DYb{@Da6@D,މF@D @DQ 06@Eᐳ@Eo3מ@E5z@ELf@Ec@Eyn{@E2@ELh@E"yB@Eӣal@E"\@F%@~@|M@wV/@nͅJ@c`lu@UPW_@ "j<@ $@!F,8@!NXҴ@! @"i[@"ӳ@#My@#*JSr@$.2y@$]d@% m=(ns@%za@%irK@&UB@&]]=@'.#;&@'w>@(c@(p,VU@(y@)E @)eNt@*%]D@*J#+@*(:N@+S'_@+ @,#Zʎ@,cv@,#Yݺ@-Z)@- |d@.'a=@.@.Aj(@/Z1AE+@/n@08M@0EZʦ@0w! c@0Xgv2@0ܱ;H@1@1A~@1s0iz@1-;#@1H(@2^Q@2:S@2lK@2<@2bj@3q><@32,6l0@3cuʱZ@3/H@3<@3$J@4'a@4Xa@42@4d@4^;@5V@5LMO@5}Sw @5J5_@5Y  @6t2@6?'Q(@6ozTL@6<=u@6B<@7%œ$@70EH@7`Y6C@7`Mt@7\D @7LȐ@8 1u(@8P yO@8$]@8 @8U~@9@9>{@9n?f@9財@9T,@9{\@:,A"@:['`@:@:]#ff@:SbK2@;z@;H&@;wX-c@;,@;ա0*@<@<3ps@9@>7j+Wd@>fc@>zʏ@>o6@> qđ@? @?O5Ԭq@?}ډ@?CZZ @?Sbp@@l0q@@}F@@3g˨ @@J:2^@@ah @@x"@@1@@Wg@@\8@@%J@@B)[l@A\+3Q@AsW@A1@AHLIO@A_#[@AvCCM@A@Atp@Aȓ3@Ak@AN@B^Ć@B0$^R@B.~@BEOl@B\t@Bs@B{Z@Bf'aY@BN{@B5 @E|,?@E,@F >@FZB^W@F/Sp@FEꍜ@F\ƕ@~q?sI@|@w@oڻ@ 2$@ x@!$(S7@!KI@"n#@"v@"^\@#nŬ^@#@ܧ@$SH`n@$ġ*W+@%5Tj_@%jX@&G@&K@@&K;@'`6C@'ͦ٢@(:IN@(*B@)G7/M@)~5p@)MK,@*U>G{@*ҺodF@+*@+E@+e [@,fǍїs@,ϼ3T@-8e7@-o{H@. @.pS,D@.K0@/?Bɩ@/OY+@0?i@0:jj@0mH).@0_s@0[K@@1Hy @>M e@>|F&@>`>@>ڜE@? @@nx@@ޝ@@cG@@y@@c /@@@6@@Q}~5@Aİ2u@A) ,@A@@ nO@!3\zɟ@!CA@"%r@"I3K]@#b@#[@#~^j@$r'#@$G@%X1c 0@%w D\@&;5@&|#@'zn@'58@'F>*@(i'P@(AG@)Eg?@)Ͽ@*eF@*ZV@*ߞá@+cyK@+ηP@,9/U0@,*@-e@-xPr*@-Q-@.K>@.GSjY@/ @/%W@/@0*2kb@0^..@0y@0˙^@0{?@1-DF-@8,o@9#5W@9S@9 @9e}@9@:P@:E,j@:uX@:z۩@:Ց]T@;@;5;9@;egFI@;@;h"@;BjQ5@<%@=pd@>0l@>`$i@>n@>/ >@>Rs@?WZq)@?L9ua@?{h@?v@?!;}@@_׼e@@,"F4@@3eo@@K: *A@@brd@@z9[dV@@@@*R3@@r @@@@{HA@A\1@AKN@A5o@AM=7N@Adk;0@A{ȇ@Ax dC@Ap"Z@An ~@Ar.J@AY'O}H@Be@Bu@B6'$Y.@BMg[@Bd`=@B{-@BP@BG[Wl@By@y@Bا9GO@BD|@Cm@C$>@C5Hz@CLj( St@CcLN@CzuK@Cs@C@CMG@CB{@C9qm@DBT@D)c@D33G9Ɩ@DJ:M$@Da?@DxAy5@DA]0@D?o@D;Y<@D4J@D,90@E!h_@Eq{L@E0YU2@EF$'@E]Bv@Etws@E@E,% @E @Ea@EA}@E Os-@F @F+נgD@FBHev^@FY.6@Fp[ف@F.ʃl@Fjo@Fq|@F˜knN@Fg񰬵@F1$@GBӎ@!?o@ B@!@%v?H@%@&]B\U\@&O @'A Y@''>v@(#Q@(f@)z@)r(@)Whn:@*O@*cw@+*1e @+xP@,Y/c@,pa'К@,n@-Gmg:@-3@.N@@.eqK@.y@/\@/R3@0خU@0Le@0_*@0o@0GW @1TRW@@1QCA5@1׎ȉ@1 ZoN@1ck@2.p2F@2SF{ل@2$E*@2ޅ$@2@3N@3RUZ@3@3W+@3@459@4P q@4vM@4{@4 |[@59N@5KU\R@5}]B@5Tp@59ro@6 11O@6D·@6v@6#8oE@6ٴ@7 6:F@7|@;o>|@;Md@;Ϗ @;Ű7*@?W%>8@>oȝ)@>K@>nA@>\@?-I@?]9#V?@?]H@?A;M@?̾@@ -B(v@@%I},@A͌Rb@Aߢ@AmeGT@Bى+@B+BCqb@BB@BZ je<@BqjV۳@Bb@B $;@BwT6@B>.@B6wu@Bki1G@COwf@C,6@CCFc;C@CZ"š@Cqʥz@CJ@CDH},@C}.;nz@Cγ~=@C@ @Cw@DG,%´@D+sb|s@DB J@DYkr@DpIk@D -@D+QG@DIg`@DdGA@D} /@D<2@E":O}@E)QC@E@AV@EW ~@EnuB@EÇ@E-@Ed@E`x@Eg@EoZ@F @P@F&?@F=Y @FTm@Fk@FTt@F}@F @FǓ_>@F}A]@FfMo@G LyQ@G#1/[@G:X3@GPA@GgNcI@"?wx%@!% @"<@">XN?@#4Ut@#U@$(U%v@$@%"I@%Zn@&7]@&ye@&=<@'aP@'ԗ2@(FoX@()G@)*0S@)I8@* @*zG@*:n_@+X:h#@+,@,5"V[@,@-@-|t@-@.U3 H@.I@/,d1@/ٝw@0)z}N@06kX@0k0wx@0v@0ZU@1 @1>@1s 4@1p_g_@1ۨS@2M?@2CUӽ@2wXZ@2k6\@2i@3h%@3F$#v@3y FO@3Ӭ@3@4S%[@4F A@4y @4#@4ޥG@5TGT1@5Cn}@5vt$X@5箁!N@5GN @6 !#@6?ϵM@6q9@6 s@6#~E@7 DZy@79N%@:P<\@:-@:>>@:LS@;@;Dy-2P@;u.~@;nL|@;wa@< @<7)I<@{@>JY@>z־@/@>|Yy@> 1@? 2&@?:5@?j7@?xf@?J鼲@?@@@@,R:@@D%@@\seb@@tC8@@P@@k+@@@@] W@@ɚ@A"H@A s@A2;&@AI=@Aa Z@Ay</k@Aݍ@A3X@A.@A׶@ALr?@B@Bo_P@B5I @BM@Be yų@B|S@B y s@BO@Bt@BzH@B$@C ^x$@C %6O@C86@CO̮Cs@Cg[@C~f 0|@Cpl@C"rHu@C{g@Cc @C' @D yVK@D!wE@D9@DP^W@Dg.PA#@D~Y@D-)/c@Dlv@DĪ@Dԏl@D IE@E RG@E!sd@E8%@EO:/@Eg7@E~<&@EdSZ@E[ҧ@EìH@Eic@E{j@F @F #/l%4@F7;Au@FNQ)r@Fed]@F|v~'@Fc@F{h@FlQ@FبJ;@FPD@G%j@GT@G4[@GKʘ#@Gb<6@Gy|bQ@G Nd@G+גN@Go+@#?~U@"@#< }@#9@$5>Z@@$nD]@%)u;s@%$K@&ߣ@&O_@'(ma&@'|~!#@'iQ@(e5@(@)K>B@)4x56@*/P @*3wA-@+˳8@+.g@+ġ(@,aNR ]@,7{a@->p@-O@.@.F)p@.i@/aL@/а(@0@0RkO@0i- @0_E0@0V0T @1(SO@1]d`@1"@1NJ8A@1E@202 @2e_n@24@2J@3*ԉN<@367j2@3j(l@38(@3ѾR@4c0n@48 _@@4le*@4 M@4 3F@5;Ș@59VCЌ@5l\2@5M{@5)G@6 o@67@6jHq@6!ǜ@6SK@7H@74pj@7f\|l@7֡k@7ʶ&N@7*L̻@8.U@8`Q@8)@8z6s@8?"&:@>S(*T@>H@>K@>:Xl1@?k:@?DQ}g@?tѕ6@?#&0@?Fk'@@_On@@H%v@@2}M@@J@@bXl @@zY@@X@@4@@~ߊ@EF$I@E]r3\d@Et@ES(~@EK @G j'@G1I@G@@GMي@HY gy@$? ƫ@#ٷmj@$< "@$ڡ@%5]7@%4\@&*{ ?B@&x q@'[]@'|tR@( @(lEٺ@(V0K@)i(a 6@)@*Piu@*.g@+5i4@+3@,V[ N@,d@,Zx M@-i1{@-ؚ]@.G p@.7@/$rI2b@/N=V @/@06{i6@0l+@0%:[aW@0=!i@1.<@1D6(@1z @1"Y@1a @2a@2O-Ө@2۔6J@29@2y^`@3#DR]@3Ww@3 / @3Y)Q@3+2@4( v@4\S2@44o@4X`ML@4>z<@5+w@5_4C}4@5f@5@5FDb(@6,v7k6.L@<  @<=~@@=_@=3etT@=daOR@=Q @=6*@= n@>'ಣ)@>X@>`$շ>@>KH@>?(@?R r:@?Ks@?|l/N@?~I@?_vd4@@nMs@@u@@7B@@Oj\S@@g @@i@@ǀJ1@@ݪ,V@@@@($@@(@A ދ,@A( tԔ@A@ &@AXAVf@Aoed@A_]@Af@As,@AϦ&@AD@@AfSа@B@E@B/@BFϛ@B^pQ@Bv3@BOTL@B)@Bզ@BՕf녹@BP˶@CPi@Cf@C4nA@CL;t#@Cc@C{nr!b@C1@C%@CS@C[tT@Cs@D (B@D d F@D8=@DO_R@DgT 5@D~(=X@D^b/@DZy@D^hl^@Dv5@DRG@E 2@E#'@FǪ6@FbTl@F1@G r 6@G$W@G;l@GS%0@Gj\[m@Gx{#@GnX4@GA+-@G#j@GP@G{L<@H ̳@H#Q@H:5)@HR@Hi0͑@%?h8[@$Z!@%=K@%-{D@&67/"@&Faw@'+j Bu@'^$@(#?:@()J@) z@)`ˋ@)o@*l:@*̋@+T>@+ȷ@ @,:sGL@,RFq@-F@-x1 9@.6jģ@.pǫ@.gv@/O@/s@0ט'-@0N6#@0=@0dE@0}"w@1( 0@1_RI@1$@1ˍ5@2rt!@274a@2l@2Ql@2׮":@3 @3B,@3w.=U@3J@33@4UeD@4IC@4~SIS@4&@4.؛@5 '@5Oqs@5 4S@5i@5ꭐ@6\$@6Qz=@6wg@6A@6= $@71Y@7Rnr@7'v@7؝.Q@7-*n=@80@8Qhڗ@8D@8>kiB@8T`@9uo@9N쫿@9n@9]JZ@9s1 @:ч@:J\2@:|.w@:@*H.a(@>[cq&R@>s @>x@>sd͢@?c?ME@?PH@?#e@?W'x@?J@@ &@@"@@q@@Ʌ3:@@j@@6%r@@e@A:F@A, ,1@ADڼE@A\4 @Au@A)g&@A;4T7@AIW@AS]@AY%@B\@BZf(@B5TwZ@BMK;@Be>@B}-q@B]* @BOt@Bf; @BtHsH@Bz 5@C }¨@C$S*@C<&@CSGޞs@CkuB@CQ @CPlI@C4|P~@CL-@C2Ug@CFN@D @D)ɣ@DA^t3@DY h@Dp.˰@DZ4 @D@Dg@D;W@D֝p@Dnk$@Eb@E-@EE$/@E\iqa@Et;epW@EŽ\1@EG)}@EҨ#@EGU@Eā`@F>o;@FI@F0*^@FG4@F_ t@Fvy^)@F@FL,h@F@F5DF@FwD6\@G@s@G2D-K@G1>#@GH{@G`9@L}@GwPA@G@G+;a@Gw@G =@G #@HO @H)놙@H1ԋ>-@HIɚ@H`P[@Hw~1@H@HD@H0O9@&?@%=U@&=:&,@&oO=@'6[/@'kK@(,E[@(9@)7a0@)*S@* r@*[Z@*I@+o]`(@+NL 2@,Xs焖?@, Z@-? 7x@-F@.#hK@.kj@/Ȃ@/wYJ@/1@0+V?@0c^ȵ@0(H@0ҏ6@1 @1@ֹ1@1wNn~m@1tΞM@1n@2sR @2Q'a@29q @2GY_@2_@3)nZ@3_)@3@3ق#@3<@442If5@4i2m@4=@4N4@5WNr@5<T)@5p}!_@5cЏ@5?OD@6 nU@6A欒Y@6u ʠs@6oy @6B=@7 X@7DSq@7x;Ks@7-@7#݈@8zaC@8E-@8x@8 1*` @87/A@91X@9Dq٤#@9wFU@9@9Dޡ>@:4ْ@:B{FT@:tWU̴@:qۊ@:Ձc@; *'@;>o@;p ?'@;ުI@;(@<T@<8Й:@*@>[%"@>6@>BR[s@>ŷKT@? ) @?R$7j@?=[ǫ@?`v@?y~@@ Cɻ@@#'@@<@B@BʧM.@B9$@B,K@CꋘW@C* HϢ@CB*6@CZR@CrqJ@C[=g@CAB@C$6'@Cq@C:4@D @D)@D1bKY@DI1r@D`@DxƼc@DMT@DOO(+@DGm@D˔Gz@D*g@E;©b@Eb@E64L@ENM֓@EefG@E}@EE"U@EB@EćӔ@E$Y@E"@F V@F"ꥨC@F:|9ݚ@FR 郕P@Fi"չ@F"c@F xJ9@F/ B@FDZe$M@F1;@F@G)h$@G%6v@G=I@GT8H\3@GkPM^@Gkm@G[@@GAV}a"@Gɨ)j@GP@GqXc@H`#@H'0^@H>5@HUf5@Hm>rT@H4*@H<4@H8%2@Hʇ"@H'@Hj@Ihi@'?;@&J@'=YDe@'p@(7н;@(x*@)-@)@*j:@*|:@+F'M@+./@+M@,rvɏ@,@-\ F@-@.C{h@.s.x@/(Zy @/ȣ@0H~`I@0>݅U@0w=Ӈ@0k/F@0gE.H@13@1Vés@1C[@1ʼnnm@1g@23ٱ@2jc8@2@2׈ ק @3 +s@3D)Ml@3z.R@3!3@3f @4Md@4Q9F32@4,@4H@4>N@5&[t@5[]\ެ@5CB@5 @5@@6.[R?@6b*,f@6B. @6˒w9@6ˤP@73H@7g@7@7%.@8f@87P1k@8jDF;@8mm@8 pfb@9bx^A]@98 @9kb@9(Ix@9G@:SuE@:8N@@:k8b.@:]!a@:v@;j`3@;6=y@;hB+@;`e@;us@<GϽе@<2@'Q @>Y@>םѤ@>~@>-{@?Ɩd@?QT^d@?@?Lw6 @?ȃ4@@ fw@@$6q@@<]@@U{T.@@nF@@8@@@A&&@B pؘ~@B%f@B=yο@BV6?-@Bnoj@Br@B(0@BP7@B,[?@BRu^@Bs݁.@CQ@C/<J@CGdf@C_j@Cw◓G@C@C5El@C#͡@C[`@Ckߖ@DT}+@D@D7dKS@DOǘ&@Dgt @DA@DHd @DcN*@DB@D@D1`֋@E˅$l@E&@E>l:@EV8K@En @E(fF @EFD@EKrG~@Es@E;:@EzԹ@F/9@F+`@FCf@F[<_@Frt@F@F0ɿ@F3 @Fpy@F g@G @G={#y@G/G-!@GGc@G^֪@Gv8@G r;@GTn@GBL@Gԙº7@G7@HGf@H@H2F1"@HJ?J:@Hax]'@Hx;1B@H[F@H -@H4n@H֝@Hກ@Ii /@I\,@I4,Q@IK"i@IbK@(?Q]B`@' N"@(=uJ@(ra@)7aϱ@)-@*-Ȑ1 x@*ױ@+!V@+9\K@,dO!ǽ@,8~@,(_ bD@-u"._@-ˬ@._e!oW@.ӹ G@/GO@/#Q@0಑`@0PU\@0Ie6@0ڱ&;@0m bi@12ȎǨ@1j&3@1$@1Ҁ8 @2yC$@2Ird@2FT@2nN@2pj@3&Kt @3] k@3o@3U@4KI@46u@4l~@4g@41krF@5 * @5Cjyt@5xo@5/S @5gҮ_@61C@6M@6p@6@bN@6s@7 <@7Uar-@7@7AG@7$h@8&P @8Zfo@8fg@8Skʩ@8*@9)W6 @9]S>f@9:@l@9ĵ!j@9;e@:+v@:^N@:4a 3@:df@:Ҿ@;+c2@;^베@;zJM@;Wg @;$^S@<)#x@<\u{h~@"&J@>THbq@>\x@>d;@>_L@?MF@?N04vO@?b+&@?ЗU@?o.@@ ލY@@#t}Z+D@@|<@Byr@B(@@B@|"@BX$!@Bq9ట@BUTLu@B掚)@B6 H@B҂}@BH/-@COO@CMH@C3#d,@CKR,@Cc?P@C|%SI@CQ[g@CzӘ @CĞJH@Cܿ2t@C?d@D X6@D% (C@D=-@DU.yZ@Dm:i!<@DBK@DG:M@DHZw@DFwH@DA4@D8`1@E,i\@E-4@EE ɨ.@E\/1/@Etm;@E @E9@E@EZi}@E2K%@F/!@F7&@F3Qd@FKt)=@Fc=V1@F{@F<@FEw2@FE@FԨt@F#q@G n/l@G!! @G8Ѹջ@GPDyv@Gh*,8@Gv6@Gx'Բ@GC|P@Gƻ@GYԩ[@GS@H Rܙ@H%$G~@H<徑D@HTJ V@Hkٳlf@Hf}3'@HUr}@Hx/@H"P@HX@H@I@I'#@I?xQkO[@IV?@Ine䅎@Ikv@IJx.@IL@)?be,@(27|@)=G@)`@*7+T!@*|v@+.tć@+4@>@," #)@,>@-9.@-{ "@.W'3@.wT@.W@/bΌ@/0T@0%QP@0_6( _@0!@0҅ @1 }@1D iX@1}lX@1;D@1_f4@2&E@2^/@2p @29>^@3؄@3<y@3t4K@3Bm@3,K m@4afJ@4O-@4Mx@4qm153@4؉:@5(Z@5^ʶK)@5@5l@6[@65iF@6kx@6Yؼ @6Ց2@7 Z(@7?v@(@7tr@7pJ@7*6@80+@8GZ#2@8{ף`@8/rH@8y`D@9 h@9LεF@9@9?'k@9賤+@:u@:P@@:[@:qp@:h'@;{(U@;Q=0d@;/WX@;oS#T@;@<o@@>M1m@>b@>*\d@>=@?8@?H?@?z@?w@?@@@@!7@@:'T@@Srk@@l]7@@C:G?F@@#@@<0[@@@@#@AjH@A/yuO@A2l@AK;@Ad] @A} @AR@A^.@A#jP@Aߛ@, @A23@B+?=D@B)S@BA[@BZaN4@Br;=@B\{@B2\{@BG"@BԵ@B @C@E@C͢@C6Ee@CN@Cfn"@CE⡅@CZy@C2"@C"}M@Cd`.@FR6M=+@FjY@Fir@F߁Y]@FCe@Fɖ @FnD?Y@FB@Gh^@G(=LM@G@Fq@GXxS-@Gp? ]@@GCG@G@GQ]@G> T@G#>@G2;@Hay @H.3@HE|qd@H]mՊ@HuUi@H~Sv@Hc+p`@Ha@Hӥ%d@HB{,@Ihu@IuG@I2 @IIy@Ia1__Z@Ixq@IMY0@I%&@I`*@I.P@Iii@JtO@*?$ V@)Q@*=@@*D\@+8C@+%c@,/@,y@-#(|Z@-)x+@.2 @.?@/bkt}@/y^@/YH@02 :z@0m7Z*@0u)@0x]@1?\<@1Tmo@1(u]@1L#{3@2>41@287Huz@2q`BU@2!@2$\@3-@3R m3@3;@3N fX@3\?@4/ r@4g!P@@4)7#@4 G@5 %@5B#/@5x{@5>$@5 `KJ@68M@6Q+;@6w @6(@6F:4"4@7'ʕ@7]4_~H@7%r@7Ǻr$$@7qu@81ܯio@8fɝƋ@8?@8]u@9Eq@99 @9n&"@9y^@9@: @:?0g@:sE@:G<=%@:5-F@;`!@;B6T @;vS@;5s@;ݯ@<J.6@*a@>Cd@>vxz@>0@>H̖C@?v'3A@?Ajw @?sB@?߁@?_n{ @@\@@ @@7DC@@PM[N@@i;t@@#up@@TC@@.N@@wwG@@@@@ABٕ~@A1@AJ~ms@AcYg@A|/3@Awĺ@Aʭ=i@AƐ:@AQ¬@A U@Bɨ@B)v]"@BB$6@BZ̷ H@Bspz@BBm@B@B?9@B4b@B^ J@Cw@Cj}?-@C7,@CPeb@Chܲ.L@CO],@Cb@C)AE@Cʏ@CC@CP2@D2O7@D,ײ{@DDTb@D\@Dt(x@D5@Dy6@DAE@D˪@D.m@Ecwܲ@Em@E6Aw+@EN]@W&@Eg]X@E7C@EX{w@Etܿ@Eǎ^^@Eߤ@Eg4}@F>@F'o@F?ܦU@FW@Fo嚟@Ff@F:@Fĉ @Fc@F @FX@GO`@G/ \@GGv;@G_[ե[@Gw=L@G+"@G-@G?@G֪@G~>WR@HO}^@HU>.@H5Wmy@HM@Hezd {@H}>x;p@H꽾@H@H{0C,@H4Q@H@ @I O@I#SL\@I;v @IRyf<@Ij[hq3@If@I T @IM['@I/\@I9@I*@JWr@J']t"@J>I4@JVHv@+?@@*&@+=S@+p~;@,8LΉX|@,\@u@-/xGG@-<Џ@.$F@.W "@/@/L@0!'\g@0>߫@0y6@0IH@0cF@1)#m#@1cMG$@1=<@1~#@2ztĊ@2I5É@2激@2 @2ضl@3-f%m@3eV@3c@3KT@4 Pj@4Ec@4| @4h@4z} @5"k@5Yܯ~@5,ʒ@5~]KC@5 FD@64Ł@6ju@6A@6fN@7 n @7CZOB70@7y*JP$@7"u4@7yie]@8Ϩ@8O`sP@8@@8ݽ@8R@9$P@9XtJ@9͋@9ke@9;~}@:+)Z{@:`SϮ_t@:Ѳ@:@:^[@;17@;ehA9@; @;ͱyA@<NL@<5k~}@e@>8V@>k4yޛ@>E@>H^@?;6Y@?7!fR@?i1@?c\@?~7@@C T@@fc@@3j@@L,@@f1'}V@@g{o@@2|F@@|X@@l&@@Α@@.v@A/A@A/@G$,@G^ h@G [+@G~@H _@H$J@H<8>@HT,]@Hl|z@HZ@H6[&@HqK@Hޞ @H㹧j6@HfON@IYa@I+%]/'@IB̋@IZ @IrzĴ=@I;im@I;#I@I ra@Iri@3wg{@3 n@3PY@4!W@4YIG@4Y(@4BC@5A @58Ҫ@5pCL@5l+@5ޞ :1@@6hױ@6L @6ir_@6@6ð@7'A@7]kqT@7g@7ɼOܗ@7$x@85g)@8kgYf@8I41@8֫Q֦@9 (7~M@9A5PA@9v0bGE@9 B@9)?@:0#@:K @:}2@:О@:p@; {@;R$@;X@;eo@;ﱂWu@<#zw@*R0k@>]`@>9`5@>ĕ}Q@>Zң@?+ 0N@?^O6 @?o^WF@?āl_@?|D@@@=l@@."@@Hݸ¤@@aX@@z3B3@@>%]@@^@@2@@$ @@d u}@Ab*@A+Ѹ7@AD@A^'}@AwI;@AeR@A|@A@Aۙ#Αs@A%^@B 1%@B&!@B?AEo@BX @Bqm?j)@BS@B4-@B9e@B-@B$@C@CQ@C8ߔ@CPZ*U@Ci3Ѐ@CFv`@C2.@Cp@CN>@Cw@Ca@D.y@E*@E+@FZ'3@F/նB@FG@b@F`%P@Gl @Gv0 ?@H}dIh2@H*}@HB@HZ@Hr}B@HvR@Hl#p_@H_e{ @HO"@H=\XE@I(9@I%O@I1T@IIٮ @Ia 3J@Iy˟8@IrH@IKp@I!@I\LI@I2@JcZ@J `Y+h@J8)Ѓ@JOE$@Jg}@Jwi@J7z(q@JB@JƯ @@Jh-@J>M@-?޻L@,5)@-=p@- @.8s/.@.@/0Pi/@/@0iJ7@0O `@0>&nN@0t{j@1c@1@ =@1{uIt@1c@1l-@2,4Xo%@2fh@2އ@2%%@3h@3N\8m`@3(1x@3S@X@3@42ٶ@4k֘@4>"S@4ܡ ,8@5ۜ@5LH<@5C@5+ @5F @6+ʒ#@6c$rMK@6_i@;@6yX* @7s9@7?NM@7v ^MYv@7 ;@7(z 3@>NQq@>(S@>3o@>w9@?u@?P$<@?}ç@?w@?rW@@r]@@(r@@BD䞏]@@[K.@@u^W@@X8o_@@].\?@@W@@@*@@@A ő@A'emY@A@D@AZ {+@AsR@A@A_-@A Tq@A:|=@Ae@B E@B#@B@>pq%@> 'E8@>w=@? R;p@?@h@?tFaq@?lٔ6@?Ӆ@@w@F3-@FL ;Jg@FdUj@F|J%@Fq[e@Fv@FL @F޵j$@Fܗ@G{Vҏx@G'H9@G@3R@GXL@Gp޽S@G/2j`@G|[s@G>r˚@G x@GPO:@H1R@H͛@H3\!@HK>YA@HcrQ`M@H{$@H[@H(@H"C@HG:@Hhk7@I @I$Qf@I+ @/a@0@0Zv#@0tB@0jpc@1!{@1P@1` %@13@2[$@2A@2}tbTb@2S,#@2Q$@3.qzS@3i2@3)h@3uT@4ݯ@4Rv|@4.QH!@4ŷHl4@4ڸڥ@58BFCƖ@5qFn@5!`@5K9x@6]ʏ@6S@6$@6@6 ͛@73"@7k,@7V=@7ڋ/g@8ؾ; @8I5ׄ@8 9@8 @8ˆ@9$iA@9[13@9^z@99@9be@:4g09@:jrE@:?;@:֐7@; ^K@;BC@;wrX}W@;>m@;ȭ@< @)GRhB@>]ʗ@>;x4p@>ƚ@>w꽙@?/%J@?cPŕ@?lm@?v.@?qX @@]@@3~VN@@M>@@g_^y@@56@@)i@@@%@@΍<@@G9@h@A=@AP@A5J@AN @Ah]8@A#@A[}I@A1) @AΛ4@Ad@B@BG@B4S比O@BM @Bg h@B_?`%!@B_@B$ @B6@Bs2c@BF"@C܃ȖS@C10@CJ0J?@CcQx@C|nA_@CA@Cws@CǦ bp@Cஇ-#@Cdk@DY@D+!l@DDޛ-@D]NlH@Dv|v@Dc>g@DEA@D#+@D@DҰ+@E y@E$oHy@E=8@EU{b@En"@Ew{@E.v\@Es"@Eѐ:/3@E<)w@FMYq@F-n@F4%Vp@FL_dw@FeYRW@F}!z@F|Av_@F :]@FǑr@FВ @F#cY@G۠@G)XR@GBZ@GZy뮑@GrRWу@GU|b*@G:@G#KeD@Gԅn@G74A@H?fm@Htt@H5n@HN>N-@Hfe$@H~ךa@H @HdSC@HǦo1@H3rr@H Ha @IY@I(JC@I@ @IX @Iqebq@IH|\@Io,@I-@IѴO@I{ Ό@J,Lp@J@J2=5G@JJ1@JbBY!@JzPXN^@J[@JdR. @JjVu@Jmd;@JnǦ@@K l]@K"hbR@K:a|K@KRX &@KjLR@K=`@K,ɿJ@Kci<@K(@KU-0@0dr@/H;@0 jk@0^|t-@0"[@0 R@1X@1VhIZ@1 J@1<9m@2 28@2JfjuJ2@2c@2¡r@2_h@39"@3u'.mD@34Y&@3 ։"@4%_@4`r}7@4RR_@4\ƍA@563̈@5G⤾@5a@55@5Ъ%@6,.F@6e/J@6cռCr@6\p@7Pl@7GD'2@7hDr@7 O@7{|@8'0~1@8^@8;._B@8͑B@9@9;–@9rd-#@9yp@9.@:,7*A@:Meh@:-`d@:@:6X@;&h@;\K\)@;6BĠ@;ә9@;>^@<4Mv,c@˫K@>H?@>}5@>= I@>MN@?|=j@?PCk@?~@?ɽ_`@?7&b@@pW@@*9J*@@DU@@^`=@@xKC@@o@@m{C@@@@ۻ@@@A[ O@A.)$Bd@AGTd@Aa8@A{f4x@AvE"@AR@Ag&,@AJ`@A$`@B-uV@B.(A@BH@C@CDC{@Cn8l@CI@DK@D(0@@DAY@DZ+@Dt@D 0~@D $9@D յ@D5@D ~@E }h@E"Vf@E;*-@ET*?@EmA@EYD@E/rex@E#@EΞ@E@F]S+@F.@F3485@FL5@FeI;m@F}O;@F{&@FP@F;)l@F"@F5> x@G@G*f\5P@GB!ר@G[C@Gtr@G|@G $ᅿ@Gb߬@GoO@Gb:i@H@Hc@H7Ǻ@HP^0@HhI@H-@H"@HN@HKo@Hu@Hã;@ILfp@I+ @ICa@I\1Ŕ#@Itx !@IyU@I\@I99*@Is6@I6#=@Ja@J@J6@@JNlp@Jf@J~R}@J@Jҗ@J3+@J:e3@JSz@Ki.@K'}13@K?@KWP2@Kouu@Ky.@Kb@K×@KϽ%@K@Kom@Lm@L/c@0ڎ9G@0_H@0Ǒ@0 (.M@1ig@1[0Aֵ@1:)@1_l@2am@2Q*ʝ@2b\p@2o\@3PPf˹@3Cf>]ZE@3ڧq5@3=|@41g_ @4l[P S@4@a@4ᦌ0r@5$@5V*@5&Rc@5uHܪ@6z@6= AEt@6vUܻ8@6xt@6s!)#@7!Fœ@7Y@u@7|-@7 &@8!sp@8;?@8s;ϵQ@8o@8~T@9m@9Q_u7x@9GVW@9@9@:.e@:ez?l@:k)@: *@; u@;@;I@;v@;xY@;'@<E4A@1ٸ\@>fآ@>he@>,M@?Bf@?:䬅N@?o8j@?nGx@?B @@].@@!"@@;`hՙ@@Uxxgk@@oId@@@@{@@m-@@%i@@*e@A (p3@A& @A@ *|j@AY(b@AsՓ'D@A.@A2d@Ce@COHjF6@CLLO@D @D%(@D>L@DW~TI,@Dp"@D\@DA@Dx@D/`}^>@DD=1@F>V9@G@G*bƷqK@GCѨ@G[f?@Gtdg @Gur@G~J1@GE!v@G S[@Gs^@H&}^@H i@H9/>@HQO@Hj)bM@HݺJ@H&}@H @H,@HRb@H4@If ޫ@I-Fd@IF6yc~@I^X@Ivٲ@IV\G(@Iؿ@IįA@IZetq@IWW@J Q@J!CD@J9dT@JQϺ} [@Jj@JPe@Jg@JyD=@Jg&@J0]@J`Y~@K @K+jqga@KCW@K\ ?j@Kt,L@KL@KjP@K:j;@KԞЩ@K@LȳQ@LٻJA@L4:@LL5[e@Ld@L}U;@1ۦ@0ߩ{W@1Sg@1^-@1{/@1R̚j(@2j(@2W3V9@2@4; w@4wE{@4!@4O$@5(w'Nl@5c!|'@5C@5Z0:@6 ~@6Kz@6=F@@6D>@6/@71Bσ@7kyL@7|@7B@8d@8N Cy@8pzxJ@8{1H@8o @9.h@9fC4@9qن @9ρ@: Ç@:D- @:|C}@:od@:d@;!u'@;XO}@;@;Ŷ&}@;C%7@<2\)@M@>NM74D@>@>6H:@>+-@?#h@?YAe/@?l@?)7xs@?!Kt6@@y@@0/c@@KO^m@@e @@Y0@@@^ @@uEp@@θ&_'@@筲8@AH$@A/#m@A7G*rD@AQW@@Ak`@Ab8E)@A\PJ@AOG@A;4@A yoP'@1;(c@2Q@2[stn@2+@2o@3N y@3RFK@3Jer@3 Έg@4k@4D,?@4̆W@4 @4@A @53%@5no@5;@5䊟 @6 :5@6YoJ@6slT@6c@7v@7AdT6ER@7z<@7V[#@7ZAu@8&R@8_xe@8k@8¬@9 w@9B"O8@9zC^]|@9eþ@9h5@:"Kމ®@:ZX@::2@@:@u@;/6@;71D@;o1'Ж@;K@;I# @<.v%A@3@K@>iń@>:d@>J @? ks@?@~b'@?ue\N@?b4@?k@@ @@%}x@@@#@@Z(L@@u%q@@ʠ.@@_o@@gue@@4@@JpX@A^6%f@A-^p@AGQ6@Ab @A|6x$_@AY6ſ@Atoh3@Aʈ<L@A䔶@A[y@Bn@B2@BL8X@Bfhs\<@BJ 2@B&I@BŹ$@B\@B}c@CT=x@CK@C4Qk@CNs @Ch꣍l@C!@C\ @Cf@C΅N~P@C޼!@D5@DD@D4{@DN$A@Dgv~@D@DFj@D鉹@D!NX@DUݾF@D@'@E>!@E27Op@EKy$ڹl@Ed @E},A@EZ#@ENd@EwZL@E " @E@FםCh@F-@FGbI_@F`,a@FyŜ@F+Hx@F-/@F4y@Fm Z@F@GiD@G'x6A@G@8e@GY@GrM@Gl }5@GDN68@GX@G @GtX@H~3p@H BP@H9.@HQj@Hj{&i@H1>(@H˛@H @H=%@Hгc@H( @I+o@I/zRn@IHbA@I`+@IyyhK@It@I!ԖK@I2Mj@I۸0@I;Θ@J ^Ϲ@J%7@J=[>b]@JV'l@Jn)@J 9@Jx@JM@JIN@J#e@K8K@Kl\k@K1ǔ*@KJ]@KbuY-@Kz,@K@KdX[@Kîȴ@K'F@K:yg@L |!@L$3@Lѥ@5BC@6+r0@6e4n}@6&1@6~@7n@7OX6I@7@7l@7@86K,\@8o7@82@8DaA@92eLe#@9S4@9ޢ@9*_j@9_$@:5 0l@:m@:EH@:Qѱ@;I` @;MZu@;|@;\{@;s|d@<*[&@s@>MBvt@>r%@>4Ug@>:y@?&+|@?\O7@?{=@?ǃA@?"@@W|1@@4+x@@NB|Q@@iq*w@@@@,RM@@7Y@@ӽ/@@:ߪ6@A/|@A#G@A=eA@AWیL@Ar/D @A{.@A忺@Aw@A/Dݥ@A\c@B)Eu@B)[ E@BCM)@B]@Bwj@Bы=x@Bcv?C@Bli@B߭؊ @BhM@Ct)@C-N#c@CG!Z@C`= @Czޅ@CuPJ@C/.L@CW@C?@C:Ag@D9l@D.zbu@DHX@Daq//@D{.a(@D݄@D5KG@Dǰl.@D' s@D@ErU@E-i4@EF-@E`'yƇ@GWz<@Gpvn@Gn@Gb@GR@G?g=@G'<:@H q@H}V}@H73S4@HP@Hiu\@HF@HƯ@@Hݩ̧@Ḥ:@HeW@H$xܴ@I@I/aHM@IHKq@I`@Iy!@IRΫTr@IpN @IÛEW@I;f@I״'@J pu@J&>!@J>@JW'Ǽ+@Jo@J@J@_:@KW9 @K/eL@K3L@KLNwO@KdA@K|O&@KRE ջ@KL@K\BE]@Kwk&@KIt@L, w@L']6@L?ݧ%@LX&)@LptF,@Lbd@Lqș@LNS(ԓ@LёA\@LS@M  @MK^vt@M2A@MJ@@Mb@2ޓa@2_L8@2,C0@2S 쉦@3(@3[O0@3h%@3Wfj@4s@4R> @4R9@4lX@5 Mh^@5Fr. @5PS@5M2jx@52z@65gn@6q@60V\@6,Z@7!)8@7\V"@7 `0@7Ph@8 lu@8E^@8(4@8]vI@8GHt=@9+3>@9d '@9rʎ@9ƿ@:[@:H4`R@:3\@:D9U@:dd@;)U{l@;aZr@;~0\@;K&@<Y&@<@@@<歵@=7@=T`@=3]9@=¿E|@=1%@>05at@>f?b@>N/ @>Ӹ0@? E@?@K9Pj@?vt3 D@?@?,9@@ 8c@@'$01@@BFy@@\,@@w/'m@@o [@@*!X@@@@& @@&@Aj@A2L ֢}@AL&}I@AgO4@A1!@A2_?,@Ay@A]4@AI^@B_@B8G=@B:@BTRX@Bn@BcA@B@B@Bq7@BT@C n%@C%s@C>Vg5@CX@Cr9e'@C|@Cd;@CuN@CFo@@C#`@D u@D'$@DAOmzl@D[ؔg}@Dtvd@DXXAAH@D*r@D%1q@D./̫@D*u@EK8*@E'ҕq@EASA@EZ% @EtG@Eݓ @E%@ @E)=8@Eǖ$@EMr@F 5n@F%e@F?I7h@FXJ@Fq/@F%@FV{G@F= 3@Fuc@F/g@G vIp@G"@T)@G;aN=@GT~sIa@GmߗC@G@G9@G*-yc@GEz@GG}@H9ʑ@H$@H5@HN <"J@HgUZ@JWf,@Jp ^@J4ػ@JKym@J愘@J~[d@J%@KA@K2X$@K40j#@KMFbx6@Ke˃r @K~M:@K̰E@KH@KNVG@K8@KKW/@L@L)c@LA󤸉@LZ[_ͺ@LrG=@L"`.@L&@L@8RCį@8-|^q@8<3yo@9"Y@9:d@9t{L]@94@9?:@z@: kjN@:Ysa!@:Zm@: *c@;q{y@;_wK@>G @>~M@>lzKT@>&8υV@?"Cou@?YT-@?Q@?+*ܙ@?u;@@U @@4f[nWX@@OlC @@jhj@@[:n@@CX @@"Z@@\Qh @@ĔQ-@A @A&A]@A@(=@A[̚}@Av:]@AѣR@A`F@A @AdQ@AVP@BHP@B/@BJ bB@Bdd Q@B~G2@B@B;F1@BtL@B!@Cu|@CWn@C6Uad@CP'CC@Cj6l}@C>;*@C@Nj@C< @C1nS@C!@Dċ>@D$i@D9ŗ @DSUb@Dmk @D4ٱ@Dv@D@Do ͞B@D!VyY@EΙn[@E!u@E;+p@ETA+@EnKA@E**&@EiH@EiS@Er[@E,a&@FfuN@F ٟF@F:GZ!@FS(N@Fm@Fs+o @Fxp@F# @Fsw@FG@G&@GJ~=@G7RZ@GP`_*@Gi8@G*8@GWbK@G%y@GΣ(@GF&@H0/@Hzw@H3  @HL}3y@He% a@H~-I)@H0r@H0&)@H+w@@H#Xx@H'-r@I%@I,ZzR@IEi@I^i*@IwY@I~eZ@IX?@I.@Ij 1@Ip@J @J%cb@J>(!x@JV髏@Joe@Ja~P@Jt@JeϏ@J|>@J)F[@KӯR)@KzK[%@K5A@KM@Л@Kf[\E@K~$@K@KD${@KȰ9]@K=ok@Kȁ@LP$N@L*ͬl@LCV&@L[J@LtQ'@L!@L@<@L~Cp@L#kd@L/m@M\I@MdjnH@M7ɷ@MP,I9@Mh#g@MK6@MC|m@M@Mh@MCRAt=@MC@3G^@3_˄@37^@3h/Z@4L@4[L@47@4Bk E@5 N>#@5SI.@5c`@5ޙ@6 \A@6GF-@6:'t@6`vg@6,@77|K@7s .@7f@7^)@8$/@8_f`J@8 8o@8ԉix@9U@9I@9>q@9@9@:0*5-n/@:i{@: @:gCg>@; S@;Mx@;3a@;T@;ع2@<0>1@&0=eE@>^ f7'@>Yç@>zy@?pI@?:tN@?qOʄ@?g-@?޿G@@ @@%듡!@@A!mBT@@\L퟉@@wmv@@x'@@AET@@Ȕ@@96@@|Q@Abі @A4?/@AO&8e@AiݮD@AJV{#@AX6@A@M@AԯS@AOJW@@B ؎@B$tz@B>2@BYy !O@Bs9@B_@BMQ!@B%od@B~ M@BY,@C7ʒ@C,Zr8%@CF@C`ɡ@Cz[@C8ww@C<"@CUHn@Cgp@Cs @Dx2@D1v@DKo`@Dea\@DMV]&@D3r/h@DKLjS@D*@D!P-@E?w@EWd(@E42p@EM'H*@Egt:@E@Tv@E쪧ze@ES@E5Im@EXw[@FhP@F6@F4-@FN/1a@Fg/\@F:)@FYLZ@F-@FhBcB@F@G7I@Gpx,@G25m@GLKX^S@Gen@G~0]{@G5hd@Gzs'@Gʻaj@GQr@G/9JR"@Hbӕ1@H/*@HHH @Ha5x@H{MV@H%6@H@;2jx@HVr@HiMy J@Hwu-@Iy]@I*/f[@IC@I\O@Iu2-cu@I}@IqB$@Ia3BK@IMtd_@I6 Zx@J ۑ@J#fE @J<4%@JUyE@Jn9@J^~@J.ND@J6V@JêM@JD6,@KKL@K pO@K4¨@KM~h(@Kf3e[@K~`\!@K y@K?,@KɃ@KP@K/+Z2@L-'K@L+j@LD@L\M@Lu+͛R`@Lf@LH@Lұq@LY͉ @Lx@M_\i@M 2ΰ@M9Yu @MQZtr@MjHg!@Mb*@M,2 v@M@M R@MmfR@M@N6%E+@N-t@NE1@4M@3߶/@4< dF@4^rcg@4].J@420%@5Z9`@5XpL@5Eۼ@5Ӂ@60@6NK 1d@6+ @6҆"@7BY @7@}q@7|7݉@7Yu@7w@8/p?A@8j@8V8M@8T@9w@9V j@9yW@9ʽV @:L@:>S@:x&@:Nh̑@:C\@;%|X@>;G@>s k@> a@>}@?֭E]@?Qg@??i@?Pr5@?Jr[@@ő%@@1 @@MXx@@hY @@ш1@@*(Ŀ@@[)@@ՁsV@@X@A Rz+@A&i8@AAξp@A\N&,@Awe@A8%@A[ @A-P|@A@A!{@Bnw9@B3F@BMĬ @Bhch);6@B '@B B@BhR@BҎ[@BB1@CuHq@C!t @C<>8>6@CV&@Cp豙u@C5@CyB@C(|/@C_}V@Cʄ@DD~ @D(f'@@DBP@D\@DvG@D2[&@D^@Dīj@Dޡi@D=@Ez 2@E,^Tgm@EF<&v@E`+@Eys@E t@EzU@E;t4@E^@Eu1@F^9@F. (@FG! u@FaR] @Fzk@FZԨ`@F6@FǤ ^ @F+H @Fc@G,@G-!@GG@G`;F@Gy9iuw@G[Mn@GKo?@Gtyx@Gsg@@G>e@H޶@H+bB@HD3@A@H]>`X@Hw*%G@Hd;\@HN@Hf@H[jOU@H":E@IH3ܤ@I'i7@I@3@IYPc@Iri@IW2@I @I(7@IR@ID#@Jjg @J!઒5@J:Թ@JSXp&I@Jl=/@JVl@JG+^@JuzW@JW,T@J5c'@K%@Kz#@K3iJ@KLE@KeY-M7@K~#V@K馎^Q@K@Km 4@K)Ƒ@Ku @Lq@L+MD%@LCqg/@L\o%@LuT}?@Lgr@LG|.`@L@"8@Li@Lxݾ֤@M ɘ;@M! @M:7@MR0@MkSQEv@MßO@Mc_ @M*@Mh)gO@Ma(@MalO@NڏV@N/PP0b@NGN@N`4s@Nxco@N @4D|@4_?,;@4@@4|.g@5m{C@5\51@5{@5؝LW|@6~x@6T@s@6螣j@6ήaq-@7 Xkb@7HX-2@7ߎI|@7(@7CͧH_@89,׶@8t^@8n1X@8[8X@9&'@9a*@9vMM@9׀@:5@:Lcw@:*ߣ@:޷d@:k@;4]@;nI@;%Q@;-n@<^{@ӲaK^@>OV J@>ܯ>X@>?@>{s@?/$%f6@?fc@?,i@?Ջ:@@i$(@@"m@@=Zmx@@YYMޠ@@t.l@@@@O>@@Ƥx'_@@cU@@/\@Afm~F@A3y@ANm!"@AiG@Aݏ*@@Ag9f@A[E@ARZ[@A5c@B .e~@B&w˿@BAGߘ@B\+@Bv N+@B;@B3!@BuA@Bwȁ@B5@C|@C1#y'h@CK@Cf~@CZ:x@Cr/P@CVO@Cϱ#jY@C[Q@DQ`O@D,(Y@D8(J@DSj# @Dm@@Dk @Dv@D@Dj @D̆@E ,v@E#:Z@E=@ @EWCb@EqTzA@E$vM@E|*@Ez&]@Eda@E:@F Uvw@F&>@F@1"@FZ\{a@FtiuU@F @F}kn@F(׹@FΤ@Fo L@G {F@G'bDs@GA4V@GZc.@GtI@GP@GK?@GŀO@G:tV@GUI(@H Wlb@H&~ͯWM@H?];@HY@?RA@HrPy h@HFՌ@HAS?@HY7@H@H@I [4H>@I#@I<$aO@IV'@Io3e@I_Y@Il@Ib@Iˮ@I4@Jg@J&ߖ@J8%*y@JQ2 @@Jj;5ʠ@J@p@JBqb5@J@Q@J;X@J2 O@K%k (@KD2m3@K2@KJ{3T@Kc̥@K|(@K@Kk@KC @K-N` @Kqآ @Lp@L*05s@LCI[ @L\ )S@Lt1 @L1 d@LH{@Ll@L״}V@Lf,"I@M H_@M!8Uy@M:h@MSW @MkJ5U@MP@Md|@MB"H@M?B<@Ma&@MC=@N&@N0] @NH@Nal܈h@NyA@Npo@Nx@Nj'q@NJ@5%@4ߺi{@5ETF@5^B@5|it@5.@6}/@6Xǭt@6R@6b*Av@>bAW@>6uXt@>e]P@? yx;@?Cs==@?{S#@?@?;ͤ@@.x@@,dG@@H)@@@dE%@@ _@@q@@N|"@@oMɨ@@ z@A Cc@A$J]@A?u渰@A[3ӀH@Avn醖@ALJ@AȬ&@A7n@AW@A+Q.@B r7@B4zڣ@BN5ݴr@Bi'O^@Bn@B):e@Bas~@B'k@B,TGO@C ?^@C%Huv@E/*@E@E44@EN@Ei2&@EQ?@E\@E Tk@E>Z@EYr@F7+@F߂@F8R3^ @FR@FlŢ@F`Uh@F/:]@Fɼ@FӾ2@F}L/@G7J6X@G @G:0@GTF|@Gm@GXhW@G(c.@Gf@GQq8'@G޳$@Hg7g@H i$@H:j5.@HSkOe@HmZd5@H:vo@H95a6@HU̴@Hz@Hei@I :@I/Id@I8k\@IQ-ʸ@Ik6xɔ@IJa@I@Ig@IVy@I; @Jm@e; @Jo @J4Ŵ?@JM'-@Jgn-@J-cv@JHVZ@J_0i@Js@JT%@J`@Kb@K/Ag@KH@KaJ@Kz!D@K:b@Kz4@KoHX@K[z@KD3@L*KH@L) [>9@LA댔k6@LZ9P@Lsҹ@Lt@LF@L~ Q@L@L|@Mn@M!0޷@@M92~@MR@Mke`_^@M3@Mdc=@M~G@M+"g@M;+?@M|lO@N U@N0#@NI`U H@Nalr@NzS@N+nI@NY@NOOZ@N~j@Nh5i@O ,@O&vE@56*@5_ A @5I5z@5ލF@6G@6\D@6LYY[@62@7@7Tu@7"@7i@8 y=+`@8IRύ@8ײ@8iy@8,Y@9:@9v/m@9M'4@9@:),S@:d[@:a fc@:=@;;. @;O@;@;)Ԫ@;GV@<8Ao @c'@><:a@>tQd@>B+@>`R@?{+Q@?VƌD.@?l=@? /@? mǼ@@vA@@@7[[>@@S4:y@@o/@@j2@@wq4!@@!Z0@@ݿy@@S2Bg@A)(@A0ZD@AKO箽@Ag6)@Ab7@A2=@A3CP&@AtV3a@AOU@B ؼ @B%U@BA|K@B\)@Bw1@B1L@B(.m@Bg7"@B@BR20@C=@C3zu#@CN?xJ@Ch#Vd@C@C]Ao@Co:@CӠw}^@C69@D&k@D#Lq3"T@D=}p@DXE_7@@Dr.r@D"E@D@D@D9MB@Du+@Ei_+@E+@EEP'@E_Dpw]@Eyo5@Ez@E@E[@E5d@EF9@FQ$~(@F0V4 @FJUzҙ@FdOvb@F~B ?@F1%Gx@F@F O@Fʒ@F&k@G,"@G3S薆a@GMi9H@Gf߻y@G@GWG@G Z@Gͺ,xY{@GdQ@H ܉@HDX@H4E q@HMhA@Hgn{EK@H@Hފ@H Y@H͈XI@H5@Iz(k@I@Y@I3Z֮ @ILd@If)@I}a@IUX@I?܇@I˔9-@ItKP@I0@JxV\@J0e@JIHz-@Jc8ז@J|p@JB`\@Jէ!tc@J6!P@J*?l@JOA@Kq.@K,@KEҁ@K^@KwF@K:}@KQ`@Kr?@K:@KN>@L @L&.D@L?e @LXن0s@LqIΟ@L/Q@LԆb@L@Lg7@LF2!@M"@Mb@M8Jn@MQ @MjsX%%@M?@M@M3+aI@M͒`u/@MR >@MD@Nf@N0/@NI5f>@Na99@Nz@@N@ڌ@NJ)@Nďe@N2 @Nި_@Op^ @O' bτ@O?@OX8[@Op@6S@5߽*@6MŊ%@6^2G@6/@6Xǃ@7׋@7Yc@76@7 TJ@8lv@8O\@8y@8ye+#@9}&k@9C,@9RWx@9tI@9h^zV@:3.x2@:n: @:6T_0@:zx@; ϕ@;[_@;S}hj@; k6@< vf@@>L@@>O@>LVq@>͔Kp@?0\_v2@?i#(c @?xM&@? `?@@ +Ha@@%D$3@@AP/x+@@]O@@yB@@)I@@}`@@ӛ`C@@ b~@AO;@Ae@A;˥w@AW4G)@Ar @ABd@A@A&@AJ@A9@B1 @B2wWvn@BMGsQ@Bh5@BK{@B/:c@BFYx@BTl@BZ ]@C Vbf@C&K@CA6_V@C\x&@Cv@C&@C,ɏ@CWwPG@C)@CƽVA@Dr@D2@DL4@DgJ-@DHʧ@D`w@D+ @DZs@Dsx@E8Ȅ!@E pE@E:&9@EUS-]5N@Eo4o@E@E2 j@Epʆ@Eبc@Ey@F '@F'*Q&@FAI(@F[b@FuvS@F?m@F@FÎ i@F݊ [@F@Gs)@G+_0b@GEEР @G_'S@Gy rZ@G7в@GI/3@Gwt߷@G>N[@G$DE@H[ts{@H-v@HG)QU@H`p @Hz߻@H&@H!Ym@Hb-s@Hg7u@H@I@hӜ@I-^m$p@IG'af@I`0V@Iz"5TJ@IaƷ@I v\c@I|@mG@Iec@IMy@J7րh@J, 1l@JEg u@J^ԱR@Jx—@J\G-@JZ@J̔r;@J- a@Jk@x@Kj@K(*@KB;q@K[=X@Kth\ث@K]@KN@KKk@K 2@Kp @L b`@L$/T|@L== @LVH-@LoOg@LS1@LSK@LP@LJ;-@L@@M36+@M#Hك@M7\@MO@Mho@Mѝ@My@M}@MW`0@M-'@Mފ\@Ni@N/ ㆄ@NHh9 }@Na/RB:@Nyq^@Nx@NrD4@N.)p@NA@N @ONЋPz@O&^@O?_<@OXUL@Op] &n@O 7Y@OCK@O-ɚ@6|J$@6_@6Q3G@6ޞ{@7~SEV@7\lK@7@7<N@8HN@8Urȗ @8 @8t }@9 A{=@9J9q9@9\bY@9Ñ]g@9KWi@:<(mt@:x.A.@:6$@:^i @;+6V@;f\F@;#@;@<=t@#6F@>\lU0@>!@a$@>hB@?@?A܉@?z"Ĝ@?_0@?@@YXt2@@.H@@JH@@fBיf@@ @@$jM@@f@@|LQ@@ @A\@A*a@AFk(N@Ab&Ql\@A}W@Az @A @@AФx@A)C&@B@B#@B>|\õ@BY;lW@Bu-գ@Bwy@BS6{@BЙ@BmK@BC—@C`6c@C3s[:@CN~&@CivO@C{o;@CmTJ~@CVQ@C8]n`@Cn@D d@D%'}@D@o4R@D[)b8@Du܎صc@D @D,._@Dݖ@D^K`@Dh@Eu>@E/U@EJo$@Ed⧳ڼ@EO U4@E@E ;d@ElY@E$>@F (a@FPM@F7x@FQ۪@Fk@ʍ@F*@FRv@Fs[)@FԏG4q@F<"X@G@G"@G<$nQ@GVĤ>̨@Gp@O@GD?Z@Gϝ@GjM%@Gq0@GPz*@H *@H%v@H?>"@HY@Hsa-y@H"W @Hޠ':@H;@HH8@Ho@I 2@I'D]@I@FP@IZ@Itc7@Id@I6~M@IZ@ID͆@IŐU|@J AAC@J&I@J@-F@JYu@Js"?@JpB"@J}@J2E@J؍ʝp@Jo@K 8@K$S6@K=ҧ˪@KWz@Kp]bzX@K{@Kيp@KzR@KFZLL@Kw3U@LbD@L VE@L98k@LS8Ñr@Ll5Ǻ@LPJ[@LhsI @L|X^@LЍ0 @L隚^@MW@MBR\@M4@MMc Y@Mf,-@MK@M@MxP@M}E~@Mi@MSk&@N9NQ@N.bЀ@NF\i=@N_C@Nx| @NLX@N]@N.ho@NXO @N8 @O *A@O&T1O@O?SZ@OWՕT@OpD@OKh@OKNn@O=/F@Ogfa@O@P`@7 @61$ޔ@>ku@>KcD@>4p@?f9h@?Q]@?@#@?-8T]@?54~@@@l@@7y3@@Sőn@@p!@@aK*|l@@ߒ@@Ļ5=I@@Xy@@7&i@A´@A4BcR@AP&ެ@AlޓU@AwB*<@A?~F@Al@Aۯ-b@AVZ@B:r@B.)M@BJ@Be3@B_@Bne]m-@Bs@B'?l@Bv;9h@C ~}@C$@C@*_@C[UFڻ@Cvv݌G@C_ho@C?W{@CǨB$@C\@Cy @D41 @D3vIN@DNU̹v@Di-:@D #@D]ml@D:@D@3W@DJ0F@E cA@E$@R?@E>W @EYr@Etښ@EK0@E K@EÄy.U@EEB@Eed@F @F-,D@FG(<"@FaƓ<@F|'/S@Fnt}F@FN@@FҨ@F 'm@FOd @Gxo@G3`׬@GM@GgIXr@G͌E@G@GĠ]V@G#@G&@H @H2Q @H7 "@HQޠ@Hk@HyUi@HQWO@H% @H`ш@H47m@I-TǞ@I CWh@I9v@ISjn@Imgik'@Iď@I|)9@Ia@Ig[@I휛J,@J3]V@J Ź@J:SJ@JSa%@Jmb̈l@JޔO@J`@Jy⩧@JN 8f@Jz@K*{@K&U@K8qf @KRW\:@Kkc@K @Ka@KT@K@KG l@L*ы@L΂ͭ@L6 W@LOF~2_O@Lh|@L~#@Ltk@L M@L2@LWw@Lx!@MaČ0@M1sI@MJh;@Mc{j@M|}0+@Mx@M@Mi@M ]@M dQ @Nju@N+ G@ND@N]&@Nv@4v@NjC@N:@NW@Nv遹@NW2=@O 4xֵ@O%50@O= l@OVmfS@OoP2@OZ_@O%f@Od@OҴ(@Ow y@P،@PzB@P@P'3@7o,[@7_Ti@7Yaz@7ެE\@8s%.@8\c@8(!(@8ف@9ϱ@9U}@99 #@9г@: w'^@:Kc@:ٚ@:ģn*@;&K?T@;={dI@;yRu@;@;r@<-Cl@pK@>?=@>yr-|_@>@>z {E@?'M7|@?a6,D@?,#@?{c@@@@#S4@@?"@@\fWD@@x.#@@B!z@@>R@@@@(Γ@A\,s@A" YE@A>ݫ@AZxl@Av{ @AH=+@A@As P@AHn9@Bx@BҌ.@B9b@BU2-ow@Bpqb8@Bhƌ@B@BvOb@BJ$c@B^%@CÈ4L@C1M@CLreN@Cg "}@Cd!@C40g@Cc_@CԊ}/@C宅-@D # @D%uca@D@ЕB@D[͞@Dv©@DX6@D(@Drg@DH֝ԓ@DYB@EnW*@E2*@EMV,a@Eh%@E%'@EUV@E_@E҇@E@F+f@F"L@F<@FW o@Fq{6@F&@FDP|@FKv@F n@FB껿@G^@G)\F'@GD 9!@G^B>\F@Gxs|Kl@GU@Gڄ@G^@Gsx@G5^@H$, m@H// <@HI4 ;M@Hc3Z @H}.5o;@H#{Nr4@HJ@HL@H]H2@HŚ0m|@I[@I2x-@ILJ0"@IffK@I @I,`@Id'?X?@Lz4v^@L1j@M`M@M.f@MGFf' @M`py@My{F@MۀS@MO@Mgn>@M~@M&/@N9@@N)H] @-@NBT`v-@N[]&]g@NtbP>8@Ne u\@Nd:xj@N`?@NY#w@NNz@O Akh@O#18@O<x@OUU"5@Omԃ@OiQ@OȜ]@O$@OjR@OB{@PV@P @P\~T@P&H;@P3' sy@P?huh@PKaDr@82<@7(:LM@8\6e<@8^\7@8*@8ܤ9P@9@@9Yo@9ˊ@9ռA@:w]@:Pp@:Q,{@:r@;cNp@;E$5V!@;c@;@;TNł@<6bHC@+@@>KV@>k 5@>3$g@>!䱿\@?5KIV@?oU~%@??,@? @@[92g@@+#:H@@G@@dknd@@"K@@Z@@1H@@֥bG@@ dK@Ad0@A+ ph@AGO}@Ad#@@AK 6@AfU5a@Auߓfm@Ay҆@Ar[K@B _|@B(As@BD33@B_@B{Ӯ@B_U9.@B k~@Bίy@BHn߁@C3I@C!]߰@C< @CXLU;@CsTj@C@Clg,@Cź9@C0'@C<Q@DoM@D2BNa@DM.1@Dh@DA@D=O@D @DzU@D+qRU@E )Ku@E%TT@E@h5@E[c|@Ev0H-@E¢&@Eih@El,@E$*@El@Fi߬ K@F10@FKgj@Ff) "@Fȇ+@F3Yꈟ@F~@F#I+@FɦYo@GFo@G\0@G98x@GT7k@Gn^>P@G]):@G9Q@G+@Gc۳6@G`u<@H `!7@H%B@H@ @HZ+Cmf@HtC qX@HU21)@Hb @Hil@Hl@Hi@1@Ia`q@I*To)g@IDBzQ@I^+*\f@Ix@I@Ih=@Iş r@Ioz@I<@J(%@J,@JF\9@J`>ģ@JyĻ^@J @JPnFM@Jk @J^so@J;ҩG@K֕@K-mL'_@KF@K`UC@KzE@KRet@K JCm@Kƞ5@Ku0@K-@L@L,nζ@LE-@L_>wF#H@Lxʣ@LR$@LZsP@Lı-@L3@LTX\@M˰@M): @MC.C@M\oN@Mu@M+Y@MJ@MQ(a@MڀğpI@M ;@N 0y@N%.Z@N?@NX< @NqXHd@Npa@NbZ@N&2@Nե0R@N@OA@O Ly@O95.e@OR@Okd@Oe@O@On@Oϋ/M@OwHq@P3@P $ѽ5@P,@P&_ @P2u[{C"@P>X@PKO@PW @Pd# (0@Pp"@8]JC@8_g@8_B@8޺*\@9jh@9\/@9X$4@9M@:4@:UI`@:q\@:FGD@;P$@;KӛXYk@;ё3j@;Šw@<A#4@<>wQ@|@>W" @>zATr@>?}*"@?:u @?Bc&CU@?|&{@?"m@?!raX@@<@@2XG~@@Ob @@l5. @@"5@@T.@@Wm??@@n$r@@}r @A򴡎@A4n@AP_8@Am,W!@@Ax7@AQ0@AL+7t@Ak@A.Z@B?ҹT@B2D @BN=Wn@Bj,@Bl{A@B*@B8M@B|r|@B6lkq@CLj]@C,5hVh@CH(KC@Cc@CC%ac@CU@C9 @Cѥ)@C @DdǤ@D#@D?JZ@DZA @Duyf @DT4@D4t@Dr\@D@DB@Et4@E3'@EN@Ei 2@E`U@Ey@E23@E~7Z@EJD}I@F @F$̄\@F?3<@FZ35@Ft`@F~a@FFT@Fį/Wb@F=U@F>@GGS@G.at@GI8LH@Gct@G~b@Gs.@G?@G(F:@GyPº@Hƞ@H ~@H6J?@HP_m@HjF@H]@H @H7Q@HV_tmG@Hpx@I-H@I!?@I;Q{@IU @Io@IN@I@@I@)q@Ip(@IWo٢@J :*2@J%Ia@J>:@JX񵂼@Jrq@J_28@J% @Jg@J٥C؄@J^;@K  "@K&?@K@n @KZ`i@LYv@Ls7F'8#@L|@L v@LV@LY/A@Lak5@M `@M%$l7@M>˞BT@MW%@Mq-G@M~N@MkNZ@MVP @M\iP@M0K+@N(@N"b@N;SLXQ@NTW5n@Nm/D@NE@N5;Ss@N:Ҡ@N_#@N.7@O+@O@O6O@OO (@Oh nBv@O夓X@O @OC\@Os@OOϰQ@O;<@P @Pq@P%1R@P1z)H#@P=2@PJh@PVG@PcQ,U0@Po)t@P|3*C@P@P:@99' :@8Śt@9cj4@9^@9:7P@9}@:oq-@:Y@:U@:rV@;y6@;Qxc<@;rն@;0C@< ;\@&̜S@>b__@>Q$G@>Ii@?ĺ@?NDJ@?M+@?CZ@?Vz L@@U7u@@9o]@@Vy@@suWDoy@@at@@?du5@@X@@ϟN@AA@A (W@A<A@AYJu,X@Au@A8J@A4P@At@A?@BJm@Bװs@B;ںZ@BWL@Bt4u@B#lYH@B "9@B8{@Bޯ@BBg@C:ث@C7PO @CS =}@CnHc@Cg۳@C[_@C&@C( [@Cr@D$\F4@D//@DJq2@Df[8W@DL@D˱ @DCR@DӀw 0@D@E {@E%5뙽@E@!c+@E[5@EvB7Fk@EG WS@EDI@E:=@E(P=]k@EFm@F)H@F2ǃf@FM}@Fhc`Y)u@F&'@F}y@FT@FHuMm@F@G@G#.G@G=DU@GXQ@Gr6P@G\M޴@G9dE@GN 2@GܽkV~@G'?@HwK@H+we@HFA4@H`LL@HzM\@H'Y%@Hi~aQ@Hɥ}l@Hi @H *;@I8@I2_6-7@ILT@If8;`@I>/@IĄ!@Ia_@Ixk@I?N@Jt @J @J6бq@JP'a7@Jj˶X@JR=@Jd t@J@LY@Jk'@Ju`@KD@KG @K9H @KS Z@KlŕL@K}P@K1m@K[hV@Kӌ3Qk@K3챇@L@L uh@L:@LS2s|@Lm9M@Ln#>@LSW22@Lٺ.@L\{eu@LW@MVW@M͂Je @M9@c@MRv1`@MlM@MmX@Mcs@MI h@MѦsu@MJl@NV;;@N@N6w@NPBIg@Ni@N>@N @NM7@N·#ձ@N群|(@O!͆@O"N{@O3O1K@OLx'@Oe/7k@O~U'@OHn] @O X@@Ov9@O/#8M@OB~@P a0m@P/V̍@P# >'@P08Y@P^<@Pn,k@P{.@PȜ@P@P[@P k@P~G@90@9_$@9f57@9)ce"@:럦$@:\-`q@:l@:ჲ@;@֞@;VM9 @;&/:V@;*H@)@<Dk@|@=H@>0j1@>lG.@>H@>aq3@?@?Yy@? 4@?k!@@V= ]@@"ט@@?Oe@@]";@@zG @@[Px@@a҈?@@X@@Aη@A @A'߫@ADp@AaUA@A}:P@A@Ap@AӒ;@Af@B e_@B({@BEU@BaFĺa@B}z`@B @Bt^@BB @B +h@C 7Һ@C%Ůs@CA -@C]X P@Cy[Է@C$GFS@CM@C̗v@CB_@Dbe@D|@D; =*@DVr"s@Dr\@DO F@Dx@DO@Dߩ@DRm@EDkΆ@E1BA@EL@Eg4d@E?S@E8 r@EQE`@EbpxN@El23@F nrU @F%iHG@F@\@F[I&[@Fv.©@F m)@Fb@FƳ:@F|Erh@F>@GVsT@G1^9@GL]g@Ggg@GRH,@GB{(6n@GV@GeD@GhK@Hp-8@H @H;cUEGP@HUӳ@Hp>35y@HA@H(@H[ J@Hٮv@HT@IEh@I( u5@IBő@I\ @Iw0P@I^n@@I[A@Iũvdv@Imry@ILM&@J@J.\@JH @Jbk>@J|ϔ)@J O`@JZ@J6Jq@J6`@Jʌv@KB#t@K1aF1@KKgۈ@Ke>?@K@KJ@K^$@Kiצ@K)Đ@Kо@LG )@L3P!@LLc"@LfM>@LQqL,@L,@Lئ?i@L-}F@L#@MVg;@M@M3pi v@MLa@Mfz* @M l@MuR*@M؏@Ma@Mk7&@M>s@N .@N2 k9,@NKn0N@Ndcw@N~' %I@N~+^@N@N!@Nn)@Ns@O@O/@k뢖@OH@Oar?@OzN@O)@dK@O[ADr@OƊ$@Oߵ2@OB{@P @P@@P""wk@P.3@P;9(@>uL@>I7@>e9@?( @?d[#R@?m@?bb@@ 3Q@@(@@FZ#A@@c^7"@@~@@_$@@A@@76@@F6Ź@AH+iO@A/:3@ALR@AhS@AoMkz@Ayߐ@A'^*[@A9`4@A[Fw@B3@B1]&Q@BM6@Bj.@@BO~@B0f6@B=@BA8@BjYe"V@C?@C/?jL@CKl@Cg3Y1@C)@Czjz@CX 9@C- v@C}@D2]+@D*oL6@DF!@Da/(@D}\8rb@D$wN@DwDq@DE@Dne`@EQO@E"Ch@E=U.@EX@EtC(@E2@Eµu@E]?@E&^;@EK#@Fis@F2@FM%@FhAY@F `@FY@F~K<@Fi7|@FL|6@G (<@G$L ۈ@G?!@GZl@GuVM ) @G@GSI@Gs&v}@G.:@G{@@HVZY(@H/g,-@HJzvr@HeK@H*$@Hc_@HxI@H=@HTD(@I,q#e@IG6@I8t8磍@IR0@Im}@Ia@I/7#@I1r@IǕ@ISc_@J @J$j @J>cX@JXzF@Js /:@J"+m@J3ő@J?j@JGH75H@JIѪM@KGQ$@K)@5C@KC5 @K]$̺ @Kw;@K@K؝C@KĶ4.V@KޏX }5@Kd@L4m@L,q]w@LE'KA@L_"@LyJ̜@LV<@L@LoUpH@L}@Ls(+@Mn@M-gd@MFV@M`Jq@Myߊ%@Ms[+@M4~@Mƍ@Mڿ\@Mx?@N3f@N,7I@NF n@N_2"=w@Nx7@N_a@Ns^/@N/@NޒsuG@N񬟝@OMiݟ@O*tѱ@OCm@O]KiC@Ov"@OAt@O, 3@Op@O۰oA@O?a@>@ @>}pTlf@>ˑ~@>]U@?2 j@?mq\@?:@?Lc@@bYF@@. L@@K@@i-3A@@/7@@ NZIN@@cgf=o@@ުŦ@@ⱀ@A q@C^ '@CG }@D'ӽ+@D4c@DPDo@Dl~@DFe@Dhl@D7 ޯ@D:l@DϬ-@E[@E-ޱ&pi@EIY/O@Ed%j-@E4K7@EnA@Eہ@E?\@E툅Cu@Ff@F$oXQ-@F?3@FZ]T@Fu^@F@Fj@FƸ@Fta@FS@G2G@G2@GM F9@Ghjs/H@GE3%P@G>"t@GeD@GӭxOH@GmUO@H 'z@H#3j@H>iZ=@HY/a@Hs,.@Hjء @HvŽ@HÎN^@Hx@H5@I@I-@IGAA@Ibk@I|U!&@I2yw@I3l@IWl@I3F@J~Cp@JDr@J5d 4@JO?nc@Jiu^@J_@Jҍٰ@Jmp@JR&@J8Ha@KPZvB@K c@K:q>\@KT{m[@Kn*@K1X5@K|^@KsX>y@Kej@KS[@L =@L$!UH@L>n7@LWދfH@LqO)^@L3@LXR@L#4$@L7@L@M kt,@M&%?@M?*@MY&1@Ms<ò@M=GY@MdÍ@M.@Mb@Mgdzt@N ( @N&F@N@κj@NY @Ns2@NeM@N6;@N@N+<@N*#@O ݇@O%!@O>(|@OXRR@Oqoq@Ov@Oso!@OV@O"1@Ou{v#@Pgb@Ph@P,,@P*ρ,@P7pjz@PDe@PP@P]JS@Pi '1@Pv~9/I@PI@P=i3@P@ho(@Pf/@Pd&d@P׆@P΃O<<@PIP@Pb^@P%П@Qa͓@Q 5Bȶ@Q+P@Q&?hBz@; i@:@;n"@;^O @;AC@;>@<©@ i[x@>GГ'/]@>e@>o@>;N@?:i,@?vc@?Ź@?@@E%}@@3}Ye@@Pߢc@@nT2@@3X@@İ8f@@Dp@@@AXKWs@Ae&d7@As@A (@A.V@A@B#c@B$>@BAk@#@B^!U0@BzPlD@Bfd@B4@Bz9m@B @C ^y?@C%|}@CB1I@C^^o$@Cz(aw>@C{@CJW@C6DC@C,(@D5~@D#4rUr@D?)͕@D[1g@DvA@Dh@D a@Daof+@Dq@EA#@Ex@E9@ETIA@Ep?O_@E%~@EB J@E·@E$K@E~+@F p@F0:@FK3=@FfyZ@F #@F>eF@Fl6@FӒQ@Fy@G @G$y7g@G?ⲛ/@GZ:c@Gu|e@G3o@G!@Gƨ%&@G@Ga@qIQ@H3Cb@H2@HL눍@Hg&$g@H>1T@HL@H@HD@H_@I&g@I"no@I<"@IW*br@Iqw@I+@@IWr@I.!@Iہfٖ>@I_'`@JIX~@J*Fc@JD@J_N3`@JycH@J^'gQ@J#.>@J_zޕ@J}K$@Jx@@Kҍ@K1 Ws@KKD :T@Kec׹@K}~ @Ke@K]u@Kͮ @Kq@LLY@L/@L5-~x@LO'_@LiǍA@Lg@Lik@LLP%@L+=@LnL@Mh' @MQV@M8}/z@MRF[@Ml p@M`}D*@Mj@MElϝ@M4@M쬢H-M@NZD%:@N @N9s =@NSKЎ_@Nl<^@NU@N@NG@Nb7@>Mԥ[D@>Ğ@>5,@?%]}@?A@?~2(@?A@?Q_@@kB@@7u @@U-mWj@@s2/@@YG@@I@@̽%U@@W!%@A3u@A%XV @ABIH@A`@A}ft@A@Ayf@A@Ab@Bc(@B+ @BHx@Beb@Bx2`Z@BANm@B|.x@B؛1IZ@B5/Y@C@C.Fi!@CJW@Cg(D@Ctm@Cܐ+f@C& ,#@Cd1@ClJ&@D@D,dѝ@DHN@DdH@DYtJ@D"@DA]@D.o@Du@E n5@E(5ZJ@ECe@E_~D@E{SO@E"~@E^@E!4@E骊@F+'@F yz@F<.0@FW{ @Frۤ32@F3/@F 9@F̙/@F u@FF@Gx"@G1>>{@GLm`>@Gga @G0(b@G뮫@G F@G x@GnʭI@H %@H$Y>@H?.@HZ7R~@Hu|,@HNS@HKA.@Hz@H_x@HT@IV@I0м@IKXՑ@Ie@I+ G@I'0@I.I@@I?XmM@IO;@@J?܃@J@J:*Iv@JT̤@JnL @Ja4Z@JU@JZB$@Jh*@J8ﬡ@K q@K'A;p@KA#@K[G@Ku@K5T@KF7s@Kl'|@Kތ;@Ko@LJ @L,i@LF[@L`pm @LzV @L Q@LzW@L.@L$@LIA@M-(@M0:-4@MJw\[@MdTU2@M~-++@M+C@MX@Mˡ G1@Mi1@M.c@Nn @N2S_@NLe0@Nf!]@N-ߵ @Nx\xI@N!ta@N=1@Nh@O7@OEFcS@O37@OLʾy@OfY@O堉 @Ombn@O z@Os 6^@Op!"@OjVڏ=@P pbmc@P)G@P% %@P2_qc@P?L4P@PKw,@PX i@Pe_>z@Pr %@P~ @Pc=5@P sT@P@PYg7l@Pܨ@Pʠ?@PAn@Pk(@P~K8@P4@Q xrn@QN,@Q"x@Q/|@Q<a@QH@QU72!1@Qax@QnVw9@<ݸU@;E@<s͖}l@<^wyu@<&m@<s@m@=ahd@=Z{@=ё@=gs@>#pQ@>R|"_@>t@> ai@? q:@?HK>@?}*@?f{@?ƕ(4@@@@;gQ@@Z+ ,@@xo)@@Q@@Z@@+@@&Q@A C?@A*`@AHvd0@AeI9G@Aib@AWY@Ad>AT@AcK@AHH@B@B2#c@BOu޿@Bl+!@BՠCT@Br H@BÏP@BYRֆg@Bsb@C/3@C6kp@CS8n[@Co @Cep@C_cK@C@@CP.$@Cӧ]@Db@D6, "@DR_y@Dn]6J@D".@D"kA@Dȣ@D*mu@DF@ @EG@E2x @ENnw=b@Ej@7-cr@E}@Erf@E'> @E-f@EMkY@Fn׸@F, ꎊ@FGy/@FctK@F~@Fvc@FlV0@FϷ@F+H1@G"@G"ZtJ@G>ly@GYM;ޕ8@GtI@GA@G9@G͙@G(r@G$Ds@H/u)@H23ʹ>:@HM1`\3O@Hh(?@H{U@H'?ĥ@HS@H@HnupX@I h~u@I$2Pq@I>zi@IYy.F@Itj-@Ibx@Iӻ)@ImĤ@I M@IPÍ@J;Iy@J.8q@JIS8~@Jc֨vE@J~TX߂@J i}@J@T]@Jͭv:@J@Ky4-.S@K@K7/zS@KQO~@Kk0@K3|z#@K_@K1 @K٤F#.@KQ%@L @*:P@L#l8O@L=Uf@LWS|@Lqp@LNl@L4N@L c@L5U@L$&@M'!@M(%:@MB@M\$6@Mv[@MJݰ@Mu@Mv@Mݠw@M|@NTB @N+(I?@NDΟj@N^į#@NxUW@NP}v@Ny @N̎-D@N߄b@N9@O8@O,gi@OF?c-@O_䡎@Oy)罐@O$ @>WC #D@>P @>03@??G{@?Ni@?V @?@@Ȃ)k@@!nYgB@@?K@@^c/Z@@|G@@j=nګ@@zi@@x~Q@@e^@AA0@A0 @AMm@Akn?y@Ajm@A@A W &@AwW$@Aaف@B FF@B9_1 @BVDT@Bs@Bߛ@BC@@BU@BL_@C[Dk@C!i'j@C>0k@CZM\@CwuÌ@C;ά@CҊr@C]+@C0S@DQC@D"@D?L*@D[llŕ@Dw6oXE@D}CH@D'e@DQ@Dp@EJK>@E 7w@E<0>m@EX\@Et{ȥm(@EaԬ/@E> #@Ex@E踭]@Exo@FVCrH@F7eJH@FRGO@FnMI@F@Fr[@F@Fvdu@FI@G[@G.V(@GJ!C!Y@GexN@GUNY@G{ @GQǤ@Gҋ@z\@G@H@H$ @.@H?*N@HZ@t@HuPc{Sd@HY"1@H[/ms@HVU@HKvS@H9^@I!,G@I2Qh]@ILޓQ@Igw@Ink@IK&J5@I p@Iu@I)V@J1@J"~@J=*@JX!?@Jrsr1@JO]n@JA(@Jg[*@J c@Ji3Æ@K Y@K,UBe@KFU@Ka,@K{`@K] /@KH$@Kʝ@K&@K7i@L}Qw(@L3j@LM И@Lh11$yl@Lc5l@L?p@L;=@Lޓ@LPX=@M|o@M0 @M9BFp@MSOpA@MmY: j @M^+|@M^'@MZ*@MRTZ @MFfO<@N 5iS@N#!\@N=0@NV) H@Np r@N4<@N{@NNi\'@N7Y@NR@O  @O%r~@O?1J@OX@Or ϩ@>Zl@E@>#B@>grR@?}@?Se"-@? l@?ΰϩ@@ I@@$ΊL@@C2-E@@an(7@@ I/@@Wp@@ |q@@ڼ|@@5v@A:u#w@A4%@AR@Ap@AC~u@Aҟ[@Aɖ>E@A(@BwMn@B"Σ2@B?NI@B\7^@Bzw@BY;)i@B̘D@BѢ;\@B,Ū@C ia%@C(z@CE@CbrǺ@CC,r@C0؈@C4B@CkTrV@C ]w@D8?@D+*@DGZڨ@Dd`@D({@DdV@D4Qo@D|yP@DtG@E ߱,@E*@EF8x@EbN@E~[v#`@E^roy@EX\r@EHE x@E/XzQ@F Y[@F%d앵@FA@F]r B@Fy,g@F |@Fto@F*zI#@Fÿ~@GTu@G.@G:_Pf@GUS@GqI*I@G@GœX@GpiL@Gà5@Gzw@HT @H0ky@HKǩʶ@Hf!@Ho @H@bQ@HZ@Hn@H{c@I 6@I$؉1@I?{1u@IZnH@IuZڇ@I@|@I u@IǐO @I@I'@Jc?;@J1%L[\@JKT@JfPʛ@JG@J3@J@J5ȳX@JϔlE@Kc'@K I4@K;{{F>@KUM@Kp}̳H@K: @Kk @K @KCsӟ@Kш@L.@L)a_L@LC^N@L^@LxSU@L@Lܽz@L@LRx @LzarT@ML@M/R@MJ]@Md'@M~DPq@M]hb;@Mq @Ḿ88M@M挐@N@NM@N4 @NN @Nh@Nvh@NdƇ@NND@N35I@NYI@O.@OaIF@O7%@OQsE@OkAZgt@O <@OH@OA@OQuv@O )=@PQ@Pn@P8_N@P)i.N@P6=S7@PC:ի@PO:@P\'N@Pi|U@PvGIFF@PΒo@PؙsR @Phx@Pc 2@P%@P浵+@PϦn{?@PcE@P@P&@Qnn@QIl@Qo:^@Q(Z/@Q5e6 @QBnw@QNŝ@Q[s=ň@QhR6J@Qt܎z@Qrԙk@Q^N@QZe@Qd{@Q@QXʲ@QIb7@Q@=@=_Όɘ%@=z0@=~6@>2[i@>]@ <@>_@>}澹@??@?W5@?@?ӗ@@n Y@@'zpu@@F2I$S@@d=m@@df@@ @@Fm@@ޛ. 5!@@$@@A mt@A9* @AW6NJ@Au1N@AF@A~@AνT@Av㬵@B K @B'A@BED*@BbB73@B,aR@BDǮ@Bڭ>@B/@BPr=@Cw@C/v@CL E@Ci^@C@CtԻi>@CNmm@C@CE\K@D;v@D3@Ef@E$AW@E(L@F#,@F0SH@FKξ@FgcdK@Fk.@F@FF,@FZ@FKЅm@GcV*ۧ@G*( @GEqx@Ga6<@G|@OTL@GF Q@G=?t@G6@G꣄6@HE@H!fA@H8S@J?Z[@JY%߬@Jt_mI@J|Kc|@J=!@JD@J߭b$@J\-W@Kb @K/di_q@KJJHx@Kdk@Kw@KOY@KV @KE@K_}"@L U$@La~@L8ﵺW@LSYLh@Lm;x @L3@Lz۱@LPQ˒@L", @Lo2@M g=@M%ُ@M@9$@MZs@Mt27B@M٠1 @Me&@M-Vk@MP=@Mo@N;@N+N+@NE@N_}@Nym@Nٕt0@Ǹ?f@N1:@NPz/@N[@O5@O/s@OIzٺS@Oc^O@O}? 3@O=Z@O3a@OF@O}Z3@Oe97@P w@P"@P%cR+@P2?@P?C@PLqr6@PYJqB@Pf"_I"@Pr#X@PTY@PV&ƴ@Pn g@P= N@P {%_@PռR@P̟GW_@Pg6@P-G~@PH7@P@Q u#@Q5=J7@Q%$@Q2_b@Q?j@QL# @QXڀ5@Qe]9;$@QrD @Q~bq@QOX@QX1Ѓ@QK] @QǗ@Q]u @Q|B@Qׯ" @QVђ@Q7)^@Qs@>U< @=`63@>}F@>^@>9[@>Kvz@?+f@?Z4@?Z빒@?׬emu@@ cz%@@)䔢n@@H@@g @@X_@@T,9@@ÔUϋ@@9@Ax|@A܌ɦ@A=$ʕ@A[Z&@Ay~n@A&E@AR9@AӄAO0@Ad@B41@B,Nб@BJf@BhG_@Bٞ: @B]h|l@Ba@B897@BIϪ@C@C6NJ@CSFz @CphF@C}8@C̬O@Cǁ4F=@Cp$a=@DR|@D)W!@D:1@DWҟv<@Dtf8T)@D s@Dd\l@D<0@DŽ@E>Hk%q@EZ2\@E<Z@EXr @Et  @E %@EIŞ#@E}Υ4@E ]K@FSL@FkԈ@F9x@FUzk-@Fq5&=@Fif8@FZ-T@Fū,Џ@FN&@FR؀ @G8@G4؎Q@GPB@Gl=@G)@G7^@GXR@GڥZ@G,0.@H?a@H-"bbZ@HH1@Hc=@H[@Hr@H @HS@H8@IՓw@I# 5%@I><Uq@IYe܏1@Itx&N@I=Uw@IvEPX@I3`@Iυy^@I|@J'Dz@J1–}F@JLb6@Jg$VM@J~z@J[*P@J2O<@J6(~@Jl@K>)@K#TWz@K>ė@KXaq@Ksrj@K:@K,@K^6@KE@K @LT.@L-r@LH''@Lbq@L} و@L~@L<@Lpk@LX4@M7a @MG@M5KD@MP=I@MjXJ @M}W@M-W@MX.T@MӔ|6@MԲG@N k@N"*;T@NL @Ow@P4&Ol@P!r@P" &@P.)V@P;ތj@PHlL@PUqGB@PbOj@PojS;@P|Is@P&&5R@P q@P)c@P%2@PB@PZK<@P,@PY@P a@P@Q d/@Q-@Q"ђ@Q/|~@@QDxN@Qk3"C@Q!5W1@Q,@QȈ&X@Q:-@Q6Z@Q2@QF@oC@ROs@RMa@R!D@>E@>_->@>?@>׻9@?A2M@?]V!@?:T@??@@ E@@+)@@J i@@ip-@@r@@`~^@@}Qߔ]@@*#c=@A;@A"HR>@A@ʄ@A_>@A}i˥@AW8@AЗc@AX@A67@B9 @B1QB$@BO@Bmp; @B(N/y@B$@Bka@B @CrÏyH@C$ @C6sY@JYO?Z@Jt-ѡ@J'@Jto@J@J຃VX@Jl@Kw)@K1M^:@KL3٠@KfC@K_5@Kkۗ'@K%W$@KMp@Kɮ@L01[@L!ԅU@L @M̕T@MU= @MWQ5@M㦺N'@Mî@N6@N2w8@NL@0@NfT@N2@NO*.@Ny@NϠw@N id@OIL@O c|@O8HmR@OR Ӵ@Ol-0@O6=@O;@OZ@?Q0@?^y@?HC @?a4@@$X@@-̺p@@LǔQ@@kg@@7@@@@d @@۾U@A,ɂ@A%RP@AC R@Ab{o@A5O@AY_@Ai7@Aq=@A $]@B? @B6NuXP@BTL=@Br:rI@B/@B̈́jH@B˧ X@BW2X&@C{Bî@C$&3@CBq5@C_yI@C|@CHV @C_L@CI]@C=@D-=k@D,F.@DISMAE@DfS{*@DG”@D/5@D Vߜ@DɎ@Do#Rj@E\sdMu@E0 R}m@EL3m@EiHV/@KY٢@KtƳ}@K#H/@Kh蓖@K7Q+@KL@K8P@Lp@L0;}A@LJ( @LeB@LEƬ@L G@L"Yg@L f7@L곾J@MB\N@M6ׂ@M:Pm6u@MT }@MoJ@M<[U@M1`@M@MD2Q@Mf&@N }2@N(b@NBr7@N\>Q@Nw *c~@NS@N3a?t@Ni]@N hP@NBhZ@OsP]@O.a]@OHj*˷@Ob0i@O} @O&@O=J@OPY4@O_M@Oj0!s@P @PNS@P&Xמ@P3 s@P@D]@PMb@PZb@Pg ,@Pt@P~e@PnNl}@P\Oě@PI@P3lQ@P̭`@P@P紣@PCi@P;zU@QT @Qi3@QE@Q) {@Q5@QBϮ@QOn @Q\xma@QiJF31@QvsK@QF@Qs@Q)@QJLÅ@Q~@Q YC@QϝnO@Qa L@Q"vz@Qmx@R5@R^(%@RW@R(sX@R5@RBB@RN &@R[q~@Rh^=@?P@?_ѳ@?R_@?@@'~@@.ɍ@@N,D@@m@@ ߷@@T @@"N@@* -@A X @A'1 "@AF@Aez @AC@A_6@A*\@Aߕ$@ATa@B6ß@B:m_0@BX@Bv,@B@B&@BІ@6P@B\(z@C "ia~@C)ٮS@CG6@Ce?N"@Cʃ@C%|c@CVz@CfJ}@CL-N@DԘe@D2X@DOI\h@Dm w@D3O@D<8,*K@D8|`@D)l*@D9l@Em@E7 BQ@ETxSn@Eq0@E\dK@EZ,@E8@E㣌s@F&ܑ9@FCX@F9 h|@FUp'/d@Fq@FS@Fb @FƠC>@F)ī@F@G l@G79 i@GSIY]Q@GoPVq @GN tI@GDDw@G1i֗@G$@G0t\@Hƻ@H2kZ@HNVm@HjJO@H!c@Hsm&@H!a.@Hص9R@HJt@I㭰@I+_@IF@IbWEKp%@I}V$@I2U3ߙ@IS-@IcEO@IF@Jg @J!ܱ@J=KR@JXX)z ~@Js@J2@Jx{@JCܦ@J@J/N.@K=5@K1ED2@KLGK@KgCaF@K9M@K)uk@K[@Ka@K@L1Y|@L#dW@L>QQ@LYi\@LsܺFOl@L+U@LR:1@L@L޲b@LZ"@MO@M.d|@MI48@Mc?(@M~V^w@M @Md @Ms \4@M_Z@Nn~@NF%@N7BU@NR@Nl~< @NܾI@N6@N+@Na6@N)Ӣ @O pk@O$bq@O>i4@OY.&@Osdj6@Ou@O<i@O w@O!a @O4N_@P(X@P5"#-@P"?3@P/G'C@P.!@B\||@Bz1@B::f@Bt(@B V@B@C=K@C.n>@CL!@CjX&?@CX@C@C3!k=@KYK@Kt\@Khe@Kn%@Knwhe@KhyL@K\7@LKx0@L13X@LLĦ@Lf)}@L4|@LFh4@Lk0@L2|:@L~s*1@M*-@M"h^ @M=@MWǞ'8@MrodG@M @M@MH1@M>L@Mj_@NE@N,x(@NFVT@Nat!j@N{K@N\T\@Nd$@N1ϭ<@N啟@N)@OO7@O4Ũ@ONL@OiD#7@O@OA@Ov)@ON]o@O@P\gw@PtK>@P"N@P*"@Q z@Q¨c@Qc@Qgq@R 775@Rp@R"ҽ+@R/@RؗO@D\Iq@Dy b@D:u@DO_@DэA$n@D 3@E ]V*@E(i9}[@EF fK@@Ec V@EJ%J@Eꃐ@Ewb@E֝M]@Ef*nи@F$4@F,ב@FIb@Ff̽@F񅎟@F<Ɲ@F@F3 5!@Fd0@G}u@G-[Fsb@GI @GeS}@G.a@Gc v47@GK}C@GְP:@GRp@HL @H*&@HF\@HbE@H~ʗ"@HDk_@HȐ @Hgտ@H6%@I H @I%i@IAu @I]& @Ixr@IpQgr@I aG8@I˝,|O@I(q @J@@J*ib@J9#@JU^@Jpyd՘@JTa@J6@J‹'LW@J+@J {@KaO@K/e@KJмv@KeΠ @K&@KH`?@Kc@Ky@K([Q@Lџ@L#w@L>|@LY^9@Lt9_@LlgG@LS4ty}@L4S@LeL@L:@MG@M0~s@MKJ15@Mf "@MUg@M~g @M0[k@MΔ 5@M.C@N&E^@N g@N;\E@NU£@Np~_z~@N'}@N$q@N _@Nڈj=.@N@OqF@O)t}l@ODHs^@O^@Oy D$@OhUX@O_@O*T@O`Gx(K@O5/ @P wGS@PI{@P%$\@P2Ӗ@P?3@PM9ے@PZrJU@Pg0 @PtB'Z@PRn@Pan6&@Pm'xn@PwQ *@P@P…`bp@Pϊ}@P܌3@P5@P%@QQ"@Q,Xa@Q|+d@Q*sS@Q7hj@QD\(l!@QQMp?@Q^=ø.@Qk+YF@Qx= @Q՝/@Q%|{@Q&N@Q,?@Qx@Q}ϋVv@Q^Տ@Q<{@Q2@Qܳ6@RyN*@Rr)R@R|,@R,Q Ү@R9$7?@RE#Q@RRJ@R_i@Rla/Z9@Ry,fE3@Rj@R.@R_I@RInrD@R b@RmVK@Rҏiq@@@@oO@@{n@@2q@@17}@@ks@A@@A-@ALG@Al21= @AX&]@Ai@Af@APisw@B&/@B%@BDXߜ@Bc8Zv@B2p@B?9@B헺Z@BCp@BHq'@C@C7@CULj@Cs0y@Ca@C2O9@Ću@CM @D ^V(@D&y3_@DDZQ@Da"@DtN*@D젿@DX"x@D׶jy@Dg@EM@E/_@ELM@Eid@EN9@E*L@E@:@E⚇`;@Eɾؗ@F/=$@F4w/@FQ=gU@Fm.a7@Fx@FQg*@F E@Fm@F c'@G3*@G5J@GRh/J8@Gnzs$@G#l@Gr̎@Gù;@G7@G*x7N@HU#;@H4xE@HPOD@Hl2 H@HMC&r@H@H8@HܖS@H<@I_@I070a@ILn@Ig|@I@ILm)Bg@I_,@I֩oAd&@ILn@J @J)~+>@JE h5/@J`@J|Q@J @J/@JiG@Jd`5c@K,@K K@K;"N;@KWǁ)@Krcڼ=@Kz4@Kٌ1@K @K6MP @K[|@Lz@L0f3@LK,_%@Lfi@L(@Lq@LP@LҰ>@LQ1@M2;@M#rHw$@M>R(@MY-['@MtŖ@M(@M.@McK' w@M#;@MoxC@N9@N/Es@NIF@Nd @N:r!@N]h@NpX3@N,)L@N_p@O:=q@O\@O9!k@OS~L@On{^@Odr@OtS@O_a@O @O$;@P@zTG@Plge$o@P (X@P-½9d@P:8y2@PHFk@PU'8@PbF@Poc](@P|~@PA@P؃!@PûI@P֟P @P7@Pp@Pf,@Ph;@PzC@PV@Q #S@Q'5@Q&(:@Q3(AH2@Q@%k@QM!ݽ @QZ1@Qg$M@Qt &2@Q-8@Q8c@Qs@Q^l@QC@QE@QΕt@Q~'@Qdθ@QI~d @R-@R|`@R_@R(c@R5y+@RBzc"@RO]N@R\5@s@Ri eC@RuZRV@RVp @R@RT @R"Eq@R7@RºT@Rτw@RL@RTqS@R{@@E@@= ]@@^2@@@A4?y:@A.\3@ANGOge@Am*@AZ7@A?Ԅ@Ah2@A}@B ~Q{@B(k@BGE@Bf 95@B X@Bd@Ba@Bu7>B@B{a@CA2@C;5v@CY@Cw\D@C'@C"=@C h6;@CJ@D @D+©U@DIU@Dg@G"@G!.[A@G>NSU@GZի!@GwSV@Grߤ@G2B@G̓og@Gإ&@H:k׏@H!mT=@H=π@HYX@Hv}Pn@H@zէ@HZ̐@Hm $@Hv%@Ix\b@IqƠ@I:c%<@IVLƻ@Ir.@I @I@IŤXP@Ig;@I"@Jְb@J4is@JP([n@Jk7$K@J^q?q+@Jб@Jw|@JEm@JuNx@KS@K,X8@KG@u@Kc!2?@K~{@KϪj,@KOJl@Kdq-@K른+@LT@L"XfoP@L=DR@LXl|Z@LsJQT@L@LLa@LvD@L@b~@RK#b{@RX`%2@Re~:@Rr\ _@R9Ny@Rp@R5-@R1^@R @Ro.@RB *@RY}&@RnE@R[R@R~z@@S IF/Ż@S@A7U@@G?L@A:@A/E|I@AO71Op@AnyH@AMW@An@A x]@AMcR@B y8@B*`@BI"MC5@Bhl@Bc@B/8%n@BRK@B㏃<@C%ȹ@C qh@C?˄@C]vA-@C{ѼL0@CH&@CF/u@Ch$@C|E,A_@D@D0v@DN\\^@Dl5Jl@D6@D@Djbx@D @E|7@E&)Dn@E;5@EY q@Evm\2O@En&n@E L|@EE!@EuƲ@F^@F%w@FBmh@F_Vd@F|@F=@F5@F\@F(@G `f@G)n@GFO0a@Gb:nu@G @Gٽ@G@G[@GA@H ^x@H*\ \@HF6>@HcBv@HH~/@HTM@HRH(@H&@HY2O~@I #>@I(5w@ID@D \@I`B3@@I|,9@KpA@K[Ff@K7"I@KS^@Kn@KF}'@KR5@K`E@Kqo@@KѩQ>@LjL@L.c 9k@LIijI@LdB@L(@LO<@L{2@LѡP@L @Mj7Cz@M"DF@M=@MY ,@Mt · 0@M @MmKU@MG@M+e@Ms@Nf(q@N0C]@NKezT@Nf8x(@N*@Nϯ@Nu@@NR`&@N 6@O@O!q U@O<#T2@OVcEC@Oqcޮ@O@Oz;@O+%)@Oۺ[n@ODZì@Pd]j@PPi@P"|@P0kg@P=Y!B@PJu@PWI@Pdט@Pr*@PX)#@Pۆ@P0@Pدo@P@P#r$@PE(m@PeR@P9L@Pql@Q }@Q@Q/}@Q)<{@Q7_v@QD S 6@QQ.B@Q^;}oj@QkF;BK@QxO[w@QV ,@Q[=8@Q^T7@Q`@Q_d^@Q]-@QYb@QSAP@QLkG@QC. @R81L`S@R+xG?%@R!)@R. ܤQ/@R:_@RGqT@RT4e@RaL8@Rnnp@R{?@Rl"@RO(@R0 f@RS@R~@Rӕu@RգIz@R|LR@RSCX@R)$w@Sv@Sлj@S"j@S/q&@SR@AO!@A/b@AO@Ao@A: @A\'@ASK=@A#gf@B ")@B,ZlFm@BKK@Bjb3@BT#@B(V@BǁLsg@BP<@C ±e@C#@ =@CBSU(@C`O@CT{ uH@C ]@C9@CZ_@C@DBn@D4 @DR(o@Dpٍ?]@Du|Vu@Dj@Dur@D8uLU@E홱C@E#Rh @EA/ҋ@E^K@E|=I@E\@Ek=@Et'@E÷@F3(`@F,>/@FIi>@Ffr@F?@F@F}{@FڛSڈl@Fm-"b@Gb@G16. @GNJH@Gj'@@Gu$@G! SU@G¬p@GZ:e@G)@Hm @H2C$@HO[~@@HkĒ)@H$ ~V@H{iY@H@H@@HLd@I׷7@I1@IM3/@Ii~ v@I/- @I 57@I R@IY@I"x;@J沊]@J-ʘ~Qp@JI1@Je{@JIg@J@J#@JԅiM@J5 @K *T@K'3l@KCGߥ@K^@Kz?In@KWg@KF@Kv@K3@L@L@L:fi'@LUy@Lq!`@Lam0ˤ@L@L鲘@L$?YH@LY@f@M@M/y@MJs@MeO@M Z@MV=@M+)6=}@M2l@M4- @N0u@N#'S&[@N>!@NYQ@Nsׅs@Nx9b@N@Nā*+@NSQ+@N ef@OpXS1@O/|@OJi6@Oe"~@O{@O@O1-t @O6@Ox=rϲ@P[@PD*@P=@P*g,@P74x=@PD=T8@PR/V @P_mX@Pl!@PyР[@P^@PQ9@P @Pg@P|@P(@P=4@Ped@Pޢ:@P@Q Ԁv@QJߎ@Q%|@Q20FW@Q?Kg@QLdk@QY{NK@Qfg@QsN@Q@Q@Qу@Qgں@QKV@Qs@Q#@Q<@Q/>?@Qe@R6r@R@Rq@R)mCp@R67f @RCF:@RPΞ@R]Aד\@Rj3',@Rwu+@@R H@Rz1@Re:*Z@RMN@R4aD@R3Z*@R<0@R@R@R,@S};@SXր0u@S3XX@S, .+@S8j"@SE@SR­@S__j@A#xM @Ao,g8@Aߟ@A&@A<Ԧ@A;A@BY8$@B-@BM!!@BlghE@Bڜi@BRҵ@B@B踰eJ@CQ@C&qk#@CE29C@Cc1U@C[ @C [@C};@C@@CS'g@DC@D8I%4@DW @Du)ۯ@D9sIYP@D:&@D-tU@D1]@E @E(,@EFm{$C@Ed@Es0@EP*]@E;ɨ@ES #@Ev@F#lg@F2yҕ0@FO@FmU@F5ө@F]:/@Fy{-@FȰW@F f@G|}@G8}>;@GUcuݘ@Gr?CA@Gȍ^@G&x@Gȕ}@GH@H\@HBV@H;(WXX@HWV@Ht9xK@Hg@H%e>&D@Hɍ @H#@IC%@IB@I:{Ŀ@IWƙ@IsH(sv@It6yC@I \@IdzsL@IU(KC@Ig@Jֽ3@J7Ҳw@JS@Jo@JdY@Jv.@JL8z@Jw@JJX@K8{@K2\@KNK`@Ki~;@K]@K9pL@K@@K!d@K$~@L-۸@L* K@LF@La2[@L|M@LZBз@L733@L (@L]@MTm@M Ü@M<*ar@MWb?oq@MrH`@M74x@M m5@M .iT@M${@M: @NJ@N0UR@NK[t @NfZ@NU]:@NJ@N:@N%a{@N n64@O;8 @O"vy@O=ٜ@OXm*<@Os9'@O h@OMTy@OÀIȬ@O99T@Ox@P eN@P#l)@P$u!@P1P-@P?sӆ@PL`KB|.@PY3@Pf*[@Pt6; @Py`@PM@P !@P4bk@PnzY @Pæl2@P=|@P@PA"@Pq <@Q~5@QN@Q8''@Q-o/@Q:?f@QGc!r@QTq^]@QaVq!@Qn)y@Q{ܘS @Q@b@Q ,@Q#X@Q7:6@QI:@QY :@Qg6@Qs@Q~J@Q@R KBK@R,@R%@R2aim@R?H @RL#W@RYV0K@Rf|1T@Rs@R{d@Rq"B>@RdDc@RV@RG+J@R5ݼ@R"B@RS&@R!@RFT@S.@S!8@S+'a@S(pF@S5Q0C@SB/Ea@SO ~U{@S[Y@Sh•e@Su$@SrҬ@ACO@Ax)@AȩOJ@A18@B?x@B.kC@BN_et@BmHg@B+8 @Bsr@B˧hK@B=SP@C ;{@C( K@CGӱli@Cf0@CUmҚ@C @C¬;a@C>-@CC2@D0@D<4*@DZ<@Dy& HE@DY @D}%@DӒTe@Dk6]{@E5@E-|@rJ@EKYq@Ei( @EU@EW@EFTzEE@EV@En-6l@Fp@F8exz@FUέ@Fs+J@F}I@F§p@Fސ@F+!@GO/ @G"g @G?uf2=@G\xKk4@Gyp¼@G^Xb@GAČ@G@G Dc@H 'O _@H&jf{@HCx@H_v@H|b)@H#h@H!d@HT@H~F@I 8h@I'Vޮ@ICy@I` `@I|Y[y_I@IsT@I(cR@ISma@I;Mz@J _@J%{RG@JA~@J]@j&@Jyی@JwӚ(@Jk@J̀2?z@JfRO@KE"@K!x4@K<줿@KXA~@Ktwa@K2g){@KNTb@KǓO@K9|ee@K'7$@Lq|T@L6k@LQ+dDa@Lm&@L}@L @L|>@L!2Pj@LMm @Mjl@M-39@MHX3@Mc @M~\@M-a@MhW.@MОk@M'bJ@N1n@N"(e@NXT@Nsh[;<@Nvf@N~B@NĂ @N߁&v@Nzؕ@Om@O0\@@OKEjÐ@Of)V:@O.>@OŒr@O٩D@Oчyi5@OS.}B@P@P@PK9@P+9@P9h@PFXFK@PS@Pa/@PnPU@P{b@PQn@P3@P{(.c@P@.@P'w̻@PC {@P؂nt@P@P;c@Q1G%@Q gV@QNn@Q'4w+@Q4 @QB*Q @QOV^@Q\YG$@Qio#@Qv/(@Q@Qsl@Q3R!@QQBxQt@QmEќ@QŇ`m@QҟQ @Qߵ@QZY@Qt!@R@R@R! *1@R.a"@R;jSa@RH&6@RU,'?@Rb0#*h @Ro2G@R|3'Fb@R2l?@R/=cx@R*,W@R$z@R*@R\@R9@RLp@R+M@RY@S z@S@S$@S1ۻB@S>ru@SKX6_@SX=L_@Se NMU@SrXu@S~>H@S @S9.@Sx5U@BbD6&@AI!@Bmj@B/Tv@BOB)c@Bn @Be+h@BG/@B5L%@BvR@C #`@C*ٯ@CItW@ChȺF@CG0y@CmC@Cx^`Q@C0!rl@D7@D!mFn@D?8i˱@D^iA@D|3Y@D%Rd0@Dm @Dץ;Zg@DΡ@Es65q@E1{U@EO9m@EmM@EH@EoX@EdDNO@Eⴸ@F̽[@F m@F>1}@F[<42@Fy @Fu]@F٫@F1~[@F~ZSw@G {xF@G(VÍ(@GF M@Gc?ё0@GT@G^q@G^H@GS @G>@T.@Hat@H- W@HJ=@Hgfr@H>S@HP@HW@H1K@Hϝ@IOm>@I/@ILI\J@Ihv@@I[|U@I~@Iɣ@I!XTD@Ie@@Jv~(@J.@JKR*Z\@Jg',@JDN@JX@Jew@JjM@Jh$r*@K^(@K+L@KG3!$@Kc D@K~{;]@K '@Kl#B@KKk@KKծ@L w|@L%l"h@LAgF@L\(@LxPSU@LПH@Lrrޜ@LaI@LzrS@Mk@Mi$7@M8% yZ@MT>h@Mo @Mnk@MR"E@M |@M69@M/^y@Nn IF@N.?(@NI[{ C@NeSV@N.0G@NP"]:@Nleh@Nу@Nd/@O90@O"@O=Z/ʨ@OXʧ@Os2@O-#D@O},X@Oe&@OGH@O%f@P j@Pn3^@P%Q%@P2+>5@P@t@PMyL@PZNT@Ph2^f@PuM}l@PR@P8 `@P)@Pڮ™@P(5g@PtW c@Pҽן@P& @PJF[@P@Q1D(@Qa@Rv@R1G@RH@C,*-y@CKa[$@Cj"D@Cj?v@CK@C|L@CtT@D@D$UK@DCK@Da5q@D%@@DqR@D v@DfP@ErP6 V@ETZ@EJ!@E2W@E E9@Fad'@F%%7@FCP @F`Sq@F~GyT@F -@Fۈә@F/@F@G>J@G/5*V@GL}鍾@Gi=@G`#@G,1@G/1@G@Rv@GGn|@HC@H56#^n@HR<߼@HnUu@HЊ@H5C#@H[(@HAus@Ho0D@Ie_`@I8-@ITߢJ@Iq^)@I^M@I!h@IƂR@I&}@IFK@Jź|@J7j1H@JT-a@JpiM@Ja r@J$@Js7@J 8M@J!A:@K.@K54m @KQ2{4@Km)f*@Kd@KX7@K_;@KܼBy@KU6@LZk@L0@LK*@Lgq(@LE2a@LNC4@L90@L/#@LJY|@M U~@M([3@MDac<;n@M_)$.@M{TB@M'Rs@M/|ngV@M͓ @MU@NJtbJ@Nk@N:gF@NV0y@Nqq("@Ns@NS@N@N=Κ1@NbQ@Olb@O/^@OJ rAW@OeV @Oo}H@O33o@O%Ϝ@O@O@Pᠻ@PN@P7oH@P,3 @P9g~@PG T@PTvn)@PaaPx@PoB@P|Re@P '@Pb@P@P,@Pm*r@PQ@P˽@Pdۛ;d@P zF@Q\R@QG@Q#>\@Q)K8^@Q7Pz@QDX7r$.@QQV@Q^Ӹ@QlYyG@QyF@Q}pT@QQC@Qe@QT6>@QCTd@Qo۷@Q՚Z g @Q8V@QE@QE#@R 1'a@RQI@R$p@R1A@R>\q*@RK.`@RXXJ@Re!<@Rs}O@R#5@R&w@R5^@RAɖIr@RL/Ij@RV D@R]Q@Rcd6>@Rgy$Ӊ@Ri8%@Sja @Sivj]@Sfv@S)b}3@S6\}T~@SCTr?n@SPKۺi@S]@s@Sj4@Sw%c@SB@S(|@S tj@Sݕgd@Sǎ@SįX]@Sі@S|57@S`)@B7@BoM5@Bv@B7@BG5@BĠ޸@Coz@C-@CMGh@Cl^@CA<@C?y@Cpk@CtE:@D Nh@D&@DE o7@Ddz~Ʌ@D)gN@DC@DVf@Dvi=@DD1b@E܊#@E9t@EX8(@Evk D@E0$Qv@Eg9@Eб{@EK=@F _A>]@F*|"K@FHOZN@Ffz(k@Fl!@F}˻j@Fñ>@Fܳ2@F<+ز@GKD@G5)H 3@GRe@Goeo:h@G8r@G{^@GǴ@@Gf@H%w@H]@H<+Q'ɿ@HY.@Hv(\Q@H<0@@H\G@HئCy@H{,@Irc@I#1p@I?@I\2 @Iy5@IϗaK@I`v@IwR@Ig@JG dJ@J$LFb=@J@Ȉ@J]鸧@JycXz@JY̌x@J`@J1I@JeǾ@@KfPL@K": փ@K>WZ@KZE@Kv6@K/&@K8b@K}h@K\\l@LΜ&)@LwK@L:?@LV_荂@Lr-xcA@LhSBd@L3W@Lke@L蛅@Lvl@MnyQ@M4 c@MO C׀@Mk6C@MTS]@MGB@MƊ0@M?i:0@M2֭^@N@N+ @NFQC1@NbA}@N}p=b@N@N/>>@Ns@N*@O@O!l@O.@Ph1ד@Pv/m@P"N@P%哲@PjU@P1@P156@PƐn@P<"0@PI0CP@P@P>@Q LH@QӉ%@Q#~@Q1<钗@Q>`L|@QKƂ@QY #o@Qf^O]~@Qsc@Q`@Q!I@Q^#@Qy@Qѳ>@QrH^{@Q=/ ky@Qop_@Q꠰@Q|@RT@R';f@RP4<@R,wC}@R9k0m@RF@RS@RaT@RnAR@R{:#a@RTU@Rl>@R@R.@R^@Rɺ3 @R;*7Z@R׺@R|@R탸w@S Қ#@Sls@S%R8@S2S_@S?Å@SLD-@SY%5:@Sfƪ@SrN@SF@S(@S @S!_Ŝ@SU@SL @Sͫ@Sڙ.xg@S`@Spؼb@TZ^@TB]g@B31@BL&s@B˚sv@B'9@CI/@C.rb@CNtA!@CmG@CP@CEB@Cw^@C e^@D $q@D),on@DH"| g@DgK7@D% @DRb\@DQV@D<@E%s@E G@E=}~(@E[)j@Ez7@E '\@EB@E#U@Eh@F -P@F/0x@FMt@Fj.C[@FV_@FN@FMB@FD=@FO12@GC3g4@G:ɿ`@GXU/@Gu̘z@G8}A@GL@GQw`@G8ܕ@HwfG@H%Wڐ@HB- @H_|)'@H} c>@Hq@Hk@H @H6@I F@@I*\B@IGzk@IdI@@IeI@I/4@Idv,@Ivh@IKg@J-wj @J,M@JI2%@Je2 @JL7@JzwB@JF@J+:`0@Jw`@KJ@K+[@KH--,@KdYR@K~@KpfK@KZ|@KQ@K|@L ǡ@L($u@LD{@L`A@L|~"#r@L[(YR@L0}+L@L,@LƶX@MC@M#BXW@M>&@MZ#@MvI1@MP#@MX@M[{@M䥖L@N,op@N$[@N7)7!@NROV@Nn oq@Nvoj@N,[)@N7o@NۏCq@NKШ@O-~,@O-te_@OH+P@Oc.$d@O'R o@OX]oI@OR7I@OЩDXp@O׶@Pr(=@P+@P-fq@P, 3b@P9o3@PG@f@PTR@Pb _p@Po%2o@P|I@Po E@P@PPο@P@P(ӻ@P͑\@P@P[vrI^@PX@Qa\@Qyp@Q@@Q+,Ÿ(@Q84QEc@QE`=G@QS)]Tv@Q`y0T!@Qmߙ1@Q{dW@Q[hi@QO@QSp@Q+v.,@Ql@QʫS{@QI@Q#@Q\v@Ql@R g@Rj|@R',xњ@R4[@RA@RN )@R[e3@Ri@Rv*t@RN-q@Rp N_!@R @RA$@Rʟ\@R.`|@R߿@Re&@R*!W@R=B@SO:$i@S_)e'@S m^[@S-y@S:]@SG@ST@SaP @Sn| @S{,}@S䋚y@S@Sk@S>i@SuVk@Sɍ@Sք=@Syޫ@SmaNS@S_B@T Pjj@T?k@T$-An@T1_@C@B@CJcS@C/@COKz@Cn/ L@Cz 2 @Ca]:@CYkig|@C쬀M[@D \@D+$@DJ7Wou@DiAAL@D; @D#(fa@Dz3B@DIVl@Ew@E"r(l@E@P<@E_<d@E}d@E @Exm@@EHw@EЉ_L@F1B@J5x[@J4HG@JQl +@Jm)@J@J ]@JrZz@JP˰_@JC@K(a@K4@KQ?*L@Kmq?@K5h@K,R@K!s@KFi@KdМ@Lz]@L2T@LNe@Lj8@@LC3/@L}zV@LhY@LL@L*KH[@Mքi@M-П@MI@Me\- 5@MM@Mo@M|[@M$J@MhX@N b g@N&x,@NB'ݜ@N^U@Nyݼ#@N-1@N @NTq@Nf{@OQ/@O,S@O9@OTA5@Op*DE@Osq :@O)@Owfq@O/ @Ob>@P tk@P\@P$ @P2}@P@ ݌@PM"@P[8^@Ph4C@Pv#07@P|@P!+A@P9J@P#!@P }=@P@PpDK@PSD+@PL 1 +@Pj@Q |hl@QCM\@Q$@Q2Hp@Q?&@QM+"@QZ_Hi@Qgi@Qu oQ@Qaʣ@Q @QX@QP@QhGa@Q9@Q-@QrV(@Q쵇b@Q@R5Іs@Rrȼ@R!@R.4=@R<`SB@RIS@RVG3@Rc4@Rp砩U@R~$ H@R@@Rj1P@R`;@Rc6U@R܎p4@R =@Rf@R> @RZ@Sv@SqB;@S/S@S(ѣ< @S5]]@SB7e,@SOҌU@S]_ @Sj:@Swgs@S%8@S-]-@S3@S8܍Y@S;{H@S=h*@S=U,8@S;a@S8ZF@S3w`H@T,l@T$P(@T R@T-$@T:jRO:@TF%0@TSWGI@CO5N@C/l@COZ@Con@CNKڊ@Cnt@C~"#@C8@D a'@D,E@DK@Dk*@DIc x@DV )y@DS@D>Z@E@E$k'A@ECA@EbH!r@E@En@E:@EX@EpI@F@F7J=qD@FU~Q,!@Fs y @F@F{n@F˶x@F3#@G B,@G'uT_@GE@WFp@Gbn~@Gq@@GYI @GKp&@Gك@GoJ@H@H1l@HOO1SM@Hl]1@HbC@H4hpV@Hk@HD@HY@IǓ@I80O^@IU{>@Ir@Iz@I2@Iɕzx@Ijæ(@J5,U@J!uw@J<C@JY_ @JvHG@JiԄ@J;ܴ@J2E5@JLӉ@K@K!=:@K=&c@KZ Z@KvgH@Kt@K@@KK/&b@Ke"@@L@L@L<zj @LX, ~+@LtCS@LR B@L[P@L\6Y0@LVHJ@MI[j @M5 k@M8NC@MS;@Mo@MPT@MlmL@M0KO֐@M @M@NU""U@N1Y*@NML&b@NiATW@Nؙ;>A@Nj)f@Nw\ @NzT @NS;@Os{n@O)5@OEUyO,@O`%@O| )@O|z@OaS@O%_K@Oq"]@P\'@PPި@PS˱@P+54@P8na-Z@PFd_8S@PSH@Parn@PoY T@P|>!S@P+Ve:@Pj@P6+!@Pn@P6ήq@Pͳ2@P-@PT@PQ9܈@Q~,N@QRω@Qm@Q+i*@Q9C @QF@QTg*@QasZ#@Qn@Q|3@Q @QIUx@QBgC*@Q^)#4@Q1ؒD@Q=@Qٍ~f@Q2u@Q&kds@Ro@R k@RY@R)?G j@R6~@RC|@RPQO+@R^8oў@RkqT'@RxMEC@R޿~I@RF4@RC@Rs6l@Rt@RlK@R-@Ry@RF9/[@RjB@S 6l@S@S#G;@S07y@S>%O^@SK >@SX8 [@SeONJ@Src@Sv@S7y@SȈy@SL\@SU@Sj.i/@SMZ@S̋V^j@S&@S!@T~@T@lS@Ti~@T(-@T5bN@TBcU^@TO?]{@T\l@TiP0@Tv匊@C eT3@CoQA}T@C͜@C9uG@CPnJ@CeA@DH@D.b߇@DMj$"@Dl]#@D`&H@D9|@D[@Dk8z%@Ejm:@E'X@EF6K@Ee @E£(@Epq@E@Eߟ1SF@E5>@FRz@F:+@FYJ@Fw 8?@F@FE@Fj@F$J@G'Q@G,"{@GJr?@Gg1x@G L@Gz@G39O@Gm@GY@H @H7S@HUd@Hrį@HP9@HWT%@HʪD>@H\ی$@I/-@I"c7Rw7@I?:(,@I\@Iy@A@I/@IR1@I/@I[@J 40@J'q&@JDDla@Ja i|@J}]@J';F@J2g_{@J%@JtՋT @K 3A @K)$R@KF'@KbR,@K@Kr@@K J@K02 @Kknk@L ޔy@L) @LEN{@LaZg.@L}zS@L4;@L=H@L |9@LI@M $3@M&&c(@N!ɠ0@N |,@PLmR@PZ9Y_@PgӞ;l@Puj@P6@P%@P!C@PԀ:n@P9x1+@P@PGL@PʆA@PKRBl@Pɳ@_@Q Ex@QH @Q%6Η@Q2jƾ@Q@*>@QM=3@QZ3?J@Qhg'O@QuN@Q8{1{@QmS@Q)H*@Q`W}@Q D@Q:@QuB@Q'@ @Q"m@Qv/@R'*A@R@R#e?@R0n?@R=« @RKA8C@RX\Gin@Reɨ!CJ@Rs @RJN@@R-w7@RY@R<@R43@Ri߁@Rϝ@RωVr@R@R-@SZ>@S||&@S!I@S+@S8,@SF7@SS=ӹ@S`]Zz0@Sm{FO@SzsA&@Sի@Sʘ @SW@Swi@S tS4@S[:]@S,ul@S;"i@SH Gpt@SSI@T \,@Td㩷 @T$kA@T1pʂ@T>s,0@TKtI B@TXte@Tes"p@Tro߮@TkFǒ@Teʫ@T];!K@C% @C!@C?@Cp@DR@D.@E@DNr%@Dns@Dr37:@Djk@D@DHH)@E l2N@E)((@EHF@Egr#@ET@E%N,y@E漼@E☡b@@F;9@Fl@F>Ss@F\Ɉ@F{19 @FZ߉@FAz@FI@FD11o@Gf@G0|@GN-@Gl@Gp 6@GRA*@G(]c@Gd@HE@Hc@H= @р@HZ^Au@Hx5@ @H@H3~$@HСyU@Hv@I ^ )@I(o@IEc6O@Ic* {@IY\@I~z@Id@I׬鸬@I"X@JHF@J.W\@JK@Jht=@JMt@J<@Jg@JۢW@JWo@KKhH@K1@KND J@Kj!;!@Kaʣd@Km@K^z@Kd@K;pw @Lx@L1t@LNKLӽ@@Ljz$@L4%@LW(P@LJDpN@LwzT@L,o_@ME>@M/,g@MK~@Mg =f@M~VM @M @M@Mη*J@MT@Nנ@N+pL@NGDF@Nc<@N~טm y@N)9@NQ@Nk|@NC@O Z@\^@O$JN@O@˸@O\+S@OwH>@OD-@OL@OFFG]@O-@PG&@PNc@P7'n@P)?W@P7a g@PE [D@PRmv@P`Zb&@Pmz@P{^@P<@P I@PpL@P I@PvJw@P+@Pںu@PFG?p@PU @QW@Q]R}@Q^_@Q+޽s@Q9\Y~@QFי@QTP~lz@Qa@Qo;Z5@Q|Sz@Q8@QuY7@Q+@Q^"ҿ@Q[z/@Q)+@QڌE@Qx o@QJhJJ@RlȂ@R5 @RWu{@R*w@R8,=@RERf1H@RRǺ]@R_GX@Rm:pN^@Rz>{@R z@R^]@@RS9G@RV@RԊA@R KB@RM>@RM$@RCy@R?@S (ŗ@S[#A^@S&p58@S3羧@S@e@SN\'@S[:a@Sha&@C4G8@DGT@D/>g@DOT:@Dn~ @Dԏ@D 8_@Dz6@D:јz@E ib@E+VeX@EJ|2V1@Ei;e@E"@E(O@EpeR@EE``@F q@F"@FAe@F_?w$@F~墛@F'=q@Fl$@F>@F,@G\KG@G4)Q@GRT]i@Gp@E*@FlR@F%d3@FD,|q@Fbט@FDw@F*{ X@FQo@F5F@F@GV@G8\.@GVs@Gtxo@GW^@G(}@G:~H#@G@O@H 9@H)&Ć]@HG3(@Hdr @H*~@Hb:@Ho1@Hۻ4=@HVni@In@I4kS@IQDy@IoU.@IIK@Iec@Ie^d@IՎ@J)@Jd@JO_@TqÛ 3@T~V|3@Tq@Eʝgcu@E:8T@F´eT@F'@FFi68@FeB@FN1]C@F J@F@<@FW)g@F@Gi#@G;@GZDMn@Gx8@G5w@G&, @GWY@G{ 'rK@HIǦ@H- '@HKJY @Hi_@Hsd!1@HMY@H@Hޜ-@H i@IAZ@I9 (@IWxz w@Iu[9-L@IxW@IZ(!@IcKs@Iăg5@J @J%g !ֿ@JB4@J_x@J}ǯX@J4/O@JOä@Ja@Jj_1@KiCD@K+_AC@KHL2:@Ke0.@K O4#@Kݬ@K]O@Khy:@K!@LQjC@L.y9Xee@LK@LgnA?@L?sm8@LcS@LF_@Lپ@L.x@M>@M.S@MKQ$D@MgهhQ@M@+@M0X  @Ml2Om@MؠU@Mv@N@N-@NI-=)@Ne?5:@NJNL@NNfbNl@NL h`@NCW@N3uN3@O P@O)4U+/@ODkP'@O`P2/@O|$7U@OP_@O(b@O褕@O# @P@PtŜ@PGw(@P-궭@P:6@?@PH @PVw21-@Pd;3@Pqظx@P9@PyYC@P2i(@P J@P-|g@PO@Py@PߪtP@PTQQSy@PUC~@Qhܗ@QAݘ@Q#C`@Q1}̩@Q?#1 @QL6v@QZEZ"@QgHd?@QuhΠ6@Q0@Qx@Q $#@Q<@Q,@Qƙ-@Qgd@Qᗃ&`@Qd\@Q0@R  x@RwE<@R$;@R2Zt\@R?ȡ7-@RM42 @RZ\+O@Rh@Ruk @R%@R0G@R@R:@RG$;@RŠ@RD@RL@R %@R%@S@+f@SI*O@S"tߙ@S0!j/@S=h@SJbE@SW?@Se3zO@Srs4@S)O@Sb@S'=aR @S_ݱ@Sp@S]x@SC@S.\@S^+T>@Sk@T@T᧵@T zy @T+0@T8U*@TEx{?[@TR@%@T_@TlE@E!@EN&r@E@ɩ@EH @F qb@F)crI@FḦׇ́@FgԻz@F?8@FO7~@Fo'=@F/y<1@G2LL@G x@G?@G]*@G|w@GXp@Ggi@G+ݩ@GnRmR@H$@H1M1,c@HO@kD@Hm@HP+@H@Hn@H?Q@Ia@I!W^@I?vY@I\܅tH@Izl'@I{A:@I@Ix@I@J P@@J+p1SU@JHo|@Jf?T@Jf@J8@Jٳg@Jvd@J&@K>_&@K2L\{@KORN9@KlN˶@KB I@K,@K#@K @KQ`@L >3@L6>Q @LR8nr@Lor@LJC@LC@L~|@L ,A@L@MF!$I@M75@MS~@Mp`6~@Mo@M;0@MjH@MӬ@M3@N3 @N6hBN@NR[{@NnZ0@N܆ń@N@NB@NW@N=@O>~@O3W@ON4@Ojꎾ@O`p@OV%R!@ORb@OWC@O"¹f@P(E@PW@P$@P2wS?@P@aOLP@PN5;}@P\Ab@Pihz@Pw-"@Ph-@P-hb@Pv\L@PٲV@Pn;*`@P(c@PI@P(@PHL"@QCD@Q07|@QP@Q)5 @Q7dfS@QEB@QRK,&@Q`j@Qn\5@Q{@QLCϫ5@Q@Qrv@Q5E@Q@Qr@QڢP*¥@Q(m)@Q; @R-P@R@R)t@R+@R9;h@RFV@RT@Rayrh@RnS#@R|VѬ@Rfl@R+l@RT@R i@R[0@R̼.hs@R2@Rxgs@R@S+ʣ@S@S{b@S**`e@S7{Op@SDK!@SRVz@S_bu[^@Sl>*@Syd@S8by@S{얢@S5@Si$j@S;cCg@SwA@Sֱ@S]k@S!@SV\&@T &7t@T1@T%'˓@T3 0@T@D.܎@TMnW@TZM@TgMsJ @TtYe[@T9F@T)+m@TIr@Th@T R @Tàa@Tкeg@T. @Tӆ@T+@Uk@U"@U2l[@U,AH@UFY%@Eo@Dd@E3Hm@E/*@EO\mX@Eo\@E;S@E#C@E͗ @E<ƚ@F K:!@F+KP9@FJ]bWb@Fi%@Fҏ@Fګ @FD)@F_%@Gf@G#R$@GB@G`4*E9@GE }o@G:@GKj@GڹzrV@G}@HnBlQ@H55@HS1.@Hr~}@H H@P*@PG@P)rV@P7AN@PEDХ@PSVf@Pav; @PoM%J@P}"@P[^@PW@P;I@PXݐP@SL ?f@SYa%8@Sf&@St`B@STi@Sb־@Suݝ@S5-"@S|@ScHz@SL@SGyy@S뇝tJ@Sų?@T1@T@ToD`f@T|й& @Ty @T$x@TK̎@Tq}@Ta@T˷@Tذ~@TĆ<@T7b̉@U1 k@U KB@UcR@U'zd@U4U@UA2@UN}Y@U[9@UhiDƠ@EO@E/N@@EO V@Eow@E^Ȱg@E _@E΢Ip@E);q@F a@F-=.@FLVPO@Fk@FT8|@F킠[}@F@Fw+@GX @G%CD@GD9@Gcu[1@G-A2!@Gٴ|5@GrYa@G}@G3&@H:@H9WH̸R@HW2 @Hu%X}@O*L63@OFl`A@Ob@O~+Ce@O@O@OҫX4Ş@O @PK@PBl@P!57Qj@P/%S@P=_(@PJb%@PXc@PfiAdk@PtyF@Pep@Pav^i@P:$Ac@P$@P9U @PDz@P~Y@PIC J@P@P}$n@Q @QVoZJ@Q(:@Q5͕; @QCC:@QQ9x!@Q^h@Ql@QzHwZ@QE&6@QP!@Q@ @Qh@QPv@Q"{@Qپ#@QWy@Q-@Rl.@RZ@RD%@R+3)ӳ@R8r@RFGqDžZ@RS+[f@RaRaf@Rnӗ@R|Tޠ=@Rҩ@RNB:@Rǭԧu@R>+@R K@R&&/@Rڗt!E@R(@Rs7y @S|A@SFD.@Sn @S+Q@S8sz쁓@SE֧7N@SS22r@S`@SmU@S{Ac3@SRf@Sh@S?Q @SB@Sކ q@S+ncB@Svu@S忞Tj@S_K@TLb~@T h'!@TR@T(~9@T5P@TBgd@TO<@T\r@Tj6@TwlSҹC@T/@TQ@T@T0r+P@T]4k6@TƈG@TӱW@Tf{@Tx ,`@T#@UFY@Ugϗ&@U"U|@U/?Y@U<8@UID|@UVeWp@Ud d@Uq"GΤ@U~7Y=x@UJ7C@ELB@Eoyi@EIU@E;@E`̿@E ai3@F@%l@F..l@FMp@Fm 3@F`OP@Ft=P@F @F~xK@G J^ @G(}7@GGI@Ge@Gюk1@Gg@GRJ@G` @G\@H/s@H<s@H[)Y@Hy>@HͨQ@H=C@HԀS'@H5b@I߹@I. I@IMML@Ik@I Kr@IRP@It5@I+!Wl@JC@JBSα@J;{S@JY}\@JwDX@J]Ĝ@Jf@J9}8@J_>%@K @K(0m s@KE ͍@Kb'@K L#c@K]#R>@Kj@K׺/TJ@KV @L!@L/`z@LLv{@LiW,@L[+@LDJ0M@LɦD"w@Lܤ@Lw/@MAma@M3@MO-@Mloo@MPH@M-@MV\}@M'@MtM@N@N4sh/@NP+cʿ@NmUbD@NP΍@N@NqN@N$@N @ONȓC@Rg4W@RuU2!@Rݾ @Rc @RSR@RhˆM@R)i@Re*\.@R0@RX=@Rφ@RD a@S w"A@S&ɟt@S$.@S24|@S?kSp@SLh΅h@SZ9vb@Sg@St~:@S_^@S!;@S@Ss5@S,7@S"x|@Svg@SUI@SnjE@Sh3M@TyWv@Tuf@T"I jX@T/#ô@T(#@Uf@U*C@U7@UD?U@UQ}6@U_'@Ul5$mdT@UyQrL@@UmJvp@U,@UJ+@USу|@Ey@EAwg@EyI@Eun@FbpFɩ@F/ e7@FN!˝@Fn3#@F6fa@Fد@Fj@F뱠!B8@G G#a@G*9'@GI&Z=@Gh.=@@G'9E@Gr @G Œ@G㸽.u@Hw+ @H!'b@H? @H^^ܶ@H|3+|`@H`@I3 h@IQ.E&@IoPI@Ift^a@Ipld"@In? @Ia/@JH$*@J#%L@J@%@J^>-@J|wV@J(M@Js@JiǶ@J{~$@KK@K-7@KKqkT@Khl]:@K9i@KAECJ@KL;Kq@K@KW)2]@L/b\@L5x@LR.@LoF@LnS@L&Xv@LL@L-@M]}@M]YB@M:Wh@MWP{S@Mt`/@Mپ`@Mo(@MBh@M4Z@N@N %=@N<]p@NY@ү/@Nu_0@N>tm@NX@N_@NDm @O@O 9@OQ&@Q"@Qz@Qr"-s@Q(so@QQP@Qʏ0@Q>g0-@Q43#@Q٥@R=i@RLDs@R@R*&uk@R7@RE`n~@RR(@R`ZJ@Rn&;T@R{0'`@RI% @R v @G+@K C@KA2-@LzG@L!@L<}1@LYO@Lv|@LC&X@L 'us@L߾@LE.@M7@M$H@MAF-@M^+@M{H9@M[@M*<]@Mcq@M|aC@N f>8@N(1gD|@NDhO@Na[e@N},Y@Nd:z@N fߧ@Nӏ w @N ]^@O |tFc@O(^@OEM-8@OaT@O~;@OQE @O9b@OҠd@OMˁ@Po@P̭@P!u@P/l@P=[@PK8@PZws"@PhK {@Pv=\@P>@P- O@Pq@P0s&@Pڲh@P=@P״ׇx@P坆> :@POҍ3@Qf:*D@QFK@Q#[#@Q*x@Q8՞|#@QF{B@QT|@QbLi@QpӁm@Q}j@QH@Qo ,@Q10-F@Q@Q­@Qh@Qw@QSR)-@Q*6@R8JƏ@Ri@R"{J@R0:]|@R=t Z@RKI@RY'vA>@Rfl@Rtd/@R@R=Q@R-f%J@REΈ@RR7@TK @TX@Tf.Mo@Ts|K@TɍM@Tsٯ@T]"@Tڴ@T`@T.!M:@Tp)+@Tݰ\@@T?@T+^@Uf9b@U3@Uש@U- @U:A@UGtx/I@UTg{@Uaԯ >@UoQA@U|.Q @UXl@Us@UPh@U' ٔ@U#/@U~!̈@U5Lji@UT@Ur:*@FOg)@F/M@FOҼ<@Foҵ@FeaU@Fpp@FαM4G@F=n.@G $-G@G-#ocJ@GL~i@Gk.@G2Ln@G/Ioi@GKE_ z@GX-1@HV:$;t@H&E@HE&@HcXcg0@HW3@Htk;@H)j;@H޹ S@HHmLj@IӦk@I:>L@IX0@Iw'V`@IOb@IO`i @IȦ:T@I=@J@J,$ak@JJ+󺢢@Jh'ಹ@J8@Ju=@J?|@Jߩ':@Jn[TI@K(@K8"N@KV~ @KtJ@K e@K3@Ḵ0@K% ʄ@L?J@L$@LBGj@L_;!}@L|و/R3@L֌@LG_@Lp@LbX@M0 :@M+Nl@MHH@Me۳@MvL@My@M@A@Ma4h@M6ZWLG@N*@N/p@NL-@Ni:ue@NQ@NaP-@N+@Nu3@NQ!;@OI)@O1Z@OM`@OjF8.@O@O f@Os\(@OAڵ@OXR-@P 1`@PRޕ@P&oQ@P4<2@PB`N*B@PPEw@P^@Plq]1@Pzń@P @P ^j@P ZE@Pl-@P @Pkm>@P϶v@P@P@Q[@Q(E@Q"l^X@Q0O_@Q>0C@QLrGw@QY@QgϘ@Quy/@Qjl;!@Q:]@Q*@Q @QJi@Q`.T@Q#DL@Qn@QVc@Q]xń@R @RZI@R(Ǩxw@R62.H@RC#w@RQk@R_7L@Rl߀@Rz81@R'ѹ@Rs79@Rf˫@R=@Rp@R3U\@@Ro@R[[@R1:@Sz䶦@S; @SFVu@S+$/@S8lP@SF"h¶@SS}Gn@Sa##J@SnW=@S|s@SzXF@S q@S[d@S;~@Sd0@SS@S?y@S窙m@Sx5@Tzaiٻ@TV@TB[6@T*sWt@T8m@TE_@TRH#@T`8C@Tmlkސ"@H ]'@H(l~?ޚ@HGm70@Hf_3y<@HB}@H@HkF@HtV@IF6 @Iȗ@I=x髬@I[ s@Izu2G@IV6@I?:@IՒVS'@Iѩ@JG/@J0A6#3@JNdL1@Jl|!%@JL@Je@J}^X@Jh"q@KGs7(@K G8@K=R?>@K[)@KyZl@K:@K~@K= y@KN@L Lu"@L*ÿ@LH5eG@Len@Ll@LKfq6@LkBE@L֍K> @L@M=[0t@M2cP.@MOy@Ml_|X.@M@MC@Mâ @MD@M=O4@Nc@N7= @NT@Npی.i@Nk@NYc@N ^@N㹞|@O^@O*5@O9s]t@OV!eː@Or1A@O&@@@O̿;@Oy@O{'i@Poq݆@P0@Pe@P* @P9h|@PG5@PUS*9z@PcmG{@PqPX@P@PZ|@P@P=:@Pq E@Pn^)@PG@PQ@Pȓ[Y@Py4@Q -q4$@QLj@Q'*@Q5w@QCngy5@QQUN @Q_9e @Qm؞@Qz4@Q!n%@QqX}@QU@QW@Q(H @QB#V@Qs_@Q0H@QR@Rn*F@RB@R @>@R.R胿@R< c@RI@RWxI@Re+d@Rre9f@R@R40=|@RW@Rz@R'x@Rdܺ@RhA`t@R9@R@R9Z@Sc%@Sd+@S#@S1ٻJF@S?f::@SL_@SZ'p@Sg @Su3@SR@S79@S#ֿ@S2p@S({^@S%ԝj@SӛfJ@SV|7@S\@S A@T ag]B@Tz@T$87t@T1@T?:٪@TLks@TYΈ@Tg/SL@Tt9x@T>`U@TFd%@Tk@T!Tj@TL@h@TĠБ@T~>@TB>=@TX@TݟJ)@U(q@Uq@U!͕6@U.]}@U@U ;@UC@UGa@Vr_@Va@VÝ݄@V)@V72@F- @Fi W@Fʡ*@F@GiEC@G/Y @GN.!@GnGa@GŅL0@G3wV@G̑v’@G̷@H L@H*N @HInH3@HhdH@H}@Hx@^@H^] @H7WGM@Iq&@I!:@I@n@I_d8@I}@I/CC@ITX@I4f@I|f@JӆzD@J4R@JR\x*@Jp/_@J@m@JН@J@J@KF@K$Ջ@KBf@K`B՗1@K~\ @K h@KjES@K׊3 @K/?@LˏŠV@L0]]@LMdnT@Lkc\EO@L؎@LC(7@Låec;@L@LN0_@M|=@M8>=@MV 7@Ms2ReL@MU3@Mp@Mʂ)`@MEN@N-@N!&+@N>wj2@N[`%n@Nx@e@N@NQB@Nγy0@Nt0B@O.3b@O$K.@OAs3@O^.ij&@Ozy~"@O^4@OJJ:@Ori$@Om@P,&@P2@P!"",@Q"[=@QFh4@Q@Q:,T@Qř@Qp@QEQ@Q_(@Qo@R @R|}L@R&CСA@R4U @RA&$ @RO#@R]G$@Rk@Rx= @RpE@R$+~R@R3 l@R֠@R0@R@R؁_M@R&R@RGn@Sjd^\,@S7@SUS@S*>tn@S7S(!@SEk? @SR~g@S`Em@SnYV@S{uK@S5P@SeFJ@SDjr@S@SJ}7@SNn`@SHN@Srd@S>qa@T6@T,Y9@T-tD @T+͆@T8@TE>[@TS[@T`^@Tn-@T{EUd@TH1@TZm@T(@Tȷh@Tv)@Ty@T*t@@T_@TEc@U*@U|r!@U|p@U)ߨ@U6g@UCoK@UPx@U^B@Uk[2@Ux:t@Ue@UN9x@UB@Uŝ@U8L@U@xJ@Ux)Yd@U⮫o@Uɔ@UϕA@V Hu̅@VxT@V$@V19@V>5g@VL(K @VYQY@G@y4w@F+@GB^P@G/@GOj㘼@Go@GF]u@GL H @G˃N6@G:&@H @H+a@HK+o@Hj]+@HB@HR@HǙyV[@H˪`@Iz ;@I$Ui@IC#!Ȯ@Q&+p@Q ڨ@Qo@QHzM@QS @Qj@R]edž@R2v dP@R40@R+Ծ3@R9F@RGl!b@RU4֤x@Rbu%U@RpH@R~~/g"@R :@SK@SYC$@SfL@StryR@S @SIM/@S)dBz@SZa@SC/8@SLX@ST@S =@S]{@Sm@T ^3$@Tۀ@T$VI@T1 |@T?GM@TL$@TZ/V@Tg9*@Tu=@T~4+@Tg@TS4V@T@T @ǀ@Tń@TJ*@TF<@TN@TLb@U\:j@UkzU@U# lJ@U0a0@U=Kq]@UKX@UXV枍@Ue6Ly@Ury@U@UY@UVA:@U˜zʚc@Uڠ@Uo"@UU!xt@U@Vʥ@V@V9ٮK@V,nK@V91R?@VF$|7@VT\Vc@Va3@Vn`961@V{@GOR}@G/Vd@GOշjV@Go$@Glx@Gb֟@Gοݼ@GP l@H b"@H-BKAz@HL j`@Hke.@H8 @Hk@Hɐ@H%@I>@I&ٖ@IE S@Idr㓮@ICriGD@IpO@I@IeriS@Ix:!@J@J;3@JY0@JwA@JR.uB@JW@JX:@J%x]@KT"b@K-xW@KKP@Ki걳@K"@KbF@KÆ@Ki @KA!x@L'@L:hI@LXӒ/'@Lv;@mT`@L@L|@L@L-@M >ҳ@M'R@MDcLs\@Mb[d@MzR@M@MOoyj@M׎Pf@Mh@Ns@N/ÞŽ@NL7jk@NiK@NX=@N\+@NYB6@NMM@N9ql@O= rn@O3טI@OPϵI@Om譅@Ob @O fI@O:u@Ox@O.eLU@P 爝s\@S x*Ak@S&(@S(҄@S6|9 @SD#;@SQtE!@S_k@Sm T;@Szn@SF'W@S@Sxm-@Sk[ @S8ı@S3B^ @S{M@SO@Sږd@Tcg @TX߆@To @T* @T8rX@TE8-8@TSm᪔U@T`3[|@Tna8ZL@T{@@TL`@Tt:@T0O2X@T<@T @ݱ@Tw\e@TpA8@TG"@TcYL@U]@UrÝ@Uұ@ӱ@U*0ˑR@U7HM@UD8@UR@A@U_)i1@UlKğ#@Uz?x@UHd=@U(bG@U/Lx@U{%e@Uj)C@Uj:@UV%@UWE@@UH4@U"C$@V c.O@V&-@V&{@V4/v&k@VAUCR@VN@V[Ęx@Vhb@Vv-D@V_wP@V-@V&6@Ge!!@Goe@G*@GT@GnNʝ@G FS@HC@H.U P@HM"Brr@HmIzOx@HR@HE@HDf?@Hz9@I U7@I(h,@IG6f@Ifmw@IOg@Ixs@Ic++n@I)B7*r@J;m@JB@J>-\@J\%l@J{FU/@J8 @J-*@J֏Z@J0@K/l@K1ny@KOޢ@Kmɺ[g@K挦@KZ@KE8@Knn@L@L!#8@L?B2@L]j@L{Kr}v@L 27k@L`l@Lg-@LZ =@M[@M-,;@MJ"@Mh+M@M:\@Mdw@Me J1@Mݻ@M K@@NM*o@N52@NR,@No3@N =@N&@N8<@NB;bz@OD#W@O> /@O;0F@OX &@Otvw@O\@O*@Ou @O9m;@@PznM@PՈ ƒ@P,t9@P-@P;}@PJ>@PXdR@Pf~AO/@Pt4϶@P)~g|@Pda})@P欱@P4@P@P.‹@PXއ@P@P߫i"@Qęd@Q-5 @Q'M#@Q-@Q;(FÐ@QI9@QWGv@QeR@Qs[/,@Q`yt@QbP@QbIA@Q^ۘ@QX4z@QOqv@QCV@Q4¸@Q#?UX@Q+o@R E@RE@R(޽F@R6<@RD @RR\h_@R`5R@Rn ,X@R{r@RVNK@Rܶ@RLX9D@RY@RW@R΢!@RdxƩ@R$`@Ry`@Sm A@SU*ߌ@S! 1I9@S.@S*@TLvB@TZ@TgQ@Tu@T7@T@3b@Tz"ua@T=O.@ThdT@Tܜ{@TN#@TG͆E@T-gC[@TV@U  @Um(@U#Em@U19@U>GL;@UK0T@UY^fyQ@Uf?W@UtM@Urq@U@U!@Uv9S@U"@UA!@UkPO@U޹a@U@UPh\@Vc|0@VsC@V!&Tp@V.jOSx@V;-@VHT@VV,cs.@VciӮt@Vp~#@V}w@V}@VOy@V>@Vݪ @V0 H@Gv7@Gf@G֛0@Gyk=@Ho.H@H/# 6Y@HNDf`@HnYlq@H!@HP.7*@H̴Q@H +<@I Pr=/@I* =@II>e@Ih&Ub@II@I׌ w@Iț@I&@JG@J"K>7{>@JA1X@J_K @J~XA(-@Jh@Jx',@J{@Jf@Ko@K5%z@KSső@Kq8ޮ@KcJ@KX @K::b@KP*s@L[H@L&[xGw@LDQm/.@Lb<@LLe@LD@Lu @LلZ@L=6>!@MJO%@M2RO@MP-@MmZ@MH@Mȩ@M?; u@M㬸&@N:@Nl.s@N;*@NY @NvK=?{s@N-J@Njc@NDU@N3@O6At@O%#Lɟ@OB+!@O_*Vޙ@O|"%X6T@O-Mt@Oܘ@O*@OFI@PBܗ@Pٺ@P#3O@P1ewzy@P?OM@PNF@P\h7@PjYR@PyS@PKX|@Pѷ@Pq@P .@PIp@P΀eR@PܴqM@PIY@P@Q<ڄ@Qcm@Q#a@Q1KYX@Q?J@QMOw@Q[r@Qj #@Qxh@Q+d@Q7$$p@Q?@QEs@QGY@QGr{6@QDT[@Q>a9 @Q5:@R*Dk@RqDJ@R ߫@R-T@R;eyq@RI5@RWZWh@Reږ@Rskj@RGZC@R!=@Rc@RM@RQ@Rn@R;L@RS[w(@R`J@R@S W(}0@S$@S&J%d@S4F @SBKÁ@SP-y@S]}@Skj@Syw@S! a@StKt@Sm C@SŵJoJ@Sjt@S @SخCo@SLW@S Y@T/,@T1@T(@T*D@T7օy@TEf6@TR!r@T`LD@Tn{> @T{@T4s@T@TK'@TA@T.@T̒@T ?@Tҥ@T@s@Ull }@U:c@UN#߭@U*,8V@U8(V)s@UE@UR"8@U`aIZ@UmƅΆ@U{)@Ud}@U[@UG?f@US@U唉@UUZ$@Uجpp!@UE@UTa2@Vs@V v,@VCuS@V(@V5e)=@VC#\@VPj @V]Q^@VjUfg@Vx6\T@VwyV@@V@V)W@V0@Vju~+}@Vǣ;,<@Vo@VAg@HDDP@GcQ@H JD@H/Y3*@HOqAC@Ho%P@HuV@H]@HHvT@HWkKQ@I U֠@I,?@IK\_dr@Ij#@IX@I &5@Ib@I7@Jc@J$&6@JCʯL@JblEX@J+sL@Jݒ@JZ@J6Kh{@J ;@K)fh@K8}@KWgǍ{@Kud!L@KS)@KR@K7 @Kg!y@L f1"@L*fu@LH=;@LfDs,@L`Ƈ@LS@L[#@LdD@L6y@MZ@M7_r@MUn6@Ms@MEyj@MPs0@MP@Mb@Nx% f@N$Pdm@NA}0@N_/@N|s@N_my@N eġ@NG8T@N|@Oe`Ĩ@O+Ϗ@OH썝E)@Ofrz@OS&^@OB@ORο@O9@O$v@P l @P[33V@P&@P5.\5@PC.@PQH5<@P`OHu<@PnU@P|@PPy@PcR@P2/@P1n^@Pv?C@PҶn@Pwl@P.a@Pe}ڀ@Q 5E@QɜJX@Q'f@Q6 ^@QDGީ@QRk`|S@Q`!@Qn@Q|@Ql˙Z@QNr@QL@QAJ@QSk@Q#@Q)Iv@Q,@Q,F'@R )a@R$&xKm@R%6@R3?O@RA@RN*@R\޹@Rjȶq@Rx a@RM9:@RvȑO@RV= va@R3o@R h΋@R)@Rٺb`a@R@R]N/@S+ $@SQ @S&4t@S,@S:IL@SH (@SUbK@Sc@S ( @TK8@TYLy@TfyL@TtpD@T?@T@TYpf@T @T%@TŪ@,@T,}k@T୔K@T,L "@TXQ@U #R@UQ@U$<=!@U1@U>@ULmoh@UYt{#@UgJ~@Ut>@U )}@UAN@UW;@USzs@U['@U@UuĚ@U?@U.G@U@V@V7"@V"-@V/޹w@V=0 @VJXv@VW͈h@Ve @Vrdb@VT@V@V:N~@V~[@V @VH@V@˧@V~|.@V麌Llu@V @W-w@HOJP@H/1@HOu"z@Ho4O,x@Hrz~@H'+X@H̗R@HaV@I @I-^.L @ILŖa@Il @Ihn@Im@IЗ@I딉@J}+@J's̸@JE{]Fg@Jd.*@JK˜@JIL@JO?@J @Jp@KH>@K;q4\@KZ]&@Kx4F@KA@Kfk;@K+@KA@L?@L.JWu@LLXQ@Lj@Lhv@L'tZ@Ls`@L kΚ@M,@MH@M@P\LU@Q @QpU@Q @@Q,J],Z@Q:}]@QH8@QV@t@Qe"@Qs+=nq@QO @Qoϡ@Q.t|@Q@Q#`@Qӣ@Q/D@Qc @Qi@RQ'@RE`=@Rb,%{@R*[@R8)ӌs@RF _2@RTY@Ra |@RoQ@R}X@Rx,@RH@Rc@R} @R`A@R@@Rk&@RY1@ReYm@SG@Sz1m"@S$KRe@S2 zmu@S?2?@SM=҂@S[vie@Si;y7@Sv^@S*pik@S{@S7LN@Sc@S/ɹ@@S[2~@S Μ@Sn @Sk֥S@TE{@T t@TgϺ@T) ]ҧ@T6{@TDP23@TQ9@T_@Tm%fđ@Tz- @TS;J@TD@Ty%,g@T P6@T令@T#sB@T٭Tu@T57K!@T&@U? of@Ul'@UA "o@U*"*@U8;M_@UEDN@US-v@U`^!@Un3$_@U{c@U.s @UkU̧@Uط%@UDf @U(@UV@U{GCË@Uo@UA+1@Vo%#F@VL~2@V^kh@V)a@V7w>@VDkjYl@VQ5N#@V_3@Vli@Vy> @V G@VWX@VϘ@V_A @V7LX@V~ڀ<@VK?@V`Oy@VJ7@V!@W 1͝@W· @W&D<@H1@Ho#:@H@H [}@Hs-@H)M@IϨ@@I.fv@IM@Imd9D@Iͮ+/@I'm@IsjNS@I갮˛@J CX@J).Wb@JHkv=n@JgC@J-@J@Jʉ@Jb@Kq:@K )=@K>Պc@K]tu@K|"@Kn3@K 5@KzMu@K Rܠ@L74@L2p^b@LP'q8@Lnj@L,^K*$@LNLA@Le@Lri3@Mtԓ@M#ll@MAZz@M_> @M}Z@M:o@M@Mlf8@MG[@Nɜ@N/j/i@NM@Nj%@NGy@N,H~@Nȣ@No+o@N@O*s?F@O8{IY7@OUò.X@Os=@O;m87@Ok.=@Oʒ@O-1 @Pdڀu@P쭱@Ppx@P-u@PIy)3@QLk@Q[/"@QibAθ@Qw6B?@Q@Q4~~@QT@Q2@QS^zx@Qpٷ@QڋVGy`@QP@Qk@Ra@R'@R Zf@R. @R<~@RJ/X@RXA@Rf􆯿%@RtС@Rې @Rr@RWn@RQ@R#@Rș{@Rցe@RgY@RJF&l@S*bm@S'#@Sq @S)vB@S79@SEhn>@SS9@SaE@Sn՘$@S|gG@Sg@TMq@T/@U͚@UD5ly@U#,\ S@U1P]G@U>ӛ@ULTc6@UYNz!@UgQ%X@Ut[F}@UG @UMq@U4M@U{v@UĔ@Uŋ4@@Uho@Ufٶ@U6@U:{`@V[Ab@VVe@V#k5@V0u@V>.?bU@VKKg@VX鿵~@VfD{@Vsc@V)6@VL>@V&@Vc@VDwb_@VÓ @V?@V-Ծ@Vx[mI@VE%gR@W=@WNG@W e+@W-@W;AoB@WHUH@HP_@HJ`a@HFK$~@HWv@IuMS@I/+ӛw@INҪDQ@Inj @I0r0@IkO@I՝p(@I1P/-@J ~)@J*'T@JI@JiY'@J' @J/;@J*|-@J/Ep@K@K"05@KA7ڏ@K`O%@K~@KQ@K6c@K>æ@K?ů@L}@L6@LTw ["\@LrK @L~`@LI9x@Lz>l@L ;@M G)@M'@MEҎ.@Mc{T@MT1@M)|U@MtC@M[%n@M&ҕ)@N8@N4HW@NRNXre@No@N}@N"d4RQ@NȬLm6@N-MEu@O@O!_@O>{ʺc`@O[C@Oy//:@O}I^3@Oe09C@OF @O4U@PUoY @PBX~W@P" RJP@P1[{ʈ@P? k@PNd7Q@P\Sp@Pk^>@Py@PI[@PB@P& ;@P@P܅V@PUl/@P޳w!@PKS@Pe@Q ™P@Q 0@Q&UI@Q4lXe@QB墳̚@QQ(@Q_h7a@Qm#%]@Q{ک@QC@QF @Qv~@QlW@Q̫@Q(k@Qbx @Q75k@QTb@R o@R5@R%35@R3jC@RA h`@ROќd@R]r@Rk`yp.@Ry*@RL@Ry@R3Tw@Rbg@R͓@Rͷɼ@Rۧ%V@R镹W@R} @Si!M@SP)F@S!3ה(@S/@S<:@SJϻ`@SX^k*@SfMj@StUC@S'L@Sl0k@SՔ@Sf@SXA>+@S;@S/z@SїFS@Sd9u@S!W^K@T /-@TT@T'K=b@T46N@TB)@TP`+"@T^K@Tk@Tybh` @T ΣO@T5@TQv@T ͭ@T@T-.+:@TǚԜ@T_@TL8@UL@Uߋ5@U%N@U*;mK@U7ǻ@UER;@URp^0@U``6@Um]l@U{g@U<8@Ug]W@U=j`@U_@In @II5@Iqp@J ey@J,:jW@JK@JjpCe@JdJ@J"]@J:T*@JD@KABt@K%1_@KD:,@Kb@K+]@Ks @K$E@K\4@Kcf;@Lw@L9sz~M@LWޔ@LvUv@L @L ̮4v@LST@L(m@M @M+^V@MJyU@Mh$4iq@M.N@M.$@M%A(@Mɤ@M2 @N|@N9s@NWa]@Nus@NQ@Nz|@NIo]@N벚@O A*ƙ@O&{@ODC@Oa A@O#<_@Ob*J@Oׯ@O3mc-@O}@PLD@P|=@P&@P4@PC;^y@PQȈd@P`Q@Pnwz@P}X/@PJܫ@PPOC@PơB@P9Hp3@PŨL@P?@P{{ @P7F@P@F@Q `@Q@Q*N?kH@Q8Jm@QFbM@QU=PW6@QcZZ3@Qq@Qi>A@QMɿ$@QF@Q1@Q~@Q+;!{@QZg(@Q5Ѻ@Qw N@Q<]@R [DD@Rt8@R*8.쟻@R8RGY@RFjFW{@RT~@Rb@x@Rp@@R~C2@RR@RW@R@R˘@RĿ&w@RҺ@RƮ@Rl@R@S ˴u@S};b"@S&iu@S4R]܌@SB9@SPK,@S]G@Sk*K@Sy߿3@Sd,@Sl0e@SBHYf@S<ʬ[@S˱@S̳1@S` M@SI@I@Sa@T2DmW@T4VW@TW05@T-V@T:є(m@THӉ(@TVBA @TcC+@TqO@TZM@T &i@Tq۔@T_@T$@TífB@TQO@T;@T쒤?@T04si@U˶@Ue.he @U" g@U0 =@U>%wf @UKP@UYFXx8@Ufq@Ut_Z @U@Uph@UO=&@Uz! 0@U @U|t@U:P@Uv<@U@UiV@VI#xz@VU6t@V#S@V19{@V>(>@VLa@VYڛ5S@Vf q_@VtUg@V2U@V!*@Vh@V@VE4^c@VģI@VRlx@V[@V,'@V [+@Waaң@@W@W"b@W/X5@W<) @WI9AT@WWAH@WdT,@Wq56x@WH@Wb?@IO@I/!X@IO0@Iout@Ix<@I//YS@I؁kё@Iq@J H"@J-wY-@JLX@JlCsd@JYM9@J @J ^@J2@KLªUL@K'YIz@KFXD@KeK>@K1j@K ,@K@KVЊ@KK@Lw@L^N@N\;@Nz\j@NQqn@NvB@NQ8ů@N[@Og%@O,@tz~@OIӚn@Og]@O߈@OX}0@O㍘@O0φp@OV{*@P Ɓ@PC_@P)>ז@P7 E@PFyiU@PUB@PcJ0@Pr3i@P@PGJ@P˝t@Q٧@QO'+@Q%@R?d@RkJ0@R J@R.΢X@R<FE@RJon@RYV{@Rg6[@RuM\%@Rb@Rtߩ@Rȭu@Rd@Rb @Rɠh$@Rפt@R2@Ri5 @S^KM@STW@ST#}@S+^b@S9uωF@SGdKRt@SUPr@Sc:2U@Sq!}@S[@S<@SȘP@S?B@S@SY Oj@S/ @S+@S'@S@T o]3@T9I0@T%pk@T2]@T@P@TNKWĸ@T\ ^@Tiƥv7@Tw&@T9 ؛@Tg;v@T@TT3 @TV@TɰG@T[g@TB@TأF@UPz1@U b{@U q@U)2d@U6>{@UDiːT@URT@U_Yr@Um-hv@Uz t@UPXe@U7>5@Ukai~@U@U@UxMo@UًU@U9@Uk@VY"@V@Vd@V*~9/@V7L@VEpʅ{@VR:@V`Wm@Vmȼ{@V{7ػ@V'aS@Vg@VzZa2@V @VIF@V˭r/@V@Vq&z@Vud@W/Y@WH=@W @W)?N"@W6L@WCU#@WQ?+@W^SrJ@WkrS@Wy2I=@Wx&@W4@WPB@W_-y@Il@Iog;@Ip@I;.@IyUvu@I14@JWY@J.u @JN0H@Jm~ @Jv e@JLm@J˞Z@J<-@K G@K)C@KH^ٯ -@Kgm"@Ko6/@KdMb@KLIVx`@K'ʞ@LX-|@L $@L?qHf@L^}@L| @P̿}6.@P?@P麡@P2 A@Q/@Q̑@Q#ɼ5@Q1jT@Q@T>@QNO&@Q]a@Qkr}o@Qy@Q /@Qr r @QK@Q H@QT21i@QϘ@Qڑ@Q ؏@QT~X@R @R)٭@R$$K@R3#A6b@RAO[\@ROxy @R]@RkՀk@Rysd@R&N@RgY@R1A@RF |C@RX|y@Rgaiv@Rt89@R},e@RG/@S*@So|@S"SG/@S0@S>V@SLv{@SZj,d@Sh\n@SvLum@S8KhD@S"~@S p@Sz@Sҝt>@SɲT@Sא@Sl)U@SE-4k@TIL@T G@Tc_7@T*r!'@T8^˲f@TF)Y@TS? @Ta4@To| 6@T}>wgq@T 9@Ted:@Tv@T/~@TBԄ@TϚܲ@TMO+x@T{@T˳@UW܎[@Uә̷@U!&0@U/O|3@U<>Ղ@UJt@UX4{@Ue7@Usm`.@UqrM@UZВ@U4 B@UeČ@UZ =@U~@UwnK@UZ@U퍺D@Uf@VfZB@V xR@V#C@V1#R2@V>mi@VLf33;@VYX@@Vgx3@Vtk.T@V)@Vu@VN @VW @Vf@V3T@VҞG.@VI_@Voߨ@V̄%@W:&@,@WG'l@W" ϼ@W0]|@W=gS@WKl@WXq&lS@We1A@Ws @Wvx@WX4@WP]@WmOX<@WihQ@W ^@WU叶X@I@IJv@IM:@I<@Jz80@J/3\]@JNz@Jnyi#=@J@JW3@J̓@JU@K I*@K*JY@KJ'@KiRD@Kp_9w@Kd(0@KƅJ@K|w@Lgzy@L#EF @LB6!@L` @L v@LDj@LJe@L~Z@L ~ O@M@M6/@MUhĆ@MsǒT@M<٨@Meu9 @MΤ6@M2S@N wԮ@N)#2@NG9ñ@NeEI+@NHn@N@(@N/LNi@Nk@NCJb@O¤ t@O6@OTK@Orb@O[@OUKbN@OiX1@Ou@PJ4:@PڏB@P Eݏ@P/>X-@P=qj@PL345@P[O|@Pi@Px@P<9@P؎ @Pp@P0$@PQN@P#FA@Pެx#@P1$@P6@Q 1@QV7i@Q'#;MW@Q5t@QD[k@QRr_c@Q`v@Qo@*@Q}@QYcu@Q\@Qm'@@QGQ@QZH95@QӨQRc@Q!j@Q:)@Q/S0@R yu@R@R)9c@R7q}!@RET z@RSؒV a@Rb|21@Rp3k<@R~\e@Rpj@Ry@R@R-@R*@Reȵy@R*I@Rn@Jo5܃I@J0@J}Q@J Ru@Jy¦@K л@K,^.c@KKx;@Kj #@K5S@Kb>m@KȂ @K^S@L^ܠ@L%ki@LDc@Lcb @L6Q@L6@Lc@Ll^ z@L@MZK@M:96h@MX@Mw5"@MRx@Ms@M\TE@Md$<@N X@N-$4@NKR.l@Niv>'@N+%@N~ @Nå|@N+`@N꾭G@O~&0'@O;]@OY4v@Ow9/f@O߅J%@O'3@O3@OeK@Pse@P[H@P#Q@P2MH^@P@l,'@PO\< @P^F)#3@PlM@P{} @PR !@@PD@P_@P:<@PΫ@Plԯ@P7IG@P@PU@Q Okʗ@Q&$@Q*BG{@Q9$KT @QGo@QV@QdE@Qr`@Q`Tdx@QPq@Q, @Qԋ@Q V@QF|\0@QםwV@QcX@QBl/@RZ,@RA@R!jo@R-eoDf@R;Vĺ,@RI'0G@RXv@RfVj@RtKU@Re@R{@Ry_@R@Pu@Rf@j}@RɉMi@Rש~ub@RC@R_Z@SG+@S @S ?Z@S,/%g@S:d}@UH}@UV~NH@UdNiD@UqAT@U wo@UK8@U~*4@U-z @U6A @Uև@Ut8cd&@U@@U쩰m@UA~$L@VZE@VkI@V"M i@V0j U@V>G@VKH=d@VY2i@VfA@VtA!wR@VƤ@VI@@V|;@VJc`3@V$}W@VCWD@VҽH'@V65)@V.@V!ػ@WʦC@W r@W#ui'@W0Eb)@W>Olc@WK%@WY"HeH@Wf@Ws+@WR}@W v@W~@WtYue@Wю@W-&[f_@Wч!j @W߃3@W6M @WT@X#eX@X13w@JOr@J/"h@JOڊV@JowX@J}# db@J7gc\@J@J@KZ|@K-Ý@KM*Y[@Klf[^@KwP@K@KB@Kqob(X@L-O@L'@LFGa@Le:"@L=h@L~L@LUF:@L O[@Lߌ(@M[@M=;,Ҕ<@M[Ⓗ@Mzi~@Ohln@PY@P0/:>@P&N@P4.I@PCI@PR`G0@Pa!8@Powz@P~1TV@PM/+@P!@P1<@PT@PI@P֚1%0@P7t{@P-@QfF@Qet@Q$}@Q.ey(@QJ~@QV{@SM @S[U@Si @Sw*G@S2G8@S7/K@S9yY@S9)@S6EX@S0$P@S(@SIm@S?%y@TqK-@Tﳦ@T;{@T,P2@T:`@TH8/@TVq@TdPS|@Tr-@Tjɔ@Tؓwi@T@T4p@T\I۽@T+U@TY@TEP@T5@TRP@U 0@U<@U% x@U3Uj@UA@UN$@U\QA@Uj6b@Uw[dd@U?@UI~@Um&d@Ul3@UI=A@UQ@Uה9@U79dO@U@Vv@VX@V#Ӝ?@V)FZ@V6s@VDr@VR@V_>`@Vm&4@Vz?=@V?D@VZc@VQ@Y@VR*@V[C@V@V^sN@V{ԭ@VZb@WP@WO^S@W&6@W*=0 @W7~@WE$疙@WR,'@W`X@WmqR@WzY.v@WGs"J@W0@Wx%@W{U@W@`@WA@WءP7@Wp@W\z@XK@XƜ+@XjNk@X(y@@X6)@J$K@JoCĈ@JW@J/Ru@J~[xK@J9Jr@K(h@K.0(@KN @Km{z@K @Kn@KHKw@K(;@L O6*@L)Z@LHf@Lg@L4S@LZ'J@LĴ@L @MsZ"@M!A@M@c@M^6~@M}d <@M=@M@M!(dGD@M}|@Nj@N4{ @NRL9@Nq-ުb@NwN@N.@N땈2f@Nk@O7;I@O&Oq@OD\r@Ob`i@O[>Z3@OLUf=@O4/5@OH@O@P 90@PK@P(7Yv@P7r-~@PFF.r@PUJ@PcF@Pr"@Pn47@P-@P@P7y>@PSrR@Pk@P٭)@PUT^ @PG|@Qn8@Q4>'@Q"F@Q1`ꄡ@Q? &@QN~G@Q]=g"@Qk@QzSI@QXP@QH@Q+EU@Qs@Qd9w~@QX]F@Q;~@Qv=@QH@R dDf@R!L@R'z@R5oat@RC˝V@RRof@R`^@RnMg@R|5@R1i@Rq@R@R/z@R T$@RTu@R h@R#@Rߎ@S " 8@S-Zm@S'PC7@S5pܛ)@SC+@SQ.@S_Wj@SmՔ4@S{-@SYu@SS@S@S`@SѲ @SVp3v@SG@Sُ@SVj@T@T@T#QF@T15@T?3K@TM'@T[/@TiϘ)@TwxC@TZ^n@T:忓@T@Tߐ@TY@Tʣx@Tx@TJ,f-@Te"@U绡o@U*QQW@U|b@U+Cge@U9=2@UF牙[@UTh׎@UbINC@Upl@U}=5@Uxz@U.@U@U(@UCU@U@Uݜ6+@UF@K@UE@Vy-@V7@V!Ħ @V/xwa@V=8p2H@VJ@VXKVo@Vewk@Vsy!j@V$Ǥ@Vo*@V09@Vjd=@VLI@VWjw@V`6=@V@)ؚ@Vlǟ@VD@Wr9}1@W @W#pd*@W0@W>g7:@WK@WYW&@Wf̓6I@WtA[$d@W^v@W#wg@W@W@@Wk1@W@W= :@Wߣa:@WS@WkG@X@X-eQ@X"r1:@X/9H@X=Cj7@XJ@XWS@J2v@Jd@J<+@J㨎k@K@K/;plZ@KN轊7@KnQ@K^ @Kt}@Kߘ@Kw,К@L h7@L+^A@LJ\@'@Lic8@LS/@Lf\VB@L@v@Lȷ@M͙L@M#\m@MB5]z@MaaHKV@M%P 6@MާTZ@M8@M.e@M%@NQB r@N7V@NVI,@Nt@Nfs@Nny}7@NϻB@NަrX@O 6iU;@O*dA@OHbk@Of6z@OZ(@O)@O#@Oް_@Oܼ8@P ?H6'@P,A@P+u@P95@PH׌-@PWvH@Pf+~P@Pu[rO@P)"@P^'@PR"@PzU`@P8}@Pk@Pܧw:e@PXs@P@Q3d@QUF@Q%oj@Q4@QC0g>@QQ+A:@Q`Z b@Qnj;@Q}up@QO#@Q9~@Qh/@QrR6@Q֧@QpM,@QWyx@QR;@Q>\@R(*S_@Rn @R*W@R9O!Xr@RG@RV @RdXf4@Rr3W`@RP7@RFPK @R9 @R*@R%@RW<@R֔vT@RHU@R(d@S9O@Sj#k\@SKzBS@S+Ö<=@S9 X@SHY@SV4~6@SdT`<@Srq[`h@Sa@S5@SV9@S}W@Sې@S @S7&u@SȎ@Sog@S-E@T ^Va@T@T('u@T6@TDvZ@TRޝ7P@T`KA@Tnj@T|!@T+@T|@TaÈ[@TD׿@T%!@TPJ@T0@Tq@Tn@Ueuӯ@U7n@U#kV@U0ּri@U>%@ULl@UZ4{+T,@Ug 5@UuqbC@U~m{@U=մ͚@Uوm@UI@Un@U%S @Uh@U㌠ @U=5@@Ut)@V Lx@VBԣJ@V'^@V5(@VC6t@VP$]@V^ydž@Vlo@VycS@VPK@VLi@Vi. @Vg@V*@V:~@V&@VWM@VHC@WnMy@WsPI@W}F@W*)@W7@WE@WRkt@W` G@Wmt@WzQy@Wqӂ @W0@W]׵@W(.@WBЙC@W˲ؠ @W!5}/@Wn9@WӚ@Xb__^@X%=@X0K@X)!@X6d@XDYZ@XQ͘Q@X_,@Xls4@Xy΄*~S@K?*@J@Kۓ@K/})@KO&j@Ko=; [@KF8@K c@KRՏ@K C@L d@L,5Zx+@LKd@Lk(aKm@LiTW@LhD2@L@LߓΘ@M @M%@MD!@Mc/@Mh0@M"@MGpB@Mwu@M@NXЯ@N::.@NYQ@NxS@NvH@N‰@NS<5@Nw|@O@O.D6@OL d6@Oj@OR6r@OaA@O ʌ@O@!@P@P@P}m@P-t@Pm@QH~@Qk,>@Q@Qu|@Qϟޏ@Qr/@`@QD@R`@Rҿ~Z@R ABK@R.P7>@R={[@RKy/@RY}[v@Rh9fЊ@Rv;@RhX9@RA2@RC3@R@R-7@Rv@RڻRVl@R`6@R=\-@Sym@SZޫ@S!c@S0V @S>N @SL|xmp@SZ@Sh.$@Svw[@S9{?@S89@SU~@Sp @S:"@S˝<@Sٯ2@S翂{.@Sh]@TpM@T߅=@T@T-Ů@T;nWW@TIYz @TWAE@Teڵaf@Ts/o@T7:8@T7n@Tw@TW@T}- @Te5G@TJ7&@T.9,@T>o:T@Tb@U _f!@U8ϟ@U(|cf@U6R @UD%hZ `@UQD@U_Ŋ@UmOI@U{\洢@U%S @U8n@Ul@UqVB@U1N@Ug,@U۫>@UdAz@UIN@V˵e@VCێN@V 6w @V-"r0L@V;F#@VI> @VVq @Vdiz@Vr5tRW@V 0@Vzͤ@Vg@V7M@VT1@V$fp@VцG@Vj@V4P@VCB@W=Qcm@Wc!@W"5./:@W0{ywy@W>a@WKq@WY%8@WfA)@WtT@W @Wt:@W@W^V@W6@W'e@Wy'@WɄ(@W`=@W"@XA@X}Q@X#p@X0v@X=g@XKW0+@XX@Xf!G@XsL\@XD@XD7@Xk@KOMIe@K/@KO7'@KoBd@K]@K>^@K;s@Kds@L!a@L-P@LM>0;@Ll鉖@L@L33k@Lun@L髏t@MԼ+{@M'q-@MG;h@Mf @M?u4@@Mꎊ+@M`@Mo@Ni @N'@N=ڒK_@N\b@N{9@N7Ҕ@N8{C;@Nֵ!b@N'I @O @O1+6@OP?da!@On%@Ow/F@O+=@O)?v@OKpA@P a?@PMz3@P\@Pk9OJ@Pzme@PQU@P0an+@P $\@Pa@Pij$/@Pӂ;@PL%0@PEr@P@QR2@QK'@Q,jt@Q:8@QIaf[@QX ;`@Qf0@QuUP@QN@Qc@Q'g@QnB@QKt@Qؽ @Qb'/@Q"@QjѨ@R9@Rd)O@R#@R2Pe=@R@UY@RO/Zwa@R]o3@Rla@RzeYiO@Rƾx@R$n@R~Ib@RQWA@R*@R{/@R#@Rݚr;@R\Ũ@S >ȕ@S@S&#u@S4_*"*@SBf@SPν{@S_7 /@Sm2f@S{`Zy@Sa@SӡB@SBm#@So@@SR@S9( z@SS4 @Sk@@Sn-@TtxDe@Tr  @T$@T24=`@T@@TNɝEB@T\@Tjw@Tx˥/@TY}@Td @Tdf @Tû@T4@T̍J=b@Tzz,(@TeL|v@TMrw@U3)c@Uw@U> b@U-x@U;lM@UI0dq@UWh@Ue>q]@Us@U/@U'e@U@ULՎ@U9@UG>@Uӡ`@Ud}p@U%a@U?M@V %Z@VZcɆ@V&z9@V3@@VA}4 @VO/p@V\ V9@VjlT&@Vx:"@Vl@V}f*@V3!D@Vuь@V{<@VQM@V׺]@VWlb@Vp@WߙJ@W"%@WRe\@W)K?uJ@W6ݴLM/@WDm=@WQD/@W_,C@WmR@Wze@W"O,@WЍz@W+S?@W@W-$@W˫vj@W(&V@W@W0L]@X b@X Rn@X}|z@X)D@X7a#ܫ@XD]@XR=ڍv@X_@XmHO@Xz}@X+Ul|@XIG`@XR6@XPb@XpxH@KZF@Ko"@K=3@K쒋@Kσ@K@O@L41$@L. do@LN%Kg@Lm@H@L# @L2@L?O@L=ї@M _@M)w@ @MHl v@Mhf@M[x@Mg@Mͪ@M|T@NXT@N!n:@N@qB@N_KC.n@N~@ND@NJY@N߫@NiѰ@Okb@O5^N%@OSo@Or*y@OU@Oh#@O{s@OHIc@P@PΤA̡@P"ܪՙ@P1J`@P@'(@PO;@P^:N@Pm55@P|ϷI@P獗@P|u@P@Pm#r@PJ+=@P#2ρ@P}@PɞN-@Qߜ@Q[@Q @Q.@Q=S@QLT'@Q[d~@QiO~>@QxeWN[@Q@Q"t/@QTn_@Q ~@@Q^@Q"MR@Q޵i<@QD.5@QZJ@R WH@R܊[@R']9@R5| b{@RDU5(@RRx@Ra@U@RoA@R~@R@RO.c@RQQQ@Rږ@RX@Rh@R⿋P~@R<ӳ@Rcn@S v@S @S*C@S8;D@SF:@SU@ScDw@Sq}jfp@S@S&@S+eJ@SDʶ@So.@SƗ4@SԽ ݟ@S߬@S/@S@T 7c/ @TOO@T)dq{@T7wI@TE`@TS(@Ta;Z@ToGFC@T}-@T@Tz @T'T@T@Tæo=)@TѝFmn@TߒCxP@T턔@Tt*@U b@UMW@U%6?ٮ@U3;а@UA!Ta@UN"ސ@U\ލ?@UjX`Kk@Ux{@UTo@U+^ @U@UZ+@Uj7e@Up&*@U<-@UV~N@U @Vc@VV+3@V]PN(@V+ש*@V9!5@VGPf@VU =+@Vb_&@Vpu~c@V~(:@Vٿ#+@VN}@V6@VTK@VŠv@V1*@Vm@Vz0,@VQjs@WW A@WZ5 _@W!5 Xf@W/Yw@W=(@WJY^@WXS @Weݪa@Wswؕ@WȢ9@W6$@@Wܴl;@W3@W1ǩ2@Wĸ?!o@W<6 @W߿eU@W@'@Wsm@X>8@XL@X#4<@X0hT@X>$u@XK=@XY %@Xf@Xs%@X^@X5:3@X7ұ@X 0@X A@Xq@XZ^@X: U@Kg@Kf( @K܏P@K﷓@L"Z@L/Bj +@LN~R@Lnp@L)s`@LtH@L*$@Lzux@M e@M+HH@MJ'@Mi#?@M6@MD-@M(@M0n@N-Dڲ@N$ @NCa @NaǚP@N @NnG>@N&[@N|#@Nu@O ^<@O8\TО@OWCn@OuY@OḪ@Ofk@OHt~@O^@P@P @P$K_( @P3=@PC@PRS@PaJ@Ppb[ @PN@P%@P@P0@P"jc@Pm@Pتn@P1'@Pc'@Q:%Y@Q ii@Q"ږ@Q1@Q@jҫ @QO,"Q@Q]$P@Qlk`H@Q{[@Qc*S@Q&2?@Qh"@Qa!@QIJn @QR?@Qn/@Q*@Q\@R U@R<p@R*x0e@R9Mrpx@RG@RVQ`@Rd[@RsGD@RUƌ$@R0i@RT9@R գ_@Rtf~"@Rڬg@R=Rx@Rѓz@R1A@SRw5@S@S @S.Kg@S<L@SJ$@SY*M5@Sgn5@Su@S75^.@S)R9@Sbhs,@S=(@SBb@S|C@S(/h@SS@S{@T0ʬ@Te@TD~"@T.{E@T< @TJ3B@TXHZ@@Tf[7B@TtkMM@Tx@T ~@TS@TI@TTw@TȗwU@T֖'[ @Tg@T<݀e@U\@Ux@Uka*r@U*[i@U8I6@UF5OhS@UT̰@Ubz@Uoo)@U}_*@U&xF@U$v@Ufm+e@U@v \@Uҵ@U5d@U޿L@UxO@U_@V,ϔ@Vc@V#ڭ@V1NҺ@V?IA@VM W@VZ`6g@Vh\[j@VvEQ?<@V@E@V, @Vmَ@V! +@V48@Vȃ?!@V1?@V).@VW@V/@W V8@Wzgo@W(/@W5r@WC\|^@WPt>+h@W^@Wl-LϺ@WyS@WZPB@W˄@Wܜ@W>@W(@W,R@WطH<@W@~){@W!z@XM@XѼ/@XT @X)ԩ!@X7SB@XD}a@XRL^#@X_A;@Xm>}@@Xz @X*z0@XPL@X@XI5@XDgs@XZ`@XŤF@X/Rh @Xl@Y6@LtEߟ@Kr@L%9@L/8rY@LO:@LoD@LT@LP@L-@LW@M 0S-8\@M,e<@MK@R탼@R.{"@R<`=@RK3wޅ@RY[P@RhB@RvP)@RD6`@R[@R8jdh@RY@Rt;@R͎J@R?@Raɇ@Rj@S(Ф @SF@S#a .@S2< 23@S@8h@SNGb_@S]3Tr@Sk]@Sy/#@S셸@ST@Sּe@Sœxc@S>@SG`6@S|@Sœn@Sʭ@T L@T7ok@T$_y\m@T2"s@T@[@TN[8@T\$`@TjƫZ@Tyf@T,莴@T>ȧ-@TO9ɉ@T\L @Th;@Tp!j@TwAI@T{_ը@T|nz@U{]d@Uw,`@U!r@U/i\c8@U=_@UKRj@UYB.[@Ug1( @Uu4=@U7@Un'F@Uӣm@U2@UQ@Uub@URyM@U,3zF@Up@U@V q0 @V~?j@V)N3^I@V7e-N@VD}@VR}5@V`vig@Vn;D@V{gr{@V@V}꺾@V:A@Vl@VI@Vd` %@V-@VЃ@V|T@W+[ @Wؚ'@W )k@W.,z@W; c@WIyf0@WW@Wd@Wr^E2j@W1@WH4@W2@WʰS@Wa@W}@Wщ@WА@W_< @W8#攫@X)Q @XNql@X"2@X0]եX@X=@XKfax=@XX5@Xfh(@Xs懠XS@Xc;O@XGܴ$@XWx@Xn@XEt@Xĺm@X,W@Xߞ6*P@X ё@X{m@YwSz@YScYs@Y"@LO$@L/gj@LO/F@LocY@LM?$h@LE+if@LH5@L+@M1]%@M-@MM6wP@MlTe@MV@M\m@MʥkB@Mʌ@N  @N(5@NGMm@NfZ55|@NZwb<@NOEH@N9DH@No@OA@O@O>oH@O]!g@O{ɓ|R@Ofd`@O!S@OׁR/J@OC"@P 9@PnkM+@P(V@P7X9@PF|c"@PVx"@Pe-_E@PtE6)^@PXapk@Pf} @Pp9@PvNT@PwW @T(Q@T64@TES@TSCY @Tahj@To"@T}PY@Tͩ@Tce@Teb@T|@T"Σ@T3$v_@TA$S@TLh,@TUQkm@U [@U_FN@U&a_b&@U4`t-u@UB]Tz@UPWi-@U^O'@UlEu@Uz8Ђ9@U)ٻ@UO@U~@U0u@U@Uͼ@U۠,{:d@U`d@U`_ji@V=-+@V@V CU@V.ƒ%kH@V<@VJly@VX<*)@Vf N,@VsBW@V8Þ@Vg@V- ">@VZI@V)@Vqwq@V.@V]@V֎ @V[V@W N@Wx,@W&va@W4%ٖ-@WAө/p@WO {@W]) @WjѴas@Wxw;@WYv@WM@W_/Ӧ@WpO@Wzl2@W6F@W @WgI@W;Y@X9L@X#g^@X-@X)CS@X6d@XD[ 2@XQZts+@X_mCv@Xly _l@Xzwn:@X@X{;@XyjM@XyO&@X,@Xp J@X(GQ@X`?Ad@X\@YIvi@YsՍ@Y-SY@Y) @Y7 Tz@YDvzlVE@L ;@Lo:@L}wG@Lx@Lχ[b@LGTB,Y@M@M.:u@MN5@Mm@M@PHn@PWAb @PgwNO@Pv3ߴ@@PR T@Pk`<1@P\@Po@PDtM=@PУm@Pߦ@Pb>GZ@PCJR@Q Y!@QٳP@Q*rD>@Q9Z @QH?N@QW>׊@Qe܀@QtD<_4@Qw|@Qx;@QD @Q 8!@Qѣ"@Q͒33@QN~@Q߄@Q b|@Rn\@RC.i@R%Zߩ@R4lϟ]@RC!՚@RQr"@R`J@Rn椝@R}w@R!@R‡@R!4@RFQ[@R+@RԬfp"@R)%+@RX1@SP8@SP@S]#p@S+j@S9a6/@SH;!{d@SVȗ>@Sd\y@Ss\zU@Se@SZ]@Sch.@S#@S+@SOFa@Sט![@S@S!jL@TaQ#@T܆@T`D@T-<@T;FW<@TIx1H@TW]&@TeR@Ts'@T'8+@TL3 W@Tn˫&@TMv@Tv @T r@Tv48@T@T):@U 6@U% :΢@U0S\@U+9T@U9@FWl@UGD|i@UUFJ.@UcE7@UqBs@U=l҆@U5|m@U+ä@Ut@Ut@U|@UH@UX>:@U$@UC@V nk@VkS)@V&Jڋu@V4( P@VBF@VOFO <@V]"H@Vkf1@VyZc@V+iX@VvK @Vӆ@V Ƹ]@VXa @V;@VT@V4\@Ve;@W#KZ,+@W}zc@W@W,QG@W:N@WGi)@WUo'Z%@Wc;Ә@WpW@W~{q@W%"@W_8@Wvj5@W^j@W¾@W`j@W3S@W-lPR@W:Y{@XԺy@XmS( @X"&@X/6M@X=,EB[@XJ {@XXM柺@XetE@Xsh`y@X R@X|8~@XKxZ;@X@X ޙ@Xďpu@X@@Xߎ- @X a@X\S@Ykm@Yz@@Y"?@Y0f*r{u@Y=Ηr@YKKZ(g@YXX@Yf+B@L:@LWq$@L8@L@MeSi@M/HI@MN9.@Mn;H@M9`";@Me2H@MBr@M쳯xwk@N D"@N+pXYSP@NJ@Ni @N. @NV&79@Nr2@N='@O@O$@OCmY^@ObP_e;@O(f@O٦@O|@On/@O;@P ^]@Pxu;@P+R@P;3ҩ@PJo%P\@PY1]@PhڟZ@PxV2@P1!@PVf 8@Pv+"@PD@Pç@Pҹ@P @Pt@PM@QSb@Q$#@Q,R_@Q;_@QJ/r@QYDS@Qhz< @Qw\@Q:s2@QF @Q@QH?B@QA@QU@QF(6@QX@Q+@R Xv@R,EH@R(}l@R7s\U@RFWN@RT/a@Rcm1n@Rr@RE @RF{.@RM@Rql @R)@RɎ1Z@R@R杂@R 0l@Sz@S'@S R@S/ T&@S=|״ @SK2Xw@SZXk@Sh"@Sw'$@S@Slp@SGRfL@S9@S'@SL բE@S۝,S@SO@S6Qϧ@T~@Tw@j@T#,+i@T1G,@T?0/@TMܡ]@T["+@Tj+:@Tx]*E@T0N@To N@T,)@T @T/\8@TRES7@Tq@T^@TM7@U+@UV_@U!cH@U/%X9@U> @UL*|)@UZF@Uh$Ά@Uv)*ھ@U+0)@U*[M@U(!z&@U#N@U(]@U*g@U @UƸZ@U>2@Vt) @Vlw@V+*z@V+n@V9s@VGU,bw@VU5$ֹ@Vcg8K@Vp4J@V~%]@Vn@Vt4@VH @V+L1@V7 z@Vѵ3$@V߀"f@VI ,X@V@Wjm@W@W$X-@W2gYj@W?U@WMM!@W[HT"@Whk@Wv@Wgq@W2@WȨ@Wv=6@W!U@WK@Ws̽@Wo@WIXL@W`1@X ~@Xd2G@X(=G."@X5<@XCr_@XQ )w@X^28@Xl4}@Xy Ho3@XWߩqI@Xq@Xtc@XQ@X @Xpq@Xؙȸ@XO~@Xn]G@Y#L@Y+c@Y!M@Y)b`l@Y7|@YD#F@YR w@Y_~@YlK@YziHY@Y->m@M"@LspM@M@M/@MOj=@MoJwnF@Ma@M0}%@M=1M@M,@N HHـ@N,H@NL {@Nkyۊ@N<@N#t6o@N=/\<@Nfb@O@O&%m@OE8&@OdXʢ7@OE@Olj@OFT@O.{N@Og@Pɐ@P!.P8@P-sg@P<2@PL p4@P[LA@Pjq@PyóH@P1@P'@PRaL@PxhOJ@PřW'@PԶo@P·G@P^@QL3`@Q[V@Qjߑ:J@Qyg@QOǔ@Qz@Qx.Ga@QT/@Q,'@QfR@Q@Qh@Qe6@R*u@RFv@R+Ty@R:aFs'@RIHɕ@RW>@RfwRt@Ru"Hߕ@Rl?@RmK@R @R-n@RB7)@R^@RjȰ@R"@R?@S zHd@Sin-;@S$'@S2{u"G@SA Z@SO{@S]zr@Sll& @Szڱ7K@SF"g@S`@SΣr@Svgz)@SY~@S19@Sߊ#m@SO!S@S4Ɍ@T MG@TLE#@T',@T5e!>@TCW@TQ9@T`,r@TniHҘ@T|a@T@T2@TAC@TpC@TÝm~z@Tnj S@TI@T@@T5yn@U U2j@Urț @U&b@U4z?JP@UB@UP3h"@U^8P4@UlR0@UzF@U@)@U ;8@U !u@U=A@U񊖿@U |}@US@Uћ@U=p @V씘@VާE7@V"z@V0/Z@V>n6=@VLvR5@VZw\A@Vh\POc@Vv>@V\Q@V @Vf@Vh@V*@Vap@V5rp^@V%k@Vɱ*m@Wb/T@Wo1@W9|-G@W*T@W7ƋZu@WE7@WSK@Wa @$f@Wnxl)@W|,@W>_o@W9ox@W)F@W`3Ԡ@WYX@Wžf1A@Wq%@W2y@W@V:a@Xq p@X $@X Uh@X.`v@X<SOO@XI!@XW@((@Xdi@1@XrvR6@Xj@X @X;@XpxE=@XaB>@X_h@XɼVE@X F>@X엎j@X Z;@YC@Y.Nk@Y"T@Y05W{@Y=@YK6dM@YXd@Yf0X@Ys`]`@Y$yF@Yl@Yh@YOJ@MOY@M/@MO_@MoD̅@MkEh@MK9@M* @MY˺@N@@N-ދg@NMNj@Nl@N(u@NeV @Nap@Nv@O K$@O(v^@OG@@OfIL@OZ N@Ow4i@Oàt k@Oo@Pv #@Pn4;@P}"}@P.(~b@P>42 I@PMa8@P\|5@Pl }@P{e_@P@PC@P@@PF;@Pr[c@P֙:Ca@Pzo@P ]?@QMj@Q 犀@Q"$%N@Q1&v@Q@.@QO26\@Q^1?)s@Qm, @Q|"Ɂ@Q(M@Qjs@Q=@QӖY@QƵG@QՓW@Qm@QC@R@R\e@Rb/NP@R.t@R=7͕@RKy@RZ+.@RҢeY@S c@S~#@S'{@S6@SD%@SSx@Say @SoYvk@S~vq@Sf3.a@S[=+/F@Sr@S3Ip;@SƛL5e@S@SaMH@S$@TY*@TtY@T^,@T+K @T9mY@TG W@TV맇@TdLzH@Tr>@T<@Ty3@TN_.@Tl@T%@TFGR@T&py@TU$oo@T򁡫b8@Ui@U@U.@U+cK@U99U y@UGVqll@UUq -\@Uc+M=@Uq$;@UgI@U'v@Ui5@U&d@UN@U @Uzl6/@U _:@Un@UP@V Ldjq@V~Ss"@V'i@V59L@VC{S@VQ<@V_l@Vm]X@V{xӠ@V`K@VEt@V(m!@V y1D@VB5@V@Vܟ}< @Vw@VN[@W"Ed@W9@W!/]K@W/a@W=_2@WK)t<@WX@WfE9@Wt|L4@W>YՐ@WV@W3[@Wy-p@W4!(@W)@Wԣlʅ@WX;<@W *j@W:~@X ko@Xːl@X&Q@X4nͯ1@XB(h@XOyx@X]`9@XkA@Xxh@XBW@X߂%@XzF"@X@XF|@XBQ@XFP@Xj˱@X,`{@Y)@YP@Y_z4@Y).ė@Y6z@YD>$@YQM@Y_Ga@Yl3G@YzJ@YɧLW@YG p@Y@Y= ҧ@Y!*@Y,?@MOL@MoiS@Mިj-@M@Mϋg@MMC@NKY@N.@NNDg@Nm}N@NS@NW3@N0z{@N댰s@O ܨ@O* X@OIX@Ohe;f@O\@Oz @O&)|@O8TT@Pܞs@PQ)+7@P L@P0*߯@P?@PN{@P^GZ:@Pm y@P|B@P7Κ@P}g<#5@PX>@Pi|p@P1d@Pd49@P@P~@QOx7@Q [0+@Q$dqF@Q31&k@QBCr|=@QQQR'mp@Q`ZqF@Qo_9`@Q~`W@Q]juN@QUL/@QI2Hg@Q: ә@Q%eNK@Q ա^@Q@Qр@R_/@RPv^@R"Y\@R1){@R?g6Z@RNw'@R]C@RlDTTI@R{(@RebS@Rqt8G@R#U@RƲ @R~*@R%[Q@R5@Rkzr@Rvł@S vo@S9Jw@S*Xi@S9\H*@SG!@SVrE +@Sd_@Ss{@/Q@SB@SwlD@S̙@Sfᖩ@Sb@SJ@Sطu@S!>@S7@TLF<@TL(M@T wM@T/ዑ@T=^ G@TKT@TZ_n@ThUQ[@Tv9@T3@T3*b@TwD@T3<@TT@T4S@TmL,@T褰Z@TC@U pք;@U9a8@U!e^@U/yW@U=E @UKN@UYiMi@Uh@@Uv:)@UT@Ul"@UB@UЮ @U@Uʵ>@U$hD@UPj$@U"yL@Vg@V@V0m@V,3@V:k>@VHTb=@VVċX\0@VdO@VrA[!@V\9@VIB@Vw:@Va.k@VHQR@V.a@VB!F@Vz(@VҽP@V@W o@Wc[}@W'::0@W5ģ6M@WB⚛@WPi"@W^3/@WlN7@WzŒz@W⓵F^@Wh>)@WnH'M*@W14\@W/VZ@W̱=X^@Wn` @W)'@W@Xabd@XO-'@X&@X,@X:eTz@XHF@XU{;@XcjT'@Xq>@X~)@X_K`@X@X;p@XD{;@X!@X~wOD@X.@XFG@XIѵ@YސV@YrS@Y"f<,@Y/6@Y=#@YJ0 @YX;\@Yeż/@YsMۑd@YYZ\@YY8&@Yy@Y^ Fs@Y-@Y\@Yن:[@YT@YΒ@Mǜs@Mę<@Mg@Mj@N_Ho@N/NI.|@NOc,@Nnc@NHBGM@NǺ@NY;;@N@Qq{7R 4@QZW+9@Q+,@Q*S@Q'W@Qnv@Q~ j@Qog @Q] @QGA;S@R,轤@R8@R$O><@R3~@RBS"@RQn&U@R`@U R̐9@U{@U%y'@U3Ȋ@UBa*@UPI/Y@U^sm @Uli@UzN|@U +@U@@UpZ@U8`@UPp@UfJ]@Uy?@U늋f@Ur@VC@Vft@V#!,@V1g@V?Ab@VM@V[bz^@Vibb d@Vw!9@VI@V麋V@VO9C@Vת<@Vr+R@V_*J@VI]@V1֩@V yz@W@Wb;+@WB@W,@W:vRPx@WHO}@WV'H@@Wc@Wq@Wx @Wp_% @W>8@W @W g@WĚJR@W` BA@W# @WH'ʓ@W>@X b@X@X$T-I@X2 [@X@G[@XMѮg@X[p@Xi_8}@Xw.U@XSe@Xftw@X5~@X\@X]`@X)K@X֤p@XERC @XI]Nx@XH@Y Mc@YԯU@Y(N쭷i@Y5RI@YCz^d{@YQ vmY@Y^l@Yl. 8@Yy+@YHEK@YU[@Y\x$$@Y@Yi6Ƶ@Y-g@Yp7@Yۂ2@Yq@ZxQj@Zk۫E@Nҹ|]@M޿@N6b@N/{@NOT$x@NoPn @Nr:\H@N* @NKԷ@NہnZ@O ^:B@O,Վ/z@OL@9 @Ok`i@O޷@O8o0D@Os>܂@OoǕ@PZ@Ppl@P"c@P2x _7@PA԰@PQkmm@P`ܰ1Y@PpH<@PizGe@Pj8@Pmp{KL@P_@P1a@Pd\@Pۭ`@P#@P/ i@Q iE@Qi@Q'tY@Q6qX-@QF"׽@QUEh͛@Qdd c@Qs}T@Qi@Q@QD@Q/Gu@QPd@Qͽ_4@QܹK@Qa+^@Qn@R j\}@R5R@R'gQd-@R6Jԅ@RE*]@RT;@Rb1@RqU@R7@RNeK@Rk*@R @R\5@R[d@R?L@Rː0O@R~}?@S-@Sj@S"= @S1'>@S?ʢZ@SNg -@S]'@Skg D@Sz-@S@@SL8l@S֪rC@S]笋4@Sa@Sb2@S{4@S[I@S۫@T G]:@T+Hu@T('F2@T6/@TD2 a@TS`"@TaM?@Tp"@T~®͚@T٬@T0P@T@TeZ@T% @TpȊ@T)@TaQ#@TD K@U @UN@U)@U87-@UFnJ:@UT @Ub9kQ@Uq8@U-ޏ@UW`n@U~\@U0@U"-@U[5,@Ukh:@U kn@U4=,̯@UJգ@V ]k! @Vnni@V(}Xw@V6` @VDWD @VR@V`Q@Vn\}[@V| W@V? >@VyO@Vo@V@V†D.@VyO@Vjz@VYv~[@VFX@W1z@Wk_@W$l@W1@W?0"0+@WM`kg@W[~}C@Wiad1;@Ww;%L@Wz@W}&@WmM@W]@W_Or_@W-G.(@WG"@WR@Wj]@XQA@XX@X#V@X*Ӄ>@X8Wuq@XF @XS8qB@Xag@Xo>uÈ@X|F[@X @XX^@XYE+@XI՝@XbnhG@X &@Xܵ`T@X\1,@XAN@Y8n@YF#Ԡ@Y C@Y.@Y< ס@YI8v@YWT;iբ@Yd뎄s@Yr4^@Y.C@Y5tg@Y8) @Y-⵳@YT6@YP@Yjs>}@Y @Yy 8@Y5i@Zk@Z/u@Z"0 @Z0af@NOݧ8@N/wgR@NO{PC@NoK!@NDN&@NQф@Nx@N?o@OOW/}@O-続]@OMdY @OlFG@OGU@O5w@Oݾ@OD Q@PeH@PY 9@P# @P3yr;L @PCNf@PRjB@Pb @PqxC@PTu@PWC@Pub@P"+1@Pϭ@P^s@P+.@Pz@Pc^@Q Q@QIt @Q)@Q8m"@QG_@QW_H@QfC߬)(@Quh7X|@QK}@QA1@Q˗6@Q5Sn@Qۑ@Q7@Q~KP@Q$. @QXk@R x@RBF@R){@R8텣@RGِV@RV2@RegA@RtE*@R @R/@Rƕ#@RS@R_x]p@R&^idb@R霄K@R:`2@Re?y@SWr@Sҝ@S%@S41C@@SBj @SQu@S`'Ψ@Sn`_ɚ@S}dMG;@S/@S7@S'B4@S7rw@SC p@S@SS9ے@SJhB@TV;+@T9 '@TLr>@T+Êw@T:77 @TH۩M@TW!z@TeDwD@Tsk@TLԱ@Tϴw@T ݔ@Tjx@Th'O"@TU@Tm@T澙@T @UX5@U^n@U@U.*9@@U@V#@V$O@@V\@VDŽX#@V~&Z@VvZ@Vlz4 @V`F@@W Q- @WA.޴@W).jk@W7{k@WEu@WRdm@W`/)9@WnL@W|@WpyHV@WL@W'+@WN@W"^T@WϪ@W}KO @WMpUO@W(_D@XT@Xe@X"|&a@X0Br @X>Ȱk1@XK5@XYNG@XgK @Xuc%@Xgj@X}|F@X5D]@X7qt@XX@XQ|@X-^le@X @X]"@X R@Y f0@YZ @Y&߫@Y4O@YBF% 8@YO;@Y];@Yk#S@Yx j@YY ͱ@YG$@YU@Y¾ @YĞ@YA@Yќ@Y_g@Y챰@Zwld@ZT)@Z@F@Z)a8 @Z6U\@ZDΛ@ZQ!Ó@Ng=@No8@N߿@N&@NϏ0K@NSE!E\@O vߋ@O.쨭]@ONR̘@Om< @Oi_!@O[@OOR1@Ohql@P Rt@P'@P$oQ@P4`E{@PCJ@PSTX]@Pc ~@Prbd@P Nk@PA@P8ڳ@PfSw5@PD7@P35C@Pޑ$@P@P@mxa@Q R])K@Q[L@Q+!P@Q:c@QIL@QX՗@Qh DF@Qw:D@QdmŸ@Q=Te@Q@QȈL @Qg%@QT@QD@Qr,@Qj(@R @R5@R,㈯@R; N @RI̩@RX@Rgٸ-@RvĻM@RG@R75@R^%2@R6X`@R ?Z@Rj-@Rަ^@Ro߭c@R4&@S _Ѽ9@SUheL@S(nV'}@S7%@SEjQn@ST8@Sc5e)@Squ "@S!#q@S&q @Sl"O}@Sa4@SzZ$@SɎ@S ^@S/@S:Nl@T@TH:@T Q}]S@T/IQ M@T=?-t@TL>!@TZ18@Ti&c@Tw'T@T@Tm,Bh@TԵV@T8z=@T/ȋ@T_@TT=o@Ti@Tw/@UVAnC@U="@U#sW@U2?v<@U@=!@UNe~@U][@UkP6@Uy[g@UnF@Uq@U7/@Uk()\@U)@U:H@U@UB:Ρ@UF 9xU@Vj_g@VAҸ@V#@V1ȼ]@V?^;@VMgy@V\}@Vj%H@Vx60E:@VE =@VQ4@V[6@Vc@Viwg@Vl|@VnӸ@Vm K@ViH@WdR>@W\@W R @W.F}@W<8@WJ(lY@WX!9(@Wf~UJ@Wsނ@W'@W]&4 @W͡@W{@WZ@W7@WXR@W'@W£Gw@W#I@X j$@X;Xt@X( F,@X5 Q@XCHq@XQlO@X_4s@Xl@Xz(<@X~@X>@X5@X7@XsI@X+(/@Xvy@XT9@XJe9(@Y+@Y*W@YXŶ@Y-q@Y: @YHWI@YU7m@Yc5۱@YqF{_@Y~ ױ@Yz@Y& @YŽ @Y]])@Y~*]@YЍ@Y#@Y"@YJu@Zz@ZjR@Z!{g,@Z/@Z=w@ZJmIc@ZXO@Ze@Zs)C1@N@N*0@N@NルPm@OT@O/T@OO lf@On@OV3SK@O~鶭@On]@Oo@P+YM#@P~K@P%$@P5-Yܾ@@PD0.@PTga]O@Pc@@Psβ}@P@P@PM@PYKI@P'@Pt!Y@PUe@PCw9@P@Q @QT&e@Q,YCw@Q;jʈ@QK9{p@QZ|=P/@QiMԴ@Qx;a@Q($@QXȞ@Q@Q*`@QΚCr@Q @Qj]@QS@R.bOb@R;?@RD/@R.Iô@R=Jfc+@RLG @R[?Q@Rj4at@Ry%gT@Rl2@R-@Rt@R~@RÝ@Ũ@RwE@RM9@RJ@RVDz@S )@S y@S+B}/!@S:]g@SHtN@SWwXR@Sf,zV<@St޿@S4@S8BG>@Sg@SD@S%Fʡ@S5r@S]l4@SVQ!@S@TZ @Td+:@T$1d-@T2gA@TANnO@U@U' @U6>'@UDT$M@UR@Ua&&@Uon"@U}Ԥa@Us6^@U6rV@Usw6@U6@UASd@U@UO/&y@UNP1X@Uk?@V U@V19σ@V()@V6N"1@VDo&@VR`x@V`d@Vnj@V|M:L@V8@V@VgcV@V)s}@V5kjc@V@ Z@VH)fD@VN=P@VQ|I@W S@WR6E@W%O1g@W3I@WAB͔@WO9m#@W]-am@Wk}@Wyy@Wy@WeИ@W'^@Wf@Wu !@W̄@We@WEEG@W"F@XS@Xׁ@X$@X-7@X;X@XI)"V@XVf2\@Xd&L@XrQa@X\V@X$dUK@Xi@XTG@Xq"@X2A9@X@X@Xhq?@X"@Y jM@Y6+@Y%Bq6@Y2_@Y@@@YNS^L@Y\S;?@YiQO@YwTC@Y@YV@YFX@YnV+D@Y$[!@Y(, ݕ@Yņ@Ya6 @Y>!=@YtZ@Z *[щ@Zv@Z(R*B@Z5 @ZCu ȕf@ZQR@Z^H@Zl5@Zy@Z.i7N@Z)]u@Oc@NC @ODa@O/ 0e@OOȊ@OoVQ$@OZ@O&d@OY[E@O찪3@Pۄ>@Pwa2q@P&.I@P5G'@PE ?@PU2>@Pdpw@PtnbB@PP@Pg@P,P<@PIԏ@P#7b @Pѝ@Pۧi@Pƪ)@P-@QT2Ʒ$@Q7>@Q.J o@Q=huf@QLƷN@Q\I@b@QkQ pv@Qz 3@QtL@Q4ձ@QE`Wa6@Qwf@QƤ&@QGuW@Q~@Qd@R,:@RC#@R!V@R0eߋ@R?pcn\@RNv"@R]yKw>K@Rlw@R{q@Rh=@RZJ@RH+@R35@R.?@R@R wd@RQ@S-m@SbXc@S2@S-^ư@S?@W[@W@W㳾@WƂx@QN# |@Q]| 8@Qlϋ2@Q|D}q@QhCF@Q\@Q;}@Q*LmD@Qa@QהϘ@QV@Qpx@R&@R4@R#Q`2@R2jZ&@RA~@RPC@R_wEW@RnS@R}W@R.z@Ro@Rd@Rh+U'@Rg@RkH@RT3@R8'[@Sy@S@S!Վ@S0wN@S?wq&(m@SNEQ@S]f\@Sk׷@SzZۮ@S[z@S@SM@Sd@S9gRc@S`3@Sz@S|W|@Vx@V"@V0OY]@V?P @VMH @V[v @Vis]@Vw d@V2@V@V7_w @VV@VsIu@V̎Z|n@VڦP@V輭pk@Vaw@Ws9@WY<@W ՘ܪ@W/zT@W=P8@WKl@WYW@Wg;@WuznY@WXF@W8@W`n7@WfB @WN^@W9@WѾ4@Wr.c@WB$@X #@X-@Xrd@X*V&@X89.a@XFhe@XSX@Xad[@XoH@X}XR@X]@X2{@X5^@X;W@X¤ @XqJ@X<1@X(Bt@Ẍ݈́@Y+@YV @Y#g+y@Y0؄!@Y>3k@YLS:@YZ @Ygx@Yu}}G@Y2@Y<~@YV@YG?@Y?@YǢ9v@YMl@Y+@Y+EB@YCI@Z @ZVET@Z'+ ~@Z4,@ZBg,@ZPKE@Z]nY@Zk5򇅑@Zx|@Zb"bi@Z@Z9y@Znj)@Z]>,@Z4@Zܺ1@O8J@OorF|@ON¨@O&Do@Oϒ~%@OXA)@P`@P_g!@P'0 N(@P6q=r@PFy@PV}c@Pf6^@Pu@P+@P=&X@Pߧ U@P|)@P^İ@PӤ <@P0@PL'?@Q9. {@Q@Q!,pJ@Q0 ס@Q@ 0ݞ@QOtWY.@Q^׌@Qn5r+@Q}Vբ@Qwv@Q3@Q'6Ϛ@Qŵy$3@Q+(@QE9@TJ=D@Tf@T=|u@T--¦@T@Uc.@U"v6@V f1@V{@V&y@V5$2s@VC^0@VQS@V_ʤng@Vm0.@V|-HK&@VZx-@V'f@V @Va@ViZ[@VE@V:cA@VW]v6@Vr*0@W [ @WgO@W%*@W3ũ @WA@WO燮m@W]4@@Wk;Q@Wy4`@Wz@W@W~@WA=@WV@W4i@W끗}@WM@Wo@XM8@X[@X!$L@X/+i@X=tl7@XK[=0u`@XY@ s@Xg">S&@Xu1@X"@Xh@XV,@XsRӍ@XJ`+?@XZ(@X&@X !@XvY@Xa.G@Y ,@Y{S@Y(q"@Y6{$@YDH{@YR L@Y_á@Ymɡ/X@Y{G @Y @Y~Ф@YtM9@Y*C@Yy @Y͐@YA)EK@YlQ@Yb@ZI)@Z7@ZZ@Z-BA @Z:ju@ZHO{{@ZV+ڭ/@Zc˿\@Zqj%@ZC@Z?&s@Z;ּ@Z#)@Zhv@Z@ZА@Z!w@Zz#l@Z@!b@O@O>@O#$@O:@PO@PZm@P'@P7`@PG19!@PVq@PfQE@@PvSϱ@P9@P,;@PϏ޹@PBQ{@P|F@PԂ{@PuM@PƈO@Q9/@Q|=u@Q"Ct@Q1Sm6@QA9N@QP0@Q`*@Qoev@Q~X@QGnT@Q\@Q1)Q@QIK @Q˕B_@Q݂D@Q &r@Q_Y5[@R}s@R*[@R'jo.@R6-G=@REUlF@RTz@RcU@RrA@R9V@R $@Rܮ@R tY@R,k2@RK@Rp @R'@R@SY]#a@S붫M@S&Ů6@S5@SDt@SSrgbM@SbO:d\@Sq(d@ScV9@S޹F@S= I@SiL@S0`@S49@SشP@Sq6@S+ _@T0h0@@TҪ;@T"CuqrN@T0//@T?%@TN>(Y2@T\mZ@Tkǹ'-@Tz\@T0J@TJk$O@T ./@TlU8@T@Tт~M@TC@TQ?p;@T ,P@U :@UUF@U(|d2G@U6Z@UEb@USj@Ub>#bx@Up|}B@U I@Uq;@UӺ@U12;@U!?@U偙 I@U;@U+%@UD@V.;+j@VyԾP@V4@V+ @ᾳ@V9M @VGj_P@VU1o@Vd t%@VrC7xo@Vz~s@VNgΰ@V&0@VZW@V?@Vj-@VՒ<@V4D-@V*@Vǻ@W(\@W;N@W*Uq6@W8n S@WF @WTb@WbƶM@WpoLE@W~g{@W@Wّ@WP@Wn'%@Wjc@W@WV@WU@W[@X ѓ>|@XE95@X&x+P@X4^@XB@XP]@X^s=@Xl\͚6@XzD@X)7N@X plW@X@X<@XPh@Xͅ)3@X_-:I @X6C@X [=@Yq~@YSC@Y 4[7@Y.O@Y<["@Z@(@ZNfq@Z\@9U9@ZiÀ@Zwk@Z,=@Z/r@Zl r@Z @Z^/t@Z?@ZBU%@ZoPU@Z@Z,@[ +P&@[`@PE_@O5@PD@P~@P'6k)@P7*@PG|\@PWb@Pg36pv@PvjE^@PúP@P8Pi:@P<`@Pujo@Pşb_@PH4a@P낗V@PZyh@Q![@Q@Q#B9@Q2B*?o@QBNn@QQ@QaF Jռ@Qp/av@Q)W@QaF@Q0@QYgO@Q!@Q S@Q^Z@Q)@X@Q5Ɋ@R 9hƽ@RyRFX @R(`l@R7;i@RGQʁ@RVL@Revq1R@Rt@RnD@Rڗ]@R f@Rqrd@R4@#@R%I-@R.@R3@j@R3dD@S 0xl@S) @S)S@S8x*@SFV>@SU3@Sd@Ss!e@S@ShD@S?`+@SPl @S@S̰U@Sys8O@S?G{@SK.@TP@T{u\@T%3zC@T3(0@TB>@TQGN@T_g{n@Tn@T}>QR@Tz X)@T}vV<@TN.@Tn@TDܚ@T.<@Td@TEi@Uxu@U@ ]@Uz m@U,%k@U:|$@UHO =,@UWm9O@Uei&@UtR'I@UlBM?@U+W@U?@Ut7w@U](@Uʾ@UHX@Uv@U *y@V$@VwF]E@V "@V/K@V=aW#@VK&@VYQ@Vh3RG@VvtPx@Vj@Vj @V(M@V_Yι@V@Vܘ:@Vd@V#;9;@VN2s @Wvd@Wà@W ?x@W.{} @W=~@WKx@WY9VT@WgQr@Wug Bn@W{Tp@W`)@Wr@WJ?o@W t@Wɽ,@Wđ\@Wi@Wvj@X˴\@XԌP@X$@X+׶D@X9pC,@XG_va@XU@Xc3<@Xq[@XoZd@X[ad@XEÑ@X,xb@XL G@X@Xכj@XTA`5@X@XpLM(@Y J|I@Y"J_@Y%RO@Y3Q(@YAZ:@YOp/sS@Y]>g@Yk b@Yx֔/B@Y@Yg@Y@Y,DD@Y53@Yu @Yr=@@Y0-@Y. %@Y@Za&@ZrmR@Z+&@Z+@Z94'!@ZFKo@ZTnS @Zb@#b@Zo\QR@Z}tL@Z=A0@ZCҁ@ZD@Z,9@Z:~@Zm&Z@Z d7@ZꨨR@ZC\@[@~$@[u,#@[! Br@[.Jw@[<3-{@P'@P[@P'p~ @P7j@PGʠje@PWBx@Pg@PwcB~=@P4} @P[I@Pq@P@P@P (@P@PR*@PMVf?@QN(5@Q٭) @Q$)E@Q3]%E@QCK}@QR@QbY"Qs@QqG "@QR_gk1@Qw@Q7$@QՉ@Q 9@QjC@QǛ`@QI@Qsd|@R fV@R @R*Qz@R9 @RHϢ O@RXը@Rg;Ќo@Rvk`N@R1@R#@Rh@R@RnU7@R/@RAs@RP1\*@RZa@S `ˡj@Sb`@S+a@T=xCr@T r@Tzި[@T^ĕ9@T~@T>x@Ula@U\c@U s@U/nKx@U=xF@ULt\@UZQ`@Uin m@UwTi@U]܇@U W@UA$h@U@Uu@`@U΁vh@U@UIA)Y@Ux8@V8@V`+ @V$@V3 @VA`:ȼ@VO.F@V]@VlHXɉ@Vzb@VMIK@V}i(@VZ,U@V_@1@VO:w@V \@VD/@Vxt@VFǜ@W)J0@W^V@W%25%s@W3Zt@WA؈*@WO{@W]/ @Wkfx@WzU@W@W5ha@WK@W_@Wq;*k@W΀@W܎2`@W9Qi1@W5't@X q3@X @X"J)@X0'@X>H@XLTun@XZdc@Xhc@Xv@Xݐ@Xy}D@XiB @XW{D@XCi'E@X-ZD@XPP@XN@XW @Ym?@Y @YT1T@Y+\K@Y96H@YG@YT[߄@Ybf,@YpI[@Y~^O9@Y-~\,@Y֛@Y[+1@YuD@YW/@Y ڒ@YX"@Yޕ@YeL@Z$q@Z䇖@Z#VD@Z1W"t@Z?f)@ZLn@ZZz?@Zh,2pL@Zu".@Zc@Z;ذ@Zܞ@Z0fN@Z; @ZE@ZՇA@Z+ϾI@Z%j@ZnCZf@[ B@[^@['Go(N@[4ȨS@[BzL@[P(@[]h @PG<@P7g /@PGk@PW .@Pg]@PwTO @Pq@PdqB@P6J(@PDܦ@PqN@PֈNw@PC@P]$@QTWM@QRep@Q$e@Q4@^ @QD0&w}@QS @QcT)='@Qrb(u@Qc{pa|@Qェ@Q^}@QԍTi@QE@Qϱ:@QQb@Q{fҳ@Q(@R 3 jK@R+?@R+׋LU@R;"@RJiN/@RY1@Rh&@Rx#@RXW@Rʲm@Re\K!@R6@Rэ@R".'@R>>@RVёA@Sj=l;@Sy@S-|@S-W@S<&녗@SK 0@SZ!l@Si]l@Sxyc@Sjzt@SWlfgV@S@@S&;u""@S(I@SwO@S1;(@S]+@Sl&nn@T <$M@T?@T*A@T9Ӭ<@THZ;<@TWDq@TeCe@TtV\@TBlz@T= @Tо@TN+9P@TT@T̛Q"I@T=(M@Tߗ@Tw| 1@U*@U}(@U$7츻.@U2Xb@UASs@UO:@U^c3@UlN~R@U{g(@UE@U`t@Uزf@UMތ@US#h$@U/@U[@Uސ&,@Un8$@V @V4@V(>@V6ڽ}@VEJY@VS~-@Va@VpH-2@V~(T'@VZ@V/s7@VwdâO@VgO@Voa@V?u@V}tJ@V_@VfTeD@W )ك'@W]3J@W)pۦ@W7o @WEm@WT7f8@Wb>vh@WpdR@W~k[;@WG@WF @W@Wr@W7@W/Kuwd@WCI*@WUz @Wd@X r@X}cp@X'\@X5~@XC[@XQeQ@X_gd@XmN&]@X{ɫĻ@X3b@XM@XyR@Xn+HԷ@X`oԔ@XP@X>7A@X+:A@X@Y-"@Y;ha@Y"ȩ@Y0)LH@Y>d@YLje@YZG' @Yh"K@Yuyk @Y]@YYNA@Yz@YLIz@Y|@Y|@YֵgD@Y9Qc/@YH1:@Z_`N@Z F2/@Zgȗ@Z)X@Z7e}T@ZDE1@ZRj ~^@Z`LԈ! @Znmo@Z{ @Zq(>@Z%hK@ZRv@Zw=@Z6"L@Z #@ZێOYc@Z7g@Z @@[E7@[+@["s@[-o&@[;Q@[H[lZ@[VJ@[c=@[qzA@[)@Pg7@PWq@Pg*@PwIR@Po7:@P}@Pf@Pe@P7@P'*y@Pʿv@PH@QFv L@QuX@Q%@@Q5Wa@QDl@QT_D@Qd7,{@Qs̉C@Q\)@QX@QmD@Q@Qj}@Qu{@QS|@Q„@Q)/@Rq@Rш/@R-F75@R<ɤh@RK@R[9p?@Rjm@Ry B@RM5<@R?s@RuaE@RN@RպWU@Rp@R$@RFW͉}@ScQ@S|g=@S f@S/l@S>Dh@SM^<@S\0@SkGܪg@Sze@Sq@S.@S1 @S+;@Syl=0@S`e@SD8,m@S$5X@T';@T~@TtU@T-vx@Tiz@U ;8@Uc@U'si@U6 @5=@UD@US1f@Uae@UpJ,hk@U~O0T@UX! @Uۈ1@U[O}h/@U:K@URMX@Uɍ5^@U=>@Un@V% }@Vs@VG@V,Zӱu@V:@VI -I7p@VW~ҽ@VeŽc@Vt4N@Vr@VU%@V0f@V7@V̜@Vp@V^%w@V*L)@V[<+@W%4~n@Wclp@WhT@W-js@W< 9@WJAL@WXsmnZC@WfE@Wtϟ&!|@W7(@W"na@WHyd?@Wl*úm@WS@Wɬ@Wɥo1@WQ[@Wk9@XS@X'"@X8=.U@X,H(@X:V(?B@XHa@@XVj4@Xdq*@Xrvu@Xye@Xz@Xyc@Xv7p@Xpߍx@Xi}b̍@X`@XT}V@XG6@X7Ȁ'@Y &^M9@YڡK@Y'f@Y5SV@YC2\@YQM@Y_͕@Ymu g@Y{TB@Y2@Y f*}@YvÛ@YnAA@Y*@Yh;g@Y:OD@Y Y@YŻ@Zc@Zp6f6@Z!9?@Z/)=@Z<@ZJDW!@ZXK/@Zf 3@Zsu@Z>{/@ZBO@ZJ@ZUMC@ZiM3I@Z-d@Z57b{@Z(+ @Z0r@ZY@[ t@[4tts@[%2@[3Q49@[A) g@[Nͼ}7@[\p jr@[jE*}@[wU@[M}|@[\@[>@P|\@Pw|@P@Pᄎ@P.@PA#@Pǎaj@PfTjO@P9F @P[i@QY@Q]B@Q&JF@Q6Nf@QEA@QU\Kuo@Qe2-C@Qt4C@Q>}@Q2s@Qe"S@Qq"@QwU@Q}%@QvL+_O@Q/'@Ra4aS}@Rg.@R8Մ:@R.%@R=?@RMX@R\MbX@Rl1@R{Ő@R(@Rݰ%@RH@RZ+yB@RǑe@Rfɚ@R4֋@R I@SF>@SiNԮ@S"%J@S1r@S@$ }@SO˼ p @S^^fn@Sm{@S|٧@Sr3@S@S_z0@S02@Sy9@Sm!@St@SKÈ@Tn@Ta*-@T!??zx@T054@T>$ @TMps@T\> @TkaHC@Tz*@Tu@T'@Trp:@T.n5@T'U@TҜδ@TNj@TIf@TVZ@U RƇ@U.%@U* @U9:A<@@UGwaW@UVoɄ5@Ue-m@UseBl@U)LH@Uz&@UA@U@UM픷@U{^0[@UNd7m@Uwrw@UCPF@V0Y@V-W@V!ͽ,@V0 i@V>xtT@VL7mJ@V[GI'@Vih@Vx rp!M@Vi@VRf@V @VtI[m@V u@V<`<@Vg@V %\@V[@WDW@W'@W#hl@W2 @W@HH@WNl@W\iX&@Wj@Wy&bءF@WWR.0@W @W.@W6@Wdc@W,I6i@WO~@WqH$)@Wh0z@XMAh@X2@X"s.@X0u@X? ղp@XM:@X[,B@Xi:0vi@XwE@XOX&@XV_@X[nG@X^cW@X_(@X^~v@X[=@XV"@XOa<@YF8@Y~[\@@Y_† @Y?E@Y_t@Y1@YғGe@Y᪡@Yb@YU;^J@Z '<@ZUgg@Z&r1@Z4t(@ZB`;d@ZP)l5@Z]sT@Zk@Zy{٠;@Z>o.@ZIE@Zjڨ@Z{X@Z7(Y@Zq@Z٩S5@Z` %@Z~N!@[̒@[zr, @[*rE@[+-s@[9g@[G0S@[Tv@[b! @[p(FDܺ@[}C@[p Ŗ@[|y@[@[Ox@[&@P@Pl^@P4s@Pa@P7'@PװZ@P84@Pgl@Q:P@Q֘x@Q&BY@Q6 ]C@QFMG}V@QV~tj@QeC@Qua"o@Q0@Q[N@QDa@Q۾v@Qmqk&@Q'@Q⁦@QB?#@RR@RMB@R n`i@R/٘ߴ@R?HDH"@RNEB@R^ u@Rmkz@R|Y(@R@Re6@R*P@RQ@R7|@RtO8@RT @Ri@S%Ε@S?@S$g#@S3@SBcz@SQ?@S`@So׺g@S쮳@S; @ShO?@S"y@S@Sjb7`@SZ@S1@Sh/@Tjf@T9"@T#L@T2ZHS@TA} @TPYNݱ@T_2 M0M@TnO^@T|%`@T@Trff@T:Ou@Tj@Tƿt@T}}U@T8B@TH&@UY3j@UT;r@Um@U-@U@WbV@WX=zw@W b @W<<.@Wk1fJ@Wҗ,A@W4Δ@WH[@W_S@X 3V@XTr@X't2$a@X5R@XC}@XQ!EW@X_sG`@Xm@X|%-.@Xy@X7/@X)=@X3] G@X:˘@X@%@XCn@XD1@XCأ!0@Y@,@Y<[@Y$5=@Y2,[-@Y@!{T0@YNg@Y\ϡ7`@Yi\q@YwN@Yͤ@Y-1@Y8@Y#U@Ygt6@YI`@Y)@Yr@Yi@Z0H@Z@Zmff@Z,BE(@Z:U͒@ZGĈj@ZU>@Zctr@ZqO@ZX@Z6@Zۤ@Zm(+@Z0ܪ@Zf+@ZѲ%J@Zp/0%@Z,T@Z07@[*h@6@[WxW@[$ H%@[1 b@[?sq4[@[M$$K@[Z6dP@[hw@[v,|@[ֵo2@[T;/@[&[&)d@[@[o@[0@[ղ @[Q#@Pv@P#@PP@Pb@P̙^@PEX@Q )f&@QhIk@Q'<+o @Q7 q@QFv@QVl@QfPgz/@Qv L@Qs@QesHc@Q UR@QP@f@QK&@Q0$@Qu/@Q@Rmȉ@R@R!k=@R12x@R@{`@RO@R_W} k@Rn4~Ľ@R~ JO@R}ȗ@Rֺ@R++g@R{%OU@RƲpf@R * @RP@R0}@Sm.@So]@S&1?@S5^+@SDm?<@SSD@Sb@ˉ@Sq&Q@SS@Sn.@S,]@S:.@SDV<@SJHj@SLpXJ^@SJA@SE# 2@Tggu@V]@W@WF^9;@W5@W+3]@W:7aI?@WH@WV˦.^I@WeP@WsV"@Wӛ@W@Wɀ@WN=G@WV[Z_@Wȼ(@W{|0@W @WOmh@X{8@X0@X+[7@X+ @X:f@XH8w@XVW @XdtC@XrL>@X]@X*@X_΀@Xrtr@XeL@X@VI* 9@VWu@Vf&"0c@Vt)'@V?@Vym@VU~@Vk!@VCi @V@/@V٧V@V 0`@VmzM@W̉ Q@W)rY@W!d~@W/bf@W>/H:Y@WL2 }@WZѕ׻w@Wi.@Wwj 5@W+F@WX@W<`&t@W}@W r@W/e@W3ez@WkE@$@WѢ@Xk2~@X9@X"3QT@X0` 1@X>*f@XL j!@XZ״@Xh$Rmm@Xw_H'@X;h3@XXDe@Xrc@X}P@X@X˶$!@XHS@XPh(@X@H@Y@Ygs@Y @Y. E@Y< \+@YJO@YX@Yf :@YtB@Y3@Y~B @Y(Ֆz@Yߙ@Yӥ5?@Y|I}@Yձgrr@YiD@YP@Yo@Z V6L@Z:X@Z)4ݝ@Z6 {@ZDt@ZR֎h*@Z` )@Znn @Z|F"Z-@ZFm@Zo@ZB,*@Zq@Zaz @Z.t4e@Z.@Z."w@Zk/@[Q@[Yke@[!i@[/n0@[=X5&'@[K˥@[XѶ9@[f<`@[tDk<*@[#9@[ݦ@[d2@[`@[K@[u-@[#4C@[ޮ@[xT @[!tmx@\ cb@\mm@\&Je@Q-2@P`0;@Q _@QhӺ@Q'Y]q@Q7j@QG~@QWk+@Qg>i@Qw +'@Q@Q@QVHl@Q¦7"@Q2@Qo@h@QJ@Q~c@RX8@RÈ@R#@R3֏ @RB$@RR#*@Rav@RqY@R !|@RyB@RuP@Rh@RB8A@R͡@R5}@RSQ@Rg@S LZg@S<+B@S)뺽l@S8Б@SG{7@SW7@SflF{@Suy @SȗG@S@S1@S4N@SPd@Si! L@S}i@Sp@S@T `@Tya@T*L@T94@THt@TW@TfL@TuyĽ@Te_Q)@TMs5@T2-Z@T@Tڈ@T@Tݡƙ@TuNTU@TEm\@U :@Uۻ&@U'@U6d@UE$!dg@USF7@Ube@UqP@UϽ@Ut@U`N/H@U V@UHM@UULC@U@Ub@U.'@VƘ@V[W@V 2@V/|@V> 0?@VLt@V[]o@Vi=+@VxUkFl@V@V=/B@Vү@V:ivV@Vzy@Vq}2@VY@Vi@V-G@W@W-&@W%XFg@W3U\u@WBM3e@WPlc@W^í@WmIEF@W{j72@W4Y@W@WQ6@Wg @W/@W"+@Wcuo@W@@WގIo@X 3@XP/#&@X&@X4#@XB\G;&@XQޖ*@X_D .@Xmn$f(@X{@X@X@X=З@X @X;@XVL@Xo+[ @X션|-@X@Y@Y:!@Y$B@Y29@Y@!@YN @Y\п@Yj񝄘@Yxf<@Y/)@Y@2s@YӤ@Y/@YނD@Ypz@Yn5@Y~@Y@Zޒj8@Z4Q@Z or?@Z.X7t@Z<>\X@ZJ# -@ZX@Ze8@Zs2+@ZϜ\@Z]qg@ZZ=C@Z2Q@Zĩ(@Z! ?@Zԯ?@Z|@ZP!"@ZK@[ ]@@[g3@['{/@[5BWr~@[CA@[Pz@[^@[lK6@[z |@[ƞ U@[k@[:@[[_@[V۸@[\b@[r@[Kq@[p"v:@\,@\u۬#@\uA߆~@\,|w8@\9'}z@\GlDƻ@Q'p6@Qd3k@Q' E@Q7Ҳ@QGͷ*@QW2A@Qgu@Qwl@V^@VjM4@V_16@W Gί@W@W)\ C@W7yʛ@WE#dR@WTD )@Wbi@ZKV@Z%`@Z3G]@ZAlj&@ZOWl@Z]@f@Zk'ʧ@Zy o@ZD@Zβ@Zi@Zoq{'@Zk_@ZE@Zb@Z#؏@Z @[\%d@[n׌@[>c@[- >@[: @[Htg@[VlR(7@[d3}.@[qn@[pM@[~s@[?W@[$[}@[J!7@[vg.w@[0ۏ@[8T@[ퟋr@[T/@\ 0@\@\$j,@\2gU@\?ŻOw@\Mq^@Rc@R#-:R@RߒY8@R\@Rc@S ĕ @S!l@S,zh!@S;ξ%@SK߃Y@SZjq?@Si@Sx @S4#@SoM@S@SylN@SA@S1,@SXe#!@S{UA@TT@Tvl@T۴@T.m;@T=fz@TL?W@T\7@Tk}<#@Tzr@T+@ThTw@T-<@Td@TX@TӿC {@T#W@T<݃@UlS@UIH @U#'@U,T @U;ͽV8f@UJ_C?@UYjq@Uh4I@UvIv@U[@U}p@U:+d@UZЎ@U4R@U^s;1@U9V@UG@Uf0H@V ;@Ve|@V'S#@V5M[ @VDȮX@VS&;@VaL؅@VpO6m@V~Iv@VlB@Va@V~͈@VTxV@VDž2@V@VX@VY@Wsu@W3fW@WYx8@W,@W;5@WI9@WXO@Wflz00@Wt1Տ!@W/'py@WPZ@Wp4>@W@J{@W$4@W{@W:J@WR>]%@W՗2Rt@Xw'@Xf@X @X.ݝ@X=/M,@XKmkU4@XY96@Xg@@XvV@XNi@X@Xj@XF;@X G@X65@X] ^@X\@X[v;d@Yt@Yh@Y ;&@Y.u@Y<6W]L@YJMB@YXanR[H@YfstZ@Yt D@YCt@Yr3e@Ygx@YLa@Yܗ@YȺa@Yֽ#8V@YN@Y@Z @ZY@Zp@Z*6@Z8kc@ZF {@[wVz@[\CW@[$t5Cg@[}x@[ٴ .@[qZ@[2@[@[导43@[k-@\&YDc@\9(@\}Խ?@\*L's@\89R,V@\Ek@\Sc8@\a.@\n7>@\|lu4@\<@QgƦ~@QWX@Qg]@Qw t@Qn@Qp)@Q@QnRKfy@QCq@QF&q@Q<&@QaR@R_`z{@Rn]@R%͇nW@R5|ɷ @RE&R@RTh@Rdk@Rt<6@RK@R.G@RV@RA2 @RĄFSa@RBO#@RвJ@R0~%b@R5D@S @Ss$Zh@S-ճs@S=30@SL@S[U@Sk4 B @Sz{7@Sg.@S /&@SM2-@Sك@SuN@S`@S%g@SQ @TyM@T@T!dR@T0i/@T?X5 @TOkB@T^bV@Tm$^@T|.Aؑ@T3M@T6Vq_@T4l@T/?$i@T&@T7@T k+@T!Ù@Ubk@U4U6{@U W@U/D@U>cOl@UM;S@U\@Ujj@Uy@U|%@UD.@U @Uʳ߶@UÉ<8@UDQ]1@Un@U0X@Ud]e-@V oi@V@V*hl@V93@VG"@VVRib;@Vdƨx@Vs?x[@V!ΰB@Vo@VH@Vי ^@VcO@Vj;@Vt,@V0|@Vy{@WS@Ws1@W!0C@W0c3O@W>װJ@WMHu@W[ #@Wj#'@Wx]1@WZ2@WX8@W@W%@Ww<@Wфi4@W)"j@W ?5 @W#u@X"|@Xq@X$ҟ@X34x?@XAM8@XOz'R@X]@Xl @XzR]d@XC@XZ0@X5m@X3^@Xf#h@Xϖc~_@Xx@XXq2@X d@YA@Yf8'@Y$-/@Y2%7 @Y@*E@YN@Y] @Yk3Q@Yy0@F@YE0fL@YW9x0@YgR@YvA@@Y7@Y͌ u@YەNH@Y].@YN@Z@ZV@Z!@Z/52@Z=Y@ZK[+@ZY@Zg{y='@Zun@Z_@ZNL"@Z<<7@Z'A@ZE@Z<*@Z@ZF@ZfMd@[:@[dm@[A E@[*U@[7,|@[E@[S@[awR"^@[oJ_;@[}N_@[n|@[n@[ o(@[LhT@[=vP@[s@[ݠ~n@[d~@[%斟@\回\~@\Ȱ@\"`@\0s@\=IL@\K.˲@\YC|qE@\f3x@\tW@\\V@\ @\Y[Н@\h= @Q#@Qw͔o@Q5@Q@#K@QȚ8@Q`@QǔId@QoWg@QD`IG@Q:@@R!@RhL:@R&b?_8@R6kH@REaV@RU-/f@Re+ܮr@Rt|:X@RrHb@R @Rv~@R6Q/D@RXQ@RKG@Rx@RMf)%@Sh@S=m*@S @S/m@S>5@SMSm@S]EB@Sl}C_@S{n@SIs@S+@SqJ@S&6@Sgt@Sפ=N&@S\@S=@TD1@Tq23r@T#b @T27۩@TA@TPh@T`[A@To.Ol@T~@@TN@TYT0@T`ov@TdV484@Td2u@T`z@TY4|@TNgta@U@i=@U.T)S?@U#kT7@U2v@U@lط@UO.@U^C g@Um|/s@U|RЌv@U&+@UG'8@U) @UF)I@USW @U8W$@U{n@U2@VNR@VXM@VΤ@V-iŨ:@V<~@VJx@VYjc@Vh]鼏@Vvk=@VPк@V"{5@V=&,@Vˇo@Vݪ@VAry@Vϔu@VZkA@V@Win6A@W@W%m Y]@W3Ii@WBe@WPf9X@W_T<3@Wmt;^c@W|82=S@WDoG@W@Wz7n@W;@WDƢ0@WҦ%c@Wk(@Wap4@Wd֛F@X ¹@Xg@X(@X7 S@XEX<@XSXGF@Xa=@Xp4TC@X~xb#@X 9D@X@X8y%F@Xs$@XŬB@Xҝ]@X9 9@XJos@Xzc@Y n@YhhU@Y(J@Y7%j@@YEJ}a@YSm[@Ya+@YoLE@Y}ʉ-@Y?i@Y@Yp9@Y(K@Y;iT@YK"ڭ@YZ?e@YfX@Yq @Z yo`"@Z۷d@Z&OW@Z4V+@ZBYb;@ZP}&@Z^@Zl}dy;@Zzv=0@Zm10X@ZbA[@ZUo@ZF;@Z63=@Z# @ZZ@Z~r@Zxl@[+@[`#c@[!ڱ@[/ol@[=OO@[K,uWe@[Y)@[fz@[t^@[^&@[e<@[7=@[ %Mk@[بA'@[ǦyC@[rƮM@[=z=@[@[@\ r̵i@\VFYW@\(vO;@\5r@\C|-@\QUG`@\_y@\l|@\z[@\: @\[Q@\f@\Ua@\@\̵m@Qբ@Q\@Q *@Qt o@Q!/@Q׵!MV@Q畄F@QpYQ0@REc+|@Rj@R& i@R65(m@RFe4@RVL8@Re-Qz@Rujhq@R0@R54@Rx3z@R<@Rë~p-@R>wpA@R:@RU=@ r@Sى(@SY+P$@S ,|o@S0JP1@S?z@SO)W@S^ǦZ @SmG@S}WdZ@S)h@S &@S]̶L@S9@S+@S>& N@S耠{@S*^@TX@@@T/w/@T%a @T4TA@TC@TRO 5@Tbo-@Tq"@T=LO@TU.@Th@Tx@@TX@Tˍ: @Tڒݯ@TeX@TO@UK@UY"@U%u$@U4d@UCQ&sS@UR:T6@Ua0@UpsZP@U~wrfN@UqE@U,@Ui ?@U:I@U W@UԦf @Uq@Uae@V#g/@Von|@V! 몤@V0VØf@V? \\@VM5:@V\ng@Vk&,@Vy3@Vkt@VX@VC@VNNz@V~NO@Vс@V_@Vm @V:͏@W ?0@WQM@W(g@W7^iT@WE+@WT`]@WbYR@WqWˮ@Wh(J@WD@Wu@W&\@W\Yw@W3߫@Wg$@WPu@W0@XqF@X @XK]@X,-F)@X:9~@XIPr,@XW|@Xe3- @Xt@|?@X@Xt@X[@X_!4 @XI@X@Xmt@XY `G@X@YyMj@Y@Y/ @Y-_<@Y;@YIvJ@YWjh@Yf Gj@Yt.z@YQe@Yr@YgA@Y1Ts@Y!@YDR@Y&{@Y @Y:o@Z/)@Z>:@ZJtP@Z+U=.@Z9]ŝg@ZGdV8;@ZUhw@Zck@ZqlWcI@Zk$˥Z@Zh#c@ZcZ@Z\CR@ZSJ`@ZHE@Z<H@Z-@Zh@Z Q\@[ eg@[Y@[&G@[4A@[BFb@[Px|3z@[^YA@[l9x$QD@[z;@[? f@[̈́@[@[|CAp@[Qq@[%\b @[ -f@[ /"@[]g@\brA@\,SK@\JO @\-f@\;@\IHXԀ@\W z@\d:T@\rtC@\I`@\B@\5J@\y@\1`@@\]у@\қS@\NL@\nA@Q@QY@Q$H @Q>o@QxW@Q-@RAS@RqWrQ`@R'F;@R7+b{@RF@RV@Rfg-]@Rv"~@Rk@RƷ܆@R5B@Rade@R~:Eg@R*@R>@RF=[@Sɳ @S^;P@S!ׄu@S1dGf<@S@9D@SPWe¥@S_(aF@So8q G@S~J@SZ@ShԀ@SŘ@SQ@SrOm@SU@S-W@SUGv@T{NIR@TSy@T'M@T6KL@TE@TT&@TcھD* @Ts@T&|L@TFml@Tbs@T{@Tu۷@T͡_@Tܯ*F@T +@TS:@U ,@U*@U'@U6A@UE~@UT@UcG@Urr8p@UYlί@U=f@UE@U< @Up@U˫KTv@U~K@@UN@UC@VcWe@VB@V$oX@V3/%5@VAR@VP]X@V_^@Vn2&|@V|} @Vr-@V2@Vƨ65@Vl52@VE@VԮ'z@VK@V1@W}Ik@W[w}Q@XM5(Z@X[AeF@Xiux@Xx9v!@X}E@X1:@X(f@Xr~"@XZg=@XT@XEf@X@XU@Yj;@Y>B@Y#vj@Y1GgO@Y?z@YN}M@Y\CSpx@Yjp+n@YxY(@Y@Y#[@YDg$@Y5J@YV8@YuK@Yۑب2@Y鬏xt@Y:@Zۻ&@Zu#@Z" 8@Z0sa@Z>"5@ZL.MS>@ZZ9ow@ZhB&>@ZvHΥxl@ZMD@ZPgͺ@ZQP3@ZPOe@ZMgc5@ZH`@ZAY@Z9[@Z.a@["`V@[@[e^D@[+4@[9+~&@[G@[U,n@[cT:@@[q~8u@[b*@[C`j@[#U@[\@[V?5@[Ĺ@[Ғ%,@[iA@[>ΛM@[@\ ;@\M&h@\%\@\3Q?ij@\Ak@\N揨]@\\j@\juM@\x::uG@\k@\;#^@\Q@\=`@\@\ʶDe@\ouM@\'@\ސD@]Ŋ@]G!X@Q@Q@Q= *@Qٺ@RΩ}@R*%@R'`@R7rR@RGH9@RWh@Rf1Bj@Rv絴@Rj~@R&.@Rܞ:\@Rd@R:W* 0@R(@R,a@R!˱@S}@SNq@S"ݧE@S2h)_+@SA@SQo> @S`'@Spd {@Sשl)@SFע@SVVI@S@Sz '@SA@S1H@S놋1@Sלg@T $ @TmQ]@T(@T7-Y@TG/P3@TVgj@Te%@Ttp7@TSS{@T#[zG@TH@Ti @T@TϡNI@T޷6@T:қ!@T@U Y:@@Ut@U)@U8L@UG) @UV=@UeU]l@UtZ6@U?踛@U@UͶQ@UxJ@UZ*@U9Gi@Uu}@U첱g[@U$R@V BO@Va@V'-&#@V5ey;~@VD.3@VS|[D@Vb;T@Vp*@V`#h@Vf|T@Vw @V}[@VvT@V zA@V.^@VlmdH@V .@W@WHe@W r@W/w @W> v{@WL?<@W[*Mm@Wi@Wx>KFm@WD@WG7@W>@WFI#&y@W@W: @Wݰ@W$LP@W`@X Ek@Xp_@X%vkt@X4A@XBOg@XQCY@X_gQ@Xm@X|t@XxxM#@XΜJp @X"bA@Xs@XV@X@XZ@X49@X PQ@Y +x@Yl3"@Y'S\@Y5قͅ@YD#v (@YR[?@Y`9P@Yn17@Y||@Y'F@YU(@Yy@Y@YF#@Y @YP@Y9 @YX@Z u7@Z8.H@Z&S@Z4a@ZB65@ZP%@Z^@Zm/"/V@Z{c @ZB@Z&jD@Z-C@Z2.0@Z5.a@Z6E'{@Z5u@Z2 \@Z.+6@['@[@[d@[#8ore@[1 4^@[>Z;@[L뭼@[Z/@[hRu@[vt#@[?@[T@S#@S3VF @SB1v@SRqpJ}@Sa @SqzO@Suh@SpN@S~^@SUL@Ss@S( @S݋ `s]@Sdm@SD?r@T 9@Tx@T*:i@T9vb@THCTR@TX }^@TgIbu@TvU@Txgk@Tob@T;@TC D@Tj8=U@Tьx@T]@TG@T|e@U Sc7@U@U, @U;%@UJdk@UYZv@Uh\v@Uwi@U;@U@UTZ[@U⬊O@U̬o@UгZK;@UߖLA@Uv؊@US5,@V -W @VƳ@V)O@V8 Í@VGtP@VV=<@Venb@Vs`ɭ@V@VF:@V9 W@V֬@Vm|آ@V0Gd@V@Vy)V@V"ќE@W@Wl2$@W$ ,#@W2A }@WAEXqc@WO#@W^rn@Wm}+@W{9iU@W!>@Wf H@W4+w@WJ? @W;8@Wһ&@W8剘@Wﳑ/@W+:@X 6h@X7g@X):@X7G@XF^&6@XT&u@Xc-S@XqŦkU@XlA@XR=3@X|0@X [@Xar@XǷjа@X @X\ ¿@X򪻖>@Ys(@YA3&@YgJ@Y+΋&@Y: :@YHRd@YV]@YdACH@Ys@Y@p@Yvّ@Yh@Y],w@Y 6@Y9O4@Yd%@Y@Yض@Z1M@ZT!=@Z @Z+A@\LHI@\YH@\g@\uc54@\a(!@\/GV@\ʪ@\Ɯp @\5@\WrG@\q~o@\f]@\񤤸 N@\e۝@] %}@]㍁֠@]( )u@]6Z@]D]@]Q4z@R'iׁ@R}@R'mc@R7<@RGwe@RW,R?.@Rgi@Rwt=0.@RJcB@R f@RI@Rz@Rpw@R,y>N@R݃8f@R@/@SC(@S/V@S$/@S4.Qq@SCȲx@SS^< @SbN%o@Srz@S~@SR@S'_@S|Љ>@S'R@Scs@SϧӲ@S7z@SM@U \?@U5Wr@U@VPZ@VM&@V,m>@V;E7)@VJɣO@VX<@Vg6.@Vv$5@VM@VH<-@VՉ9T_@Vf@VQO@V C@Vޏ@VsK@V$`xa@W @W|zQ@W'$iE@W5aSA@WDk@WS fH@Wao½k@WpA:@W~Ev@Wl{@W.Y@WP6@WM,<@WǢ@W)@W 0 @W/O%@Xʡ(@X+HC|@X5K@X-V@X;m@XJ@XXsn@XfEV@XuK @X-F@X#@X}\/@Xc@X=r@X˙؅?@Xڿ@XKi@XMͯ@Yk@YD7i_@Y!@Y/ދL@Y>(It@YLo"@YZƨ@Yh]@Yw8/@YwJY7@YB@Y+@Y%+@Y[_&@Y̏B*>@Yȑ@Y-|@Yt@ZHe|@Zq v@Z!d,@Z/Q@Z=z@ZLJE`K@ZZ @Zh@]s 8b@RG*'@R7Y@RGQ|@RWm@Rg ǹ@Rw @R@Ru-ȵ@RKU@Rd4@Rfu@Rְ @Rrlv@R/T@SjE@SLœ@S%H@>@S4QL@SD@ST4 -@Scϩ|@SseA?@S@Sޕh@S @SNKK@S^~@SЈe@S& @Sp'@Se)@TG@Tgl%F@T- bo@T@T=)@T=dL@T}+@Tރ/@TL@T&T@TVb@TrC @URV_@Ut`M@U &@U0@U?*^@UNAϿ@U]Sο@Ulc+B@U{n@Uw ܢ=@U{@U|$^@Uz:4@UuIxj@Ul"@U_2@UOR7k@V<ʼnd@V&e=@V ŸJ@V.@V=Ͻ)R@VLj@V["@Vj\@.@Vy/uE@V6G@V̋^U@Vy'6@V]Yr@V!326@V uq@VO@VZǜq@V}\@W Ǻrg@WyԚ@W*) 39@W8c! @WG~;N,@WV%K@WdcT@Wsjp3o_@W]@W:#@W=N@W [@Wfd@@W _H@WمR@WYje@W蛪@X}@X#@X"#k7@X0{@X?r2 @XM@X\ MXC@Xjt3@XxH@XbIy -@X@X9@E@XoP@XwL;@Xit"G@X @X(Bs@Xm@Yݚ@Y4@Y%c+@Y3@YB,SZ+H@YPzB2I@Y^[ @YmR] @Y{Vzy@Yf@Y@Y`@Y\@Y˜<@Yp@Y /Y@Y@U @Ysӌ@Z 1+(@Zqt@Z&>@Z4,?*@ZBU i@ZP|S|G@Z^ey@Zl4%)@Zzd@Za@Z uc@Z;0r@ZS,K@Zjbe@Zvs@ZݒH&@Z'9$@Z@[ch@[&6@[#O@[1ڑ@[?ᅬ@[Mkq@[[l@[iƈ^@[w⪖@[޶+e@[*{@[MO`@[݃0@[o@[˯f@[٠ o@[1t@[}A@\i@\S@\;@\-":@\;nBG@\Hꑸ^,@\Vϔ@\da@\r@\f 1@\@ǺP@\d@\m4i@\ƚ|2@\Ś@\l@\=F}@\ X@\.@] @]pC]@]&8W@]3/<@]AhG@]OJ 4@]]K@]k Y@]xˊn@]/@]EHR@RgQ@RW _@Rg&@RwՓ@R@R'vm@R4@Rv*J@RMƚ@R1@R{4@R`@@SuI@S2@S%c@S5K@SELm<@STb1 @Sd0CK"@St;9@S֊8K3@Sm,"@S*k@S@Sff@Sљۈ@S6@Sz@T @T~@T.@T.V3@T=@TMX d@T\{H@Tkh+@T{*\@T{.@T3zӛ@T6 -`@TV>@TǗU[T@TԂz:@T %@TC?=@Ut߱@Uo5@U"ȟ&@U1 `U@UAM@UP4e@U_Pg<@Ung[X@U}{n@Ur @UxzT@U@U@Uȫ}@Uת@Uw@U~/@V3g@V~h@V"sݺ@V1^A@V@F!@VO+TWA@V^ @Vl޽=G@V{3@V-@VrxM@VD=d@VDS@V#oIr@VԦ{@Vl$ @V.sc/@W@Wf@Wcf@W-G@W;V %@WJ3C@WY-2ύ@WgZ@WvHw@W&7jg@W@Why@W&@W!$@W8gJ@Wy@W_@@Wt˨@X|:@X i@X%Z@X4)?@XBJ,@XQ,G@X_hݿ@Xne_@X|n@XMJ@XqMGR@XL@XP$@Xļ <@X&@XӜ@Xc@XUb4@Y 0y@YP@Y)nE#@Y7Nuke@YF_@YTrmE@Ybĉq@Yq^2@Yag@Y>@YOu@Y=&Kj@Y+@Y/t@YhYF@YBsqY@Y~SN@Y C@Z a@Z%u1@Z*XaL:`@Z8 γ@ZF @ZT/U@Zc>@Zq9<~@Z`c@Z-l@Zq@ZȪX@Zc@Zs@Zn>@Z7Ǩ@ZNb}*h@Zc6@[ vtm@[T.@[( y@[6  @[DO>&@[RvW@[`܄@[n~K_@[|"-@[c@[ת&@[ @[-@[¾m@[з5@[ޮn@[e@[;U@\'Vc@\wSX@\$e9 @\2Q^l@\@;@\N$lЯ5@\\ ZZ@\i@\wi&@\f@\X@\tVS+@\QIm@\,@\}y9@\7t@\Jss@\􇸑T@]Z}#@]+Q@]/HD@]z@]:=@]}n/@RQ@Rws@RA\@Rp@Rl}@R :@Rǚ{0@RweR@RNM&@R aN.@SLfX@S/W@S&w@S65v@SEa{@SU=JU@SeQ9@Stb&Շ@S@SAdQO@ST%@St49@SG4+@Sҕ_@S@S㺳@T$@Tp@T @T/$jO@T>Tqc@TNf?_@T]@Tm/p2@T|,@Tv@T>@T/@T;T `@T(IjS@Tnb6 y@T簍 @Tu'@U)=D@U_@U$I@U3X@UB۩@URg [=@Ua8B!@UpXv_x@UuI@U@Uf8T@U?>@UÒ@Ugk@U@UٰK@U1g1@VMPt@V @V$q@V3T@VBO,qE@VQsjt@V`"@Vof *^@V~H?@V(GHC@V @Vzm@Vs@VȇnU@VW+@V% @Va^@WpW@Wzl@W!; |4@W/$F@W>N%A@WMl@W\!y@Wji,to@Wy G@W0ڽڠ@W @W ht@W&sJ\@WQq@WgF<@W1֝N@W;~@W3s$@X Ǐ5H@XYj+@X(rQh@X7t&e@XE'!@XTT+@XcH@Xqϫ= @X zkC@Xx@X#)i@XxX@X*@X` 5@XQ&N@X?9@X@Y! @Yzs@Y޽Ӥc@Y-@0 @Y;:;a@YIsZŃ@YXXX_y@YfL@Yu3@Y[0ڔ@YY*@YZˤ@YI@YӔ@Y@i@Y#{@Yh@Y<@Z2wv@Z'/+l@Z c$@Z.#@Z<ԃtR@ZK /@ZY<φP@Zgm:(@ZuPZ@Z1i@Z`7@ZzO@ZD;/@Zh @ZʋH@ZجZ$@Z 4a)@ZûN@[\W@[E@[2`@[-Fk@[;Y/@[Ij@[WyJ@[e,@[sv~@[.@[c, @[ 8@[֨X@[v@[Ǯ@[խ**C@[㩝ϥ,@[A2~@[۩@\ D*@\`p}@\)|W0@\7n+Z@\E^~@\SLS@\a9@\o#0n@\}  l@\@\ٟKc@\wq@\9@\€r@\^:9@\;^@\lh_@\7ݞ@][P@]$@]#tpx@]1GK@]?q:@]L̂s@]Z5@]hԩT@]vP ߟ@] \@]+@]Bn@]m2@]0:@]jv@]ֲkg@R'@RQ@RʮW@Rz` @RѻaԖ@R׹T9@R' b@Rw@SOx}@S! O@S&(@S6Cx:@SFzh#bx@SV8e@Se˧h@Su"X@SUP3 @SQ@SA!@SGzo@S:8@S{5@SIт @S3@T(Z63@T*@T!/vۻ@T0@T@%+`@TO}gz@T_ @TnuR7@T}T@T@R z@To@Ta2@TQP7y@Tʤ"@TK@T?@T;@Uy '@UQY@U&DZx"@U5| _W@UD`L@US7@Uc jR@Ur5I#7@UZX@U{@U@U@UrP@UݒF@U0~s @US_.@UUd6@V C@V Ad@V'H۔@V6m {@VDy;@VSQW@Vb%9@Vq&e@Vƀ @VB! k@VЁ@VeFǷ@VC*p@V @V?r@V3K@VW@Wkm@W6 {"@W#,@W2ľ2@WAYG@WPG]@W_M3@Wm)@W|t8,@W(@WL1@Wd@W4ڴ@WF@WԂJ_@W&@@Wcg@Xde@X#t@XVUa@X,.%'@X:Ng@XIQ՝m@XW߾!@Xfk @Xt)2;@Xy\]@X@X~x%O@X]g@Xy#-w@X@Xi@XQw@XPv@Y+[@Y-uY@Y"W @Y1Yz@Y?fi@YMʲJ@Y\,|@Yj(uh@YxqS@YBSq@Yu9@YNS@YC v@Y3T@YFrt@Y18@Y{Dq@Y%L@Z \2@ZNe@Z$A;@Z2v@ZA @ZOH#N@Z]6@Zkco@Zyw$|@Z!s'0@ZRZ@Z0U(@ZF\@Zس@ZeV@Z(!@ZL@Zoa h@[ R@[I@[#jF@[1(>@[?@[Ng@[\*}9@[j=8@[xN@[] d@[k7=B@[vu@[ @[@[̍9@[ڑЀm@[蓣HU@[p@\aDP@\@\ :@\.@\@SM}U[@SDaG@S4Ю@T2e@T\b@T"1X8@T11܃@TA:TU@TPr:@T`1@Toj @TjR@T6:S9@T@TQ#@T4UM@T R@TecMJ@To@T 1@U U<@U)o@U'Gi@U7"S@UF_$@UUEL@Udsb@UsJ B@U+N@UUz@U|I@UhYp@UШ@U"WC@U ť*@Un'm@USff@V #.@V-m@V)4P@V87~ T@VG7N4@VV3ƽ@Ve,ʴ @Vt"r{@V_@V\@VkC@Vٽ=@Vxr@V͢ g@V܁|@V]@V7 uz0@W 3{m @WO@W&c@W5}uX@WDGT@WS?`@Wa @Wp T@WR^j@W @W[K@W|l@W.~@W@W׌=}@W6,O@Wm>s@Xd3@X%]@X (@X/a/@X=&@XL@X[(d@XiM@XxJXA@X^?VR@Xaϟ@X@Xotg@Xқ@Xr @X@Xk.R&@X"@Y Z^)[@YJ'@Y&?s@Y4ܳ@YC$`@YQx@Y_"O@YnSPb@Y|r @Yk̻@Yu7@Y?EF@Y,7V@Yăx;@YU7@Y,߇@Y}oH@Y#!@Z }+@Zbˎ@Z(j@Z6^@ZE4LJj@ZSv=PZ@ZaV@Zoc@Z~./o-@ZgDYF@Z@F@Z%h@Ze&&@Z6-}@Zelc<@Z@ZUEj;@ZP@[ n@[0@{@[(S@[6sD@[D`[?@[RŎe@[`0@[n3@[|}DT@[qF@[!|_@[2^@[Aą@[O@qZ@[Z2@[db;m@[l*ڱ@[rA@\ v3t@\xyP@\%xp @\3w?@\AtmGm@\Oo{n@\]hT@\k`A!@\yU Y@\IW@\<3@\,/V@\q-z@\zwb@\H@\g*@\Pd@\D@]@]rKY@] T7@@].3@]<\Z@]I@]W[=@]eR=3@]sx @]Nc@]"@)@]@]tu@]I"@]c %W@]/;@]XT@]-@]m@^ Pe5" @^@R,l@R. @Rdf@RU7_@SV@SŨ@S'x 1@S7y̌f@SGQ»f @SW$[@Sf@Sv|3 @SeJ@S>bhK@S~q@Sš~@S^B@S @S w~i@SSl@T/T(@T]@T#|0@T2'm1X@TB:֦ӣ@TQs/@TaD9@TpÃݢ@T=`@Tms@T%h"Wx@T@TDw[@Ta{{g@T™\@TF@Tx@U ͱ_/@UT@U)ko@U8 m@UGl@UW;@UfyN @UuC|@Ur!s@UGMm@UJd@Uu2@@UTO@U%U@U`X@U @U1@V ,rA@V>+@V+M$@V:X|&@VI`~@VXeY6@Vgf}N@VvdN@V^ @VV î@VJIAD@V:Ko@V(@,@VFy@V@Vݿn@V@W jn@Ww^6@W)N z@W8#[@WFp{@WUÄPG@Wd @WsW @WurU@W=1@W4J@W]Y@W?p@WΉ?@Wڂ{*@W4ϻ@W @X(R@X8BO@X#ߊ{@X2k @XA$ه@XO\@X^^і@Xlƒ@X{ @X"@X̃%@XB]W@Xγzh@XXK! ^@XXFe@Xc=@X @Xeg<@Y q@Y]FoK@Y)#[@Y8JҒ@YF@YU.X@Yceoˮ@Yr ymX@Ys/l@Yڋ%{@Y?W@Y@V)@Y栌@Y`L@Yּw@YFa@YmF@ZHյ @ZR.D@Ze=@Z,𙴹@Z;B<@ZIJIu@ZWG@Zein@ZtHO@Z\1&[@Zb)@Zu>f@ZmNo@ZLM:@ZɃފ=@Z׷6>@ZxH@ZD.@[IM@[v0Ui@[I@[,9 @[:aU@[ID@[W6҂H@[eWh~@[sv _@[WK@[wܩ@[Ie@[0^"@[/S@[H}_@[}Ө@[%v@[3HR@\>@\Hy{@\P#@\*V@\8Zܦ`@\F]KI@\T]˵@\b\}@\pY=̄@\~U@7@\N7@\FF<@\n@]]@]j+k@]xО`@]@]%a6'@]d懍@]; jj@]t@]@]ٳf@]烸&\@]Q87@^a@^@^A]@^,{C|@^:Ax"@S@R64@S O[@SXiF@S'ңE@S7}A@SGBd@SWz@SgR#Z@Sw&@SU<@S15@S;@SA<@S2@Sձm@Sb#_@Sjj@TV@TYI@T#@T3pRL@TC&|@TR @TbC \`@TqJ{@TOnl@Tˠ@TI@T@T3u@TΡs@T ڧ@Tq^/@Tڢ:@U 1?@Ur,G@U*1*@U:3& @UI]{@UXSO@Uhx@e@UwU@U.>-@Uӫ@U@U9W@Uioc@Uҕ@U=@U<@Vh@V"4ޅ@V&l@ZMM @Z[v@Zize&@Zx1@Zx @Z@Z[M@ZB@Z)@Zͽf@Z~@Z1QFi@ZgK@[w(@[@["mHa@[1-G@[?ZI@[M0@[[!No@[iӒ*'@[w ;@[{ @[;ʉ@[Y:0X@[v_Ѯ@[y@[̩8@[޺@[G@[C@\Y@\ )I0@\!NE@\/#k@\=, @\K4g@\Y;y@\g?w=@\uBZ.@\B0@\A7O@\?%J@\:`iq@\4Pq@\,C@\"x@\.&~@\ Q!@]6l.@]x@]נ@]*Êw@]8oEw@]FNơ@]T}.5\@]bbc)L@]pE#@@]~'@]]}@]u]g@]ù:0@]΁@]xh0@]QO@]'G@]Y@]b@^ŰX,@^r7_@^$@ @^2 6@^?f|@^Mo=@^[k@S' @S>Μ@S'"F@S7t@SG[(@SWCA@SgY Z@Sw{kj05@SSN@S'40@S U@S3@SƄB$!@SD k@Sd@S8(E@TfH@Trg@T$Yb@T4_i@TCi9@TSl@Tc.X6@@Trx*@TL @TՍי@TYhZ@T_+@TUC=>@TCVW@T@G@T@TK@U لv@U@U,Cɤ@U;:@UJ||@UZH}@UiL@Uxa@U*;!@UmGf@UU@Uf%@U" F&@UVpp@U㇮@U8@V:@V'3@V '4@V/F@V>b2#@VMzKPt@V\@Vk)@Vzzw"@Vli$@V9@VGny@Vü@V@VԺ ]@V㱃1@VoP@WDA@Wa |@WlXeJ@W.S/D@W=6l@WL|@WZ-2 @Wiϻ%~s@WxCK@W{-@WMZa@W@WXP@W°Uh@Wv*@W9@W2`@Wo@X p@X(q@X)@j(@X8I@XG>/ @XU @Xd1|@Xs< <@Xw֔@X9k@X!S~@X?@XWѦ@XZח@Xك'@Xh@X&@Y2p/@Yǁ@Y"Dq@Y0r@Y?Lf@YMNq@Y\KUMX@Yj;@Yy@) @YlX@Y+0@Y(Ң@Y `g@Yz|@Y/ @YMz@Y쳼|@Y@!@Z y[gk@Zؾ@Z&5.ʸ@Z4L1@ZB_,@ZQ?A@Z_@Zm@Z|5A@Z_@Z@Z Y@Z_HV@ZäN Q'@Z5a@Z(M@Zf!@ZOXaN@[ ;x@[P=@['L0 @[5@[Cr@[Q@[`&@[n>aj 8@[|h| @[@[fNy@[:Y@[B@[Ս#@[=\2@[Z,@[tJt@[6d@\ X@\M#@\%D{@\35R8@\A@\OT3#@\^!L3@\lt@\zA_@\ I@\$$e@\&@\'0m@\' @\$y/@\ #B@\ =@\9@@]c@@]_ٻ@]!^b.@]/^ @]=<@]K @]YT;L@]gK:@]u~Gm@]e睈@]Kq@}{@]/UH@]&&@]3<1@]1F&@]֮$:{@]T+@]d} B@^=KxW@^ @^l @^)>3)@^7~Os*@^E`.ȸ@^S/QaL@^` @^n@^|wN@SGk@S7FO@SG8J@SW*@Sg8@Swaʔ@SaY'j@S|C@SU$@S([@Sp@S@S憥@SFլ@T:t@Tߚ k@T%jt@T5@TDjh@TTdq@TdO2rV@TsRo@T5iY@T@TU,@T^@@Td*2@Ty@Ta|@Tџ7s@TMޣ_@Ue@U)݂@U-?@U+@Zeg@ZkG6@ZǶ "@Z]c@ZExA@Z:@[SWjc@[ ځ@[LQ4 @[+3H]@[9S'@[GKA"_@[V1ϣ@[de˕@[rꎩ[@[w@[FO@["w '@[L'@[tX@[Ǜ9@[տ8$@[C@[uC@\!ܟ@\=i@\Xn@\*qL@\8Io0R@\Fg-@\Tg@\bs@\pў$@\~X@@\>@\SVG@\}\@\7@\7S@\ ȡ.@\ er@@\ +6@\ a8/@] J@]?2@]&''a@]4ж@]BL-?@]PI@]^Ȏ@]li @]z@]j@]} @]g=@]Naf@]4n@]c\@]@H@]8@]{8@^Rq@^uw\(@^!Pe@^/([!Y@^=\@^J*݊@^Xh͋@^f}d@^tN8wR@^v @^G@^[ޞ@Sg@SWN@SgM]#{@Swka@SӂA@S2@SL{@S}@SV*Y@S*>b!@Sa @SÞo@T\@TI˵@T&d@T5{v+@TEn}@TUt,@Td6@Ttjp@T M @T#@T=N@T9@T^w-@T0@TnOER@T[-@Um~K@U9A/@U[-@U.+@U>8?2@UMt O@U] ^@UlfН@U{Ë@UYi@UqC΅@UON!@U3@UX]@UמQo@Uv{E@U.@VY@VѴ@V#$va8@V2b@VBk@VQG1ے1@V`l @VoL@V~@V@V8D@VJ@Vd@V /\@VU@VQU@V!Z@W $@Whi@W$@W3 @WA @WPオ]/@W_u@Wn>'@W}B@W@Wp@WM&@W(Vx@W@W= @W~Z&@WtaSg@X@"@X*@X ݙq@X//@X>RB @XMry@X[hh@XjP3@Xy7uB9@X!z@XP@XF7@Xx@X˜ov@X=fmR@X߸z7@Xk>@X@Y H@YN?@Y(Ks@Y7w@YFfY@@YT,' @Yc qH@Yq;(@Y/{@Yi @Y4L@YU@Y0f @YȪ@Y"^6@YDH@Y !ӗ@Z{/@Z8{r@ZV8@Z-#@Z<'?Q@ZJpE@ZX[ @ZgP|@Zus%{@Z @Zd'[%@ZdX@Z@Ze^wu@Z˶5a@Zy@ZR$@Z`y@[ 2@[,e@[!q \@[/h;@[=Z0@[L1腯@[Zn@[h-C@[vA_(@[N{}@[JW@[|`1@[jr@[w@[4@[0LV@[Xԁ @@[ @\U˺@\Ų<}@\ $b@\/@\=!T<9a@\K<0@\YTQS@\gk3@\u#@\r@\1b@\q]@\[=@\ZY @\ً~p@\@\CB@\`F@]n <@]b`@]DC@]+2@]9_@]Gr@]U p@]c)@]q"vC@]I@]km@]4@]4@]zlt@]e@]OWR@]7*v@]Z @]@^ $8@^)@^&{ @^4f۝@^B`C@^P;q\"@^^̄&@^kH@^y@^u@^jA@^<7@S}B@SW;@S+@T9@TŖA&@T&T9@T6LK7#@@TF;@TU s@Ter@Tu!-Z@Tc@Tp%@Tv@T0Ѭ@TD$Y@T @Tg@T_S@UxUV@U<@U x@U/{@U?h94T%@UNm@U^GoY@UmL]@U}]D@UxJ@Uո5L@U/q@UK&@UK@U%{Ã@Uo3)@U@Vp@V8@V%t1{@V4Lq@VC]]@@VS c@Vb>-g@Vqgê5 @VֽJ@Vmpo@VώB@V?z@V(@VmPN@V)I@V8(b3@VC 6@WJA@WN_@W&Px/@W5Mr@WDH\@WS@g@Wb4Xl :@Wq%eV@Wa@Wso@WV@W\@W0q@Wʌq@WgDp@W@Ç@Wy@X镟B@X4@X#5@X2Ql@XA7@XO(@X^Z!@Xm]v @X|ر@XӍo@X;c @X>.gh@Xjh@XŝR3@XIΜ@XN~d@XC@Y=rR~@Y޽_@Y}oD2@Y,{@Y:Cj@YIJ7@YWރ$@Yfpp )@YtS@Y=@Y7O@Y1@Y$2m@Y-@Y(|@Yڦ=@Y"@Y}@Z;(@Z1v@Z"nD@Z1j@Z?Sє@ZNCb3@Z\@Zk @Zyx@Z@Z;3/@Z'@Z%q @ZNo:@Zϥ@ZgΦ@ZM^@ZY82@[R@[:@[%Cg@[3 l@[B1@[PW]@[^u@[l~g@[{y8z@[Si @[Ph@[3@[b_@[.C@[`-@[ސ@[쾧ʘX@[*@\  ~@\<.%D@\%by@\3,@\Ai^@\O@\]X(^@\lCO@\z@\8! @\O@N@\d@\x;9@\@@\ΙwT/@\ܧ\2v@\t@\1@]Da @]WJ@]"5@]0.w@]>֣=Z}@]LY@]ZSn@@]hГJ@]vaH@]d@] ߦ@]v@]1}@]>6@]ʆ@]uW1@]beS@]M΁@^7@^RS@^5_@^+@^9]@^G~@^U@^cnlk@^qKvcs@^&t@^AR#@^سLM>@^R~U@^eB@^W:@^)독@^b? n@SF@S]?@Sva@SYNc@S6@S׼7E@S86O@S~vs@TXIV@T,y@T&P@T6Lj&@TF@TVNr@Tf , @TuÑGQ@Tv3@T%/@TE@Tu+C@T @TӳmH@TKt@Tha@UoY@U)@U!@Z5,@ZCx R@ZQQ:@Z`YXo@Znƌ'@Z}1wQ!@Z6@Z!@Zd!}@ZƔqT@Z&FH@ZӃñ$;@Zor@Z8)6@Zb@[ ߘ @[6$@[)LÍ@[7Xl@[F!@[TkkO@[b9D@[p@[= U@[zh@[D)f@[m@[8oO`@[rnٟ1@[Ԫ S-I@[|@[@[ECE@\ u @\ʷ@\)β @\7Jt@\F ي@\TF@\bjۼp@\p @\~@\:]@\ݬ@\e@\O n@\3`ce6@\H@\\`@\m@\}bN@] ]"{@]R@]'k@]5@]Csuk@]QR@]_s@]m}@]{iC@]/@]Pl@]8@]?2@]4@]ϖX@]݊m@]}ߧ@]m+>@^\@^I@^#5%7@^1@^?.nM@^Lg@^Z5)@^hb@^vѱI@^z9@U"x΃@U2+e@UAB@UQ @U`1c@Up j@Uۥ*@U@UdHd[4@U|@U6@U̚е@Up@UT:|@UJ1"@V /@VPP@V(C@V7@VG*ُJ@VVk͗v@Vek,@Vtk@VՑ@VL @V|@VҴ@V$0@V"Q@Vr@V4ya0@VO@W fg0@WzY@W*ZC@W9ThV@WHi/@WW?%^a@Wf}@WuF@W4@Wa7b@W|@Wb6@W!F@WmX^@WXn1@W@_p@W$@X 4;.@X[@X(g(@X7>Ej_@XFo@XUBD@XdMFo@XrE[9 @X@Xq. @X5 @XA@X@Xs @X-6N@X4~6M@X2@YJ}@Y D@Y#W?@Y2O]@Y@ o@YO{)B@Y^@\Ď.@\6im@\.)'@\N@^`6q@^mT}n@^{׻oqB@^BZ;@^0@^@^dLp@^C|?]@^!-@^* @^׬G(@^mH@_ 7@_]_@_"2K5q@S @Sl@S;@S櫅,@TԞU>@T>8@T'hcj@T7V@TGZZ@TW/EZ@Tf{@TvYB)@T$[ @TT;C@TJB@T{BJ@T~ց@T.j=E@Tٝ=p @TY|,@U"@U;@U#Z*b@U2n @UBk@UR ) 5@Ua @Uq @UIb@Ug?@Us@Uu;Z@Urt+@Uz&;\@UF.@U쪷><@U -@V gkg{j@VXaF@V*ٞ@V9eއ!@VH,@VW!Q@VgB#@Vv@VÕ\@VU>:@V6{dy@Vj֝@Všh c@VO_@V*e@V)@V9Oi^@WX|z@WtK!@W,۶@W;ゟ9@WJ4@WYHw@Wh͖A!@WwթSv@Wچrn@W3Y/@Wڶa@WI@WR)@Ww;@Wെ@W龜V&@W}x@X yn!@X__@X+BU7@X:"VI\@XHefh@XWو:@Xfl@Xu+]@XVIr@X%=a@X (@X vc@X=Ӆ@XCh^@XT-@X@@X}sS@Y 50y@Y뽫@Y&bf@Y5OTq@YC'3@YRYֈ@YaP@V@YofR?@Y~V@Y;0B@Y|;t@Yu@T@Yee@Yǥ>@Y9@YGD@YZ@Zy,@Zq @ZH1@Z-0'@Z<1@ZJ@ZY#`p@Zg~GlS@ZuJS@ZoVT@Zᅡ@ZW7B@Z1>@Z6E^@Z̢m@Z _?c@Zs%@ZKm@[v@^Ɗ#@^m-b@^NH&o@^-_@^ ́i@_ 9Ϯ@_ub@_'s&}@_5tBh@_CJpK@T_W@St$q@T]p@T @T't@T7z@TG@TW#@Tg[^&@Tw0b@T`[@T9Ns@T[}Ѡ@TV!/@Tm@TM@T傎|n@T2A@UiG@UB?@U$(@U3'@UCa+@UR @Ub.@Ur )@UBmn@U$P@U@@U"]e@U@Up@UހwGe@UK@UV3*@V 5@VY]@V+y@V:'[@VJ(p@VYz—@VhKM@Vx^@VZ@Vv@VuA@VJe@VRI@VӇr@Vxi@Vu@Ws @W8Ch@W[ʓ@@W.|+/@W=.1@WL@W[u@Wj@Wy~c@WMAx@WgsC@W O@W %@W ew@WL32@WW@WH@X[IT@XڬZ7@Xv3X@X-@X7I @X&[@Xa@Xc@XP;@Y 1j@Y8 @Y)y@Y8>#@YFìJl@YU @YdTP)@Ys?@Y-@YRqy@Yf,@YW@Y9vn@Ym@Yqn@Y !,@Yԟ@Z3WXy@ZBt@Z"R u@Z0f6$@Z?hn@xv@ZM0g@Z\t@ZjA@Zyw%D6@Z!@Zpb7V@Zӻ@Z`YV@Z\_@ZG$!@Z޷"}W@Z$K@Z]'@[ Yu}@[`ϟ@[&łrP@[5('^~w@[C@[Q @[`C @[n>@[|ީ@[J1@[3uW@[ e@[?@[ČtEf@[׷Mq@[ ʈ<@[hyv@[1a{<@\ H.@\1Z:@\(pk`@\6|`A$@\DS@\S!K!@\aXϛ@\o@\}8+@\1U@\!FC@\OUA3@\zߍ@\Ĥ@\C:@\"O{\@\!@\8DK@] XP@]v4@]'ۦG@]5[貭@]CPw@]Qu9/@]_e@]n[M{@]|@])\@]7W@]C@R@]N#%@]W~@@]^a@]d>$@]h @]jͻW@^jy@^i/@^$f.M@^2a@^@[$@@^NS@^\Ir1@^j>Vy@^x1'l@^"Q k@^Rī@^x>@^f@^O@^E;S,@^٩ @^*O?@^s%@_V@_80@_@_,h^@_:2w!@_Hr@_V+q@_d`^@T'Ƞ@T{b&@T'R,C@T7@TG'{J@TWUk@Tg@Tw@T\_=@T2R@T7@T@TƖ@@TY^=@T>@T:[@UYo@U6@U$'@U4Z[@UD.N.(@USYǕ$@Uch]\2@Ur1a@U̹[w@UOK`@U/~@U.ry@U@U-T37@Uߧ4@U&ơ@UP@V SGQ@Ve @V,˃$@V<-@VK-E@VZG'@Vj@W"z@W-W @W4d&@W89@W94[@W7w7@X2C (@X)/r@X!@X0?"x@X>ؐ`@XMqz@X\@Xk@Xzo\nV@X{:@XXP@X2 @4T@X DԬ@Xݎ:@Xӯ@X}2@XIP@Yř@Y&3@Y~gN@Y,]W߹t@Y;{@YI @YXQzQ@YgE-$@YuIL2@Y @P@YX[f@Y{@Y 7@YS|@Yx@Yܘ߾@Y7f@Y"\%|@ZnXq@Zngѝ@Z%a5-@Z4,c@ZBq@ZQJA&@Z_ ) @Zn^jkD@Z|'@ZiBu@ZC@ZjmEi@ZO@ZbJj@ZĹ@ZPg@Z@Z62@[ \@[|@[*~C@[8@[GMF/j@[USt@[dV@[rsŖ[@[ї@[-HT@[ƅ@[H\@[38@[Ȇ׭C@[>@[' @[t >@\@\h+@\N„@\,@\:m@\I@s@\WV#O@\e@g@\s͉C@\9N@\=r%@\r@\W@\'@\'+:@\3|V@\^8@\xI@]$_w@]@]@],h@]:<:L@]HZ<@]Vw<}8@]dB@]roC@]'4@]׈d@]"6@]@] {@@]SVl@]'@]2@];K{@]C$Q@^ H@^L6@^)N@^7O~4\@^ENYu@^SKJOX@^aG b@^o@@^}9@^/ @^$w@^@^ n#j@^uA@^߬"l@^ԯ@^C @^-y@_]5@_xs@_$\Y@_2@?k@_@"9B@_N@#J@_[)Y@_i9@_wIRr@_s˽G@TGv@T7@TGٜX@TW#F@Tgj[@Tw@T"@T*@T]\|"@T3F?W@Tqx@Te@T昵e]@T[@@U}O@Uԋrd@U%1@U5;/@UD׿<@UTJE@Ud4@UsӞr]@Unk`]@U$@U|@U'x@U z@U8w]@Uv@U9q{@U_\`@V)@Vbd@V. nZ{]@V=t]@VLۢ@V\>y'$@Vkl@Vz@VPL4 @VΥ@V8@V@S@Vlj2-@VθA@VZ@VNp @Ww3@W &@W""@W2#BB@WAPnR@WPy`5@W_@Wn1 tA@W}jj\T@WTu(@W%x@W+Sq@W=tHq!@WL\2c@WX]}@W`E^@Wed@Xh?֜*@Xgd5p@X#cqF@X2\m$@XAR\-L@XPECδ3@X_5) @Xn".J@X} @X]@X Oߕ@X/@Xo@Xq[o\@XJR3@X7{@XO@Y @Y*@Y Z)@Y/"h@Y=k9 @YL".@Y[iM@h@Yj&5@Yxr4c@Y 2]@YLrD@YQE@Y -@Y\.Q|9@Y K@Y߮@YT6T b@Y%g@@Z Xo@Z5|:@Z(@Z7ig@ZFgԣ@ZTy'@Zc&A@ZqXg@ZB,@Z̞&@ZTͽ@Ze@Z]Žg8@ZD@Z]@Z[@ZT>@[Mx@[Ad4_@[s@[.%P@[_@\M5gX@\[y!N@\it@\wb@\;_/@\xYy@\Ό @\բ@\"~@\W] @\ۊJZB@\M5@\j 8@]>@]B,C@]"llL@]0G܅@]>[q@]Lݣ.@]ZL"@]i(w@]w>M@]Z֍@]u@]R9@]~@]C=@],@]b@]+@]N_s@^ S@^ T@^ @^.'\̑@^<-PL@^J1cj@^X3ű@^f4y@^t3@^0X@^,bع@^&`@^G@^@^ @^c<~8@^F:U@^@^;''J@_ O@_\V@_)!]@_7z 6@_E`첞@_SF@_a),=@_o #_@_|Y@_a>@_ᾔ@_q8@Tg旷@TWV@Tgx@TwIU@Tխ @T!V@T@Tkm@T^WN@T4 @TNZ@TҶ@Ui2@U^atq_@U&[EZ@U5&.@UE@UU?W-@Udy@Ut=̭@U93@U|@Uu3 @U X F@U 6@U0VX@UH@UB^~ @VeX@VDeI@VfoQ$@V/6p#@V>AU@VNx@V]@Vl9@V|O?4@V#>"@V Fs@VcԽn@Vc5,@V m@VV]D@V砖@V &@W)b^@Whv.@W$8\D@W3=x@WCa@WRAʌ@Waod@Wp3tb@W@W䫬@Wb@W"G|@W;Ӻ@WRX@We]@Wua@Wy]B@X]u@X*sx@X%oL@X4JM@XCRS@XRYP=@Xap6@XpyM@Xjs9@XYe+<@XD[I@X,@X 3 @XE@XD@Xեh-@XI@Ya^@Y5r9@Y#oV@Y1@Y@n>@YOk( @Y^1@YlO*@Y{W=@Ytp@Y0b>@Ynz@YGN+@YS>@Y9K@Y~ΞW@Y_[/@Z @Z r@ZT}_@Z+o, T@Z:@ZI2a@ZW_%f@ZfenۊI@ZtUF@ZCs@Zh@Zvy)@Z9|׸@Z#@ZJp@Zf{P@ZRQ\@ZYv@[P]g@[,@[#E@[1<@[@16/@[NY~@[]@[k\n@[y @[Xa=@[y@[&"ZLI@[z8@[1L@[I7@[ަ!@[vN@[Z>1@\ M:C@\q9z@\&W1@\4\@\B @\QC\$@\_ie.@\mն;+@\|@\`ON@\ۻ@\?Pb@\!U:ʛ@\]O@\ј6@\о?@\X@\<F@] n}ۣ@]@]&Ϊ|.@]4řs@]C' 9@]QP__@]_wr@]mW@]{dfA@]e@]G:@]!fp@]>@]YQى@]rQc@]މ@]v@]{@^ğ @^ y@^$H,G@^2"@^@@^OTc@^] R@^k@^y r~ @^<@^ou(@^@^)@^ Y@^ HhS@^T@^ܧ@^6z@_yΟ@_D@_ Ǜ@_.]x@_<ڙ@_JH@_XyUU@_fb|o`@_tIO@_/@_ @5@_yG@__m@_?@_Ǔ"2@TW@Tw'@T|L@TpTb@T@Tk(@TǤ@d@Tׄ*̄@T_Nѕ@T5R@UnV@UԀҲ@U&H<@U6`׵@UF 2L@UU@Uev#@UuCr@U u@UO@U?C%,@U8@U|`@UwL@U⨫! @U8@Vif @VL(8:@V 4@V0Om@V?JG@VOC@V^<}@Vn& .@V} ho@VV* @V_P@V@V@VvW@VtD;@Ve#@Vlf@WlNA@W@W&B$c@W54v@WDÚ@WS<6@Wc-|,@Wr_Jn@WC@W|@Wb@W%g@W(:V@WFc@WaJ9`@Wxq@Wf/@X 5V@Xe-J@X'@X6ty@XE$@XTŽ@XcE}׳@Xro@X4]@X7@XZ@Xz}@X|!@Xe%@XLnvb@X0;ky@X')@Y8@Yr@Y%@Y4xtb@YCKE@YRQs@Y`!@Yo,d@Y~{U@Y@'t@Yy@Yd@Y?@Y:D@Y偭@Y*T@YY|@Z @Z~"Զ@Z b~$b.@Z/ U@Z=0?@ZLT_~@ZZWVm@ZiqC@Zx/'5@ZzG@Z`@Zf@ZZ@Z@ZϥM@Z0+H@Zhz@Z?yS@[ +@[F2@[&Ųu@[5CQ@@[C@[R6p5@[`oF@[o!/@[}o@[@[qj k@[ @[F;5@[ŭc=e@[d$r@[u@}@[ @[4(@\ 6@\R@\*Cy@\8H]Y@\FAy_@\U@a @\cv@\qރU@\*s@\t8F@\@\Iz@\F0b5@\Ljk@\g@\f{@\C{@]}d$@]" @]) @]+ rI@]9SP KT@]G ah@]U\y@]cմ"@]r @]4Q*@][ၮ@]\(j@]$Y@]lA@]CG@]3@]"03@]<fE@]Uء@^ m:j@^ku@^)tid@^7sء@^E!tR@^S@ @^a}@^o/\@^}[Q@^Os2@^VM@^\S@^^ Fo@^aj@^x@^s(@^>@^y@_ O@_B@_%׃e@_3z@_A)@_O4@_]Ѓ@_km^@_yww{@_a@_JJ@_2;sM@_5T@_W@=z@_?+@_R@_@T(@Tw%t@TB@TD@T/h{@T׿R@T@@T@U`Cc@U6Mq@U'@U6Ck@UF $M@UVcF@Uf# @UuA@UR @UG@U_@US]@UD֏@UK@UW-@Uɫ @Vq@V@x@V!oj@V1Ua@V@8J@VPZj;@V_ @VoODU @V~+/@V4p@V7+@V F(@Vp>{@VЍ@V/B@V@VKѕ@W 3#~@W^'#@W'Ru@W7T@WFZ V@WU@Wd7=r@WtMq[@WI*@W}38@W b@Wً^u@W]@W(F@WK^e@WjWVl@W\F@X 'T@X@X)&@X8e@XGt5@XV|@Xe_s@Xt.Ѿ@XD@X@XWɌW@X SL@XQI@Xń.@XݳVI'@X;@X:y@Y kV,@YM؂@Y(,@Y7 b@YEKJ@YT@9@Ycm@Yr_tR@Y.k@Yxyp@YõP{@Y@@YN]e@YRm@Y6h@Ye@YC!sP@ZY@Z}@Z#_e@Z2M34@Z@ V@ZOdl@Z^ rQ@ZlfCN@Z{S߁[@Z@Zpo@Z,N@ZAB@Z[O@Zp@ZZ@ZM@Zߊk@[ 'Pķ\@[m@[*59G@[8g@[G9UyA@[U!/@[d5}v@[r#L@[( )@[6w@[ J@[0@[4@[_+r@[ʕB@[3`@[O@\ZB@\`L@\0@\.[@\<{m@\Jk;@\Y-Vt @\g2@\uI@\(Pg@\x=>@\:6[@\@\[P@\ˣ^_5@\a@\,A7@\n~ @]U@]{@]!(z @]/be@]=D;C@]K@]ZT8)@]h7 @]vhiK@]&@]a@]r$@]B_@]?@]e* @]وk@]Ъ@]@^G`@^ַ~@^ I@^.9}L8@^\`@Uu@V_O@V"@V"!p@V2IG@VA\1 @VQ_hE@V`u@Vpeɨ8@V⭤ @V[ۑ@VC@VB%r@Vr|@VWfj@V܀x<@V@ @VA6$@W a@WH@W)GE@W8G@WGY @WW-]@Wfr@WukS@WbQM@W.v@Wfs@Wb:"@WENa@W@W#@WI%@Wmy@X m@X N@X+@X:ۭĐ@XI:r @XX)@Xh V@XwЕ@X#4F@X"%0y=@X#8@X! (@X=@X#@X9>@X3m@X#@Y (@YpI_@Y*jE@Y9e@YHj ;@YWGܖJ@Yf#@Ytb @Y>ט@Y]@Ys7s@YA.@Y &;@Yӝ@Yܘș@Y[~w$%@Yw@Z2y@Z27@Z&K^7@Z5M6@a@ZCR@ZRdxA@ZaX@Zo)tEx@Z~g*b8@Z ,=@Z}!@ZR@Z\^@Zǎ@Z(nh@Zϻ@ZV!`ׇ@[,F@[yڼ^@[/I@[--z@[<@[J4P@[Y*C\x@[g "͘@[v-F @[Řk@['‘% @[ׅY@[ ~ͭ@[Y C@[v@[rba@[ pf@[M)@\ ('@\ gOS@\#}2@\1ꒊp@\@L|Gu@\NLè@\] @\keuh@\y?Ӕ@\M9@\l? ,@\v@\w@\`dQY@\ϭe@\I_@\BN@\"@]ϛ1"@] @]%TP @]3Q5@]A@]P B1@]^GՁ$@]l,V>@]zŧ@]"@]K3 s@]L{B@]{a^@]'@],߅@]2̱@]#|+@]H@^l{@^W@^$n ^@^29@^@}3@^OGt@^]Q@^k4@^yJ*p$@^]@^p@^~@^/p@^-`@^ͧz@^۱x@^ }@^RE7@_@_cW@_!:9@_/ӓ@_=@_KdT@_Y5 9@_gi4@_u0@_@_oغ@_E-@_|Ή\@_l:`@_Z\E@_F2@_1B@_tm1@`l@`t @`g^7@`Y?@T#x@TM@T6jh@T3S@U֮@U2@U'.f@U7[@A@UGb#|@UW9Ew.]@Ug $Z@Uvٻ@U$䥃@Uh&@U(f@U"h@UŜ0@UO| G@UxE@U-[@VO@V@V#}D@V3)՝t@VB-!@VRQz@Va.@Vqhsr@V,/@VpWi@V-G @VhyѪ@V5D@VPv)B@Vݾt@V)@V@W @WSAT@W*K@W:V^#@WI[X=2@WXy@WgsН@WwDdG@WӃH@W;@W Fu@WIV@WÁ@WҷBٖ@W+yG@W+-@XC/-D@XjY@X"e@X-@X@Yh=8@Yw1q@Yb=@Y;2@Y:+o@Y47@YC@YІ`=@YR 2@YA@Y€X@Z <@ZhJ@Z)' B@Z77ƽ@ZF @ZUSο?|@ZdC@Zr.2@ZiF@Zv<҂@Zk_@Zhٞ@Z4=p@Zʱ12?@ZQ.@Z @ZG# @[$‰@[eR@["PhC1@[0N@[?rze@[N$@[\8@[k!Z@[yĺ@[@[#!@[ ;@[@[֘-N@[ВK*@[ @[~@[@\ al%@\Ϝbm@\';EA@\5v*@\D N!@\Rr";@\`ր>Le@\o7@\}O@\@\Oˆ@\/@\!c8@\U:?X@\ӨNJ>@\^ٲ@\Hn]@\K#@] @])~@])p!>@]76@]ESDU_@]T:=@]bz ~]@]p,@]~H@],ΊU@]d[@]Ú@]ΓL@]Ľ@]1ֹ8@]_I:@]EP4@]"@^ !%@^X@^),F"@^7Pc@^Er:ҙ@^SK4~@^a@^o#l@^}25@^b@^L@^-[@^A@^SQ^@^da^@^s%4}9@^8/@^x@_ W?@_f6@_&W@_4@_Bu5@_P!4@_^H@_l1A~@_z-@_Ʒ@_3[t@_O@_9Ι@@_~݆@_qH|@_cn@_S_x[@_A@R@`M}@` I@`k@`"@`QT)@`%@U&g@T@UH@U`@U'*s@U7 @UGhC@UW@UgcP@Uw:mt@U 5=@UpE@U(@Ujh@U+8@U@U埯X|@UShv@V Le@Vt@V$T@V3QM@VC[fQ@VS0@Vb?""@VrY#@V @Vr;@Vy@V{ˉ@Vt8u@Vt3@V@V^)@V7i@W 8B@Wdu@W,jz<@W;dm.@WJv6@WZ@Wip Xj@Wx񣭑@WQK@W[,@WS@WoEs-@W&p@Wcl=@W㝐^xl@WTyE@XMQ@X6Z5F@X b=@X/4@X>lζ@XMc_@X\CR@Xlb@X{(V2@X>$P@XPR@X`ci]@Xlߐ(?@XvJ|@X|@Xʠ@XX4 @Y}@Yx3)@Y ou@Y/d;0@Y>U=+@YMDP$@Y\0$@YkeZ@Yy=Ih@YCg@Y ?{@YĪ@Y{^@YSo3d@Y)_*@Yzk@Y&@Yu@Zd/8@Z,6F>S@Z+ @Z:^@ZIttA@ZX2&@Zf̌@ZuM@Z[e@Zs@Z@Zmlm@ZE&@Z@Zj.O@Z~6@ZTi@[P"s@[W@[%(@[4 z@[B$ѱ-@]܅-z@]ᔺQ@]0OU@]-}8.@];ٽ@]J6Lh@]XW}@]f}z@]t*I@] w@]_~pR@]\ʮ@]it@]蚞@]I@]H@].; @];@^q1@^C@^pa}@^-Ͱ@^;=@^I4 @^X@^f4!r@^tU,/%@^u䁠@^A.E@^@^˕k2@^@^)@^t)@^% @^7,@_HCv,@_W@_dB/@_+o@_9y8@_GT@_UDi@_c%@_qe5#@_g@_La@_g@_0.H@__c<@_Ł!>@_y*@_pg>@[ j;@[g-`@[(|0S@[7N+Y@[Exn@[Tems@[c6@[q/@[Dg.@[ԤI@[bÝ@[޵Y@[xw@[\@[ׅoO@[@@[k!@\'<@\d`@\ol@\.uJ@\<f@\K^}.@\Y)H@\h?Vi@\v*.Qs@\"@\qx@\ç@\Kq=@\ F+@\u|@\mxH@\~ @\#噋@]|E@]Ң@]#&F@]1y[WŜ@]?ɼe@]N#@]\d@]j;@]xi@]>44@]6@]ţ1@]}zy@]Eq@]΂i.@]ܽW-@]@].pM@^dݼ@^ %@^#ɰ@^1$ @^@(w@^NT|8 @^\"E@^jԵ@^x@^Z}@^yh@^9X@^YsU@^w锲@^͔pߚ@^ۯ; R@_LHK>@_ZS%j@_h]k%@_vfDF@_l@VE p@VT`7@Vd_x)p@Vt?gl@V{@V>~pf@V( |@Vi$y@V @VфpI3@V I@V @WWu@W6_.@W3@W.x@W=]l@WMVX@W\f@Wl%>*/@W{7I@W1@W@VT@W]@W4G1@W;Z5@W׈Y@W6MT@WN=@XYO@XCjG@X#ئ_z@X3 @XBAF@XQrc @X`@Xo @X~&@X͌x@X:i@XXJb@XsnH@XʋrD@X٠[V@X.z|@X(@Y̨a@YY琇@Y$ @Y3ݼn@YBxF!@YQA*@Y`!q@Yo u@Y~4@YH @Y֯@YS @Yra@YX%M@Y;Y@Y*@Y/@ZWkf@Zoc@Z"ӵ@Z1T@Z@$U@ZN@Z]d&@Zlͯl@Z{JP"m@Z :h@Z͑ܺ@ZXCK@ZF]@ZF-&@ZӵsY@Zi ݝ@ZPs*@Zb@[uFC)@[ũ@[+r,@[:ke@[I :@[Wdm@[fK۠@[tC/@[P<@[D@[gy@[=y]@[=ee@[Z>'@[.@[n@[2@\yٴ@\-@\#|+l@\1|9@\@u:@\N@\]f4@\kI_"b@\zN87-Q@\8@\-gB@\=a-#@\p@\m ~@\R"@\7@\황@\PV@] W̅Y@]?@]' ;I@]5eL@]CȌ@]R3!@]`aȜ-@]n@]|v5@]L Є@]<:@]}Iʐ@]$,@]i= @]ҫI@]^8@]+,A@]gt@^ Z@^#@^(U@^6H]b@^D|\A[@^R!H@^`3R@^o Hm@_VOi @_Yμ@_[C@_\m@_Z- @`b @` s@`c_@`@`U&@`&@`-Қ@`4@`;HR@`B{Q(G@`IrAd@`Ph7(@`W^5nf@Ug.\@UW@Ug}!@Uwpr@UפO;6@U"@UO@U(N@UeҴ@U=Z@U]@UoSe@V@VqKx@V&3(м@V5𱐖@VE*@VU^$q@VeZ0l@Vt9@Vd+@Vr}@V @VE4؝7@VK/@VqcFQ?@V,]@V5s@WC@W_vd@W E@W/@W?@WNB@W]62w@WmdZS@W|@W5e@W+pch@WWQ0~@WR @Wɪm@W@WP< @W 47@X.8{@X.cø@X%r!>B@X4LDW@XC@XS']e@Xb]@XqI @Xk@Xۙ@Xu@X:Q76d@X\ @X|/@Xۘgm~ @X걂tWa@XDžd9@Yui:@YW @Y&1"w^@Y62@YEIa@YT @Yc <@Yr 2E@Y@Y}Y@Y0hX@Ywi@YfQ@Y@Yګ@Y!U@Yw@ZXGK@Z7,!@Z%@Z3@ZBõ:@ZQY@Z`i@Zo7wQ@Z~@ZW|w@Z4x0@ZX{@Z0 X@ZWk/@Z֕!@ZP  @Z@[@[oJ$@[ j@[.wy@[=xQ@[L!I"@[Zǃ!@[ik@[x s@[Uu@[I4:@[㹍N@[{U@[Ʋ<@[ϥTV@[6-@[Őr o@[RD*/@\ ܵXr@\d @\&l7@\5nmA@\Cn@\Ropk}v@\`[Y@\og%@\}P\V@\V@\pH@\=,@\*y@\(o@\Ԉ.@\+ @\Y4B@\60@]#S@].}.@]*,q@]9Bri@]G a@]UZxU@]dO@=@]ry&@]@]J+ d@])7@]t[z@]3wm@]}\}@]VzK@] fi&@]OO@^,@^8@^\4@^,M`V@^:*G@^H@^V5Ҩ@^e-{@^s`@^\@^fR@^ns"@^rE'@^G$x@^oi@^֖ÙV@^=<@^\@_ @_ 3@_?:<H@_+[;@_9v.s@_GN@_U 3@_c@_q @_0I#@_@_KK@_Yԕ@_zA@_&<@_. Ff@_5ɗ@_:]@_>~,@` KT@` @`~@`D}@`"z,4@`)<@`0ۀ,@`7a@`> !*@`E5@`KS+@`R6@`Yxב@``f@`gܔ@U1g\'@Uwva@U0mm@U蓅Ѽ@U@U}@UǨwH5@U׉p@Uf.@U>I5@Ven@V@V&@V6s5@VF5([|@VUd#@VeE7V@Vub*Y@V! P@V=E@ViK@V@Vï19i#@VK(e@V|SQ@Vy%@W @Wʴ@W!@W0@W@%J@WO7K@W_@@WnK.@W~@WscA@W3.@WE`Ȏ@W6@W<@WeV/@W9J]@W>@Xe}$,8@XA#@X&!@X6F~"@XE@XT˄㚫@Xd @XsC,@Xz eԩ@X@X2@X ʭ@X5l@X[@XM@x@X쟶@Xߙ@Y 0<)@YJf0@Y)Tk@Y8S_\@YG!LHz@YV,D@Ye4?0@Yt9D:m@Y;V-@Y:zn@Y6N@Y0 i@Y&@Y $е@Y @Y;_@Y?@Z [@ZD@Z'KK@Z6t<@ZERGi%@ZT,E@ZcDZ@ZqGȑ@ZD@Z|@ZJc@Z/h@Zc7Q@Zʣ|AN@Zf)t@Z&ŭ@Z䔄@[ +V@[Y? @[#xH@[1v@[@td7@[O$[U@[]й?@[lz@[{"ĩ@[1j'4@[k<@[ ʤ@[<p@[F6p@[{@[w3,@[ :1@[)@\ /m@\_!W@\*I{@\8A@\GZ3@\Ud@\dc\!@\rً@\b5c@\#R@\YQ%@\~Q@\GK@\ɻou@\-9@\膮@\ ~@]um1@]m7@] FqN@]. |@]=^d@]Kp^G@]Y{!]@]h-M@]v5a~@]iBX@]8q,!@]l`@](@]2| e@]́{@]QyU}@]"@]dr!@^$̟@^@^"5ڝ@^0wW:@^>  @^LV=l@^[223@^ima2@^w$@@^q@^0\s@^E~@^v]@^_@^ԟ7@^@^+#m@^S|@_ztt@_"@_!5@_/r@_>@_L"}PV@_Z?c!@_hZ1N,@_vsN@_A-@_}@_o@_.@_Ǹ@_Fm@__9@_8x @_ q@`3@`F@`7@`@`q@`$;~@`+lP@`2D@`98/[@`@dM&|@`G$S@`NiƸ@`UDЛ@`\y[}@`crh@`jk@̮@`qcsL@`xZpK@U4J@U˺\@U@U Li@U$@U뽙@U+@U0t@Vg+@V@@V';@V6P@VF@VVu^:x@Vf8N@Vu4<@VCy:@Vf^*@VB@Vou@VnƤ@V@V;Kw@VRhd@W똯&@Wj@W"׾@W1@WA)7^;@WP%@W`0)@WoCe@W( &@W9@WvtH@WB@W>u@WU0"@W۹@WPO@WwtWL@X B@X'z,@X(z:-B@X7ɇb@XGhz@XV]@XeA@Xt?i@X#-[=7@X^L#@X"X2C@Xʵ;@X B@X*)@XU @X|P@Xm*@Y y@Y;@Y*}@Y:"@YI)IA@YX;S7O@YgJfV@YvW:H@Y`0@YfYޢa@Yi)@Yi:@YgG@YacO@YYu|.@YNDo@Y@?Mq@Z /k%<@Z@Z*cDz@Z896@ZGQp@ZV}@ZeV',@ZtlKh@ZEG@Z1>@Z)@Z \P@Z8@Z\X$@Z%M@ZQ@Z@ @[sF@[2v;c@[%Jt@[4;@[Cax1@[R@[`ny@[oz?\ @[~(M;@[[@[},@[$,@[~y@[jK@[ ^j@[A@[B9@\۰@\r.B@\dhA@\-Sek@\<'<8@\Jk{ĕ@\Y@Ձ@\gɐX@\vPOh@\u>@\W4@@\`@\Ub&@\;<@@\Je@\€X@\7:e@\Fj@]o(@]b@]#I{v@]2c㱥@]@̝,p|@]O3}f@]]TYT@]k#w@]z[@]@]}@]rH9@]@]!V@]v 6@]ς@]\@]i5_@^ @^+H57@^&K} @^4o@^Bss@^QG@^_]3@^mMB@^{죖 @^*n@^RI@^(.@^~@^R@^* GC@^[h]@^ @^8 @_ 0ΐ@_"½@_&7T@_4^u @_Bc@_PׅM@_^sxs@_lY66@_{@_# )w@_=ئF=@_Vf@_nl@_5A@_ϘU"@_ݪ- 0@_뻣M@_%;;@`1&@` )G@`R,@`gJ-@`;n@`'@`.\@`5@`<@`C{@`J鷝@`Qy@`W7 @`^@`ensf@`lcM@`s얃͸@`zҸn@`޵z@`֤@U6@U"h@UN@U'Z@UU/@U1i@Vu@V,W@V'h`E5J@V7A@VGb6U@VVCk'%@Vfdg@Vvw2@V:G@Vs@Va@Vj@Vf3@VR@Vs;L@Vɉ@W4?@WXp2@W"U!@W2i'@WBI+N@WQFm@Wa2hsmy@Wp{n@W;:@W@W4Є@WD@Wߢn@W͏эye@W!pZ@Wd@WB@X +s%@X\ϓ@X):G@X9;'w})@XH5@XWS'U@Xg+@Xvu @X @Xi7`@X=w@Xy$u@X±j@Xy@Xʮ+I@XH@Xtӛ"@Y1@Y5:@Y,崗@Y<@YK!j @YZ:^j@YiP@Yxdf@YtAF@Yu @Y@YM@Y×[!2@YҘt|@Y`cU@Y|@Y@Zd@Zu+9@Z,eugz@Z;S v@ZJ=ޮ @ZY%X!g@Zh E@Zv=O@Z9$@Z&@Zh@Z]yjL@Z2@Z^G@ZeԳ@Z@Zm}@[ 5 1@[@[(Ar@[7t!%@[F=IK@[T|daU@[c`,@[ris@[:<@[ϟ$n@[k@[,Pw @[־m@[@[$ @[mUE@[i:.@\zy@\@\"?BSN@\04-)@\?l4@\NCC@\\g=,V@\k Lf@@\y~s@\7g6܅@\܋G@\Es!@\Ʌq@\K285@\ʵ-@\H.@\I_@\<_A@] Wt@](3n@]'F@]6 Gf7@]Dz=d@]R.K@]aQ@j@]oh@]~ @]s@]@]G(%\@]+kl@]w@]\H(`\@]ⴵ@] .@]_8#@^ K@^N@^*QS@^85DZ@^Ft@^U2}l@^cyC@^q$w@^W:@^CL@^@^|| @^_@^7 @^p(2@^?'3@^ېkN@_ħ@_?Hg@_oH%ݐ@_*d@_8E3@_F4p@_U@_cBLޓ@_qgLdr@_ @_&@_r@_2x@_&@_!:@_:s@_R9 @_g=D@_|v@`GNy^@` O@`WaI@`^3[C@`"d6Hi@`)ikjg@`0mӣ@`7qoX@`>t@@`EvG @`Lwп @`Swy@`Zwam@`av]m5@`htC@`orr^@`vn+@`}jo@`ex5@`_=n@`YY@`R%*@U9R@U @UXD@U♄@V؎7@VÉ/@V'@V7W@VGi:@VWB+Ő@Vgi@VvF5@V]M@VzΛ-@V=VIB@VN@VŷN@VmM$@V H&@VqK@Wx T@W~¨@W#;4@W3_T|@WB@WR@Wb"]܌@Wqvk@W;i@W@WEG@W,2^@W@پ@Wθ߽@W-$v@WN B@W h@X tQ @X6 0@X+<7@M@X:fi@XI@XYN!t@Xh(@Xw @XA@XG@X ٘@Xqe.@XV@Xӓ@Xsd@XҾ@Y7<8@YgTM@Y?5@Y.e@Y=> @YM-AM(@Y\(@YkE@Yz`JJMY@Yw@Y#@Yu@Ym{@YŶaqD@YԿ1x@Yİ$2@YI}"@Zo@Z@ZUK@Z. @Z=g{w@ZL @Z[Ń@Zjudpp@\M@]:7l@](O@]+-^c@]9!@]HM@]V(@]d@]sh%Ԅ@]ԸA6q@]>L8@]JP@] d׸@]px@]af@]2L@]@_@_Vg^@_&jO @`&oa@`E@`Ek@`X@`6 @`$.@`+Y;l@`24j{@`9BI@`@ۃ3@`G@`Nl|@`U@`\W@`cll@`jqC@`q1Tp@`x,@`bl)^@`@`F@`mc@`ؗKP@`@`̨e@V;@U@VЮC@V;@V' @V7/~]@VGn7@VW{{8@Vgjw@VwC9@V@VdZ}@Vy% @V|EK@V?m@V!@VD2e @Vq?>!@W$@WӔz@W$}%@W4$E?@WCn@WSeM@Wcx|@WrZɶ@W*\~0@WLl@WD܅@Wif@WP3@W@E @WL# @WC@W:Eh@X @Xo@X,@X;K&@XKMkߊ@XZ Y`@Xj 2@Xya唆A@X*k@X +1@XWRk@XT*@Xn$@X.1:@XpUo@X@YXJ@Y $](@Y!Tcba@Y0sF@Y?[^@YNc,{@Y^ @Ym*N>@Y|K85@Yj, @Y@Y~@^ε8!@^Ϊ7D@^O5@_@_1@_% +@_3:P@_Apc @_O@_]נJ@_lz@_z75k@_eQ-p@_"w@_~@_c"@_ @_.y@_R >@_sxTb@_^@`@` QZ@`fR@`^J@` uL@`'x@`.!Uc@`5+밲@`<3v:-@`C;OE@`JB4g]@`QHM@`XM̨L@`_RF@`fUn@`mXŜk@`tZ(Ҋ@`{\Mj @`\5@`\]C@`[ʴϸ@`Z Lu@`W2@`Tc@`Ph#@`K2@`F.@V'>s@V @V'X@V7<5@VG3@VW6M_q@Vgq1@Vw @Vjuq@VDD@VDyo@Vr@VƶKk@V~d@VBBR E@V-@Wm2^@WtH@W%(x@W4A@WDj@@WT)I@Wc̾Rv@Wskr@WH)/@Wn@W2E@W @WM*@WsV@WZּ@W7R@WX8[(@Xѐ&1@XGD@X-[<@X='@C@XL͠6@X[5c@Xk^0H@Xzv@XvW#Y@Xt@X9@X@Xms@XֹF@XeR=@XG!A@Y9q@Y@Y# @Y2< @YAq?bi@YPFx@Y_'bx@YnFo@Y~&b5@YLX@Yn͔7@Y@2@Yl3@Yєg@Y9G@Y"3@Y"Q@Z e;@ZO9٨@Z$ D@Z3"{@ZB$ G@ZQ$@Z@Z` TU@ZoY(@Z~@Zy@Z6EU@ZA)"@Z3~@Zȸ6"B@ZןeCR@Z悰d@Zc@[A@[ʟ3@[!1d?@[0&=\@[?@[NrS[@[]A@[l E;@[zf@[n@[bą@[$V@[n=@[ġz@[\e@[l@[ )@A{@`Ey^@`L l@`Sl@`ZFDux@`a4 t@`hX[mU@`oS$@`v@0*@`}]@`<@`=R@`ίG@`[Uk@`BˣC@`fzz@`/ @`e @`B@`_q@`ʾ5n@VG@@V7@VG|@VW\Ϲs@Vg7S@Vwċu@VaOG@V}@Vk@VEMy@Vo@Vt^@V@V~Pim@WDO@WT@W%sf@W5xMg@WE+#@WTۗ@Wd1׍~@Wt.9@Wv(@Wr05]@W@WR@W:&dA@WgƇ@WVhYs@W߱j@Xdw0@XĆ@Xc@X.ݼ@X>T@XMp@X]6"O@Xlπ@X| @Xn-@XŔY@X--,@XO@X BW@X2KY@XylYV@XRC@Y@Y_3@Y$xX@Y3֌)@YC[3Z@YRW@Ya/@Yp{@Y@Y_^(@YG@Ymc8@Y j@Y˱zZ@Y]V@Yb'< @YF:@ZV#@Z&7@Z&5 t@Z5AS@`:79@`=Eh[@`?V@`A.@`Aͬ1@`A;@`A˛@`?u%9@`=*@`:׹^@`6S*@VgCx@VW@Vg@Vw} @Vn?@V߭5@Vz@VcT@Vlm@VFS @Vɛ @V@Wn+@W @W&GNJ@W6l A@WEåw@WU{m8>@We/@Wt @W&@W3*@W@WxXz-@W@Wҭ-&{@WAr@WҶ@X_Ѡ@X/i@X n8^@X/h$@X?oC@XNȵ@X^`I@XmV0@Y Q@Y@Y<+@Yg%!'@Y͎@Yܳ/ z@YԦ?@Yɞ@Z X<@Z'u@Z(<P@Z7O?X@ZF^@ZUk0&@ZduQ@Zs|ʷ@Z@ZW@Z\@Z|-!@Zu0@Zk$I@Z_|u@ZPE@Z>W@[ )%/@[l @[&u9q@[5ٛ@[DN@[S#ͦ@[bvJ=@[qO>I@[%3@[sԅ@[ʼKE@[};@[e?u@[/yU@[@[练N@[}Л@\=/@\,@\"4p@\1n@\@%T@\Nء@_j@@_xwx)@_ @_B [@`ϴKQ@`ֳgM"@`ݲ"&@`캈5@`s@VE` @Vw<@V9@V)@V٥]@V28@VǬO}:@V׏@VmW{i@VGU3@W =@Wsg@W&U@W6gl@WFIq@WV E-@WeƴH]@Wu5e@W3~Н@W q@WGH@W9v@Wݹ3@W~o@WH @WLN@XI @Xd@X!h3@X0Ps@X@x6 Y@XOmQ@X_z`|@Xn<@X~mr/@X@XR@z`@X]@X(r~@Xˏ%.R@XE@XQ%)@X Z@Y O@YZ[q@Y'@Y6q#@YFF\R@YUY @Ydy@Yt#@YR@YS@YF -@Yr@Y,@Y[d]E@YކI@Y-e@Y#@Z tł@Z@Z*3l9@Z9L8@ZHc[@ZWw7W@Zf@ن@ZuU@Zܷh@ZU'@ZUN,@Z\@Zk3@Zϭr@Zާg@Z6a@ZO@[ ?ڃ@[tt~@[)af@[8KI{@[G2'@[V@@[d:@[spbи@[46k'@[c0@[g&!@[<7L@[@[ޢiY@[۬$/ @[w(@[?@\S@\c[U@\%C@\4ISvB@\C @\Q@\`w0 r@\o,aC#<@\}6@\+@\=["_@\M@\501@\:o&6@\`O{@\ @\"tS@]DY@]\P@]=F @]-D,@]<#(@]J_@]YGM@]g†@]vbYs@]-b@]u@]GJ\@]X'@]O@]́/P@]j@]zi@]Z^@^k)@^ll@^$Us@^2Ƒc@^A6@^O @^^$o@^lxu@^z(<@^EK@^b@^  @^jps@^Ȫ@^$@^~0@^ֲ0D@^,@_ Ah@_Ӹ@_'$R@_5sb@_C4s_@_R o@_`TE @_nV@_|I$w@_%6@_gSi@_L /@_廪@_"e̖@_]J_*@_oU@_2@_{@`,@` (@` #r@`l@`!9@`)Th@`0%|+@`79}I2@`>Lےm@`E^A(@`Lp~ge@`S,7@`Z]@`as^@`hJ@`o'f@`vNƀj@`}i@`@`N7@`*@`Sw@`'!F@` 1@`tԊ@`co%@`@`c/@`!eF@`$'|L@`%u@`&P@`&>A@`&,C@`$@`"Ni@VH_@V];@V,@Vx@V>^W@VŅW@Vs@VR@Wn#Lp/@WHU@W'@p@W6Bl"@WFad3@WVc@WfKɎ@Wv :$@Wɻ"A@WZ@W7v@WSh@Wĕ:+@W>2z@WDc?@Wv@$@X!ފ@XX}m@X"QD@X1F@XAqSR@XP]@X`@XpN@XZӜ@Xa#@Xy8W@XĻ\i@X`w @X봰m@X8D@X)}"@XAn@Y b@Y[@Y)3@Y8na@YGN@YW)>2@Yf\wL@Yu%@Y=s@Y-T@Yl>}@Y'y@Yf@YP:@@YJW?@Yy@Y}4@Z T%@Zu @Z,}@Z;:f@ZJWI@ZYrwL@ZhI@Zwγk@Z@Zf@Zˤ@Z%Ms@ZH@ZY@Z߱xS$@Zݹw@ZF7@[ ш@[W q@[+oޯ@[:9@[Im@[XY@[gl J0@[vQ8D_@[4a@[]@[n_@[3@[\@[~B @[Q@@[#%}ؤ@[eI@\ 0@\@\(OX^@\7@@\Eֹ k_@\T@\cTm1C@\r+;@\Ȑ.Ǫ@\ @\3<{'R@\Dͫ@\q@\A*Rt@\옛|@\-S@\;{@]߄V-@]LI,@]" @]0$eJ@]?Y:H@]MI@]\ɝdw@]kHeq@]y@]?t@]@]Y@]\@]j@]z1@]s>Ja@]3^˶@]tp=@^ ~@^l@^'.`@^6\ڕ@^DӴ@^SD,F@^aŖ@^p$N@^~S' @^5ԥ@^e@^aK@^2 {g@^ƕ?Ɨ=@^]@^UZ@^IOx@_m@_hq@_/w@_+ /<@_9j z#@_G/~R@_V x-@_dZE@_r^U@_Mg@_;D@_l @_{@_ U=@_MM&@_֍Ԩ@_V@_VJ@`Bh@`ȍ@`\x@`K@`@`$'@`+?60@`2V<@`9m@`@ģ@`Gw19@`No7!B@`U@`\e@`c[(@`jbI@`rݏ@`ya@` ]@`-\@`:#-@`E@`P@`[. s@`dU@`m@6{@`uN@`|/dP@`Ƃ}WF@`͈UE@`ԌŒ!D@`ې³@`#.@`r@`'! @`E^Z@`LU@a@a so@VJG@Vv@V.L@V۩@V @V$@W7@W<q@W'n@W7IR@WGv@WVab--@Wf@Wv2@WN'@Wr|@W̹'@Wfg@W;6VV@W{S9@W^@WC8*@XfC@Xl@X#(EF@X2Q8m@XBX}@XQ!-@Xay @Xq@X@XZ&@X#^@X 12@XA@XȠr@Xm̫@XS@XGd@Y =@Y:D@Y*t M@Y9}3@YI+/k@YX]o{@Yg֤m@Yw&@YrK@Y]@Y$5@YFm\@YÆ7@YÀ6B@YS-@Y4 y@Zg|@Z5ˑ@ZŴo@Z-*ZtR@Z=tL@ZL<N@Z[]cL@Zj| @Zy@ZELT@Z @Zy ;@Z߈@Z"\@ZR_'m@Z@Z @[i%w@[ M\@[ v@[.#@[$@^4m r@^t@^Xg@^֩@^] @^Ru.@^ع[_@^A=)@^'d@_'@_@ʱ;V@_ TY@_.ֆ@_=R8p@_KF@_Y3@_hRH@_v.*;@_Y@_Br@_n@_ه.@_"9w%W@_i`R@_ڮ:W@_bu@_30e@`rU:@` u@`9e@`ݓg@`0C @`&Khd@`-fz@`4K@`;Cf@`Bb.X@`IȨZ&@`P,s@`W@`_ rw;@`f`?[@`m0{r @`tBYK@`{T9d9[@`dx@`tznA@`J@`g@`Zգ@`LU_@` e@`@` d@`ց`@`,fL@`o@`-xB@`@`@`e@`?@`6@ayt@a Q@a U@a ʧ@a PʓG@VM,@V@V>@V@WE>@W'l$M@W'@W7@WGo] @WWJM{@Wg ~<@Wv҇Ɗ@WG@W@WPfxn@Wg@Wϰ^7@WՉL8@W>?@W@XW;@XH1hM@X#-'@X3S /@XC.\@XR9@Xb`u0@XqƔB@Xy@X-j@X:F@X[@X~GW@X@1@Xޒy @X@X{]Eq@Y 0^@YV]@Y+Y2@Y;#]@YJ;|1@YYq@Yi>RL]@Yxn@Y*@Y;,0@YE@Yzx@Yˡ@Y^\@Y@Y=C@ZK@ZP'b@Z @Z/-@Z>Xh@ZNǻ@Z]8rc@Zl]5@Z{T\u@Z@Zk5&@Zkw@ZS@Z06@ZGNA@Z>G@Z+\A@[3S@[9B@[!< 63@[0>@]Q39@]@]~ps@]0@]ס:@]0|@] 3@^G{L7@^ҾW@^ V6;@^.?[}@^=\Ye@^Ke1@^ZZd^#@^hY@^wPF@^/s@^>@^@^#x@^ h@^@^mɟL~@^կ+@^?o`b@_:@_ [hSP@_$lI7@_2*Ԯ@_A+U4@_OHx@_] z@_l;#E@_ze@_!37n@_;uU@_öT@_ܜcu@_*t@_v{n@_-@_ $@_O@`Sp@` ߳0@` b@`,S_@`!K=@`(iH}@`/v5@`6(@`=;Ё@`D@`K%@`S }c@`Z#@`a:_@`hQ'@`of O@`v{l<,@`}R@`dl@`ۗ@`L1@`ַ|@`[ @`.`@`˫@`.'y@`i@`)B@`4\v@`>C]@`Hf_X@`Q@@`Yp@``*5@`f %@`l({@aq_@a u^#@axp4~@a{,!@a| ^@a&}Y@a-~F/@WO9A@V (d@WM.@Wm@W'yc#@W7w',7@WGB @WWn@Wgpy@WwKEL@W!ݒ@W?jg@WB@W@WR@W{@Wҟ@W0@XBx<@X7@X$r'@X4M@XCU@XS+(n@Xc4@XrA@Xg`@@X@XCw@X0o5@X@X$㟷@XߦO7w@X$4.?@X]@YlI4@Y|N@Y,}@Y@\!f/&@\0@vU@\?@\M@\\s]Y@\ku|[@\z]@\(!,@\u@\@\z@\=@]WJr@]e@]tۅeQ@]@^@Ÿh@^OKM@^]ؘ{@^lPIE@^zϵS@^Mo@^ta!@^A@^$8@^.|t@^ѡغ@^:\@^{@^9@_ [I@_0&@_(,ԃ=@_6,@_D\o@_SXD@_aGoj@_ph@_~r@_ Y5@_%5@_|>]Q^@_s @_$#@_u?@_Ě*\@_'`@_]lo@`p6@` Cs@`5@`=\@`#^ X@`*@`11@`8h@`?9`@`F @`NG@`U0ؙ.@`\K0)=[@`cdI@`j}v@`q:U@`xvN@`6VM @`طB@`f*@`B @`M@`&,@`7n@`Hk@`X_1@`ga :0@`u۔`@`̓u*@`ԏ@`ۛxnT@`⦆x@`̧<@`K[@`d@`?5@a'*j@a ؒI@a:e[@a K@a!D@a(ꨑ@a/LC@a61Tߔ@a=Wg@W'Qۜ@W@W'[Q @W776;@WGڬ6)@WW@Wg<@WwRw@WqZ@Yqy@ZIvrɸ@ZRw/@Z# @Z3@ZBN%R@ZQT4@Z`@ZoB.@Z!]@ZN@Zy. F@Z0w@Z'@Zio7@ZG@Z @Z9s$@[Oc@[b}@[%rñ(@[4;ǒ@[Cw@[Rј@@[ajd@[p`^@[@u@[ AO@[Qq@[@[}{@[p*.@[_Ց@[L⨖ @[7U@\3 F@\}b@\#:WB@\2kg@\Ak@\P;,@\_X-9@\n/ )@\}s@\^@\{@\om@\9 7>@\nN@\Ŵ@\uib@\HD%@]R@]’X@]{@].2tɀ@]<@]K*?@]ZJT^q@]h:t.@]wT)@]MCc3@]l@]\Q9@]<Q7@]ܞj@]z@]@]ˆ4@]H\@^ ީ`X@^r9{O@^'@^5ܭ@^D 9*d@^R\@^a4jZ@^ofβ@^~@S0K@^2r@^Dl?@^@^?|x>@^ƺd@^3)y@^Gg@^-2l@_d9@_m;r@_qUIi@_+LND@_:IS'"@_HmȖ@_W-k@_e~@_sD2|@_C|is@_\@_ @_\K@_y@_#Z@_ewJ @_:@_ Y@`h<@`FV0@`.'@`"@`GzF@`%koya@`,8@`3P @`:@`Axw<@`I ,@@`P0@`WNfT@`^k׌ @`e@`l(%8@`sĵ@`z&S@`O@`˞X@`@`5DH@`JV@@`__l@`s3q@`62"@`k@`@`ȺiH@`4G@`4+@`i̓@`a@`v]M@` OӞ@`a/@a"@a,0@a4V}@a<7@aD#P(p@a$J=j:@a+PK-i@a2UdQ@YN.&@Y]BPZ@Ym@Y|fG@YK!@YTV1@YɌ@Y@q@Yul/7@YQ!^@Y%#@Yya3@Zɕ'@Z)z@Z%`s/@Z4'@ZCsS@ZS+1@Zbh @Zq\@Z%-@Za&X@Z? @ZmG@Zy3@Zd%i@ZU@Z 4@Z(,E@[ EiVo}@[_5K@['v( 9@[6EE@[Ef@[T?@[c(@[rÕ @[*@[tQ}@[7F@[GȌ@[¨\@[̻^C +@[۱l@[o8@[t@\bn@\oj@\&Xm@\5>+@\D""@\S$Tn3@\a S_@\pR @\)s@\psW@\EkQ@\ݞk@\,7@\ɵsT@\؀;f@\Ib@\Y:@]@]j@]"Tq(@]1‹@]?Nq@]N2kX@]]:ܫa@]keQ@]zܩ@]O䂗@]C@] b@]O2E@]v:Ʊ@]ҙ| @];aB4@] @]x,@^ \!@^@^*D+ M@^8tR@^Gk!@^UV@^d6u#@^s@^,2P<@^*Na@^ 9Z@^5#Z@^`@^7~=@^صP2@^1OC@^) @_$\^@__@_!VN@_/$@_=|A@_L_W@_Z^c @_i6V@_wi@_J0@_k!d&U@_X@_/'^y@_[N@_ѿ@_G0@_E@_@`P"@` dw@`@`"`@` J9 @`'py@`.MZ-A@`5 @`<Og@`D@`K#CH@`RE]@`Yejȝ`@``|Ҏ@`gp-@`nH@`u2u@`|DS@`}s@`/0@`Il|@`b#@`zio@`+@`RB@`+҈@`Xe@`#H @`GA@` MQ'@`@`,B@`< 2@`KI@`Y<~@`fW@asK- @a &@a;ˉ@ae@ag_@a&ۭhr@a-ޝИ@a4h@a;O!@aB[J\@aIX@aP˖&@aW @a^r@WgVu@WWi@@WgxK@Wwrޱ@W}p@WaFn@WgB@W. ?@Wr0@WN&e+@W%V>;f@Wpw@Xt7@Xi C@X&YV,\@X6EO@XE<9@XUCj@XeMaNB@XuM@X@X[>5@XVl@XV0T@XG,y@X#9@X|@X/@Y0t@Y18%@Y b@Y0BZk@Y?#@YOEݱ@Y^!ļ@Yn:I@Y}K@Y"=rmX@Yʞ{@Yڪk@Yc꧐@YO@Y)J@YnԤ@Y{@Z99@@Z@Z&޸+3d@Z6,-@ZEw85@ZTpԾ@Zd,V\@ZsD @ZP}@Z`@Z @Z+9L7v@Z][w@ZΌ`@Zݸ@Z8@ZBso@[ +X@[L/g@[)i$n@[8:@[GVL@[V%@[er@[tӊ@[M6j@[N4Y@[r@[H2@[$q@[E=@[I@[Z`'@[b@\ @\lB@\(C)4@\7'@\F$dBI@\UxQ@\d]Zc@\s@R D@\ U>*h@\CK@\޹@\l &@\@\[)#r@\,`J @\,V@\Ǐ/@]qF@]Y,J@]%kRϬ@]3Or@]Bqn@]Q`H@]`jǽ@]nՓKm@]}S@]A+@]Ҫ@]%,@]Sd#9@]g/l@]թ1@]P @]%#@^TD@^:W8k@^.4@^-u>@^<h@]@^J@^Y? @^gBBk@^veS?3@^L @^/=@^=@^mO@^ vf@^ͦN@^)1@^\ @^*!@@_n@_$&C@_$En@_3h*nj@_Aqk@_OƔ@_^pO@_lkjO@_{NTz&@_Q.@_$f3@_`@_' $@_WEk@_ѹf@_v @_yD`-@_9\@`b@` O=@` -^@`bB@`"E3W@`)n˨'@`0ˇ@`7%>@`>}.7n@`F t$@`M.uv@`TR:-@`[u@`b@`i@`pYsh@`wV@`AmL@`3oo@`P@`l@@`度@`5l@``@`XP@`-@`/:@``@`.yy@`CQXQ@`WS@`j@`|/^t@`@`As@`u@a܌c@a @a{M@a@a!@a(" @a0in@a7(@a>ƿAJ@aE E@aL(CM@aS.F@aZ4jI@aa9sŽM@ah=Vt@aoAK1@WX @Ww!;X@W5l@WQi@WDr 0@Wǭ@Wǯl@Wד2Lm@WszP+@WO T<@X&y@XƇq@X&qr@X6L[T@XF[D@XV%@Xe @XulI@XP~1@XO@XO@X`J,<@X~WH{@XӬY@XMqN@X것Si@Y 1@Y8@@Y!@Y1:X{6@Y@Dpe@YPLo(@Y_ЁD@YoP݉@@Y~d@YG0~@Y3@Y/z`@Y ,@Y Ϧ@Yss4:c@Yجx@Y:6@Z D@Z3@@Z(LW@Z7ھ@ZFSf@ZVBH@ZeNg@Zt"@?`@Zdlc@Z]@Z@Zؼ]x@Z>@ZG5@Zzd@Z*@Z@[ 0,@[)sR*@[+M!@[:oJ!{@[Iη@[Xwn@[gw@[vؾ,Zg@[C@[g6@[ hȋ@[r;@[s@[#Y@[&>}%@[&te@[#!\-@\ @\#э@\+ @\9:@\H6N@\W_X@\fY(G@\uV@\H=@\{@\]")@\;[=@\:i@\{l@\oN@\ݢ@\pGI@] @H,;@] 1"L@]'7@]69@]Ehj\v@]T,M@]bV @]qb@]jޢK@]%i@]cO@][@]H>@]|Na@]ت42@]WS_@]i<@^K4s@^Qk@^!z@^0ɑz@^?8"@^ML@^\rG@^k ӱ@^y:K$T@^9$S@^(Y@^^|@^@^z1@^ @^ߏ֛@^*24@^-9t@_ + @_('@_($@_6$f@Y@_E)>@_S5n@_bK6/@_p{nn1@_~@__GG{@_8@_@X И@X~T@YS##@Y1;@Y" @Y2!Cs@YAp@YQB z@Y`f)@YpVY@Ya@Y[=P@YB@YST8@YA7@Y=@O@Yܭ';@YH@Y@Z @ZK@Z):;@Z9@ZH` !@ZWPa@Zgb5@ZvW,,@Z@ZJ_@Z3a?"@Zve99@Z¶[>͂@ZH30@Z-07@Zd9@Z+@[i8@[>@[-"#!p@[@^練@^rk>@^@@_Eb2e@_ @_+1@_:d@_Hõ@_W&@_e@_t@_~V@_h @_k&*@_MO@_O @_ʽ䂛i@_*k@_ރa@_fg@`3&@` eۂ0@`M@`{|@`ilEN@`&'l[~*@`-U#@`4 ,@`;X@`Ba @`Jb@`Q.uA@`XW*l.@`_~m@`f[A@`mЋ@`t-+@`|~@}@`8@`[6i@`}Fm@`'>@`.@`]4Z@`@`3.L@`5ܔ?2@`QK@`l=@`цT)@`ؠ7m@`߸@`wA@`_C@`x5@`Æ@a'A$o@a :\@aMN@a_[`@aqD[@a&:@a-@a4t@a;٠@aB!V.@aIȽU@aPԫzU@aW<@a^'}A@aeT@alV@at;^@a{ z@at@a@a҄@W]+#@W,'R@Wd@Weϲ@Wۦg@WD@X@X@X'tI@X7Pt.@XG( m@XVY"5@XfB'@Xv'x@X_@X#@Xѱ@X5@XW׼@X 7?@X?N@Xi@YJ@Y0@Y#Y}@Y2@YBt@YR(@Yaԍd@YqKgR@Yp6@Y_v@YƆ@YfԵ@Y_@Y_YY/L@Y֤@YJ Z@Y Q@Z (]@ZJ,@Z*~@Z:\MGm@ZInA;@ZYV >3@Zhs @Zwɏ[t'@Z]c@Zm#.K@Z;o@Z:@ZK$L2@Zӎxu@ZY@Z z%z@[H[}@[$hd@[@[.!/@[>Ľ@[MA //@[\jf@[k(DJ@[zf@[,%@[[p!@[ B@[%ǯ@[;O@[MӢ@[]z^@[j 5@\t4@\|+@\ 36@\/ꓞv@\>*@\MQ@\\{c@\kr@\zh 8a@\Z*?@\JA@\8C@\#?!@\ u@\Yk@\!@\9@]6N@]pɂ@]JR߈c@]-!S@];O 6@]Jȱ@]Y`@]hfQ L@]w1 @]}@]¾@]PΫ@]G@!@]޽S@]= V@]O`@]8@]@^ RED@^U*P@^(@^6`@^E^ @^TPz@^bim@^qSX|@^!}c@^Ŵ@^5HY@^Ѭ!@^k󻞧@^!@^ך9@^.;@^-85@_Pg@_w*@_ iD@_.t@_={4@_L@_Zd@_ili@_w0@_p;@` r@` As @`v7b@`J @` @`( b.@`/>5-@`6mDQ@`=@`DʫxU@`K@`S#ɨĖ@`ZOr,@`ayS l@`h}@`oO@`v8@`~ę@`?yK@`dЍ@`*o:@`IN@`¢o_@`a@`'zz@`11@`P*1-@`ni&@`̋)l(@`Өfe@`&W@`߸@`.;@`x@`*(@`B<@aYv@a o3d@aJ3@a8o@a!LQ@a(%@a/Ԁ@a6 @a=6v@aEa`@aLW@aS W@aZ-3@aa:E@ahFT@aoQݦ@av\ "@a}eB(7@anc/@av35@a~ s@aV@aH:b@W_\j@W1JZ@WBإ@WO@X1@XȎG@X'@X7mZ%t@XGuV@XWQĹt@Xg)fۄ@Xv"@Xņ@XW@Xama@X&Qh@XQ10@XբYg@X[Bw@X7E@Y@2@Yn,ho@Y$7F@Y3nn"@YC_I@YR]@Yb9@Yr0 P<@Yó`f@YS @Yci@YixCy@Y@Yq8@Y@Yk@n@Y."@Z W*@Z9D@Z,6{@Z;|~@ZK1@ZZlY@Zi©o@Zy+f5@Z%+@Z!@Z1B_@ZC+$@Z&@Zx@Zbcw@Z[I@[.@['c@[!cDU@[0V@[?Ѡ@[ObO<@[^48G@[ma&@[|19@[]g@[֯@[+@[@[2};@[KT@[b@[u2>@\sBt@\8Q@\"q@\1~@\@@\O}@\^X`@\mԧ\@\|N@\/?@\z @\2]2@\]'@\n @\[B@\D,@\+@]Wk$@]v@] s @]/WZ@]> }@]Mb}"@]\8s%\@]k i @]y2&@]@]xw˙@]B6@] ]Q @]Գ'@]Ғ@]S@]na \@]νh@@^ @^@.̜@^*'ױ@^9~@^HZU@^W @^eGr@^t`@^ 79@^pn@^S@^ued@^E@^27@^ΐDv@^h0@^yTV@_2@_(w@_#MW@_2Hzo@@_@՞Bv@_O`@_]@_lp:S@_zK@_y"҄@_D5g@_ynU`@_u@_qL@_6dx@_b@_;@_KKUl@`ޠ?X@` Q@`Mn.@`l@`"{P @`)월@`1Ϊ@`8R @`?q1@`F4@`Ml@`U N@`\?@`cla7@`j)@`q×H@`xߊ@` @`?nV/@`f))z@`t@`f]=@`SI@`dU@` @`A9@`cy\@`DŽ$-hq@`Σ@`wU#@`]@`nZ7@`;@`6J7@`Quoڹ@ak@a@a",@a@aˍ @a#Č@a*Ď@a2 /U@a9?@a@1,G@aGCp@aNT@aUe|V@a\u6@ac+'Y@aj[̇ @aq@ڝ@axqС@aY"Ǡ@a"@a{@a׉@apl"@a蘃/@a+@ao@Xa6@W6_@X@X@X'@X7]j@XGzǑ@XWw@Xgv[q\@XwR4@X*@X#B@XaPCR@X@Xdt C@X(r[@Xt@XWl@Y^r@Yh*@Y$@Y4ru@YD4H+@YSъv@Yce_{N@YsJbo@Y@Y7TQ @Yӹ@Y\!R-@Y@@@YruM@Y@Y{̗g@YJ@Zw }@Zey@Z-d@Z<֭9O@ZLE@e3@Z[@ZkG@Zz}[&@Z@Z=Kx@Z|T@Z@ZEi6b@Z֗0%wC@Z݂y@Z1v;@[zQ@[[@[#+i@[2Aq @[A}y@[Psg@[_ḵ@[o!9v@[~RdH% @[9n@[-Z@[El@[+@[rA=@[:S@[Wa{ L@[qlC@\Ó@\>^A@\$ hA@\3%c@\Bʋ}@\QCO@\`P@\o߶ 2@\~yE@\X@\&!@\`c@\tˋ@\B@\صւN@\:@\mL@]}%@]eP@]#K8@]2.IX@]Aee@]Oq @]^`8@]m@]|zdA@]N3=@]!>@]: @]>@]Ɗ:@]S ;@]k×@]h@^'[E@^_H'\@^~\@^-@^<4N@^KH0@^Y79@^h@^w_ǥZ&@^ |@^?@^cB@^ B@^@^SZA@^v\ @^ud(@^0Z_@_ )'@_c(@_&tj~@_5"@_D!@_R/)@_a@g>@_oOԋ@_~W[@_I@_fpd@_n@_me"@_!@_ln]@_ @_c@`nJ u@`@`-d@`hf@`VD\@`$j@`+ĕXK@`2W.@`:/,e@`Ac&@`HA@`O ]i@`VG @`^)곤@`eXox@`lO}@`s@`zM@` FI@`8'n@`b']@`F6@`;=@`qo@`lw@`'@`Kº@`o@`ɒg$@`е' @`֍~@`<@`me`@`5/@`Sw}@`q 5@atV@a %3@awS@a]@ayIx@a&RZ@a-&5@a4=¶n@a;S&@aBhV!@aI}%@aPCg@aWi+@a^%@ae$@alUU&@as y.`@azY@a.@av @aF@"<@a*/:@a5Y&m@a?{@aImq@aRZ6@aZv@aa)pd@X'cD@X;g|1@X'̒@X7|@XG6@XWB@Xg2@Xw%q@Xw@XS=@X+@Xp>@Xנ@X֝s焗@Xfҋ@X*ϼ@YP @Y&@Y%ah@Y5wYx@YD1~'@YTw3 [@Yd!@Ys'$@Yk&@Y ?k@YQ@Y>@Y7m@Yd_>@Y!@Y|8_@Zg@ZF?w@Z/7>@Z.0>@Z=e@ZMq @Z\Ax@ZlS}Wb@Z{s]@Z(*l@ZLC@Z Z@ZOZ@ZȪE@Z+@k@ZY_T@ZK`@[`K@[Gl@[$O`@[3j.N@[C@[R[@[aY|qI@[pҹ]@[ ),@[>@[pI@[<8@[ߍ@[hJ@[ @[=hu@[]g@\{@\/@\&@\5@\DJl@\Sakc@\bǾ3_@\q@\䢂@\ |,@\5I@\c@\ - @\@\@\H@\17w{@];@]I1V@]%B@]4aS7@]C6@]RiT|5@]aKH@]p+@] @]&U@]@]@]dpgn@]5@]mDn@]{ڲ@]~@^bE@^(^@^!6_@^0v@^?k>@^N(5C@^\[|@^kf @^zP:4@^#@^J4W@^d@^z!@^üq/8@^eRl#@^ v@^x,@^Rܤ@_ %ׁ@_Vh@_*-pl@_8xvO@_G_neJ&@_UVh(@_d2'c@_s=@_Tz@_8TO@_`<2@_N'@_x@_[Z@_ߗW@_axx@_fC@`/@@` m8@`Ɋi@`"@`" @`&\As@`-gz@`4ֱ@`<9jX@`C;@`Jq4~@`Q@`X~>_@`` CE@`g>#S:@`no3@`u @`|FN@`@`)!j@`V_@`@`\B@`ֆs\@`~H@`'@`N-H@`u6{:@`˚亁@`ҿfoO@`8kj@`1n@`(S,X@`Iˠ@`joI@`t@a l@a zH]@ab@a1;@a!}+w@a(63g4@a/P{@a6i5(WN@a=ڰi@aDj@aKE@aRŢzm\@aYâd@a` @ahLL@aoumR0@av'x)Ȣ@a}8Md@aI-x/@aX@agQ@av @anx@a'W@aWe@a3@a@aûP@aCr@az,RO@XGe˫l@X7@bI@XG9@XW8~@Xgen}@Xwg0(@XG(@X jր@XwˁD@XTi*@X-`!@X@Xpk@X:%@YhvW@Y-&s@Y%V@Y5 5@YEeNF[@YU$i@Yd? ;@Yt{N<@Y&]@Yo@;@Yp ,@Y<^@Y¬2@YED@Yp@YlhXn@Z@Zu@Z ¯w@Z/7%@Z?&2B@ZNH`@Z^p!@Zm~r@Z|J@ZaS@Z9И@Z76@Zd@Z.p@Z`J@Z;A@ZI@[m&@[u'@[& @[5]Ps@[D_d@[S_}@[c39R\@[rt[@[N@[J@[& `|@[[lPb@[K@[ͽ@[G`@[1nB@[;G@\ _f1H@\ 01P@\(o@\7Fg"@\F@\Ug@\d,.@\t?@\p@\*]ҍ@\3qk@\9m-@\=@\>띦@\=Lk@\9Qb@\3V Z@] *ws@]iݜ@](KtA@]6J@]Eaϊ@]Tr@]cg6@]r`oe@]l<@]h s+i@]F?@]" =$w@]x"ol@]҃@]ڧ1_@]yu@]Iݪ@^.(\@^∇@^$+@^3rX@^B6Ե*N@^P Tc@^_+@^nv\@^}28(@^}1@^T@^WiE#@^ M@^ƺ@^hѽ@^@^! 1@_gą@_ Uϲ@_{-@_-R A@_;@}@_J@_Y*;f@_g~b+r@_vZ@_a!@_}A@_{`@_7z@_0Piz@_ͻk@_D@_ˮc@_PS@` Y@` *`@`jY@` G@` ̊r@`(#m@`/_l@`6P@`=CR}@`E E@`LEXu@`S|~5@`Ztv@`a}`@`idK4@`pODS@`wj(@`~&@`ҭh@`8@`C@`qEM[@`'@`4_@`5@`!/>@`J8|@`s,@`͛Py@`½Tt@`|@`^˂f@`2zN@`V@`yw[@`|bT@aA@a !:<@a@aCk@a#9&[]@a*V8R7@a1rz-@a8#c@a?7`@aFg@aMq]@aTY@a\ "|1@ac!#/@aj7tġ@aqLupo@axa@at =2@a\94@aY@a\V/@aQ@aʷlҲ@a٦@aԢ@aA@@a!@a BO+@a @a#@a-4#@a6-w @Xgg3@XWEOo@XgRJ@XwT{@Xܓບ@Xɮ@X@XL@Xxp*@XUFM@X.zݻ@X=*@Y@Yk@Y&j&8 @Y6/w:@YE @YU2@Yeh1M%@Yu9<@YBj"@Y oQ@Y+,^@YҪ?@Yv5@Yz\{@YⳏE@YLDžY@Zmd@ZtT@Z!U9@Z0;'@Z@wm@ZOgv@Z_ o@Znr@Z~"@Z9h@Z/ \@ZoMF@ZڣR@ZF^@ZڭC@Zv@ZqW@[Y,@[)d@['|Y@[6i@[F%tC@[UsH@[d@[tP@[Kj8@[wE@[vz @[@@[AV@[w@[ޫD@[ٚp@[ g{R{@\ 46i@\\5@\*g@\9]K@\Hv@\W[@\f @\vK@\&Z@\8H@\H @\Tjg@\^s9@\f`M@\k6@\mt ~@\m@] j2=@]d#S@]*\@]9R.T@]HE!/@]W5@]f#AU@]u @]]@]ީ @]Я@]?^@]m@]`"̽@];]dP@] @]`z@^ ܏n@^s@^'\؂4@^6)^$@^Dg@^SS@^b7v@^qDQS@^U@^ķd@^j@^;O@^.lq@^ɪEGc:@^^-5,@^_(@^|@_lq^J@_2͇N@_![Px@_0heD@_? Tw@_M*c;@_\PTx@_j5<@_y0w@_& @_=A@_U@_#@_|@_ { @_ߛ`l@_'̜@_=d6@`[@` AX@`"ㅾ@`d2 M@`"y@`)m5@`1"T@`8_ˆz@`?Of@`FOH@`NZ@`UL3@`\4Os@`c,J@`jd@`r)_@`y^ @`.v[@`,@`m@`)vB@`Z~@`1L@`w@`ۋ@`Ti@`@U@`kCɘ@`ϕ@`ֿ0L@`@`T@`6 m@`\H @`a@agX@aC@aۂB@a@a/ ΂@a%O<@a,of@a3Bj@a:R@aA̗w@aHh|@aPZ@aW@a^4@aeM#n@ale~@as}B0@azmF@a܀@a,+@aP@a~G@aB@a 9>@amP~@a, @a@Y|v]@Z@Z"5*@Z"bp@Z2Z6@ZAZ@ZQT@ZaOx&@Zp],@Z)C@Z/@Z1k*@ZSҀ@Z+C@Zͤ>k@ZLtm@Z:@ZTsv@[ e@a@[Q1@[*2_Nmy@[9Ia@[HY*@[XNP@@[gdB@[vy`@[Ot@[ @[j@[4)T@[{m}@[Ҿ@[Zl@[=ZW@\x,Ku@\ @\0Uo@\.kui@\=FM @\LsfM@\[0@\j1_y@\yn&@\ }n@\(q}@\D6@\^8@\t&@\ԈO@\,@\M~ @]Sb@]21@] O.@].Np8@]=g|@]L$q@][ƾ%+@]j<@]y`š@]p@]ZM@])W8@]}ćI@]hD@]Qh7N@]8z@]hW@]0R@^ܽdʍ@^ @^,j:@^;l2@^JA@^YH^^@^gk@^vCLo@^ @^L@^ C@^氢@^oܿ@^^*?@^9@^ںq@^l|@_ MF@_G<^@_'up@_6j}/s@_Ea.84@_S$@_bsȥ @_qQm@_kU@_j4(q@_ _a`@_,@_M Y@_Dy@_ׅߐ"j@_U@_O@`t@`{@`7v?% @`~d@`Ł)|)@`& )\t@`-O@`48_@`;L@`C@`JX8Y@`Q@`X":@``l:@`gQ1I@`n0a@`uȒJ;1@`}I@`;O@`t%=p@`J j@`/@`yb@`LU 3@`ԡ5"@`m@`䙼@`Қ@`EYQ@`u@`ڣ켭@` H@`@`)"@`Tpߓ@`~a@a;@a M41@ay@aQn@a"D)j@a)i)@a0Up@a7@a>07@aE!KU@aM>x|@aT5m @a[U 2@abs{t@ai?@ap E @awhE@a~/Pb@aq{ @aDs@a2 @aJ4&@aa&@axsnV@a=@a*I@aG@aa=@aX@a߱@a$Ue@a=v@a 74 @a/!1@a=Me}@aJUw5@bWlG*@b c`1q@bn3@Xntv@XS.`@Xo.@X@XkIF@Xz@Y!(@Y$Қ,@Y'zv.t@Y7WЭ@YG1;M@YW7z@Yf`]@Yv(X@Yp@Y6F|@Y_@YQ&@Yr?&@Y)}}@Y@Y@Z9R߱@Ze'@Z#8@Z3(mpt@ZBܟ@ZRaa@Za~@ZqghL@ZoW@ZHB1@Z3 ~\@Z,@Z;-1@ZλuE@Z7k @Z&@Z&@)[@[ @[]%@[+s n@[:f*@[JB'@[Y4d`@[iWf@[xaC@[s@[=@@[c@[!@\$hz@\ I1BW@\,@\L]O@\iU^n@\փ9@\4GT@\#f@]k@]@]!`@]0@]?_@]Nc@]]VS@]l~@]{3@]8R@]ѮJ@]@]ԍWQ@]Ŷ@]մlLH@]䠲 @]q|@^q@^WO@^ 9G@^/;o@^=Yob@^Lai@^[M@^j~5e@^yX,@^*X@^UZ@^ ~6@^{M{@^\@^#@^Q#,L@^H@^k̍O@_ )(@_ r{|@_*5@_9VNo@_H 2gx@_V@_ep ^@_t T@_E@_v@_Y2@_j@_jtڜh@_ y@_ڭO5@_K @_k@`A$@` I&@`l@`"h@` k8@`'py@`. Ei@`6A>\@`=v5@`Dʶ@`L @`SPR_@`ZF@`a<@`i!@`pPʵ @`wc@`~Ow!@`G@`@ZC@`zKw@`j5@`q@`"û@`X @`Ho@`±@`5z@`(S<@`Zu@`܋lm@`eT@`~@`@`Fx@ar+@a5Kr@aCz@aE@a@a$D5@a+kr1@a2#@a9س@a@ܹ_K@aH̄@aO#>+@aVFf3җ@a]gM@ad@akk@arv@ay3@aȝ@a }I@a@Z[w@Zu`c@^ &@^D8@^㤛C1@^l!@_2S*F@_@`cW @`@`%v@` |$,@`9<s@`l 6@`C/@`~l@`'vY@`0e%2@a_J@a @a@aiYp@a+@a&=@a-gD@a41f@a;F@aB߅o@aJɖ|@aQ+]W@aXPD%8*@a_t21t@afMӷU@amw@atʬ@a{J@a缇@a:ca@aX X@av_e{@a @aR>@am@aL,@aB@a Q@a.φ@aE@a\&֗@aqY@a憵@a@a:ǭ@a!@bһW]k@b !{@b>,E @b5K{@b@b& 2W@b-.a@b4;S#@Yr@X]5#7@Y'۳b@Y@Y'u/R@Y7V@YG@YW(@Yg{ƣ%@YwYwhoJ@Y3B']@Y .@YB7@Y_-@Ysh@Y:2@Y%@YB@Zx|d@Z0u*@Z$俽}N@Z4n-@ZDBb@ZS7:@Zce,@Zs4\@ZӒ@ZoHs@Z6@ZK@Z---G@ZлZ@ZE@ZK@ZP @[ku@[Nޖ@[-z@[=?̔P@[L}jw@[\#*o@[kV@[zR@[be@[ƕ!@['w["@[H&@[ cW@[7ʚV@[挅oI'@[B@\-@\xbO@\#U&@\3w@\BJ@\4'm@\O@\@\&-Ӥ@\M\-@\qN B@\̒|@]>@]͹8@]%0g@]4J@]D0T/@]S#E@]b2W@]q?\@]Hd@]P!@]TӈVM@]V@]Vb@]SĪ@]Nj&RD@]FBd@]nO@_y[|@_$B@_eu @_NՊ@_ʶƟ@_z*@_'92@_XUb@_{eC@_"aR@`cڇ@`  @`Z@`T6@`#W4@`*ϝ@`2=$T@`9#@`@_@`Hh@`Od /@`VW4@`]?@`e8d7@@`l|&P@`s_@`{C@`D0P@`s@`ŗ|L@`}Kq@`Bty8s@`~-@`4Qe@`ݨ@`1D@`jqHk@`ʢ@@`u@`w@`F;j @`{A@`~f@`#}!@` n@aF`X@a v@app@a,i}@a! a;@a(0RT@a/\7]Q@a6<@a=B@aDۚVE@aLaaJ@aS,RIZ@aZSm@aayA@ah)t?@aoQ"@avљ!@a~ sg@a,>@aN& @an@a{]@argd@a˝ @a&@a@a!`A@a1, as well as sim.svipc=1 *and* wfs.svipc>1 within the same run. - added items in check_parameters() to check for the svipc bad settings - re-introduced sim.name in graphic and nudged some labels in graphics a bit - introduced some changes to make the graphic look better when using xftfonts. also resized controlscreen - better handling of window closing/opening when using svipc - push to get reference tip is now 0.005 instead of 0.05 (there's no noise) - fixed a bug that animate would not be ON for display in close loop when using svipc - switched the Makefile to -Wall - 2 new sim structure members: sim.svipc_wfs_nfork and sim.svipc_wfs_forknb - fixed a bug in pyramid wfs, hopefully once and for all (bad sinc() function used). - added test3.par (same as glao.par) - fix a bug in test5.par (phase screen referred in parfile may not have existed) - fixed issue with animate being ON and preventing further plot - fixed bug in which background calib was not passed to wfs.svipc child (since 4.7.1) - fixed nitegcycle for shwfs when no svipc - written test routine (examples/test-fr.i) to check correctness of main modes of svipc (wfs and sim). version 4.8.3, 2011feb11: - move all calls to fitsread and fitswrite to new yao_fitsread and yao_fitswrite - changed graphic style to display residual phase - implemented forks over WFSs (sim.svipc) - some changes to be compatible with xft - changes to test sim.svipc yao-5.4.0/check.i000066400000000000000000000010571234404334100135400ustar00rootroot00000000000000include,"yao.i"; parpath="./:"+pathform(_(Y_USER,Y_SITES,Y_SITE)); tmp = find_in_path("sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("data/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("share/yao/examples/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) { parpath="/usr/share/doc/yorick-yao/examples/"; tmp=find_in_path("sh6x6.par",takefirst=1,path=parpath); } if (tmp!=[]) yaopardir = dirname(tmp); if (noneof(yaopardir)) error,"Can not find parfile example directory"; cd,yaopardir; include,"test-all.i"; yao-5.4.0/doc/000077500000000000000000000000001234404334100130535ustar00rootroot00000000000000yao-5.4.0/doc/MacOS103-bug.txt000066400000000000000000000057241234404334100155650ustar00rootroot00000000000000Apple shipped MacOS X 10.3 (Panther) with a bug in the system math library libm (part of /usr/lib/LibSystem.dylib) which can cause the functions sqrt, sinh, tanh, asinh, acosh, and atanh to malfunction, when floating point exceptions are unmasked. Yorick is one of the few (perhaps the only) code which unmasks SIGFPE, so that the CPU will actually generate SIGFPE signals. Yorick does not use asinh, acosh, or atanh. For tanh, the buggy system library causes SIGFPE for any argument, e.g.- tanh(2). For sqrt, the situation is more complicated: The system library calls the hardware fsqrt instruction for CPUs which have it, which gives correct results, but for CPUs which do not have the fsqrt instruction, the system library calls a buggy software sqrt, which causes SIGFPE for any argument, e.g.- sqrt(2). Thus, yorick's sqrt works on G5 machines, but fails on G4 machines and earlier architectures. (In fact, yorick will not even start on a G4 under MacOS 10.3, since there are a couple of sqrt calls in the startup code.) Apple introduced the bug with 10.3.0, and it is present in 10.3.1 and 10.3.2, and likely will be present in 10.3.3. Darwin developers know of this problem, and agree that it is a bug in Libm-47. There is a chance it will be corrected by 10.3.4. If you can upgrade to a version that fixes the bug, you should definitely do so, and you can ignore all this fuss. You need to take special action when building yorick to work around this problem. You need to define one of two possible environment variables when you run the configure script (or do make config): HACK103=yes This is my recommendation. It builds private versions of sqrt, sinh, and tanh, which correct the bug, and arranges for all references in yorick (and yorick-based) codes to call those non-buggy versions. However, if you try to link against third party libraries which use sqrt (or sinh or tanh), you may have problems with incorrect SIGFPE. FPU_IGNORE=yes This allows SIGFPE to remain masked, so that the CPU will not generate floating point exceptions. Exceptional conditions, such as zero divide, overflow, or invalid operation will run normally but return non-numbers, specifically Inf or Nan. This is very dangerous behavior for any numerical program, since you will get no indication of any problem until you examine the final result an see a bunch of Nan or Inf values. Needless to say, it can be exceedingly difficult to track back to the point the error actually occurred. Nevertheless, if you are linking against third party libraries that call sqrt (say), you may need to build yorick with this crippling defect. A typical command line to build a relocatable yorick tarball is: env HACK103=yes make relocatable or env HACK103=yes make relocatable See the README file for other possibilities. Remember that the HACK103 (or FPU_IGNORE) environment variables only affect the configuration step (make config); once Make.cfg is built, they will have no effect. yao-5.4.0/doc/Rayleigh+5starsOffaxis.png000066400000000000000000000677121234404334100200770ustar00rootroot00000000000000PNG  IHDR"GagAMABO pHYs  $tEXtSoftwareQuickTime 6.5.1 (Mac OS X)K#tIME07/P IDATx]u[4U|>i!hrB[4^E"H@%U0B!!ބze04bII@A6t9{[{9s9Z{UUoUyxOYkk׮=11f3Mоxl8`;p(vC PlG^O 4Mvdfg?aᎼ[X~ޠqx+d)V~ ZxF<<#ik8tJ.wva&'IEX:N CgDt2s|/}Bv+?a.=T8)}7p(h2i,EAZy;VjI?q^-<12)]Ugi#yQ¬tS>{8xFeꝝ3 O ,?E*{s&W*5y*Cfʦ6s6;l9LJOTνzq,8`cwfV1HS̾-[P=.Z \2$:—EُȞ@;jdG<%`зF7om}|}Xx% ㆗WxOFƞ|KxՆ(饞~OrtMs;-C?Srּ\+_Rw(XM}~ʧyZŋĪ6@~r<U=.m}⧴{C|BVYsɇz ˵?n5W`6Z~ΙIic83$O^Oyn_6ش<-Sȇ>}|FxTד -W \֟x%%-Pl8`;؎]y l8`;p(vC Pl8`;p(vC Pl8`;p(vC PlK? ɎLT$^ Ci ٷ؎WM5rhF{j-CKokPWj)-ך0gWʡ`up(vC Pl8`;p(vC Pl8`;p(vC Pl8`;p(vC Pl8`;p(vC Pl8`;p(vC PlK?D?pOxybxv ؎f~Oi^),?yqxo_oFG/ xß}x& ~~k?wq0;֯^Y/S&'<v Z޵~0~?Y\4W0q1<w_68{\ Ԕ^ ~яA$#\ <! ρG tbA0bl$rVbxCO*;ܻ";}aX|H^ab`P] W\ /hy '+K4Ii~_|u=PmO<$ghFy_^ǡ/Hs'dBh91UPxb#J/iW*.h<v/})V9-ʐ9[3؈o؇t|I/>i/ip3`O$ËsЕ)2i-+C^bXton#.Eik4䨱(RWr18*%-C'QU#^5MQs%z|SYК# U+^%w+p_ VCJڭ e]1͘ 7cѼCxNG^[ȮBſڷ R$1DXa̦5k1 ;yC , ֤?L+3*åh|6XDh?N8jؗ =^Ҵ!/1 cÃc5wOz6dli`HkFs\EhAv^ +Gr9N}h[ʉ. `;d&?ƞ> !(9/.Xu~k]4}12p,YA^g!\˖ :b|5{1e\{Q. qb0__YN~̘rd!-{IӞE:ӫ]\Bshjd #A=h-nߛ#p#ՈRm^3]nޖ\5Idᮡ~1p!Hgl.UO3͕3(Cw%7bQJz]؎šͻzIY{2BA* IAޥDElZ: HQq)ֈjL!'W3,ŰkeokbS؛\ʋa@Z7\M7Y6kEu"ƤJr3]RݷRU׼Y vZ\ 9Sr?Bi7hy_zBY vrbiqx Ur_?fϧ!6. 8xQ+%}xcsֈtʣN:aܔV330W9ٛxyE"zb$bQr7jP {zD vi4sH}S4/[~w{L4ꫮ.E!UA?\ItI륺eDofeE›e`?PEK> -b09x]+g Gஊ})3Ե[Co- ơ4%6*X$rF"/f6qdĻJ~>pi|-,%=miBNzTIgԈ0ur-b(%.GJ_M3-16bKc¼ E=s71Cڱ7^fr[mK4y4, : [rv1! ^z9tiP.~~ O,Ƥ5Uu:It{o$31H?G.s '$zF۟d3ӡ;y|v5§ uy[zix1_pO^h^X \ 7|نӄi:Mڨ8M*(:X |)CNz¨1 RSVݶ^g&3]9m4$29LL G)Z1 .RT+8 ϲ+Jz+.@")M_C ^-SgpP1wA/IrCt Hg-_鯊8ڟğb^چkωƌd=Z`;ljfy|i5V{n6"h}@,YK4rcRՖ x|iBQv]ytȉjlBs2'9/S9{jgH̑!w9 ׵R8&(ehv -roOCe-ZRq!P^_{^^o} o#ۓ5Sr0rRsΤ8@^uM?Gl$fWo͛Q‡OPwdjmL.:߻۩)$uN[;^+EE5bdjG<oB ԑU/.B%u78^r?f4od>m,n@$ɘKn҆fv4$GxlRZ#\ V_*wCd`~>D;3DnbC"^1 Qj= 5&tvޕZD!}3@>`;#I[MCVJ;r8\A$Cϙ/_npg|o괜ߤJKu9s6NbgٮהNjcC$%$n+w~  ƌɔb>G"PhqM̔[eɽ~n ϊα"N$1̗IaxIdIƤMZy\85")ZJM4d<%#65-% $锻8>^|+hVWI؎š=Wj.7q…zl+o'=TW~ZA0U$h7 Bu樓q,SxR{]dުzQ(zUCpcDDB~!Z^Ͽ={g"+ Of{-{~f$Ezہ]*-6 XN8 7qh{ަ&qg/9c15w_k'! [ѽގIAk`*VV`}G%'><\iZ`;v46yub /߹I4tUmJ^JI+΄ӱgq0x:'v) Yը l2^{f'B .L -%<:tUċfɠ='_p('^$ 7qh>IC'KTm.BAhi'!5X!ɴ*XϛuҤڮD'|MlOt%E* zNR'~uV1#U O!^~D“\q, !;U#&& oݢ6:U:d#T^8F$w3(iwg63yV, 7ŹJ멓oZ2 9P+DS'h~\c< O[fd P[1Dy1\j O qWz+.!)>CY^Dg>{ #E)O{#zk^4hK:$򛪮 ?܃U'# V$(s٘8{dHAmk iPmcoZAh&dBK/ddJ%'9紣s`E5י.EA2R,luJD~%uFSbͨL4eD&Rd6&b AӶ4(T8/zg瀽qoYϣC&AiŞ>ӐԑBNL9uc))Ws,T[;-呗-JrSu&[iZgҬU'HSO.޳ 8R! iWE9qHU& OvRo{a*Zۦʻ>j< :D_I @TM}peEw-x 'fWiuUˁ[!=+='~ĉAW$F$BB|G}Ь%Íf&7coq(w-)ԑ HCK;#KxV{P.}ޣM{v|Yg{d79~Q,*~*o̯ ?pxy9%8`C>SCIxF{%OM3P!ơPژ̛d1&+R'/~Q~NOT`gP әuv)E)>-ggVp2u1{VSMTz]  %nFn6NgHLgUNZ`;v>+fiCKǠlȇ]S"8ttE]n$d 3,$)s;!y)c=ӽc)4~.̑Q/0e!(7hE‡,csLl/6)16n7}VdZΞV =x| HiFHh! ]':^qȇgVDzf?~R˧g>3kU>bHIsڙU0.lyl0+uKE舗ن57hTB~؛:1~¿UƤhir]ZӼy!OO:ǫc#V IDAT\6 !ud;>֛|{_!C9W|HFw%UPLj}li@>$i;}d*P0VCΗCu'OWFpHiP;HC2)&>FհtYDR&R*foM{C_75!`c|gҠ -WN&N(JR֠I:)lˑCF4RFD޴*BCuVs-Q%wNG) hbe9иE.z5 OiP=ɼM'6 u)CJG0 *|x5 FΚK䐧z(I'J+OjJ gyԆPVI'{1®l@ %|d.2+#ŭ:C=bGT?_4m<]J4(?f3q_SwgLƳ,wR' i6JYNŴT4/K3}GOr|V]ҠOOw! M2Sy;[)C و#>"Ux~RM"x*8e;%w?IjJq|e3s SBM1T@s|{4v>Ğ77QD~ǗcN/(KI/FS}ī~2cE ~L&(GƜɄZp2%Tű T<uRP'33-y,EaɑUyɚ:ozrM_x$ϡj7$#@I?{y&lȔ5#LSLF`P˧nP1ȡ(矡48Ne0M#NiYg?~;lìhjX5K$ O3A ?â5II6F^\d.zs,ownCeKN7nf D- Om4%4g<?N )uy#̟QUGT3*[Vi^NPgjZV)t|KD<{#i HTcIXKt H;В4(嘽d$x3t-IG@dZ-^BxOPs7Ճ^٘|[}tؠK܉0ÛTd<@S"El@FR‹H0^Aݱq7vN_8+d}L#\8 <@EUI{2ldq/ULKլOԧr9'ճ( G*yVGno0_YEe\{*Cy1I0@~8`8A?S%}U9Z#s֟r('-iULK\yob9>xc1=m{[tT tN³'ǭk^bGTsd?@;z1W+egV.4=Ft.*xU/:G) ȱ*ZN@)u0f-㩎N9g݈*% (C)Z/P+?^sGmX4)Vy )dW>l%ǵt$@X؎9up89N`J|[4ܴ2s*F3jۇʾwߩB+U0.IIib3$@c5|8~;恺pE 8h^ PJ*x#>X4 'UY2nN EG`Z**iҲwTR-z7݃T^К^~inp? 50A֙d]9QG Er?O2i-~EN,ʀO_!i)Z3S\'G^Ky P3(z'xӉz[Cm} ޝ&sM>n48T]v3JI@mzc>D4E3dNw&:5%d%uGl\Wޫr#E!>)'MĿH{;x76Cʅso7ƱՏ?;?Z>G?M" OO_/~ӿ_9 8U lX,Zǯ$8.gb L֑LX5}&{͕f'ǞsY1;c>I 4u83&PПfsE7ql-gP;|~N Zm,u*x# Hvc L2:?%$Pg>.D3H٫sNR~l y޲<+'0f{~y7hNPVs6n4I3UL>H2x#/; -) 9ٷeՈNMhu_~&ONַg{ƕDe.[q$Y;SnPo[؞s%|u2$`;e/dR'9R·]i=uj^m7ZeŨLTl:O/V0los-Gʻ}8>8 wݍ}@)lq,[!%DfjvzBx~.>Ij>5g{Jɿt:B΃ordzUC6d/r9zF\A"[4P:{Gu]iɴ0VBcwZ 3 _pٔZM%uRmmB wpeO*]Ƌ&ϛL1u>aO臫7dE`/Ex'MS-hFJLAg<v?M(cY ;l7\u_k7fOPQ/W*{r1~9R!s!=~WiA_[HicM`a}l|}ϋבԻAe1Dò' ;(?3֐?"vu nTN3W u6: ]g&\ x9MsXp7\gxꇾn_Nѷ$uSLQ 2>̨A3L\86<-ơMuo%r_9Ҷ[Oie3?בքWf*(N_ʵ*qɒ2V|uMN}֦a>J~-P2޸Sš}+%s?\{;ZO:;C}%N4cD?RvJ ّ6RQN˽nTvCSe4Lee5yIxSjҠrQz k3C|G|0 ޞM1cZ ߻kym܃Y3bGx_T< lVKSd'-:&u᧜/R=Ҫѕ.&CR9Ӵ?MɭmxCRAjSbQ:5ߍV0U/C/\Gb;}9ϋ6ŗ{jG| V穓vI>y:i* YYRD'.9Rǭ45W0ˎ0 #,wn'ˬ?lF*;gdMgMbwN"٦:KDh: \Θ*gҕ %;m%xHUș:փjXDM˜:9ڍcNb0q98@!M&Ќt8`иűHKݜЉ4(@>`;xƓK'ps}INoI$eVeY_Τ4lSM?WGL4:A&_;'š&5.ˮc %7wI8t;ʹR Qw2! |"CdPp`}EeHLԈSD}ˑfr`YĞʾH<;@M۾c v֑a$a^ ݠG l8t^CUR}uIag~fC榄^ ?)2(3CC=7tC3mX|X_vFN$|*1:)^R"PY7u'feȇGcd:s)J9ջ!*wNܣ Gnj:]3n /pD^P؎šyVO␳m䌟YiLҕvТ^Ax!+?/N fU'Cmn-]Gkлa U6#م BrO$<:RwO>ߕsr;&>u3Zk*B'%1$Yqoq3ҷ}mO$"~D=}:8bR¯<쀖؎š_iu:ÕXO_|`M6vflb]bL=g>8xGB:)3>LEQ&0KXW@o _ ]&t PJ^ ơ_U333-5iFsH^«J ЀK# EЏdI o%:]#'kH{Е~RV5nN*)t) %Z{ƍO{!) !@ o>"7Ş4S?xJmL>*HSHz.oq4i{i%ȇlngџ2|;ETޫO~b}zO tLi]FصINF030f!-o"Pj}ѳC8s;=㍖|3':禊kǘPOC 0n u.J$ YS[>ifbHwDvиYZ]â$'ۏ.dry?N]́F~2IJ;L9F˻TL%G IDAT<v-u;q\ qw7$6֠m>vi{_;Z@:YUA"~}*w2Gmsޕ~~T#>ۣd"#')% `o*XI&o t˦*Ӓ{{{QYrw2q&N^O뛩9N❑%|1ciPZ|! c'Sc^% CgЉ4(&-Cਧ|8{7U'+HT@DyjT&o܅a"71T\#&8B)7ɷlv#>ۃ}*RC KS󾣑rګBRW`o{~ DƐʩϛ.n(Y3 O!c)!=!PoAW:"xZ ?Ak/D hy[Z<{`&y=~I*H %kGmfVv }y?9L\7_\8]i?#_ǵPsBDj{9;4)ş[JZ__1'/֚AϾ3)ơWmz{)+ Fe')q/}4qb ?eѧ>?~wӍ~G~h59\?@Am$3;f$"NOS?;[~MOqN_9`osOnr) -#cF~mg2MLdg*{ Bޕ߱`h#~x,+jG/ۙL nPȃЅxy\rrxCOՠjZO4hF$ON8tp0LFQ%=}RhFc7MK@C9◾Mfo?ݷxY"2Od >Cj,%||N]>^|߰??6~Pτqh;d6b"P#͢p4Q36 1cv6 c5$oZ24z;u~'nN'R6#A@ %Boyt/ u2NJuOgʳ賟7л) H"k8i 5^-AB'64^ws)s2IiVHX}sx$'jT1;vھ1@lк{I) Lo ZO9+d]h@^\@*osΛ4bb>Lts:(=l1 ZK>Td?I2nky͏Y?4gXW%Uқ.|םBrǿZ`;vwϩ T,E)mR6]?͗49i!|;qirUx{G "ڍN(r*b@q2^pZ![+4oy[>BC-KrӒ~#&1 /d5߲<'ǘ/~b̚R7Q0ғ7:-?U z28SEI- (R Of6 "cv^}Z`;V8|?HN,$<5#­,[& NҿT^%Fco#}I煵1=z~:eCT?K'Su$iÙɤ)stI "ݭrdm1?Hq>rsnF>OR1!D 7=Q|_~N;{HqAL޶sM)ֈ=ZEdG6N~ޏ ~{]xhǀ(wqgv)tx@II*[u+JNnZ!DvwGs΃F+ ;7=@m 5K]FD/[ǰd='x*zx!лӠ_И ^7˶HN˻G즲#^+NiWi1Y,̛Ucue`4 F=cgMC=|BWmJ;*yr4?+SPe݄#"vm2]1{G3CyBǡh}\>9cosjBa0貓Ihcz۟˕T%-¢:W*&IvqP[h:bV~nE`NO ꯋ3M۱8T焌5MKlB<kب&7A<0.ڇ#0~o:+{}* E O.f|:^rI֏D4heL6wN82"=]4rcɋK*W戗&A4`/ xKj{8HBȿCcA) tȎ)Ghb d,xΥ0曰7}]wtҠ@{>ژ|Hӽ= 8{_L(3zY.ʘ8͘r u.iAlL&|R&ɮb߸N]IP۱8TFo6gOJ)"iH:+HFYuw9/}9f6t.5# R-61֖⿿l_456Fa$kꤢT{&T`#;;rY%(uv4]O]B_ơ.%r6lo;rp2hts[;Fk@;.%j;18f o;Z.WLzgc-yG͡)u2"Q_䴊߀lx%]R˜\+rD=7KnH..L#NekZ;H!@lЃ`# 69,#,J]N!lbܔy?|io{{.luWavᚑN{ҫxiFAgK Hal2:"Sx<~OsӁ?zHBpz,b]/|o0'j\)-l9[R*uaz lh`UVYm^CHMvbY/CUsy1'BS0eO&Р`P 0ݒTPz!/XƘٷ8Sk*#;/gC Z>(Å h#uc)d>dS548 o?\[ElT3AſRCO//L75ĚR%䔃&\:Xbr;ƞtms1tԏrU_pqhw(/ a{b.}ngJܠ1Ƀi[#Zk&ӳo:-ץ25'΢] HJ_>ж:1 {=l{%q+Hvq=H`tvvCUY Ψ{ w3hl0LL,? w m7_;;w~˱ʚT#fҠ%Μk/XIW4UJLռYMtƖv{zu>L·̡RgoN&K&,~ ,ozԔXcL9Z$HC|)X ݃>8 ?Df7Fۛƻcn8׻mxs~{{9O):m08F7(%Õz)inAIù;.#ETT/ˑb=F:o{/d;7'"#!g(hyxjٓ*q:& AN6fsY) Bbwz=QBL/Fs6``;zVPD ?م;6m}|8 A=<^HZ|b>/X`̳R?xvB17Iq`j(jdAY .)%ÒV{fNhyGtnqNZTvǡ?ǘBv}G* jbѭat{_{:׆ bx?ܶ:D<~_@4n 8B(d9/Ҡս=,ii& O>UAg.g$}r[N¡F$=E%jiQb.6%S#᳦,KxÍmjZJI)rtjT3fn43io۱8hyuJY#MC\:]Qqh{8&^_xmD28ѥPmw[z$O1<=H++Hj:NTkE׫{D>j$5%7ה&!]%_A B9?#6&.%̥Oc7q΋_{MptoÅ-2[Þd9{pOGJ68}A}e~-o|kWImL^S,ǻ$H^X;Ţ$u^ҦLϳ.}Kҗ9.%ieo iet0t3HxCAOFSjlSҠv|]Po{ЏU-<F7¡4LJ{;]G ݃@&5 B*|VPvek9Ռ յx)%xN:U5jZөsV:l/Thy ?Cz~QeWG*m ޗlX,L*c:څ/R$ơC/r7TC Lys*wdn3a }){"9 :٥6tJ6>Ί~_ݸ܀tj eYc̰It]wؠxr]30f^pGbQxiVyr$K|gؓ_.c3_).̙Lo[.DU&1qw6N&kk iPmcojT*H=Jkᄈ&' rg>pr@y!k?SKxH4iwiаɇs0GPpITSN;usQyİd"Z7Nr9)S~ ZxRؾ8@ ?9 ژB))Scb)j$`Wxy}ں!΍_X<>Ńs>n IDATő@o} Ovru_~B1x+h1uSV?9!nг0։cN ͬ/Sg<^svrw3~Fa#+I@'n٬IxM灆ūǍ6&=SyCgڌDʯƃJKy3kS*M/>-Lzqõ@ޒ 6 aV\G;$#~e ٧XJ*~* 3JiǞĐYdgIH[.r'#'~d8.r6č6ɇ өg(CF5ZS;at~wβkGxáu*a/UR~7Y%)qԯdy-M^e7sPQfOe<|qפּ7ʆ7G@&]/#lAm)ݠ@&4+Hj=4T7qÑi=B𳡨e+Ṁ{G'O?>Nϲ; B3 oky‘1ୣ‹M ㏎؇Yv /o͘KxC?RRLTcOUxRyvgү vRڜ(a9ꔂ{FzNR'q=hZV'yRVQMEԛb-oE ;$oj]%L-C]kweb~7qh&z'05M{M祤Mx| 'e?~!)'$jEQ%MM!Y}~'UD.:]d] [rl $ oXAݠRR bo o,ےSrL7>8~ ]N$2d?ǰүs5ÛqŌI0SgyXi)bO#=c1.>s2M |օr~ϻd Ї=›p2Xě]84h qh9jts&Q›bQGbNz5$:ujd 6: nPlWg⺽š׸ շ!xJCwC%E&%}?3HӠ>$<60N1=a!$UOKlg\Wq(qbPyR!\51d}t ލ^x>-6~U-c'K$v9 {PC75 O ?ݐf " h]7P7u2pΌ[Yq/ ɨJ9Uiʤ(R|Mt&-@~V/Ϣ1aJ`&P{Q~,U~Kl ?U\){V>u4a᧺)"W 4Pf ڷ&'tPUɻ5&EuN{Cɱqg2mYycDo{|ԈQس"5Rr CjJP΃GnF'4dzxn;ͿAKδsÛ_#fX-:̺!Jo?>y'NwlGd@yҦBK:~_xc/>ƶo;l$jcOdJ^6InLa2gd2e 9 *}ߥ 39aZDoB4JIލm13N;@{ Zu.ԋM|4m jxNVgލV 3ZГw ߫TOoNeF>%C)l$9)tC`[Jx BX˖dP5!ݿ^_Tξx&|b  Pl8`;p(vC SE9* /LooÙ#O][77Fp(v@/McM_1[t i78mx%@>to؎7zĘKu   p(vC Pl8`;p(v_xzG6C fC6ԩsY6wZx{Л$pi M1@ v{V}`%kNzoDAZxF|o}M Pv gVO/@쨶5>^?-l<vC Pl8`;p(vC Pl8`;p(vC ?![NIENDB`yao-5.4.0/doc/aosimul-config-example1.png000066400000000000000000000327271234404334100202220ustar00rootroot00000000000000PNG  IHDR}{gAMABO pHYs  "tEXtSoftwareQuickTime 6.5 (Mac OS X):s;tIME 5[ IDATx흍ܪ$;1Not  U*㖅~?~|o<G!|!vPw!BVC!CYld_AxsT-ճ̠kf6?v|}st1Z#]gJ zHwn.Dwׇϴ[?R0n<#: &W.QP3l u8rs|ǟl]A3,Q(%5ԬZnZhz?Oo%Z2ԂC՜H>ƬF\AwE׷ d'%kS8jѽJ=jA~V1{'\Aw",D܎{TRYG2IsDnUeH 0`~РdV_.<>'j/xpe1JK9a9}GtSRnSBjxf'l~m#'.8$(Lrmv udPsy5WtVARZq\uaNZi(:'BȽ}^r` >h)s3" :)x,I1u pbVݓS`dAJE=vD7ɐw%>XTjDPw˳Ϊfy.\,qZ *k]}4'DJ1gfz"&EySQ'0H4g~N_cT#1Zd^?V{IVR5Zc !ԝ7f SJ#/Ӕ@+E: t[KL,@O%E j5%(W%0ɒ]DjH u )UyCEQգNV ?yߙu'ON" aRxkxdp]:n8!GaWLD.٢3]^CNSE8IycSNVBݙĂPtVr#UKrj$x!ft]+Ũ] Qs]fj>EwEU1Ky.,8_N\()["(1kSR >{xZwcm,͔*Քj>e|ԶPU$H>;/ޚ߷K)Ity7%Pqɺ\cUsŷqq#QmN5~<㷶7 g踜6&A.3 ykxv[7pAUXW%R2)lb}l.3o|{4oUSGpl>K)nTI;_uYɦʸ]ûDyɚ:#<\bMt윘ՊA(al)N>Αr_җCad/k+NH>.9dN%y&+˳x5Oe;Z uGb˘NZDiZ}ȪF~[:aȔ&#IRZ])Fe͕ Vw`RkxQ^uLgҴced5W|#`Ԛe8^w^(6)=̮zek+C_WrJϼOz^iKicKD'۲/*C4rL}^It"3ĕ`&[6JoB2Fsb=5jIJ^uGjt, 4j[A2f!Fp X6~zq%wxDuדμ.CKd]wu3Tt&D3U}9}wg9kyTpّ_βpe^>um,,.9Ӝ20`뺃l|)llfC#%lRj+/=ZQtKvڍcZwUl>cՇ ,D2ܕ`SeZpǃrWJi^WyV+c Z3ʲegȀXz`_ ~ uޫ%ZM665Օ`-.sWX> E](7Tn뺣.:Erz-fҒ>v1Wg\wJ9[ /̉U̷qWQqUVWYBkpu=R[ %NN**! )i˭wrGզoCMW{ݞg1h}xzXP ׅE'^AwQaәԌ(:q7;E2t>gFS\SwtYAFtwFlb]wV ]ag!nwd4SdHqC]{o3Y]Qq}:VhFiZ`HqWQnTNܕgYcFHZ5lp3jr HqѸψ;$./3;/v\*:H誤Vt&t=R cDtF\^t5-D_',ɚ5N\P M,͆Djv+W¥UzxZ[cZw{x?zk"It*莕b֚qG2J_~vd0ٹ67m2e7;~>U:7+mF3''8Yww8}B$L `~dSͧpWQUxyQkJǚOU8wT~Xڥՠ]zׅf{[xTK(/@~ä=A]7DuCWQ1)*!;gy^hZG5:4rMUڍUW8Y[^JZ\'6dZ+#|5\ը+L?Ϛ:*K!JfȐd6>jA x|8_߅ߔBGH1mnL}"GXPLyF)L=i^)d#] /.Lv2aWwǸBb]wG~{ eh&g"MowHW3\9%ʟe&,]!3;[>&г+,5*jQe{n9N;WզZ"(^+܆]3j;FU\/R"]UЙg9ƁEwndLhE幉8p=K;yj۟|!IݨʦX1*r=6hW9&PB]}{Zc[p٘xľ}̋\˲Iϳ.0=C2}NlBO* {kb `~o0Mp켷wF^['_wgt/tuqҝw_yo_hWj8<*2Q{@%ʿ2|z_wۯff' \5!~'+&[}(F7.VW<:d!ϳJTUɹ:ՉT̄;]t\55㓒_#fZe&W7 G; }0rl04wj׷Mt&;էZR,VDlA'B,RYmQTA5qW>x 0_Y Hrd63_2;ܓkg ,Sq~EuhtYc葙ЌZ])FEW]GuCt;˥\Ǣ31a}d3&2{uRr"4jB廼GBRc22fAWYzqW6O%r|"bBdN՝?!7d,~7xTuq[ !%F#X>I{ߑ". w!}{r_c0oj6Y2W6teٕklWB?v`.ߓmЕ]Mrj˵Ƨt``]v _] Sѕ.Euքl{DK/*iڠ#]p借 ϛOOvWA"]{J]6tjhG% _Lzo߈ n t5HqUPZ\I?Z}L );r w,YAc7qUMZDU9XkBL+Wt9|rRgY&\egM/\e"2Cl+-WlUpU">_y#{X xs*d8nJfBQLEQw} 9D[/buׯ_~\&Oڊ+y68Y^T],fAmx.lWɴj\0^) UEʚYMhC;Zڏt ϖe8ɕ+Ũ.J$+Bы=ƴ`]fGwY\cZ2W j*dڏƴhAFtϤ+S|:/M(vX6Ȧ3 KFvyt5ItBn.4=VW%3'&WQѕK~(gx /SߗJFJ>͎rՔ]"]pظjV-uy_UQҖ(e*;K jlR3)ZMwfk͌@ibJyE";ag_%WEy׳,՝y,(`~F35X}c'$W^5W%g0~U}W"GIXPl1;+VI=oWrU&2[]tD5bcܕN+iAB0W\e ÍsIz>CYWUkĎKX^ǣrWaR&`3z7K%ey!5 "R EWljNɦ:wg\wV/^2l2fW%+Ũ eW%*otg@ *M8AA S).פr|g*󝩀㵭>]-/y=`OgKXA78a0CEeݟ٥x.-y|hˤ|$Lvfu%;]$Y+ˮ X*U3@lq{&y1I1 `MeMZKM9K<[}Nl^֫rA&8%Nti]?S?̲!.I=AWaotRTA7 ve}\Fg<^}lCd .ѹx )tەbT~Kj[7"`+%_uGqNऩbdtmL*UIdzT^U3Zr_>Fb6y)+..k23HUyG̖5HkND;NyV ,N6k8D<]p.;~3U]pwt_RR*l 9t'kNٍ!gkpToM#gAxT"? /.2#/E8+4Y8r;hF U]}~JTdcsГ#~فI#٧`G DfV)Pw(ܚfqr+ tq#օVlT\t*jtЮ]ty)Z+! ,IDATWut%ؔ.UxuEZQE_EȊ)~dV*MٕZwl 8>>Gorցuc:mZry-B[r BdsVWk^ f+p#~걉.WhEQt&qA^6 h6bL~.c8] XU0S/Ω[qݙ=[a9w q$ Q9NӂOڮn]tg6r/11#9 a1ԝE61EEPtֳ]܉gv)XHs.5Y!\OϲRZ18W[}Lj⼸u W <:Ω]ɖz`?DN1,dI+=Ot40 j`Z*Zc )ԝ/fD|74[ZK[KE)T\d9ԝy&G!}Դ@~շ!l9zuM=T[OL}w+UmkT=E"ԝ/YȒ O宺t$&U&\J2T]℗X=~Q5Bb+%0Djf>2&WGr*q|g;ԝݪ)z^Y;;gAݱ4uSt~p, 2ׅJ+ +'ruvu32Pwzx|0nJ4T-*ovuWFbDlT\9;ϧt#6F\k ԝfT"~UZG$(ң6UdN'oq]E\;=Xm_Va).;v uPh &})9̚l"} V`fsV1qNt.s91R*dջAo9yN A`?jĴ&!ݜ5;ˋ2(;TBH;6]pm ,)LQCl朔˻"s؜yWd#ԝؼ&/셺k.lى˻"aCY u!d5tI^!24U~ߕKHR<+'l`ZܡlּSn30ttͦXB}BVm\9M D1Stu%,B YPw!BVC!CYI=&Cg/$qW?`U8Y0'7z޺5V:}r.5jrAz'^GXd埤;B~\OgBu!d5Bj;XYhh9`$PwɮkQݐ( ,.4ljG_U9rUC"e~CYЛ{*D>KEDބ`ȅM*Q,H%) )Aݹe0y!%8sMv"!v`s6\@L !!ԝ^Fg=_u.Fg WFB|̃ȅaCY u!d5Bj;Pw!BVC!CY u!d5Bj;Pw!BVC!CY u!d5Bj;Pw!BVC!CY u!d5{tнJEpMk\AW6e0,miUl",ٴ3|jCpR(tn<'o~{ބ<{\6R?.WRHAQm/!fph!ѭ#2z ބqVr^1ݷ@Jg]K:ثTk,([`RKጤZ3wK0p󅒙JlH :sl%jFRe,y$(pT%As;5J9w{09,"Af@]Λ\D;BWOy Հ0T6AntxB)zSt @j?g}FުE 5GZ TsSid舊`tZ 5}^Pww}x F1r+4j݂6@Tmwc(]M`/|;rὤ;d/;{99z}5XϼK>gZ"Ϯ#6&01#w8`ABiH%T.rìvүR~Vz ? K<@Sh$gaNiK84.j)؄[JM!xJ\͎xb_'AaF@fC!1T2ƕ !`<ψSzF[lC]vhMI />Hz3}VGiEN[PArV Ib:--N(th٨J*.NsQjBUAq凸d)(Hw>cN?66#{+Yj;E>#ClTi^cANDsG U<+DVb1,i:5y{d9 &X]i}XZ:Łtrk6swh %;EaJV4:b8umFF܈^1~JKZTu/8Pf=mtqo椤o*j_&4;Ԧډ+YUIά|4#ǙZfY&TV2ċ4uޟEJ:x pA(:)Aݹ,׸VՏr:\EYi _=> car̸CE3r7g)&㋑œK<Rxl; "W6=*4=4|>rYAUD(-Aǐ<>'b3 t0{ׅPy gZ3)ZyS M"Y?۔ScpzUy8[V6l!xo$d`H>XםxoY02иl׳쭩, iP?+ %c w^02nB"#ٙ"8p |I2@Cj<#LXD+*U럩+0*y\Ñ t客t`iɻDMQU=%)* ѽs9,'z %10rBg6;)ր,Tl:T/+Oj}QA#6ƕqpf[~V:BS{R)y^-T#!֌Pۭ([6ȾR"exKR:p串ه8icB>2xR;ь҇A{~UO6g,L&R$lUg-I?ZJ-oUY@B wd 冕4xMwˠc%:԰7UKm95l0r$u.W)l89<֐"i@NF8xa76>]UtB|sw,ET}h$$,Bq0Fj`stP#JdZ w;h-*1DNZo3CR/4[=(J] > E"J"c^*$Y(.Dj8NV䭩l6$MBJ Bz{±d?4  #ݑ!=e-1k2f!6"y|d}PDwCeFѭrev{9XՌzT}ʿlK'=iֳ?g2=-4#J*;$Pf_R'?yƍ2; va/zы;9Ķm۶n*ƕ@[ BM6뮙bĪ+kLcvZ_̔_7͡z!^2 r5\z2Gݶ_W]vYQK^Kb*enRzyH?k_'5˅*eJZϚ,iR*{pyy\v#XZsrv-/ 7p/~ O^^Ċ=9*7x."Enmذa.6,H’3ƴrN:Sjڿ,_uUmm|Yd=h?IƼ+d[?\4Hrѣ'(9˚|o3IMO}9rx{'{ ]X\w_1,%Hy3y򓟔~Ygh^x}s%)}s{nS<7M=~I5-6/A"?%mmo{qtHw%ۼ$IAHʹ|DWw]Fu2q,{cr-䨔[/}[~k_tvmڦ}ի^%u/y_Wgc9_/ ox~!sZU zZux@REaMy'lɏwYےs%kUc!T'9%wjd;S~LI'ti]zR_>991 .rO>Y ?: i_tE2e]&m.XN" myAPMy׏}c{W#򲗐.<,ǼꑁbʋbRrOnݺxR|0%|LqJ>GӳŒ}6m׼f+K3PrE>)~-Hy/}Ixw?)'6>ӏ:Hga棊#H|4m'>';Sler>9sMJy}!wq?~ _XT\uHFQ# Ej[ %÷zlYO<!\y啧r,Wpڵm۶}3y׻%M˶j#iSO-LU,|PV ӖboNky'Gi/GQ wT=u衇so. o$'諮Jo_W>VfR=[ T^%@*>RǑ`9Ti1kI[]gu)"1;kR)|tꩧ~_?닾e=Ր.+Eǟew馛J"eWc=Md7ZZ;9|^xᅒ9jT8 %^e/{Yי#-Ӝ'9H4 Vʬ)vI"xZ~# > ;9.IݰaCܖ)IHhh<%o^wU&M6e϶]>P|RsKn׆(F$*ƎEHI!%Pd>scXca3s+ gu`baz,%E_>8pcܢ.lz_Ɩ4C[jtXQQKLgg8 yZ*Zs,jmtԿzXFq|A!A8,~[愎ߣZw~_{X:Ck:x悊%?9)ɝӚíIYᾖfK=p"qζ.u+w ƺ;y\5ԏ{m 5%]mVX|*Eoa0Ql}GT=>83G9{3t]V9c}~˥\haאU!RZ\iF'a|ޣ~dos}WUnT׫+G1{f+X}4Tjdvi>8p/ i1{m[mc:f{Ytݔ_]wP{Tʒn:Қ:Csdˆp rsՐ-⹕;f1!Z@7;3W*.olnd? qaKa(-Tܼ.o+idMUPRJdmI6܀I(BJ) "$nZPEHI!%P@REHI!%P@REHI!%P@REYM =8O0|gg۫A/h0܍wwzE痯97D( c~m!( nwVI1l\>0b47k17d]_ [ "q\g1qT0| gȮ֒ﬥ8#o"鱾K߶yE∹S?qQcx[t*;F!dJվciwQE*XãSS#NOh-+sڶYD}?F$dJr?=WwW=>zDR/إ+ ZDP5*>/pgh.[hc/ %5jFU 86#[î~;uۯ _lci-ƈ/ 24Ziq*[ЏZF& KoѨjo4o񵽼|uV$f& UGi H:]#%A/%yǡ-ֿTCoGzڍa$[Uڎl#O[dHK.hLnf[NO[iYc\Ӕom*O߈\w՞r-ɺ8?`2'ݮi2`nFmR%|mI|d6B03㳜pkJR=֢ͫҭc߈֥ 1#Lإ[ [>mK9_*cԻI|VasI^(ߚ*)g@jI!%P@REHI!%P@t%e|*AN!y)jx̥k+P}F3SW0n]ۮ`#{7>\hS+K-RҶ C<)#VCI<Q[B[sx }|$JIPK˼E`.G<#OT)Emt`PsNV$P40>\t9d!Lv$EHI!%P@REBe[9ϐtm3[,h״>ϏaxS7(0%)jIn{8֩|:-T-$$@ δ@REHI!%P@REHI!%P@REHI!%P@REHI!%P@]oT>PMFoaˮG̏#Y18~ߞr\啔4ð{ȇ-;ahíʹsnBsj9g!uH^Q %3(SZƹp&6μZzUG#_3qz!ѧ% Z3m`*HsM8t펛&FۇՖ`GTۍ=TMz[}] qϲsNXq<ExT"$(BJ) "$(BJ) "$(BJ) "$(%%u}i۫O7:(" 6V$RRρ7o_cO$ ȍTl/G<14%H"sH}`L'Iomnj'ítYe%}]k-2LPDKuO ƚ3E}zۘ0ȧx1)Tb'gCՇTKw'Y=//>He83N i `{3}zkѤz,~=3Zzʵh,tom\ ﯡNq>5x\zR.+dB_k7VhR}xUYfEW3i /[n1["8XƘE㳱k澑&FPOPwcOL$c!60aX.Y %P%!%P$V-u~ }=s풒`|cޝO۳f1(s*kEsv[QI/E@>OoWka}Ҥ:=~@!q<8+-5['xA44%Y׹y\֬ߧx,4~n>>9Ѷ'fhJ3y\I|qb?# ,%SKOe[}ڒOAkhcHd4n'oC`'2n{Kqu|{YUsl|=i𾤚^-8=s[G!Tm#]Kr_Qmb]b-+m| o|@) "$(BJn[:}7c*}G ZΞx<OzN@) "$(BJnSV僚u㹄hmH=zO$cj6$Cu Oai~x`-MsӶhdf!K>N( n\@V>xYn1rVp1hTsO[Rn!HkT,-vrnb]Mkóι{-{{x,Q3n7#QI(BJ) "9coW,{x4-ubc:U;nJ;ⱎ/=*ٸ?Pϲ҇k3<x >eBV>Y j՟Xl>lM_s4zLtH:N[Ֆc2#4l𥛴GROp:͝=ڬV#[o?g83a>jۉx6 ɻ¯ڒ\g> < _mgc>j7FACR[nAdR^%V4TNNS:bvD5|0WF^i_H4 zZZ@s¹+m4 ~~bk8i鎐s675Œn-è,:Zxq8哞#Uã!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REHI!%P@REf: %䨱yIDATw *) @F7oגt5|߯גd# .(ѵ^}kI#%5 %;?яH~$ɘ9ȼěĵyfn%n+~'cIENDB`yao-5.4.0/doc/aosimul-loop-screenshot.png000066400000000000000000001400531234404334100203570ustar00rootroot00000000000000PNG  IHDR+1gAMABO pHYs  "tEXtSoftwareQuickTime 6.4 (Mac OS X)tIME  x IDATx{p}@D((ed섢Aq8ɹ9ͫɹs'vuO['Ur$1,~H]"E ]3n׏],S(LLO|tgZ4  vL&M\#kvX__|  ܹ\/!y(7zޔvA$p]u9s ˱x)k[pg}_SO=u[WU/ӜOqIr#zȑ]*#A}x^yMG}tnnnvvСC<7_?#|7?c=[D}-oy p*Η-d3O>uΟ ?Bb}}=Ϫ?<p曹Β׊x6Ɓ=ޝ R~~? ёѕMҾtw}y… bQַ|%}G㏻y}w~ \jYH qˡpm gy>|nϲD?uرc|M?C?|M7}۷}o0P_8|C2f?OsU66'x~puu>O={~R z#6y뭷w 7ćd? g&|wn7sÂ1ޮeI8'uw:_я~x?~N>W]x__E4XzBE|ʯ:t2 \._?;PuA1X"?;'v'~FΕ\S.|;ѷ&~N9r۾wyX|?W\C?CX.]$v3_O?u+,ܘ_H9|Pɛoŋ[ :ٳu-M\;Ũ.b^X__Wc/{ˬGwkwgDX}O}oo7tM*ɭGc?c\_E.܂-?\z?#t\GT쫢>._w}7}ދ?'N0~uPekI$ȕ\ȧ%l1@A7Gk^^ ɭ:77w]wO(9/_fIS@$7x3*ɓ'gvZUI״H zϛ[O=hb d\8z7M۱;A3L1ȏps}ݧ]W:055gV|<vȡh"'<Βug~g>/?AӤϞ=OwDIks=W|kJT\/ߝD ۴;A  O~?|?_|QlX&v=ww0_x+_ t.|kԧdp1J P(o3<;;(N:wO?͗Ϝ9 &|_s_җxʕ+7|$WK/TT׼]5ݗ{w[0wSĄo|y??_%5 j$[Їϟ nsyddDr*>=e'> Pr-p??y O=33KK>яXIđ)~#9ϟi|luџ|}snw~o~sO4?hw K&p)T vѹ\2ʄ7Ҝ`ww'>xseeettTt YIoon4.,AH{''3nݝ Z&P3e Na mAAEAFOOw AAt t01% b & ě   mh$s,ATݟWhUcVߋ 'lCl񵵓゙t4Dʣk_݇6z)7ϽчQj3\om[]jg&_A0YoҵCop%ew+?=7uk=;0O k6>2i3uzrg:u}[d?faNN cRnJG4=/TR]<$A 1ۼú2Ӹ{򅧆G[Q ;*\wV~}O8 Mw{]tɻX;S ՉxEkkK<.u][` uuidE v1'gl_)}v0 K9~HD67I\ؐotut^)6OWwN|\Kb;ش`x23XhcnHy.Jbe+H_YK9Vն;h͋AOy.6z^[tehd랆.AD͑AF ER{!{h蓚bs A "1VzphJ"QboI$pǺ"+ szin 6Wcc>wA@iOlh}GϔNB=H}!Q_0Jۜ5-WVWwMajI:6l\+Ns4ms$X[?,=|7`'?fSGnsԷx㉝^=B0<efZz]l= I eG]ueo &~Akh!`r0y;`rlL>˙1-]W'hBn}Vg0y)4 M/,ms^-y0Y jO71xUk53 J м9Wס>ob( m;2!pSEf$~r9P|R-lMzPT{ 4x{Y3px | ?0\L*L?i,x$ rCg$b8f Mz&۫yVч㨴!ґ"bAM c3GMń+97dB*L.^ z[" IxR:L .[[FCG4 \$ܰ\jj+Zq.ys@+JkĴв9-~mҗݲĭ/g#+A- &4N>K#2$W2kzUtɄv6z?rET UIaĞě u %0=LjmVEo\ zydbaki|p:F˨A-v3`-b{PsɕL*7:}<c'8‚ctf(scECnZޞ! +P4RE10BKIMbXёYi}bGeyɘ GEMJfVH^!U Ji.e}LKdYd;&XIk9Dm K7{[lXkF^iҮe\yn3||oN4'`Mل;dƴ ij[_F|[_ڼG4s16oB4v A[wĐyXne.ghWk`Y)lP hFf>*`]BpBS{#`j-]G@֪3[i|AYV?+drX~&3n)h)ios}. ii=g^ tSA-H!եmFi.~ YSX#L\X2cS l,(i(f^G~P@ $: jyYӪgNէ©.*%=8;18 ~jT/3vgNIT81}t.CGU#} Λ2\fhp͵Ơiqwku IͬHKNԨ˕$σpX; z`Qmk! ^e:9PW}j-xy=`;nuRě xODT)ާǒr]Ktzp'29v~̴3LcOKS>ZIfmX03N%#}-1ۜ>B6e\m=9D1i,$Zѵ;?ۨi]lq^3';\.'tUO%-yiyJUlW:`; ě>̾P_Z.DEs#U9R~ћ3La=rSs s6j~}Zl'$"5Bz7:_Hv?$ii™ĶɱtѼX5= s|c`a˲X'dkLvTj+;~D:\:ɡcu t obhۮ~p$* 1X L[[k5bc%Q1 WsfvEߕhboa#8grTWɑ r{K109X%/Ttէ?kL6XJshe?dXwj>9r #8[bm(ˎyrde/![c>HA $p;"Vy?9Ċ{Jv#SnL]dkךccVs'ʍLesX .Lsnd ,'yn`Y&b!& TeEV|U&<֮FdT/?۸le[_{]~5~({`fiV䓰z!9Ŕ `x17r@-NxHkMppƛQ:oExɬXз"M҃.oEk7gyg$5=#f@Yf\3k}dn|Խů_Ҿ7^jF3+W\= ŭi{,?#MV.9ǘcSׯ$ ҰCɃB5`* q-R2+grLvbr\nt&}c>/ jpȶG]æ1b], 1~i⮅FO* \b X"S +_gFx17}{^W?p_:}~}KOkO>)9I(;1hl|2]S㡢sBA 1X4V8YDOAVuۜEA̹RY DC4uϬ]<ɩfelO0l~\ح J\K9g񤢣Yj,PT+?jh5}U~߀.HGf,O IDATG@JyYa~\cmTT]3z^: ά1 "m?rePÛ%/|.K ~[/җW<]w<[-{FռحeOcd v2c1QGe{0*7\O :tøkSC&+*{&\{qN#\lK͑~ӷZ/z$Z=RX}Y_' ħbgƋىI[L`孖Q9:= XT̚;gi).k_RL;e3o yV\\/>#3k7xlՇ'{N-D asi6}*FO!heOD^_?3}e+ȰO]Zg֗Z ]/秋/^˥o&7͓ARc^LF>&eivsxd@*>4Wy=]#^;1kРH8-mV Uě%jx%5vn<Ө>MdĴ؋\[X_~eb+lr.5WkqBkGgkՏ:әȩ$Зg]~+x1D3wa䩇)XhL74'|+?x:Oͻ7t]Z4( X3>gMO !& (cU|ꭒ*ly2R(xwKvZ#e{RojB3; V_lmX,r2Sz? PrgF3~ GCSD`wRlXe.s |[|͙}-zɕ\n.^jZV_j_voP&BEtI/9**su boAM  9F-l-t[+<m\!3rdSeكo9=/w{&Yk,"cIgv!Z neͻ> ~(VCA '6'ȶ ]0QZ) c\qgh-ܰn\VY>3 1.W["*;ȹ}0=,Ϝ 8K$0a[3ʞyA_x̽$3/}VYp<)W2c,8N5c뼱$msrpꂼj,*ph3CGeIoc0!W_aõPӬ 0ɕ>M+O%(֨)/; c} :C 00qL?R?twU仟[/ě&怜C+[Wk<$Qf,|9s1>RKI&>Ibӎ5ג3^Ӑ( GDFʩ058\߉MCyÇf5Q,σ<#&œ ;|rp&$]KfDk\~aԔ΀qԫf;] ; x&/0c@ `1ySkZ(N|>B5iTϲ8@^X#lfTm*կ&ě>1J#cR/+KYUmjlXեd~8<B~:4e5< y`^Hܩwۜmt662Ǿb~Z$E]]7ɍi[+9i2^w;L.?߀ˏ䵮 M7Ux4b T]!e`iQAc6}xrÇ[)N m6x*pLԄ[I~:%VK&,f|N&YN]Bʌ:BĞěB}!%<A4U/Kv9Y./ԧ_\'L/~>e;+'8)y6ˏʡa%^ S7\Fn.1xC챶b~9̀.΃lL-߅8<\&Lw4u0@Av$Al}h], 1X?3כy.F.%d$MVOQVWA?P=l";# nXA :)$Dqi mI,b46m1v mqYQc=$\rn fkhGNds]{\:H14md c0}&?{7/껢PxuGh|jxo^ ZU˭:{,<[BR :)<(>?Zmr&_F@&癝L;, jqrbGĞEbCEH=~C;ޙSL & ͮF]-{ c LJCM 05(Tِ.V GRjb.Tͤ\3c%l"͌aWgA7(3ĐN3Ha/cfWTnJRayEá(d(mڛ>KʭT. H ߠhsbV5oj-OFٮ[evI㳚-6[m =NWefo8jhEeX0*z慧ͱC+{akokY_m}3/\|1Z 'nȍk<|&4m̓*.xK?/iQ{ݳh 4۴`抖L,Y9pP?7h_v uZMFS"0+O+"}=-`Mʼ Q'oFhJPbjfVZɀðɊ'ׁmz xĞ&kEɶ5m850R10ķ]wcq ,MBk\֠Nksd[`~G3o/pDvnDk=XyFNCkؗ͑5 b֪bk gkEg<-Am_LfF7W~TS~lZrXc#*PXCW"SUQ mڊX.#<sSIpj㾼u@!|SɝDKtYdkMZ_QyX }ըt0(p,XQ8NL2 ED ~h &W3u6mn~*b1geٜkڦ絈߭x &@w.ͭ:E}G-}X_wI8[6Hn\}Zy0ԎZ޶y-i0->Q8r@ۺʼ,FBUZ ~^QnP>"? 4P 4A0]ܲJEd7sJF^!}D@ۅgV1\<]0췆 ( J8K(1ֈ3)p= #H kh7";PqHɅ wO8AD{m>(*#]4*{Z LyE*/o&ev)SσH7`-<#9AD[HOvddƍ4gnƇ' zf9Hxg(BFdxg61݊?|l3vM0M#0ya>kVn;jGpszR Fo՗KY:LfGoz7Z8`Ok#j557m~9Q@Ӣ` ;pvǼUa7=&BL稾+0yi~˨(AnA!En=pTΗJē<ě`P} mqPQr:#` YCKGfd*%lUOq O*8Z{Ua"M8A ;F9Xՙ?5|9[ 8Nf8:RnA hifHx]o 2y^$T]B n策3pfk8 dG53&T]ǜ,WtKCp@^O gПO%!gxTsYPjP7.koi,?PDٜ< 7T}ڎhH3gpλuE_1c7o.bh˴h_IXm=9Y|Y>l\or/2uҸQ&_yL>\:Lf5-)$[X+Q\c3]q,3Rwbd3)SMdA~ox]r vr(~AKP53rSYJEggSn&Tbk3)7A?VƓï >WJ|E)<-v/裸  %ASAuxf19JE}5#J{,@ xkflՈH20r/.Nq85saNцnuI=7{֧UYϒ#Ni\rO\gs2~Hb334X5X5Zr@,W-hWkN!N)w5=dtvU+IɎyC-2=1m L(Uk>n߇(w@IX]Ne:'J@7 ?TNz<+h/jz.p Z/-oam+5K 9>Ě7xr\ .PXd~]!mW[ZMf$/$OGޜOL2 5#ھϛ M7 i";#9>ª4͚k5={c۸`/?DW5L5Z9Lb>@lo qem[ u "]1iBXLKe= lUR^NL6k|y@aru`qf n[Oh\/+7Jσ/K𞝔c @PUiaÛ$ b X8wnsem+yG Ǎ'*#1U7K>J'x,x&3{n;Wߙ=srד#Y*Of֯> Yb~&vÜ N7#=/a\Ǟ|V9Đ[~9X< K~97.40gi-+6qmW"7sD)m-bA̫qRSRB}B& vn[Yޮ%J\з馭@}5#99_~XVrs#2c<9z({oGח[ח#A&dGlnӉ.$+E#G<\,?N \svm"b2`M=snfǾ@Dz'f @Z IDATȿw2Z'Nܖ>&;Ľ>6q$bq,[2T& [;tO @/ 8<m5 5e뎄cMY[D-$N+<g뗫Ba]J4{\ug>S<|ls+OT#U. \M)a"mȋII,jnBwim2q  auzEBxy񏷣<(` Eo+G!̨^dbɧr;)`̼U9|J2X}Jx$ta$m.ɬdGc{'hәz93*Bfn* 6h8%6Ib+hO՚oK#mQkI{U~GM>RYLlequIWN\hf~=m]Ge׮=~iVrt6g+ۚ0<$N@{hJA/`#] .$v-ǩbѝl5Z\l⎩nv_ʵ<3֗^;~uӫ z'OZOCRP&[;V VˤA4@Щ+2#ϕ`/dawl/%DqAH33\V~fW`_za6?2]72_\(n ]p%U}`sZ9^29c8vm"bw6…yB"DE%l &rfxk֯2ca7Nyէ*vrΒhAĔN2cղ@{$!p ~Ɣ4&DQ<⡺nto:I[͵VOek|MͱjFA(֊?7 b)]c*uÙUt]WÛ$k$k5fVXs%̮/>\;tk֯([JZ}rVvB(J-EI*JB0) N7kh M <AfR歟Yw\vO&ahfn+Mn'祅̀]ľrq;xmu̎=v̳xLjy}11;ޤM"+h9+Z%rSmxOagAƜ&/? LE&,??,+;1z3,X Q?}uy4uМg#$}*nPw3 2-4,cY[0Xǚ\^?$l%9( iUA=3Q .t (IAt9}ٗNbL8V[F 2z ˛\&nϷVYF~4LMYO1mfݶVÕG?N^LNY>NAO I?B sVr'gD׋s̘V?G57fӮ_cl~ޤKVٽ2Ǚ>)\I%q.ϏVEļN;~Xnq7˲+66v{Px,r"6^H*fدTML~O%q9 1;/3L m?*cs`UsyڕBmFg`Dxy&`sV.HS >!<h337cjo{1 ƂY-/=7%9!pnsA?Zȡ͒\yIr?d(WfwQ@;DӫmBMMS[fAUkq6/WtaV(k{ަ*w^fY:.t6РM˛2~ ]CV 9V8ぱQffD.}W,u zbO@}ÇU͡C}P튮)%}@ivfƷpnF ($G\k] v acq̌p@ƌy)W2_s^"z^jyv( ᜊ V#p.XӢ.}fm3G2G<[LkMV(L{}ゝP =[]*.M \9/]ͭ6VϸrUQ^׷~0tc&__N]ɧAkNh$5k:2 _ /\l|;͞oUZkx9AAfeZBVo WQQf*٦3٬B:/ӋAH GQly(5IWn% :{hp%Z#G@207<0u3c hîMvZy!w_ p@BL7@7MwNJ)3nPo/jct]šDd'Xiod^;RiXƽz}F36j6ȔV</ C7!mL ^e9y'_~[;ڈoqfa lV;Dzi}#,X^֧͇:7['qC0d{А; Qo|X15FA [%ma76!O;:GH= B,*<."PC0VyrRn  $C rS{]bi sF6=G rAX~À5;,3;3:KGc{ ܛ:χ矸։?Q+󦀵U_=Pr5-w* k)>AAl@=|kVkXB ܬ&~tyG) bAg1%#E ^k+ADZϻI睦fV޲i8Нnӛ ?m}Kzq6h>TV"osP̘kOڍ6]6Ȍi}zD~/ ѓywA3#l ߬b${W9 gnM FHȶl64s48AAP.A &b+lS4YwOy3`P?"WPczyPlTGszFRC}d@G3 ,#U޷ۖ?#ctՔ@4Z  ci[76 \c^^b^ ACpXV"f=3SGM}SzsZmtk:CUeSzB}k辻\-ѶBp2(wJc1ۦȶ/nx7Ez>uQ $Z۴̓0o'XL-0VtK^y@tϬyzdk{-A 3!,Ԭ::sC=ZT"l%S7BɿEج_H Ow`rMFھ7_qˠ"#ϧq軴W0mI+^ᾣ^˨^Zx⁰kkyhdղ˾ivZBck.G5mr<͂.f{@nT3 }d׍nj;z m a|%7`+$4WZv(tJ"]fh*ZjlEZU#}=*j\F~&NM{gZM: q`/o8os Z:D0]ŭK9)Jdhs Ԇ^EhhԞ"/!֋BG3UȨZH ПݽMdHKgvw_H!k뇹6k}Omt `ll~*.l:]2.t9AS`%4")#2Ժb'_jnP'% Ab=>%IISN%vܷY chQzZnR:q63]h8P b7& ,v|'~Z,A^|'P J»"(LmOv)R\h\ BZU\ȶSkU}]E؎UQnhfĴ]; #vH6/P{XW\QfF\̓~pcIm[3.M?!3[6faS SӼN@%0EkАS̱|+ ș.#Ď):'SAPvjuV_,Q63sIL[\W7UEmmfԴFf̴oIJI hsDh{B1 j)NE$5:o0^HTœ`.WMd$##i6-v`ZBdˠjɼш Mf3[w5w#bO̦ =ZFv̦Ȍոqi@Ȁ3k%ux8B]wjlGh(sy"*X0j:{*ӹTQOX0l^B@{a?u1گKb|; Gj^{/ɱ6jOzbLF'=wZث2LX>As+kc? S-x-G~ WXq?g48lim躻?wc8ܐ+_kT3vd |g/wʼWvR2XߒMR*5J5;/32y>D_I-E?: +T0uè;D-I<ЗNOrcpXv`a* juKm\+,/)SHrnouF5"+2:٪[4Brh;y"ҠV'*9W] 3/l[vEw[-E&WzrWl *Ԓ߅ >-oh0ukVC+PLW/)_( Ybrk"+\`zQ0[!HjIٔPlQ jSsIN1n@t|l3?uUP %v*U݊ wTݳݳ}ny +ٗKRCnv)$^}0ub""jU1mHB"2`k2{BgJ;՘I AR`s!2{FOJ9X4z,z&h{[EvDҷSLm39U 5)0L䊞Dfʌ`\>̴df&&lTKF~1пx,6K1t8%D=22,Tu M2^%,hwiJPkVAoguvX3wI4'Ji$E|FU^zLЌO > [a7iqUhFh8/T; {iT ?m~n|៵j_ūwP?:g U (q)L;$'T X%e *3.O=DHaN z,+™hA``>98;0/< csD@_,KbKr/l.ճ13Pߊ.WUGDҷnAvG4G3+ IDAT4(EfݭHMR/dp ŵ,,m|)-Mn JB"EU@-d- sF bˠ6Ul}VfH+dEǀSA$KLU.dǂ\J :3jIjGV +x#L!d9SVmUPQ*P!Neoa1'ؘ0#S4.;4ёCG)T['2I4'ki*霬9)NEyUČ@"a-Onjϫ^IZ:֌yLrQQrV#^',3hL1xa~hR@q%ؑ{,G*/\g Xb*4J:ֳCi%PNjVL}i%*Lp=3QwNA6VBg%/齳3rBN݊~2Є mmXSpA 1}1_I1=0֊t81=2 3TAS;S##%qJC(sRd%qJ`/ؚgu;z(SklWǿyQ~G_*oI$T?@>h*qmS2b|AvqRZVjo+5^4׼C#CS%ͲZyNFG zMm1Ժ$g.ƖEگ9z`Uf U@j&f5,o;e6_4zip+Sr&y*I}Ljw&YVȰst ~  VGWP,jQ:EOI9=zfxH`uc!%Љy YcV7wF9C DU%lwNLF\{9 -'50)+Ո23&FUPg`K Al/}%&?흮ŬH-WZ[NZR(y0zN7Չ`)z2 ; u#ydUK%*R_ɲh5fA @QiUE@$ [Q$Ep']`ȥx}^VxmK`}+?qCĠom%UUʭ>ɲ=.%$6:!u.ɼ$ If `TQV`gMB5MQ. 9?mީR켴K9S-)?gZ/օz&*k9F~tL1 O&S_,  y.GrL Ɲ wٮH0}ޡE={*Cr2]Pሧd'fk,{,fwn{(sR lFf֣4þ"%fsL*r>l֏'T6 [crbؑV3+fZL^~.bfw˹$)\26H:ZfOvLIށ؁W4k6"N"[^М%A]+Zٮߓu­&)= [IkU9oUG2,Q !eM滮-I{{V(VfwǒLя˒xW~sNTWiMu65a +@])HXܕLu7+mdz\&O8Ԓj('LF5U!Ni5fS|㛧^tepW$KcnΌMdDl3zg7ZEINq7o1aM(>^B..<7A?>ypAYȲ,P||B?|q pn<*֗Zf^;;lPf'hUB#Ya+bM0ƤAӔW W+}揳Fa)WM׮P^^L}qi~ sy|YߪS<eT&tj;)Bq[lI/әN K-^Im0a̴sRvbor|{[e}B_QQ%nݼm G{wBEV2Z$)dU^0bi&?=Dq1~gGy,6=Kz1{J8l`d*Y=VfD=΀=ʻP=$`6^ް"X3b4F5nUT]+dFO)$[3`2 ߬P~Bll&@He=)s/޲9PdL ШFgy.5%2Ns9O֯2NKyTX{LX՘BRM{od$!cUhV6kXUXiI5Rmy'[eɼ*ho +!xSk#naA7 ˎǵ6M=6ǫ8{[' {NƞYh)@[g3{ܠ000%mp3r4м_o>xochV \)n,cfY(涳@.Ǻ)K?tM1rw?MCވ97.XP47_Z#mחxml9|+=;dV5O!V%_؝d ŻrR+ZnxQZN׹ 78{'tS\nZxr,١v?lzmO]X:cMX_ 驹Ldǿ mUlF"zqQ[o olRU*ޕ-$=֌6XF2ܽ늎9Is'="feaonoKǸٽ_sgKޠ@EF E E&g!GMNAhH" X3!-օP>e2gWGP]2gW1<܈tzFNϫ/DѸs 'ÚI<F&}n$suq[sJIT'[ed:E,4=|%⭙+(OK6>h95ͣ:؊ ]}knĺR6'z-.vlY:H]}v(nJoֈ׸Zҏ˟ ^x04[{mdcDq1`L7WgcF=ӀeU7,h"&OnX%eEKO]\ sLnYw^Ji;M?%idګEp="݋/ŢjCz"LNdMfQpm(qsZ²D ںetCj;ג7~C}7-2‘l-m,`] Wtl)^vK+\70ʽ'[lS1,\76-1rFw57vs{Mxw^RcD<c?aJfyWS-/u%qֳ 58=GMy[=+xcxbMWW'g^~癨ݹxxks _NtT0ӵZ24&zNm[tVc[37jc_,eC_Mg?3{- ss?}'nrvӟnHze4um9ٓ+p0y#dRuy}T:sR۔)=(͝ke:I}|%- l6_8/oa2`#}ZoeI!J9Ƥs eR=da!V7ab\㛷=s;ddd*lqU&q7+~WI*C3󮈠qa'{qq`?==ZRόA8{rx+ŀ(1,Ok<iPo_!Fօ(#evߐ;p̀^^6eDn>m,xwۮ[hM|PZși&}}p+o_&߸ɟ? ;~g^-IV:͵|eڟֿc9 vrˇ/繁j#֖Ȳ ?x"MeO~úp9&}^#j1u/'lF=Q#0w|JzSS+ Fn-nCo}Lt/Eע/vw4.]i\Iaƥ]Pmd҆Ycyw6AF7{V/Ndz[yfA=jS[Uuu@tB%=\[!BD8~[}-A5:Q$4CWe7?!leQfΐ[8l\ˀƬ))툙M;*)ns>z:Je"@LPSe}6&'ӱR癒bgXA 3fGLcd!Z yz<,b|tu.y/|uϻ6^'Ż HW}U_ &ċ婑GsV]7%kַ8"#wd(8sIuxNAn]"WO]gv@`V3ʭo9h<}5eK-%G3j .U&y;yakݬQQ:M"`zd5&k#Ae﷼ o ."vLttxB:Wrs]Ȧv?Iɕ_Zc-tSPnbw:.↬Lz)/^Ɓܸ;ׇp?>*M-z'eU\YKt&܌S,"@^vM{$`"YAsGyEarLX/۠ͻvrˡ&{ڹ< `r?w~S>,;&'Z7Vt%%7\5ѽ1>Z;OG/D@urso ML}i^kٛpK7Y#vri~91tyee,~u[T\D֭D.}CH|1{ِ`ӴBr(ad#me%/䌰Rq%A?n4.rpH޲%VMIٓn &3 ʓɒ%S\ljW/:wAmk.yXU-.TnsmmةcJx-Oť:wNnS?.bS--I$ k;ۚcUqc[7n5tS,UJ[2ԵIfO-?Xkrk%{hrtE=^GTܸJne"S7 l-S7'沚\Z|L2Dץz]7Cdb:U80>s2#5>2Z޳[Hvw6Uyvy XL—독26-|LϧT[ IDATY^NȜv[Vu9qs ?.IVmi\CvX7DXE_|Ԍ倅rG|\Rs);2gnyc>r}ei: ^n1T[2@yt֫?ю.Dv*Ll}ZdO U>]mu*,f7TfG*tW禨+Fo5Ф\_5p{ُhn}-W3 p T(iEҚx8xwuclݱy4 kM[V'[Rև塅#9-=z~Ƈ g-lu9[R%wcfT}tSYdMA|T2/B%{9[uv0w6JK~f7ܪXc^]A޴N A4p.w#-1Bzt=qdo}H,u5LKI عT%Hƙ.@FYbCwNTPt\яms%3q7':bڈ ԣł+2Q>]bY#B&Vu-KVTUmF,hi^&]=2j?] Rζ&+b9UZMe"OdmQhRvK|gnWofuB4MoTA].{uW;Nl:y9MV^PM϶1pHC}i'ˣ&"U/~k2rr(<6{d*_Fb(VkʓXeεA-#e-6 ac숈R/):!}U+WZno=G9&LsU57R޼ǴA9Ttc~@Nz#,_:-NX$oZ۞Ӕiqt@GI,2wDI;ԝ jƴ=NbuXE빱~08/, +oL"m(i=ok 1ҳk9Tִ?h]Y[c]' #or]4gǮjdj0SPmҖ*\MrˤhQuHzibE=6לTexEx&B Mwmj Kr~so:,yZ9eh,]GfnF=]}!9Iiluϲ\`XV}v~\{{[+S=g/' ru+8#&Ýy)o*YBGtǼi 7lgIJ2M=)rOO@rۣy}T}~h wd*W&}{`ec\*-v p^ooÃQKe~Y0́LHg~33|*I(2Ym\w4/S>2P_2e|+hnkiFbb-Y!:}RY32‡c]{Ƚ6۳b\dfG-<`ȘȻ:O~P+_ #dG:^ rfTHg{)C\8Ĵu@zvj7V^=o,̎Ӱlbڦ,*1d% Xca*H]7+ՌԀr+J%2pwgMwoQϊ^)cوӭK1mA2mR6/PM=xQ[ʙVh;òQWlMN@k=].km ՍԤN.%.Jt\t^Yvn##M 4+K)݂m[Ye7[ٌн֕2I?/dE2yuT5SuIEGN:dJ逼2RVfFBL\\[|vrM]RVNj{-¶]vKH4(cw ȳd5s3̜*9b9śk+ƮjG ={1-Bfi+!U"{4cJY{տw?=]>l :SJ' jtGʽk7Sc5&B'O;󆑯^9BR2۪x]o9J>z\]JrMq-.yeﮮ{`2NoFm=톩Y]o;d*&]Gg$_[|::Pvf?4 %v;_ -;BGdLd^ҷMeϔ2<};Z^ +efX̧Qݙ9~4;Dr4(,p6_yx~#ӷomog<'k;Zx)o<% 8flP%QjZ v[ 3iFuQ1VɃe [db^TiXR -CZ\P"$yjD}(fG?uS\իe [fΧ$U$LWdQMjnC*zZh\鑞oiCj\%. ٰ]rG3Rbco .yL>-^vНFhTսbv1M_tws)%@ͨxb݊*2jmb6wۙĭXe{lnjgc4hP:ݰb΋.dIfn^V^RH/ ǣ+fY0dWΦ}!wmNƭ֭d ٌ],ǩ=Soe;{iz~W$:-R m#]dTk-7w~3}qSѡ{i/uN3#)sЧdb/<>Žfѭ,Z]GB"ը=-_$1GEM = 4I\on_)pWsR[KȜ1Wb7>5M%rK-J X[|)J~oL;R&Z*Ky_Fnk57e;C߽]Ckk=bfF켇fZ}C|Zd7e- Jg{2{6?(2k֒93WF}[zťnmN.y-Jc0>Ch)5z!e]>a)i)urΜЧ.qt#L4-sTpM[mEA|jG[e2 S|/+ld9'Z0Q. ?,޹ŝzY%SJ=U_Mt&xnZһDuw~⚽g69,OqmҙC^'c,&(jt+y,y7eMZi.p$FAe,{6^j@٩ݬF6/bp-;S&En#e\<۝ޜ-xA/Xi `Yx[uEjm/W`.sshSKfs3敆U@gu-^w{Q|噱Bz+&gymj$PTJ%!*Sչ:+נŮ"JO0vi,7'{X纇 fж.L{O %*Bf2ݻqj\d3B|)'_BЊ9)nOJ5Zv듟ow5IG|P%"g|YA5YUͅ4jLhɴ'Y\YuY_w7#T 4l2Vrgg-oJu\- m$tFFͽI!y(n7sO>iRJ-S]׵nv[~l%\&M15ۆSZ#[RM6dkyvFO%E%\])1Qۮ(Dif),M rPօXG%O>K]A-­;yBFheZ3Ju3W-議NJkV'Wq'HҘK'T)Y[z8m^BI]tOQJ{E"kuvKWJ= e[233Rqj:7}r,ܲYns|6?;XrQIY~ZcVĻN19#կUc{6Μ*9u*7JJՓ<&3U v)0VVrV%*A5ӳ*VDniT4rK-7Y]JENnd3V+z\c|gyKȲ,BD)g"GE;]@wy摟ed%-oƹ-˦%\*JLdV/nc/dNvi,[\J!&[{xnWn+EŻHiN[r̭ϐ{rVh{9Zג&*Hj*;=ߴ.Q=?sȒ4 iQ2z!EwQ+6]'qUd!zEzsj)n]lJRnunޗejm݇pFJ) -ƒ2YHY(-H-"֪v\>eYr*VfD\U8@r-uHLqgXJcNmMjщʤ5Pej*Ӓ-螪ug:BٔsQSzyKk[;]uOQGnY<NM-+N]i<K~꿩 M뗛šWr,2c*'4DW|R̗3.犅ZPQhslw 'P3j=T 8@j)ht/ː;fڳJӠ6xEƵJ|SI_1u jJ΂^z݋|v|SKD,jc8[tPk'|So惪5VX }9q)7s`kUU/p@7 R]8W*z;@eK(zw]FjMkH&eA9P3 @̀x5 7P3 @̀x5 7P3 @̀x5s\)S"X0.Z^Ox~_KI_)«B|-:=œm~ݏY:s??RPorxj5N XB 06RM]pr{Bfy 4|ђS:Bڻ,Y6V0t.凌>\ aXrKu~Lz:~A>U~PP?NTOIzt1:aj*sy ,o@m(Xkտfvr ka4=3 zVM ]2L^P]5P$M7>Em5+.`k8L΢nC "9 zxNo<ʭtg6iN@ 1vځ*`nC ,LT,֤=KQTV`2WO\6ǂꮩO[3yJWzod,723WZ6cO[Q.o961}d3jڄSf 239'LT,YŨ5^_kO\&%&:U1]e;t fiF9p<+PnEA*}BJmd@T%`N[w]]- LI`j^7.e T-K0{8;_T,^\ >jr* \q9 /9 49^n#u^i1uݔE%6Y1V˹1Yd%Ϝ=ֺP̏U_?,g: etjJ7Q4kvCEū[O3%Ҙ+Q]SSlF5l lwΊ\iJU0U3"ڹX0cCy"26Ϫ92?cYM<m-o|)7ل)2W2bYE0e9QVdm^DE &OO7KN^T%GZ͈]OG'Φ]v<Ϟf,=3%+,r,l֙OO06VCIJ7`NyGULdIBT^GܙH8{EE`cxls3ԆVr^-H kKD*{j+BKiA,o@Y 6hK)<ƎrY%Ɇa 8E]Vs4_&s˂dםX%BEuə')q'4S<pqY]cV:Mթx- K ĂĞoi@C^L:nx.f/PpmX,4mc2ii U 20U<Zțn kt[ΰ3q$yyϗW-=Xc{ R88cA-a/ %l2A7 {x5ns ,T,jX~`UĨo֚om 7P3 @@7GUIѫ 4iƾ8=r>~7;xewRMD}кNE}Gnb  o 6HkDiEi]/u!? ާ;/4@ZSړRMz#iglBGks;SMkF%^E^ౖbϋO7Dz⌳~| mMX% ˍ$ ̶2MXn d[_\I%\OM$9+\j$'Q"%ho 68ݗ"_/ Iyk%u5G{@ɷ׿cijTX92v5B.Ɂqn`(j7[ޡPnƍo'5OMuߏ0A$I֦=š}\z犻uQ^kǩ6Ď4u%Zm,xx#g]6sAI/$tx\cJ¹~ 8Bl } XW;Ot5Ad5os)eu*V=υPG [7#iX, &Bڐs&~$ FmPIDATG^&Q$4kӪ'Di3ԵgO:5-c]~W{>>y'/Aj Wm'XĜ8!ָ~  F@-Qߟ\3'-h\6{FV6I9ғXwX'yoӾnyIOBiRBň⾔DvxŶ'w8Ep)JJ% ިowE!/߲ orh(1bQO4o՛#; |+ىH<0֊[~2` c3.MkVa"4{?q(KI8m.eaLXQ'{Sf.*@;J\ߌ ֈ%'/.\\NWGF`'I 8 ؐBG(4Z%G*K1㯽/S=;뚜,V*-cy-Ӹt56̜9 \n;or&8}9/cAhË=?~L򎏤}za!p'l!MHb_ S*WnO^^ݷg q'Nϼβ+w`.9pj@g.ͷ("&ʹܠrw-ipq-$0*5;%L 6TŴ/>K7qWo}V6wFuDW{qϜZ GF*lIaw8ɧ۴7Z?BCXN ޳jn0 q"C͸D_MG{'iyG5iys=P `c81ņ/>3r"-ɦ?5hQ֖0aܜ}Lsș."xs*@]xOCxr8(Lbؓs@J5OjrJHKo P` ybsGLZ)]CWVGJz*\muS'vQnӭ\Q_8htԌxOC¥Uƙs;hA&> B?<(5;n7\+rsˈî+rn԰T_d֖t1k_ ?}%gQ$pW#}B]ٷlZ3C樾={VpNs"Iw{V(.d;= փĄ|Vr\e!ቘI-ZxǾr_/[o'{r"n5;> p\7^?Ǭ"zn06⭤:}d !m:#=n[QwAWa`j{Te@Q٢NdA6ü%Ɛ[-9٥-O.)YDoRnam冐6}n|k86-o5 xuKԙŢc=g~$RĊW, @xO'&#9ZpiVK܉djrԤ'q5].)[) q0>s6 O awT&@xVԙnQqw{{8 4=iyqH-vlj $ }GqE\e'w3[bV59/;4=?]3"as7\X {#Qs\q񶤡]IC7qJG+XND{[QQ7wG'p~۩XZ A#PaxFGQ2 *6X n$/#q0g;>OO+;YjjKb.R17l{~_>7/6DW5_>(\wxDqcƼV),Sƺu+z3{s"Qg@Y>sj{[ 8<77CnfKẊ*^].4RbOR#t9?dv"߂T` np;DvKnVи~o[b(ǚ~mĻE&t K6koƉ-#y~KE]Y]̱UFHW$a8sDQ'{B/ [EQ'\[bV(wꟿWѼɥ?ƺ Yξ"R[WN? m.ӷh"n~#ԿP{PuGݽgƣ>odRY36Lwav=8; 5\_<{A؋Ĭ,o  Qf9PM*,> Ew8$k^3@sZU)FI 5Z`&ܱg:ue>JLsSOfۙgNw;,iP&Q Gk""kA$fUHZfr5OPX;#dx[X;5"MB"{Ųc,, X̃{ ,bxAlr'|e'P[9 8O[#%`ZՔil`He[nSweUJ$){~+W? w~?ZfQ BG+܊xn!v]© `xb&1}A* <#ȼge;͆ڑGc}^66=-ʊr v2tO$ = z/: oGѰ ŨHLc\SLE.|Rşw;:dl_|6QgZ\X-5f@k''HV3jiؠ>c,Ykzx7-fJcߙc3mJƐ$[熭A[Lc~u?c5B,M)ռ+2&+]Iz"YȢa'\דBԤk}bT oZּjn7lp1%$LjP d7kL^#1։3-NJ-Mv_o[~ ~Y,C"VK0\" vco&j0o4aWc\(Ibw"]u{ƁT;_lrj}Τ4CWk<7Z8."ee[tPKcWl@__ھLؿa6xCL֖qj~ o5FOxѱ7NƔ\~K̻*6:ss&'A,V$8Qsc x/=+gVS[(4{Fʝd2Őy 1)Qz;qeVJ$@g& r0 5)Ut ҏ:`FyMo5.x6p!\x˙|K(#XW@t7`ݺ>{?[xMS爺>BK9/Uܲ(61Ve^ L0a/CQ.v IdWw<)XsƺX\ĩI^g^r+:ebF ؂j66[?9^T{q-BQ1J3zg^zvo<7(EÄΖbn\]x nk❈IӔ[81B!LfBs8ΆxSZg߬D|T,FVvX ޳rkGf$fiiId!IxM6d|bϏFX~G~It,? sF- 4ݱAk?ϝ]υ}6E>KXM*zٵx4Ê'ϚSmc<#w~xn {VZKbnna$Abr9OFj578dE_OyZUĢL. 9ص;_Ew/^)iL 6*.&ib9Y \ԍV[YS2X'Hxd8N07Nxɧ2p [(nj$|.Eщ[wcd|{D5omgON/?ޭbD嚝2{̓pe +9VzV^W6s0i{^=bKEBI({VӢzjO&r9ZsX`%Q 8z*ruuO,yNΧˈ0Gq~WliݔRcR}$$LT@{v䍻1 S͐F9?|'!㵭$p$rIXT kne@|_̍{|toqQ۟W@jLǼebYVT}Ȕ̱3|Y<#^a %~go{!55&n\(7#ȼ8ШɵL ~Gli]`T0]Ƌ'iϷ2֋D9z|[Ռ`^ J}R>$fN yao::home yao-5.4.0/doc/ashfast-bench.par000066400000000000000000000041601234404334100162660ustar00rootroot00000000000000// Aosimul par file, V2.4.0 //------------------------------- sim.name = "Simple SH6x6 w/ TT mirror, full diffraction WFS"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1"]+".fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([11.]); atm.layeralt = &([0.]); atm.winddir = &([0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 1; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput =0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 2; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 2; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 2000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.stats_every = 200; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/doc/images/000077500000000000000000000000001234404334100143205ustar00rootroot00000000000000yao-5.4.0/doc/images/cwfs_subaps_map.png000066400000000000000000000115601234404334100202050ustar00rootroot00000000000000PNG  IHDRߙsRGBbKGD pHYs  tIME 42N _IDATxkUלSpi,ԶBZ酤SbVILDx) k Q JSXjLU&В .sN}ko2 dΜ}stCA O,APt!>~nxU{/'@ U ^@0 Pt!, `* @EB/d"t :  `4 ,C/.qpveج_ |>m}8oI{ƻ_Tw& 0VBcjoѴ|!"$󻌡RC1VBOb YE8 !MߓŽEPsU נI2Ti:|b)-hT +O~§ |d+.iPԵL5 uFҦxˇ (!~*i*A](-V\0Da2+ ].!t/qvT 8+Po1.*qk.tmj.t~] ];t}l\Kxv|*r`y F%N:ક{٠q|!BxEƟ0V%P+|eCX Ii1/͎>ƹbV %×q(@ f0 te@ͣƴ J0ϰE=y an0_X>Ɲi0(Xf @ 4@X$fj0D_P:5# Ĥifj^yb/c= Y7-Cx>#JQX"(eG-tE:uYz3:s@G-xV]Պw ^tW/ ³ _ !8ݯ2iqA᣾b,H>.AN=-\Nz9 {0?UK8@9OrHi^(Q@՝(zaG}#'-E/<૰JqNhcgaD `' ^'Ľ˂WƄT0KRܼ}ټ}q*zZ(JY(E/Cy0I[Q 卡mk=,Wj(ge5_+7, XFSq4Ƙ{vB0 Ʋnz > `s#(e^hko/aPسۼc wYSݎ3. M+*l٦VT{N#f+΃W }q>~;Х|.^,.;5Bz :`磸Ҿxp~{ ơ j~E^H*↾\`&+Ɨe0-xL+GO/4:`F_0 y\O:ik0 D;,ܷܷ"%I1lah37x} yPrLO.7, T~IR÷ambhx@0Z^A|eAAP{%nnhd>L.9Q Rl.?Zr=QuAj۶%ym9>5kQeq!,⌔~2omMguLr~ev<.41AџJN^E5B:rb6C7x"73Tfq@QU\B}02zB 6~&`;C qSC)߱Vct猙2kc#8oOLvCH)ѴoL 11ugʚfO|A5iʬuGv:t.Կ_@@RbT~ J_^zu7"d1=2.~Pt?4}z㣛|3{1v9=ABج8=VSͩw?At8z`9}Ws嘊@\IBY@ r$Q B ss?)c @+wP_SUZu9|p 3/AD/ERKdQ+]qGa /Y2Ƙ_T!kzy r..vuÝMAe장F?49 tNqCjy.:cwԶ =vO %P^H1LOJ@-8X:dil䂔K \<(Eq`"(!2;IФ& r;_;Xhs¬3j(rE8` >%x`6A-yk~eoO`o^~lm1NuQm#A P%dǽzcW~oY#r#]–'ܯJY@?Sk>A-V3~(L+V DJZquU*n{ib U䀮 riۥ;s?n١ (;|Hbu e+e^A>ʺGs,匦b`1-xQ~Y%ޥSd='NΔ/mDTQQ@ `GBTz, ^|y㨴KTY1O{4q2pDG<^^~e0ϴ3/RݯUodpޒ-`{Dk0L_q͜ n.NH 9\+,}kT=ɤ-jE !'*%SQ9ؓ =_U6rNfeQ049\/.?z?Uc]1l:ak֓ά*Ӟ?.Zru@=پǚ9uaqM辤hc:CTq2 ~5WT鄥 h0 00Og <`aV@Nj !L;hတ?c2 `;4@>c<]2<}aIgpkzl/ >U@iB7eKf.?s E!cОEcGq0zgK WALyȤ|LQRc[Y 9{ 5o_#s@NXƞ$7zJw.IvB*ce e޳ r^H Z q6k~id2Q'leqç!O ˀ t{-{cSPlbgvՄTjN=T @ A>J5Ez!/rT#7J/7jϻE|u4JRD8 |^Eдꌡ>Aq0J =(\x(g}cA0#!s=(F 0TC0tC@10 ba@E( >*TB<sE)@:{܎BED ʀIcIENDB`yao-5.4.0/doc/images/cwfs_subaps_map2.png000066400000000000000000000115551234404334100202730ustar00rootroot00000000000000PNG  IHDRxv8sRGBbKGD pHYs  tIME s CIDATxlVh UXd1141aQSBdnj : *Q&8cs&&nq1llSnossM Bs{߷-FJjp8 a`q8 a`23˼ݷuOôu0Ǜ'}lC}b|b׿ȟ(PVȣ cc`AQE10Ҩbkz,抹7P)cp 12%*J|JZqq\gǫ7qŒ߸wnnc0>%/1PaJXW61B 3o/￑GPRXZj(dN ,JT,ŕZQ^nfh-_t:Z8%ı2:_BEVK\t܈  p,Ekjw3nS_|j$d`:.^v򹬖:.FfK\'PCF FͳGsQ>, w|ݶy8}}7>OYroSm Hw<|?Y;e}. kZrPFDC]PQ)ހ9p+jYpVj(|0+TrLC,4 >~Ȝ+2UT2RK:1KTɢBX zj/M&d ZmKI,.W- ,.NO4, [2&o83>ehQi/-&Pr덀bz7h--F|.>,z-1Uo~gȆ\X́[+u86u\ L`ƕ3el"n.Ȭlu.+:o8P?mlbVeHEL5/s6伅=.b/%\粡K 檽LL \<՛Si2_0[,;.|\,?o0b6pj679 Z,[yL*_D!uڬ PDg{6 e-FNټ[LF FE ,ř+ Յ_SЖ_Zf'dQl-2(rngcW=IXYLzNl71E0۸Ta`264\~$2S`qs{Up]xƸL~X+ogCA,3LSL:#,. La"WؕvO'06dg0j#Xj4å{Jkيlfr& 0J1s60g/RE&[NA=v_OnDzޢEMU9 =ܹ\6,h5X dpUd m|Y&˨?_@kI{.6+j2)4i.O^U#)X,qS)7#⁗VČqou-e׳0GEY{6^<ײ Զe6]ULZ+`1#Si(`|p\߭ar梶i/qYcf7X|Lv< a)ܕǏiE k莈Xb#$\TZLTaC3i,(mE ŦkP2ȿl[~t1d{baU6)(.Z;7H݅RK9D,7j'ƣdʶ?w~ヿ.d+lbYTz`֮ ^|`ۏfB4}mpqZ@mi{;1ƍo|=(Hah*4p!&2\T'&rʮCB%s9[iPkKB{'Xy&F2Zf#NZ )rCZ.)Lmøګ 6Y\-61(Lyח6Y),A~eL8,8y}ܸ ߸˨dFǢe .+k/d&`yLɊ!٢#~llTi.Sd2ʐq===‰bCwLTDJr|K{ +),: 2͕oI-ŸTL3>k˔7Hx fa<ĺ6FNy~W}w82xj}g6B}UGٱp\̢jt>lh+ fvrOciXBhBXs Nژg0NyzcEbn0xhk?ƿmʿs m#"o|E{Wg 슃훮-;9 o̿7)3gG{(Ξz=> FgL<ރ10:OC+^c`zȎ o6|^r GlcÜoяGS~Fsx`߼ZlQSۓ P"E6)g??g`&y{deca\vTԅo/ԑ>1Tb,Õ& FE\Q?l>bD32ۭ v'eXdRb!om"X:d[MyloRVu+e* JlªB&r[>VUM6*-8^TZ  @0{?3UL\yd|f͚(_p,F:ka.yw鲭JVmv},\8n#\2b zn1k\M`ߵ;d>f~hBCqd|^@6m2F^=9)X|7bwf66,l`6ZLT\> D`6n{7;?b?oaʶŋFټPlW &b&-MfÂ,2v沅& FD׸#cM\D,<в WkE' b>pȡۃh/-m3fۋi@,4` Xԁ9Lgcf{Jwd>. &d`^ V.uZzPl3Wl 20* +{*dQ+C2h&بˢ**2" KX8h6p"ˏRQ`ydqyL!!}Si]MoW`a^TΏyt.1 O\ 0p|E7(H`D }7#4RZrĄ7.Bh6yU\".R F\JŨ"`dp ? /'?5~p-e\ȑE%GUl,@|WKi׷'*pBOPb]+R Xx&ˎp;"#̈́ %GQtV4tQ S,dXAq^tW4 &hT>2*+ 8q#q5Gcs%LF,NtuB$J4b)J/h)K-%`)b` A10bư9nx,b`QA10BƨXPcH ,||`K88kzq8 00q8 Tj p'IENDB`yao-5.4.0/doc/images/dmthres_after.png000066400000000000000000000157331234404334100176660ustar00rootroot00000000000000PNG  IHDRt4sRGBbKGD pHYs  tIME  MDATxm8P;՛ Wfb1u3>@TuMOǖe }@i@?~=^{_=Ԩ(6Om}V(}W~_[_'Mٟ[ i<6'{ܷz՞|gm퀜=o9X+s{ֿ/njcj/) {R},f{gvR)ؿ]{Ni[zmVvv?6Pyy2r+e_Xtbe{p5vޜZU2=6?*`ĥjy( CzcL=PB/َ3|-c?LSRC51[>16[)?**PCx/ [A-c=cCO]wh%9uiRem:">4Z[a}[:6_NطWz@@tunZU#5d- {6ci`@ + Z m_;/@ oa t: Щ5s_@ sa\aNˁ~߿$ʵ/ȜmTm>ZCz@@t: t:b* 贇>MӗXX(68r@p+p޵rm<:;k:| }ie i\8crn RN'm60X8vCg(:@@ @@t:@Mor(j:CL+W_5oV,լ}>Ǐ_VCVP.=ӊV+fU6=!|~ w;Rc<{nʜ{6#M;MRtXG!/x6=I{>/|Ʃ[==Y5ǃ@碽K^_jatvm@G vr@A~HkG:G _ _Rs {S%ԟ?}3t? zz Щzd2,A>h.Dp^ 0P\)Эwԥ:疛{%L:ͿVͩkX?rsüto^[4#WW9joz~ä7cMfKyWN8ɜX$z0ߖ\>saZ _Vu{]Qm5Y$&z9xk,X9aF|e~f5ЍE[.ԍ_fǺ9zt9B0GS\9~N?;n@Ϟy;鶧.:9B]#t9 #@;.@#ԹlwjxO+TWƕ+ЅyA{A+ׇ09!uW*F5GrmrS{z9ivї\loʊY+'[=N,72ԧVTܿ/w?819ַp=`Zmhᬲ@7@?|) p@2Ů9u =(7@2tmEtзzz#8bjz]#t6P>Mӗ/F?{X[ Z++ om8mv~-MbV>k3zYA+wC´g{5wiwQOy-]ro&'[eEADMu՞30^#W~V һr =R/DkWdR@В 8@? kt~pQ}2#$e$X@=tu\*r P!+> tЬޕk_mLk ʭڽr ¼{gLεg3V k^z᫯vry^ew%7 ~X)EyZ+]orKַp=`,O9ڶ+͗@Ѝ/Dy]aw/AݪVzWn.+յ1ї-~Vs(P+ /-I@'=tҹ0_v%zh_tPSİ PeQStCG/ 3"8ꗢAN{4mp.@@;GX-7w^yj/ޕ߇D6u{V>sY=u+_uyǏU<~@Q{ S݈>(r+6)7u+}Um/H9C@G=KwV=Jus:C-t@^:s^:P:Bs}hBE3_znz3""9.kLŋ@Gsp t:PG# m]C+-]nܭ0P_Ǚ@gyPsr0:M;B l=a g9Ӛfo, #UB=?~=v\ҶXf:_mqvf9=}j09Ҫg[z+#mzy!*{ ?fapsG E--{+3Gꂽ0SsNod +ίusct`?&ȝ!¡~^0@ hW9/=J=r+ Ω=v_r@G rvA@`z r:<ܯ>\"G?8K0|SǰbQrKj ϔ^U?*)Zc_p<C\uʭg[3AUߘZ7UU*ƾx7B̧4MU6r)Z#7] KylEv5Z}aao6ЯdToVO*7VǏi'ԡV;N3elbfTnr㸻Y1\90 t:@@ @@+-b\N{4}遅qrmX(W yLkQ\\m^ %Κ>h ҆4a1?j,:|8@|NBχa]85;̡3^TXE@@ :@t: )ʵ/ Ѕ0W0@a++׾ sJhbV5̜Cݐ : Sc= : :@@wƍ@@_޶}A.t:@i) pЈc0 t:>4K(]vg;Vͬ8 C.zNǙ@hXNߡ<Ǚ@?d1;8k']ҤMsff t:NEOku^6Aæם45`.)Dždt/ծKIjq?E{+}Զ[ϙN^ O}tƘVTV&3=:ǫ:q,TRc\{#rBg%{zt: t:@@ t@@ :@@t: w߿,f~?|{9S_}>Z iS^mGUisd~LqQ}k']~R%kyR_;Ω[&zSRrO{nZv~/b/z ~)i1S߭k^;TZynM[[N6mϔ2RcN]Vמ_)@oT㧔]S߭I}{az:o۞1e,=?iڽqw./!wUЇ`NJAsz-o?QWʰWzrWЋ [aS5[ߵYŦ9Ku[l/7v%=c_/zC^ vH|c̓~az4\.iC<[wح='=YНm.6U(\b9:cދtT]~!xQy{ka3Vo3Sco{z[sokCd.s>7cg}r3ɹ6彖=tJlo'99z`z^9sp\˼~9DRxICܭ-Sj_}A+9OKVYG!5_;mscU+w{֜^\kUPx?o1o9_z:%v~:1v:os|95zJ7=Ob#/%z1smOc}maj^cjм;kBu)G꾰~KlׯzgRn9rn۹āsRg~zY>(2^xq~y{X,urk׳m'͏>5*1]nOBGBg|1*YR˨=&{k_?/[F[#ǧ ;v1?K<2={em S nzR_.zc.9Og_WmA:a.|s;>{k}s5Ï1KԻYazCw}zHM5sTs#gyvB0RsOЁ~M*k -tz̥RJanIJ-f{-R^{[ך T^ə"fB!eEں1T= }=L5\r^Lɞo th >%驭 l=Xt>Zskhao!8އ3B6kkTyGr B#L'vj׶<7W#\Q\a_=th<зV-:(Z [ݾg֥Ź)ں;[mKf>ɨ|Ez y>y\2wH'sl=74J>9ʙ{Hy{Iy^Μ7m>`Vʱڶo C_|Ǯʉyc֜ yNLC={mcO= żNsRܻfslͷ(vHݗS.us#cK.*wعU֦ '9K;yFmRcv/'cT{z!e?NͅũcN=J9z1^j/>0zpo.zԇDQ]JoO G9QWȔ.ƍNkSޏ|ݣ8ۋk][|*RYݐKɀ_/;tڝzj>_szV~L^Ej\ߪRkh ͫR=g zZ=+g8.fەhS}9]?NQ4p}:tO9¼6C\zu~9z #WKp˜:#1~w~3&s}^)FZ۶顧ΗwNGˤ\\9۽ڼ!mn3~Gまv9\R=c-eKG*z/$K{p4IR$JGl~weM?ڸ)*XSs{8b_e>+wt2)s[uϚ;Rz2G]4Szj\:&t:@ t@@1m.W`IENDB`yao-5.4.0/doc/images/dmthres_before.png000066400000000000000000000155461234404334100200310ustar00rootroot00000000000000PNG  IHDRt4sRGBbKGD pHYs  tIME  3ONIDATxq8P+&tI7e$bXk I| z @m }~'{F<{QQm>vvQnޯ_>no=|P69gm-i؜0qzU{Zirؿc̵:y[mt3KPyJmSaz6K=cÚ?w9)k{lC-ƶZ٩!W[ؐwC1i}a!ݧweĖzyszkzVz|RY #m桜/ ]0-HBu տd;rj󵰎0M݇K | l=N >vo%0κ2hRCu> qdn3/lC?ԛd =?u tޡᗘ䞎!Jͷ@^X{/km·S*n~N?:a^c߲_p_t: h_ס=hAoWuԐnP6Pڠǎ!At@/0jշ*HYӾ :'mm&t:@)*}.̅r9 v3ܞ>P-- 658Qk{sH`@ t@@ :@+-b\N{4}ŁrmX(W 􀘕+p޵rm<:=kv:| }ieaMz\#{=hm:al5ԗ^ն±z?E5@y:@t:@ t:@oE|땫 0w+׾ ;eŢ`ouVxU]+ǡ]{}laW4ՊYըMl>_ՎR}'7{nʜ?~iBYןݖBrH Ə Ϟ ),[F=8=y+ +йZ/=^}#й@_5^ ׮mrA.  v@h kW 0}.o]"tvN0_A~To:aN&c`P-Av!:`D9}`RnrS\۞[n0H0j܌}!%ԅj}O^twr3Yj,Bl["ܬiEß+g.L\kA㫗xwh>~[7eEG'ytSvU:*\?MxrS[m[yZmhL}'.+3&:Jv>M!ݐ @?Op 12NKk$ПC-[m8Fh˷v?`إ@C?tkq`(zdʭڽr;^zmܦڻ5]E?ҫLSk9?8RV+v/\{?(e*нzʭJ{?`4Bt "W..}Z][\m\mw>D϶C s(pD p\};3M_\!лLgN]C.} z: t y? ]n37=-:ζ{kh2 TO0-땫 n{vjһrڠ۴5CO4V='x|C/+_u{|upŔ+o|Q_^ilK۬FY˚/1" &j`@+[땫 ^z88׮@(@%/E-?0@ p~r9?^j @ pQ߿U2o,::tC.(Đ zj-qݐ땫 욢vʭڽr ¼$?cr]Kߝjxņ?Vd2{녯}-GYJC,9mxO)bkVRr W%[m[y,Zm{D֕KQ༞3EM0t@^: s^:nAzjqMk[.3MwһrwAnS!Z}US<σ#fEԕk G/7u?tq+wZջ5j|6PnmSn|ȡ' 1B r딫 *wO\ tiP:w@G/a@@G/a@G95X~w"o=u*Έ@؞P31/ag.s:Ba@S+kB]۶[V[0"|rwŜ+̅Ё~ݾD/^ B,:.7+sEݭݐv_~~︤mBurll[x51):ǒzG3hVW.x|]yz?f2=t>ro"\Nr=s:ѡ. s( vBtj +ίusct`?&ȝ!¡ߍH]Α~W[Y=tNnGk7:]@G r:dCL#&~a@>bu%\2?cNQ]Plz,kePY>Wz.W]Xn7r}DiV}c @=] VQVn7}NR5Yͯc:vjx=8iã IF珴NCv1})J\8JY˅=̲0v3!=tk@@t: t:_biStCO, ot@\Ĭ=_ԕ]\(mGgNG42OՁ#eM~VcPC.6Ѕ,=pj8vCg(uB@@t: t:@SŁk_@ sa\aN> AVzW}AjŬj9=s'AtAܦ6z\m,;!=tAt@̰ff(f} rA : jNQvF!@@  -]B*8ر:mf,UrCw8zG;|r9!;@/'Y8&l66Te@ t*n_~Zu}- 6=יִ+uqWL9.$C3\}7Pv_zLJsP R3nyч.Џ:VjճFؿB-^luJ ܭq|,6ιu]Sb{C.z);e}Ej`l _`@XC9rOغn|?)ȺDLmu޶wB eU^ ܅l.C_ 9-zzkcܚ{cO]C"kuI$m[|>K3I])|8W+Pb{;wɱ+ʙ#Z !2KJjǭn=?vnRr{=^yyZb2:8r1mwnR^̤^۳|8ZEl=:kO71+^K\nphЗ-}eL+ȳf2áN;ELn C 9|e.^4:eޓ>oGJ=}ΙW~Jo{|ƢVO^j?C c:x_uC_ژ1YlyK=h]7ľ˩Ǽ М-,)ĜžЙOLx{˩q|S顟|3I̼|)ѳ{$o{[FlP-SPYRO(=R[b[Ǽ~&;rH_O[?vƠ%ܜt/vt=sԛrЍh%Cad ڟƣb{FX%?Hhӽ8i~ Qr{*?=GʯuvT=s)uuT::^F7C_"47Fh9|0ښ%|e=>e'ع|{Yb摉 {w-Kokbm%g'u[ד2rs0ٗ6W8j;Z\z1)ksbַO]ρ ?~ĈҞ/Rzgy z{{kח?#73Qmg΍y0r mvJ}= C5k-bk2P}lC+?R33\k6luYw> [chNoc/Z l$V_6l\ks{z{qz|!1έ*RJ{v)g[!['y9sĶejʂy[)Bjۆڮƾ1T}Sc*'kZs2T'91ubol-~>c+b:)IsZ޳Uα5{#u_NiCiW̍0K-޹bbVY~7T,)7ŶI1۵ƾj{S85Yh:8*/SczœRa\Q=G%;w)u<~0/woG]!S7:MI|{?udo/vm~K'geDwC.%~miw~Y3?Z1zCޚs}NkKݮ9ׂ 4zJ=Wh1^j ḘmW=~O?bv;EsUߋЉ>X` r֕%|^z.1[/s0ݑHCϹNy?soTjuso^:_9Ei.Zp%ȒsnmN3OV"kA\&knEWJvpAJ4ɞv.uz|y>w4赾,=H\&5zJ(Fݕ55>>j3`Om<ɐKl|)Zn=k.GpJrR|wNQN꩙rAzz@ t@@ :n_]/\IENDB`yao-5.4.0/doc/images/kbkbgcolor.jpg000066400000000000000000000010541234404334100171410ustar00rootroot00000000000000JFIFddDucky<&Adobed  *       <<o```` ????!?!?! I$I$I$I$I$I$I$I$???yao-5.4.0/doc/images/kbkfootercenter.jpg000066400000000000000000000041631234404334100202150ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHH?C      C  ?" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Q@>= h o(/_Ҋx(,uKZ(yao-5.4.0/doc/images/kbkfooterleft.jpg000066400000000000000000000046441234404334100176730ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHH-?C      C  ?-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?bO?ҡΗ/ZU~}(Q TU_J>}(joq[Y֭Wq[xĿak@EKk/CڇC_ڇCW70}|qֺJgwր=~Ȭ/_ҏ_Ҁ7~ȣy(y(*޹iWo#(lRץ |>9WѧwP@ǯK*tX-7?.h=J>=JW_t[E?.hyao-5.4.0/doc/images/kbkfooterright.jpg000066400000000000000000000047521234404334100200560ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHH-?C      C  ?-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ڏ{Pl_UQF>q?sMW1ilֺzCGڇCGڇ )/0(4|~luj Hڇ~xFh߉DZ[\~hωgPHm+>Ȭ/_ҏ_Ҁ6;}? M@'ՑS;9vm$[ v oڻjB>FOWºC-!w?@u_3 I(Zy[{Z-G~&_z픿~[hC(u{t>$5}$4GS m'0C?sWVWiHLBc9zZyao-5.4.0/doc/images/kbkheadercenter.jpg000066400000000000000000000042371234404334100201510ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHHdC     C  d" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?7h_N$Q^K 0J?N?b|cKz\ڇ(EshjOtW_+?((((yao-5.4.0/doc/images/kbkheadercenter4print.png000066400000000000000000000014521234404334100213120ustar00rootroot00000000000000PNG  IHDRd$sRGBbKGD pHYs  tIME )dpOIDATxݻq@ EQܘmzYƙڏP`sJ@vu N1 <B \kB@ma AWF"pLB *SH [(@k@v])/B@n A!@dzS 4眦6 t2 i3LNFR(@hB!WFByT 5 QA @ Bf9M 1mBІ f!NF29Ad 4m2 QA@T1=@&r2 HRq(B@f A{7@^B!A @ B!A @ B!A @B!A @ B!A @~/ˑCIENDB`yao-5.4.0/doc/images/kbkheaderleft.jpg000066400000000000000000000060671234404334100176260ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHH-dC      C  d-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?y5=O' s;nn?V?U?i_O($&h%0uUmJV;X>+__gO \]ě6U[BA|NQz/(ݠ:K 37h_N%Wf)?nK褟'uOFzj7<&|6vMk+f{]|?򯜿8D/&~} =_Ti7M\ڃ&,M/Zdr%|K1Λ+_Oҿ_9#Qdk{l_9m#H?HH?O&LJcI-jcoxx9ր>XK-xZ$xW!W++/UTYn^M RVTԿ畟UIƧ?1j7<CQRYƧ?1j7<|$5/x:khua%1F癇ʋh0ϝcyao-5.4.0/doc/images/kbkheaderright.jpg000066400000000000000000000061151234404334100200030ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*JR(iZHH-dC      C  d-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??|`nJo/ }E(;5!l@Ns9`-ƔyЇ%mOZwhî8VS]AhZ˦sjSZg?9_USN'ƚ6qM+A{aLk2$Abge߸?Z6߼8ևxWm%$Txgw?X\ڴ<m1_ە+\"IhoZP&{cZGg^n{/٬VIV)> ʟ*웇Rwwֿ?OREۿU:g_>:`6_<{_6Cm[}jޛ6?/zizsG@3f K-qω+8)٧^ ztgWj1 .?*kD}x/ͧV~xm?ڷ? _/g|7A+?J~zoN;U>@}VCe<15[Jd⫡<kHmzoX?_<{_6Cm[}r(_- G_ܝS\V_#'f:W3c0$h_ /<kHmzoX?_<{_6Cm[}EQ@A|Q[_[c@]_giXFpRN*}YWWL,a"}}%g|| oMkHmzoAg9N< #vGQ'QE {6|fuMx_H?66ֲ-{Y.7:~h6Pm ,X=OS$4QW-~&xͧV~* yao-5.4.0/doc/images/shfp.png000066400000000000000000000306231234404334100157720ustar00rootroot00000000000000PNG  IHDRhsRGB pHYsttfxtIME !jY IDATx[l\}'3DJ)lI-)$]uE_.Ю}ۧ]@@贀ZME_vhqv -\ۉuqtsth*R[ !\|яg8s_e~~Xb!@>@>@>@>:VCZRYy_-g^ /q4@>6C8h3g&^8 l-x7YRfaٳɃFߩ{s r=Y__;U{~߹'ctJ/!ش L)O?k0)N-| >( Љ'-W7YZXl?o ZF%>Q_T磘5>tnn2>ZWZ1ldPvѥC#^NhN}0߂-;lO99f2y ѡ%hI$ҟ3ce f4W7-X6(ߪDZ 6qhF7rs$?!`Yauo^ZӖyMV]p̗}Hi':oKeSkj 9'!PTTzY;vgB>usheӇ]$ԬY Z7p??P⢺d̍tn4yP'l(@>J;쾆'd): @9g)kUcEUuUGF2@>60h6ߟߊ P V򪙣oGz֎? o2V>Xw}w#?я.… a{> )~&e===\R{%en aK={ܹs}y睤lhh(\oVnٲݻ`^x1)~zyCk',/_\-1)ۿv2W!}^zu @>@>@>/P/}of |뭷:}?Ö;sL/O5$_(q{}/}:sGd۸ `ZN2\J~#mьK PPnTg BX911.7(%e;v(wEQ̭[֩{ 899Y6;;V+gffJ߄mczz: [=x \`v50̷޹rGm۶m.0߄ypG۷oO?t@>@>l[V*bkt@,MN%t]'*Jk!j]1|AjޑOW6s8@>XΕh &>}.PVĚ"$J.\õk?a[ڕn4{ +Ö97OJ_͛7ʇz();|GaehΝnlw)̗S>yMy|}< +5w (m_O]`?X |G6ArWJiA3gU|P/RO@>@>|?RJ_fK0ly,][X>|8)"X===ae\.9 +'&&۷aҹpy мݍ7ʰer0mVz o߾p/_+=V HKͷ[K> ޽,     ԰g}wyЁ~5Ve~~50^O~xpp0ۂ]z5) +_Vn`ݻ7_Aa{ʼ[>Da_N/6cǎ2l/0l9XVڵ+LްE#\gggKKj=lʼUi@>@>@>@>@> ۷o_O~07< }ky[+__&e=\۷y{yWr7/~awwʰ?aC:deyKIُpQH6v]d=ʕ+a??0ݻaeގrxx8) VEqƍz)jFLNZChp}N;2l 7;nHj6)V'|VsJ%)˛=aoVSBqrr2<{lRv7;&e333>.] +v%?fp=kgjc=V`ކZСCA+\p馧Gۊز9;w?|^xd27 (_;_ڸS4 hޘ1400VɟI l ;ͅ +WQ凂ShH|uZe8       mr۷oOFX`nݚnaedΝ;ae3{R)wE2o1̟{zzJ[n۶ĕ^vڵNd~  c޿1lihMewtGҲWج6Auj~gك|`ڴG*=l*KON`~~~@P=yOWf]n?tHt[י9R_!o OCak~'OGV+ +wV޺u+ +装{9 kOX<@g~P` ae| SBֹNFMh=V:W:H[d3ߟp7bYoC2sp#yşkE( v>H|]mmɓ'?Wb|ZVx8 xW pp@\_Z __ ݟg`yέ |tir"@GJaqފmll,r_(綾^ZV{{aeAwIx爢(;V??~y?ټk3:\+RHNNNaJ_ر#?w煘B؎9,}'ټ uX6΅۶F_@>@>@>@>@>`ӟa~ԩS|衇ʩ, ֐,lES4u)oht҇(홷i}vX6ۊEq޽,lӐwƆ6vKKOZV/0>n*188>(fTЪ@>@>@>@>@>@>6:cǎ2旷 {%ir||<ܵkW(2oh7ߛIw]___ɰ0^y;|^ aOȰkeQ/^ +w.}cN.<=="΋~K. ܳgY@>@>@>@>@>`џaG~ܹsFtQ>2lV4nqIݻwW4;;ֈ˿}ӟo571/| a嫯G^y"nIիW_U~2oy'N|;徜|/˛۷/|wK<… :th1t@>@>@>@>@>`ӟH3a7Ѿ|O 4$T?? +LK߿y/Pٳ'\`ޘ*8V捩ByC~;_r7ԩSaݻ      uolp?;n]v- ݹs'Eyݻwo|Zyҟ=Ùۿ۰26[FGނW^ 3]]J߀{^ ۷o +=V~ȸ ߟ́-? (@۵+_V=‰EYrK&Vcap5{477VNNN>my;|oߞoNrJXvI=3NE#5(#}}}.0o`{2oU:00 i`i L@7$4:?Z@>QM ?`5鿰.F@7DV8|pϟ1Ё:`MT*{;=͛7W ۦ5CU naf{ z{{; ݾ}-w }J="oY%D{D?ر#\`5;O>裫lcў#[7$K.l5E//կ~Հ+k-KgU'O'şO8a|hկJ%_{5` 糆'̅@>+}m4˂B`\k+x+t`.:y򤁥=`~~~1,6P3([P[+=N)R ˜A5::mĀɃX/] IM-`ҭA#UɠpN?Xj2eSͰpO>m$PGʼnTjg)g   Vnݚ͇]LykG}~h1cpG?o_ŷѽ{ʚ]V&f\mF[]͞o5}ӟN.\.Fkp`` \`[k#|gW̄ Oǎ yr=[4҇sn;@S#@kQ@8Ҟ+ʋ t|:AH5#H2Z}A+Ͼ5Ȫw?mB*1=,>e.<+Rtw0f?X8:P{eOV:s7/"$:֜JKO@烚iek,.ؔZ͛կyڬڢc={eDmۖ]~Kw +oߞmvYhvvʰg3rCJ9y_2ʻgqaߣ\)|a]822.ի ?<#f/1,;@gzw nrA֠)-{CӤep|rl:kVtQ>XU!9SlO =LKm1|@pb 4/:Ѻ w [ A~q.] +Nacƽ{(쎸k׮paW"rߟnq/ɰr`` )wc͛aeoooX ;v6 @ޕ1}Zɟ:7>>V ÞMZqϞ?u凬p,,[upY7N$JQ@D|/Vdq -fFª_Ih% jn  ѿaO?tN~0owNg>ز%T~'7ӆݢ(~v=͵}(_c37pyoϰDLsssaet߾}n?;v+k6Zf`m?0\෿2'fzz:);qĉ'e=C/bX{ʏqzR7@_җiNW /     ԰9aQ +5O&''Wʛ !я~=#ʼ?SKﺔ?uD(>zGqΝi;/~1jww3nݺV {ȷ|ϛ{,➙EQ\z5).}0|||||?SÎ?^[oed@Zae@,ovByw,7Mۺ5gffڵ#a۷۷a˸|qücg|_,(׏4 =?^ɓ'ʼjت49y |~zXwrwޭ~ٳ=f      L ˻Φ!ӓ-LݡSTlrr2\@XDX 孏|~`5;Ǭ$ldmx<Zrm۶͇̻߿_v^4Y-\f޿*??@>@>@>@>@>@> {g<|ccc?{oooRk׮Bbj,oږw9 ]y\w.la|̋b污Ͳ!ʻ㓯Oiޕ1w hY0~ׯ_+δEQ͕|9ǎZft̙5Fbttt?Osă۷ M'!A۹?r"4דMGgY[t&@o> tn<6%k|pX {W JǏZae,{{{E155UJ7b*{nX977WfmR_%>u޴,988]r%\`:5۶m[XQ#ukzvK6 +?rׯg|N>]O<ʎ|||||||l276lff&裏ʧz*O4!nI3b,lVggg ~q`>V{MNNy󽱱rxx8)AN[Ł-s[Q^8P2=7mo߾]f;="?޽;){K?P?@>@>Z[>PTZTzͪ+W 6AT* ldd3__WIJ2}~￿ñce-:J*y[Y΂[n%eG7L*w>g?n+5Yxx)GGa[oV_uoGj5©'vi~](o7 /7e]) +<],W4r9?d.\V.3x/X5@U|??WzG(|T!9eX|||4Gjʼۙ3gʻw&eCCCv"b _\eHӶ߄6 ]`.a߱mI߳1lZ4ҿ1˦paSO=V^|9/      @=76^pݻw˼~XqF{q0My3o+zccca`RV]gs%aŢ7K,~h=N={;/b WBܹVg? +ާرc=ggyF>hQ:ӻᄏ      L vZX7 +M&k,}^)r׮]Sn~yw=aeރ._>{͑[~fffe1ggg˭w(zzz6&&&]|NSԖݸrhh(ܷo_;w     ԰__~742tǏM+]fު.ۿX7f m۶-;=y/wͰrϞ=aeC]Cyj;w\vQ 肰aD1?hz~(ȟ:߀VC7;nݺM(_;P;w#G8 @8_`qlttt]OD8R1EQ5\/<;yʉ2,x N4V޼y1WPRw^M̻RR;wL6HfZIݻw,K(ŋk /     ԰]أ(ްrjj?+?2ӟ4[ wްʕ+ae___;m-y +w`;J,+iwr||<ܳgOR6;;|0Cvƕ ϏBy ܼgf      @={F?+atRvp׮] +  +gqFXBV4wҥp>hX911V:t(K1)wMK߄򵓷1 +ƕw +KY[oU/@>@>@>@>@>@>`ѿan +e +f_yż-X^eK;ÿ3o9dnjjgg/ EwްaXR7裏ʼ^IY%{pO>͏l o\67e5oGhq@>;vAX Bz Bz B:t|||,g'J_Ç;`ؿ|gK_fk__*}+S~ȑ_;Q8OBH i`wY,"n@>Xz`2 LkQ^3gS_ze~7K O&܍h`#<K2)+KEQlt'j^_xE`|P#|su.@7sAQ3egFoX/o\ w5RgEX_4NU;X;]Sww x:v_NΪX;u|k:iSݏ!eكN笝v:yWj1mpˎVN-v=ʵq@>@>@>:VCR,ڣEDX`YL+1}JS:oMN&@oY^۹vr\I3[@f>wPʹB%R/%HN+74Ԩi [V ?w]A%V_)4y @=ю1K||    eIENDB`yao-5.4.0/doc/images/yao_mcao.png000066400000000000000000002431671234404334100166320ustar00rootroot00000000000000PNG  IHDR9zXsiCCPICC ProfilexZgTM0Crr$dY`FrD@%IPPTE1$ "(0l߷{k[U/Eݹ@##M ȮndS@ `Y!1mՈ\|9<+DhؑrӀa1S$b7qhm KG:"!xb/L3}amG?'\6Ʊ~A\DD z <%߉5+\@x!OEn5m2R`oL'_C'_b TR%`>+DZU[[?@Mp;/&2xh`qē@ h=` ,-pn`"AHi 8 P ΀M:h]>C` <`:A"B$D )HRt c o( bd(ʅ P%tBhf%h0fy`XV` a*G"p< o5x EbEQR(5 @QQɨlqT u5FE}ALh>4ZmvD)dt.}}=~0\q Dc20jL33yEaYX1`Y*cʼn4pV8O;;xnŧ 5Kg"*%7M M.MM M?,-VV֖66m' /A`I#$  ݄I'"(L&:#YJ LIHAMWENnH/Fo@>~fcdpfd8pabcbtee,dld`\feg2agJgd4KAEJ$HOI_95ݘo2O2oxTeY`űJZ6~fbffKgec{NbWawc^~ 2>jw̜ꜞuC\\\\\׹2܎ܟxy yxYUm}·sG?%],r3yZV@MO O]`IU@*X&'EHDA(MA0QXS8DH𺈰HHȜ(I@4RZtD %, vRqI]G;?JJ8IdII,KKKfJJ⓲:(uC꽴ttLLY%rQ9\\ܼ<||y 3 O+*(I*)*)3()PnWPW U92ʥꤚگU3PKQkS[WWPWS_(xɮY9Ee`vюw!m=TN:::)::?uuuSuo=}zw1}Dc#l%FFF獖卣[7ML2MLMLON 5k?p(kj̬&֍l lی6~3˳{Sxg6{}CC#eǯN&NN3Ή\X\|]tr-v]rSw;6.޽y߮&Gn'v/zyx>J~K m#y]{7`сn A +`kt{.>!1KѤRQM{^$DFvEDGDE~cS{-97/*8:NNLKڗ4#$]np$Ljn'M(-3ө#3633pb_r*ͪjogCN:^#[s@,.U]d}%ʥ/777]aueqo㫦M#͝WU^nn)Fsp}5E{ woܼ.^wKVygGa'}gmߺbVY잻uw۽?yǢ״~q~; v=5`0pgp{hc=GlFFF\&=72|phyȫ,Y-~mۭwl*Ko`aǥUx5ϧ5{/6(??on^o!O˟S[cXo,7 TH_ Á@V;((]Xw! ( Hƾ-LaM'e%b ]7sF,²f^Ʊe},@' tU#*V%FR]*YSg*t+ U2T44ݵws?hd8e6057 4O8ay͔D{E'xb.\;3߫λg?!@8P#");4t5,1|D:%732#*9:*&4;>0A)#q%nrѾT`˴M23&dEeGɥ*χL>v=.GkI9U}0awjSrr߾Ni.|3b3Sfef^9~GT  P<_p*tlqfҚgVWZpk my {/v]zSؠ}%~kZn owdtn=pw^=Uy}IA H ~ze8dϨؗ'MOON=瞦6<;blŎWo-u|۽G5_2q|o/;C,PLu ͋>Tr$YnFy]#':ѯ212u+,)+<"2#$Q$K㥷dVdgo+4()(ǨxI3xY_[WSn^~1l~~ en\3Au !֡"{=nPŨ?GG9DG?)GNKI\LI'uJ]j~4LӟetdV!'av9,_=r(%og1w|ēEN?--Y*]/:CSS[Q]vvU>tez+MiGVt\nn +2L]5M{ޑ=^>}y\1<=71^SgSn3C/<^'GhF'}|go3]O>c\RCgtG 0!RtH [_ˠ́MRl=P6tԒ`~XU=x ERFy2PQO( }݉^ňb10H=WZO1 ^DbJ!xZD qN+/6C= )&QJZg0a bYd f}Fe[gO8)e5Ͻ*=_ ):F` `PȈhEHG-J; 󊟔!*r)iءmc+תid(nq)sg sK}+kum[};;]|)N΅.ܞz0t]3+ uS6Lq}g_H/M{jo ᬸܙUG[],TPnTQxUtaRDXqU`wN?|?|e,s"|cZqvek7E]G>X+"?~@!<!( Ԁn0x8#P34 &>:eFx-<]`# ӆv𸝸b^IU=B`E' ėtty+DH&fe6=^V'֗lQ("9N?.9];ſL$ b5[L6Q(4*+}QPPPO8٫^]@wAaQqIiY#RG\5 ؙm_֙E-ǽunnO;lX?K ऐ=0؈F^H'LqvG%Iyz{}Spֆ)_QE*E]gKMLNs`GٌFY'r5>Fȓ~R~>W@"6`H{#c!;j6@p 5yJb x@y*B},GM1ȹ|;*O vtϚ?r 11&DobA~ XnK@ ' 2  XDE##( 3o_ゐquF2/ m3gGbc[(|V#Q~I~ϚТhE Bd4 Ƞh}.Z i0g7ƞ$h:#G 2|} /N Smt/ķn\A`H&DGd4pa;r*|)*Y|]s5go~Gyy1RK!`!`@:W򹫮hw >pP3 S'xbs'>]y&Ɇ@!`!`!`%/| o >%iȧQ EHO\<>נڒ!`!`!2WYY[BtFCR#Z|GGGϷ K!0mt7d!gM}}j#K!`S%}%PܤqDpFc7 L4CaϞ=rTlBn.rK,quuua6]˼;gFܹsݳeD`GȨ[hQNv Clݺ5'Q6&w۶msv-7 C"'[3Zl(CنC}AVj*L:8ht_;ӟt說Ox |JS ;~s9'g=kii dv&;ܑ#Lm@hoow˖-sOǭvDQ{خ]ܩZjs[5Z7r"0 ifDaL8aayLUĵ)z{{ݽ0Czj2p,(x8Ν;C̆^xᅡ#B\Xw_HvbJbP&۷ow555a{{7-KpV2 C`j@X%|L>iG Rd7D8,^8s%EP< '3]ڲe[ti(&C<:-ݿ;~̭*s+a׾Ύj0 ㅀ hhKE%&3SU0":avu"&{T1Pʄ<|L+Să v"L v6-e̠Lfg*=VgG,>H۱c[܍77ן~u/ ob5܇W>n~]{/x/sjA;/e/r'3?kӷ'}!o}}ƻCcN"Ѐ!B;l;w]{W>lY޾}M7P}!0=HьBPЎhآH&aNvDQě?eDIrGp6!N#r$ܤ)@62#J'I;5ؑ!`p%:7nthHf4W{" ׹|\ v 6I.qz7D?|i_ٍ_]O3ovmc~_Vw}rO5n׀e5nt=5;MsㄆH߸ذrº27־??;Dط!`S@Z2ƒ3zYC >x0P:8pD*ZdP;^pB/""q&e<$@ L2S INPC2 i{:^p]~馛W[ N M 6,?vcs`G${,O<=#B;&ҠrVX:=:Ð8>!O]pG'2!F$dJݰrZ.Ad: kB'%ǵk_CvYrwoq;@Nw7ĝ<~֭2ݱypuh?9>Ž;+]/[&ܙ5w;aM׺yB5?8ݵ$5{!w~n^fV.y}־_wO;q&3X0 i>ȃF2%|?g&!`EC xa;FxFG4Ό(fӉ?fEB8at'r҂>]ĿhG*>ʄ~$ G7;o!PZoJx7C&{ T iVZL!`@JLf &)ƏX_YuB=>48kit9.YlŰSleC:&GނIӰm4M!` FfN4ę >t"3VoCtJ$!`LQ=0A^/Y)2i冀!`!`#P4G4{Fi!`!`dy'bڲgC0 C0 קc!`!pB"` yڭӆ!`!`=(`9A>Š܄S)!0Edܬ!qz;N@BB夶6uA!dy\V*9SI3ǣؗ.ݔFJE5?iSMӧChIծl!0zF ]d[NOyĊcyKP:u~)M}\)c*is:*F 9L"-xuYSd6ON,7 Cd툦 ڭ^R6%E;Sٜj M+ udaL(o:;M:lufM::$M6 C0f9'6|>^c3'_l'=rNӠ ǤɓKeZm[ %Tu<i{S˘ efc3iɛ !?&AZŏ)NC9d24 C0'Yψs~@&?o\MútA:ku4Z.g˟rhW*Vfejb@~r4Ɇ&o/XS^1tAV. C07Y;H:G}ڲM-=u >ٖl(_ʖ7rSѕ3}Rf!m*94/ygt=i2̤cO1K~ǚmڳMO'[9Fg!03(jh>.AL d!M*9l+EŒJduf=>Ɇ^Ӥӥia M:ޙRR_,]ŒS>LC0 !ӌh!@6\8SM~B)YRuNFo;OldCCy'ZlNj22kڝ +V}J'7]=;Y;Orrx:l!0TTuə8]Ju.gMu3\4{gX!P !Ǔ' |"1mcyA0 C`:"PTGtSYQF>y67v*|l4C]+tdmlg@،hJxB#uojȑktBxS٢:qeM2ژth{6]&冀!`གy]ߓt'gvgeC 5T7lodS*yq›6Tu%ݺ7{mV-7 /xgB&~/ҴF[ g xSL%78RѤ˕ 6zsM/W0 @>,oeC 戦CꋎtcW><: x C`"꺞u3ftBBlr[x#C772Pˇ76i}Q:ұ-\Sw&>ML0fd8-ճrC 5IoRIu9U;4.c]Ά7뭐= #e|1[TPT̑q9Nk_c`߸ꔱU<ʅ;}s/WT re O.syq7b4!`EiҦ\йarcKauQ/tLy#gvҡu]fă:-0 C `・i-8tbX5]*axCz<[1B.s1s2 !3XǜJuL}Qb#JE(x|: V7n^V &%|_t_Y{4ػЗdwAg8.]]ݞD0]u?<&6^/D;{$d]ʛ/1)P׶M'-ٴk/No|(tȸT/ 9!^FszFYN{:V{9Ç.vډ޴pK(m8n1@w_ߨ)ooW.?*u4ux\YFr`X}kHݗ;ry @0?rH ^A tC`*2]hh[1me9u9Nq*5.竓|āyEeC屟@W!`9chtxrôx!Ǭ&p&e{:S~`}Eok6 A/y^h ',ҥɇz)E?RHG<,ҳrC0 #K4y NC;QE9#͆2-ktRCcW6\p Anw]tZ7F<QwsX 7jt39p |IvI͟wyuio<(Ë=ǖp"*?^Ž״uxedGȰ4, xW;u֯U M.|_ ~|[G_>x+䇀Oy&N{Wdvzt咇|Ba :?/8*ouzn152":%%E'Jy\ko;g;mb%Ãr{b_u,ف@WP₠RbE&y`txS>:tLhɺLy~ȱ?8n}ۅO i퓕5?9P06P7ete˜ș ]\9saC!;:ѹ*wE(cxLsFk!0iL4ێND<b' > \8#ѻǤ)neCw|v^ G\ ;ry5t}EP ~.2G dx؎|S@G.SXPA7hG|s1h C0M꿪C>."&j#@g|lDXo8VNq=G_؍0dc2FL4Gc vzÖprMԙ:s%;ȡsmvB'pW !$tcQ~1ccLxѕF7Dp~\nce ͔c ɑ]\"s=I SVUI8zoK$k7F2 0Gppk2,str2!LdS.lpC p{ݯ'gBc8nĂ,.y8c}U.,wRFMv(7p΃Y`20 h} XLײjޭ}'UKkkcVXnY5]?952q 5y5nQU~z,hVGD9 =qRY#"]' }稬{bG~84(}m+}}k|B@q>孲wTꫦ&r@6 jKz_PjrY|z0-qQ׸˽}_/'Ge^+Իqu5Y_/5ur oA;TbUy!kQyݻ.mߘzNzx< <ʂ&sBqN087#g4p p=.lT*sAg 9l3 QI-Ű6~lWa&Cc25edsyO8 Gc.flB7|3p`fgp3%g\Nf*(ʙ,6Hݜ#c8bI:lٿ9/g †x bj9^$@7S&* %B\!`iƝtO=ш; 8F;v'iPe.ۜ6hyE=08} tS7)/[ԥ8Fr8^p&#gȓ~}y݁.8ѿ:!'q 2(3ߜ]H0bSht^,[\^W*'f}RaEG|޺׵QyL߰<6{νgULTIR\'ko8(!Y}ySX#*S~Ú<1 C`!`t;#fOJ@1fpJtDӓ/:IKY%߆pWȞXfgQwvMI +M{(Uut)_:ߝ?}N /nX&![7v{C¥[:Ef< y[fOGJ5 ΅]6\$;[+Ѵ_PY%;յ|PRR?.%dfgn&E© $N9JwOȩQ #RY*1&/N=K~0J-=~;̟upXs?V՛dlvHȿ,!e8<8Bڨg*tevi]+1LmK\gz䀄˛%: Uw:Ms{_*aJr=,+Po%UR~| }ؾEb5C omAOf/듗U&{8|uj oډ<^F`LNK4 ZD/g,+)K72@{RYRU.ssϬpㅱY:йMQ/b2e3|= TH{ן$)KEn>t'z{\]=Wy:'mɽaQ" 6q@NНJT9,ܘUpg͖M Yk!` Mi1HSlp:`5l-t~sM˃LvĢw_w/a Wr[C<*Ծtرv[V-~?$&BjIAoRlzzyU9Ѽ`/`, ءtYдpEr1<,v} }0D`x'$\]Y-:9*/Oy:1U?e;yo0 'Gx;;d)F^YޗI{zgb뻟8V$\/q.O~&Q!K_~P|b/E?9YE_'=WlF萚@C`z"`-Y_r<rO[m }j00>C}ɅT}:YrWF '{iv5~KVT:ӠXBj%_\Bvy9U|z&{4${eqK.}Q/ ֟IAB='AJeAYZQQ%!3G=Cٚg|â;d||;˫ !;?xȕdl!cA t[%5u E_s)K ꛅI?X^_.n?:޻om}8[BL WU#o! =g|h ç$Ѣ$PC`F!{o3x30 iwDlٙ:g!`LC`Ƈ+:~0f>M|'::a{#e_^-!1I^VyKx]9[€눬g=Uv[lj#*ԋuP°W*C?GB\(!qY:p,AV/7Q8#*LG΢m |rBr>%c-s,xSe҈Mޕsm 78 NYjrDAx:T/_b#sru^QI&-##Q%u˝\`^lmUo"LuYERs =,Y-fT8uV6 C:M5bI?eQ}|RskVDَq@?flϦL>,s1swnGc)ݤǼ6u"{ęd}69Gˉ싮GV8F$p-Pfʖ C0J`R`?k܅n=#%@] ×: vܺc8>cH@][⢠Ja(C&<#s.B*Y)'r=-9jF8~i)@0],嚨x0ځF&6vЗYpnσE~ IDATOptmֽA0gyzc\W- r޸LB;Iw yXWwlhRDFO?"_$2JWy]חoh᠄^dK(}E?YB+aGR1G u_:_vxa,)UcsT_Yַ@qL t{Keejz,J-]<ٗKUVkJZ;qK /(H·c)tB c>9TÖzOx\Ozڝ#m>ʊ#t"&8yG/DN rAA< SnI.rؗ- NG|ɚ#`BU/?$@ď$ lieޒ!`@0G41HS?Pf?YE,~Gru3#pt DpN %]Ws@'2lj֏q5zτ6P!,]1&l\g0_˴<\21tP_>k 14mdfZ1>"383zqL xPw3l6 C`"7(MN&8у> _j]{ >'CЇoܮ|\c8>O8H 99gN8 N@0/"]y-`a2zN{!Sxg AN[Xf"g3php5Ċ:)ԧyuC("Cr☍ns8K&,{/  9~<{MYӟdb}A4׈=B!|e8fl3Qp B' lL? ÌQPad 1?BF䉦27w, ApJ  32 _S!9p I9<:8K&?{Gt^'/hvc6p,"[D;Q[w2hÌ9Bd#llM-񠻷SE z_'7ˢvTYvFicoS6.s}+}ͲoYg̗5yWyEVEǾokg{o=CiTʚZ*ղCKF^sə̛:~Y_^)xt'_[GchZ $9!8>mtw]z5˧y^umm'˘g ӷ>Cy_iׯLqX1ptŜ3#ɞ\l3!d8VKg)cוp, $ {2ō$+ gԏq g6yȕKcb |H6L}cn}mZnTBfE>ڂN( S.s\Uc?yl0X2 C(xG((PA?Cg=3~"!|RiTZu&Og4(3=Ď(DGˀM<#8}]YQ"$MݠM-3r|E3\"W$,isah6[٩ٍz|cv`}&kr{QxhhHP[^_pC?F0;<4.B9r<.mM9&L\C1phyl)Ot.PP f+[47.T3A A'$vhDY&ye> >JC˅wlq9, yKdA^g652ҿ։M#C<\G#߬?!lxHaנ=yE%mF4x9ÖpFVʭ %!.pD][zX:Up0+S8?Q}&b`MB z#G0Z:$F*m}N=8ЉwǑ B4eO:9F <% ;>ЋDA9k!`@i0G4 |=< 8?|!H5>Pe$ @dQСLt6x\HB/ lU y :yk%a]2aҼ%Oo}tR/byJ~_>?h C88ĉ }惉L`s&q1 #*:"a ӖEޗ*_ OQ!٪ nso?"Rz Jǂtb s._ڿ$=gU_I7ݹן|ya|\j9*c_׷[#{d?;?r\w^vɾݾBmڿaؤ$쩓珞e%-5bw~Yցji5bWPXY3QZC9 GID8ÊŲ&ׅNi+gt@txԟys>rh=0::ғ܎(ͺHRQg{:W2 ?n}^VV&}{8Tي"hpnI WW7ɒ*?CC}된-[*;|{g͗忯%+߯:T[vGeI*zVje]h5,e SwN-r:GU^v$v,gؒgT]-ޖ'NkǙX2?qt=ae_O:.=4-!)uzEz2 ɩ 2X:hۨ+~ls2s6Pf:i>Zn!PZlh|`9d჋94< (bY?ԣumٖSfsbVWtsARqk^ C0EfDdB Z'4<&QV,!<Kj2tRѥ+=ԍT%6 Uʮ랐[jS?w,~׏K-> ;qW o2[^4O{2O|WEkvw!_BŸ/!ay}WR_vIzsc JGFdWtAٱ\9TT갨7 9 0^uk'}ȸߏ"UU*.p6WHh_]s;zhؗr)skӯ{,}i/U&!폶r'cRL}rIlK m;(aD. YtC[enRmF4G<=\Kמ#a:3+E37UST49AĴ"wL+C#?f5TdڋgIN;꧓SitcQ,&b49!`L=pHM拜!0lZ X6E=֫FaU/XjXB}CzA٥<0$>Ӽ ?*+z?!/}c,!ΑZnf٥ :VK_?x_U+aX_iP}[BH0Oyv_wJyщ;XhB^ nގEmV6g3 Lgt!fc{njYOOݎ};5;$V_T׍/Ozo['mI8sxXtYXf K S>i[Ƅ^Ԯn fuʵsf꿻ODvF`$_&TdAk C0 C02!`h&t0 C0 CdH|d*L!`F`T:r8f?z73}'I;egTHՏ{5K|99,aCT5.tJMV=8"aSTm{۽$^_%%DFWTRz OӻeWss>˹Gz% 9,o7p~yJ;xD¥*4Y>Ԗ yl|Rv>u6__+_ȋz%V̩l->Sv?+;wsrn^qJ̍OJ[ER>3y3AUd@ם1{C|EPuO򓵭G<= 4ɹç/V*tO,/%Ox9/8Au/+YC}7,vԪeﱑjOJymBmr}V-jQDc8Cq`Jې"Qwnt˚uE[hc}׺iX.]GEP'K>Nv2y̜vďYo!`3qwg*:fCvPzqI=N8.CeP7k]m9#LlePf\Q,dr@mI;?/y*ڭllGfDgq`κrwQP Mv$jֺ,`;sC:4Jl0mq}2B, dLiEQyIO9Z\t7>+,21fJSS!D;nޤתtSe%%^(?X;G%-)2Q$;|;'*2y-/UM edQ8[vZL0)/Vo#0cd~AݞkJ 3u |3Ze)#%7̑wϕ7:t8_;e]2[Ok?_mk笖e# 1_Q!KjGAZ 'v ?8@kl~瑼ē9K -. KmeWF s~VzI(om^k.C0JqwDZS;{jL; !)t>NGu˹q\q'Q/xYȩfCT&w)Vpy+@)B9DYcqPgGq&=Af!fW0%lD+L~h;S&r o8s^8 S { )>hz9SձrC0f:-@=[˅5x`e IDAT5 7s_6Wװ,Qgcv $-GK_tYX0 C Gd!O&Ǎ)\m+=pAkBgsp:jmcN qXQ:X )UNK1;8Zɡ.qS&o 8TNYa_)Y'6sAlD[utc}'äJ=;dg ie9[x/#_$->UA{$?AZVʫ_GF&d}꽵2\$I\۠ǻAy\KʿU5_םK?~_`[kd"OSBUT,Dd8kOxrs9O91 i8wB?M]yũGN+&:2<.$|.E.x)Jȁ.l6R2G4vW8]pg:<$bxdCChp(D?#ѹ ,BXYБ=>$2-!`L-:6m3 AWa_a;D?1[g6r{_HƍS2Lt v8[Gvah:āc&ٶQ?pxτ"&9-HleA!h`m8pF ySbh!pPAQgGu}4O%pZ9'Jp g ~m#'rnt "8eN)m`\r>i^8|/Sᔡys->@GhcX{u[?l֑~ݞMYz78\2YY㙞8C~$;$b?}XB:)E[՗rtZB/A]A[)/q@ yR*Yؓo@=`R֧tL-i$q\ Q|q!xDC˪gq uCp:<{k^iͻOuj6iBŸ;v_g=74 'aP<1i,#[3FL,jNjY*RLaNk2n a5#r.r[z92NKe*hcw N[G@yBAn_Y^!ro1(hS4(=-Zcx2M!Pt*Aup<⩘mHpE2Kzh|.AO:[Trw]%W^eN=t<鄲yGY0 C`0Gt6M -c1q&DW ʣLdq*;خJiKu? :NmCg?3##C6mngd=z-eJ2YDK abkudVپ~gM#73JڕVҮÀ/C8m@g O~0W`&_߻{W]iuHs޷=ڝH󑺺^Uoy-].Ȭ|"bMU}=]eۑLۂ.ܕ8[<% 왭o9-7p N/,πlHf䓤Ь[bIӼFYd[nm~yYu~UER'$;8I[޷Ǘ%ퟮC䯑{03Q٩ܽ/,Hy9 3KB l!_C'H[z$3=,j΁,K6jdT]fi"hbknT(}ȡ; &tK> %wA[^w Vˢ="f[=&(G)<}|cs*~ԣ-;ǖ4;2M>"7$3osٓM@֮NJ@" IeUd@#\#usX,kX/ὛOs,˽~cKT"(g!(Ie#/𒝙|O*%6$֣NJ@DBNW }?WOc2X&/cvH?ԁW,_7:DՏYMA̾o'Tecn?{'}5YNZ`i9C̜gJ,~4]xIPKˮ| m JJ9[ZoK~ 3t($##hDժM&CaNZc1Vqi;JyHS^L-ǘŽBt+ b1LO(//c[1%2Bx*DJȏevN #Cp1< PU`/@q3}w]7xRZpkwb^_-*:!rzpDON)eȃrU(K.m$"(RV"("H$hjw-Ms+c6~@]OF5,ne==([C05^nN¬.Xħ)]lC0߄^p9."m>.UĢC-pUM+(F`Kd8|3%Q2s}to {A p}*;[drfT/̳J@$`gH4QByE&V6j7WL7+%dox?Q]3ȁ$p|oÑ[<~ 1N+ɂD@hyE@PN|NN)"D5<ֳ"{sG[(b=FX ![i_QzqNΚ?kQwi [81bGiKb<VVT~Fkiz1`TBbX+~wtjڢJ:Y@.("(bC@vE>"("/ME@PE=uAjY8?,RȔUY֛,<(p-ŒzRZbzŬȧ;NcǐOQ?b폍a2&fk0qg< =G)lHr_s5m=( G0z("(C@EwIB"("/^@?I{||}݇m } :_7̄d{s 땾pSbR+{澜_(u(D?@b|1'[m-xk`y-M+x?ܽ^4H#5ORe"1 2e_D<4{i_Ԁ4#j3Ҋ4}H bxACȏCtJ9Dƴf(``a~=Csm~қ 1[6Y/I-1=cn>lS)(KK,rTT2O<>/meC X\,u{0-Iԕ QcLfkW)"dҊ"Al3NJeO{⹃y~&uQYLe# ؾcMC2;N˱+Uf9:}aN['CG|Q%fm`Cz&?Oo |Hv22̂>o@LYoxޤ\ sY"}?wC5)VL$05Yia̔0f_PwaJNji}Q6nn鷶&PbFd)lW4jL3-f *7`p87peݳ^鏛G~pP2d˥k;UA@ya ^Z9w<39ǴG/#PlY.U9^XЁG3!E@P Dg2PjdA2pP d,'>dM^+e؏K;A%,zj@'=I&h&\d ׇdRJ8?q 8>2IuNy"(E@Lp]h" (@xN ~Z[9ТCxE<,Yg{wy ~ H?@0}RS}M{0jftrns^#LQ]Ky '@}crWE@:F4ت!;h  h@{(!sIٺ>H=xQCP2{=ӧPFndڧrnx#ax4s kA!٧`6&X:}>PcAclQo0/3^ ŌWO 7%p6r{Aɇz UXC!4̂S,םT7|x뢶gF UA` I%)ŗq)H9)e:d~rŃ0cW<;x$`@IIJli-OCh S82oM C6 ٦Q#ű}*SDO(4*9v{Ή| vJ?zkݲΌHR5p _gOtq?s)2"}O/饕Bѣ#HWH-3Љyqtis*Pcזo!.mLQv F_51, u{?kkK`o(!m#bPYΪ@ Z=oN}';Sd8ۧ5<"P=\A4)f_"M)ioГe}'Q *MD:~M鍙;^LJȲ|.}*)r&`<`n񀋂PNJ']T9PT缔) Q6 2?pJG7@' KSG| h- %L>sIEE@HDӬ-21٤ zI t#F 1/=>ThڢsNP40M噟^O &9L>DN$h#L(PcdL} y./}q`p<zGY$[ȟl6 =TOr!=l}-("`k@@Pj:pb8<#MPC  P1ͧ%>mNz%D;? ׇN+$zE SOoB_N7T8?HݣXEqKGc=-&H',Q4S=G`u(+ו+J&? C+2^&K7W}bQ|WaB7% TA XKu'>)蠠&-QPr3r>1=2"YNr(>DsK<>-gu;/NSyZƊ9=|.| _hut7A(m\78&'mi࠘h "qb^PE`n@tnpV+Y /e32ʲgz6pA 6 xh+qrt>H˝iޱ̐|x8#.O{=ײ\FD˺,}pΝ^Z L9Dl|b?sOo>Pۊ"sֶࠁv 1$bW:/['[ wWGLc ~ia\K1`O$6˒?l%~dszXࠁiJm#Y]yqPx:LIRՉϳoαeȦ3AJ_'$/ݻw~-J } We" C"#/ IDATdO~q{͕7+$WuY$1p 'A4霥e4,Vd`: 1{3 ru*ny.7=[?w>`\mIf9޻3?=@TvX&MYN֍tMiK,f>])em2|>=2Lxn߈˱ y+gB/"m~xiH)eHEo?!O/ZTok _YߏԷ\`(vsfU`fW"^l?؅]ԡub+t&F4pK:7n'Vbs!H@zD E!}̲6ݶa׭m#~*gg=\ʲw3?|Hu>~dS-(RB '=*="K(Lt.mIL:/}t^iGk$}r)zxO%$t~E@P@NQrQ^(՞X;Bej}fK יUσZSURct! 99W:iiSV;+1kX?'j;we:ji"N>EWAg`i猋|/}>K+XbN0;>+Sop[@CwEӘP,UjqE@PE@PE@NQĤTEVMPE@PE`|"("Tx^f݆꫖YHiKB*ÏBپ}Iojl^Ve(>OZ "HWnDT4Eɏ_PX-fL3-+Ly#0d*}0,V 7Y򤻲Ƣ(vu_xf\e{\*-(wu-}mկ(s@NQrzew/S|@1n-yk{OPF g(?0˹jOPE`.`$~~%̐u@KWu-iV|qZ|roj=>|5 zHq #"U }MK4ɏB;ka{_  ΏR,4oObAr #UH(-eUfZ-SCug B9e4j)E@Pt};h)TE`6ľX*^ X9 DgЭlE@P9@`6+/Oݿ|N9E@Og5|;3.C"zLʜ@zAe䀞WE@P ibqFQ(ymMG,&Wb+7 %c$Dz|4K3Yplsi#C*~.,T\ږ:KdXNҬ|1eB9ЮA9LtL¿9trj֓SX>(fЏ[]E1KǬ"!C2Ø>0vHO,C|SF03"o xփI+C~RJ-мW2`@ơ+ưņޞ!!}q }c@:i[v?>mO`ysv`=^PE IzFOgMB@2,.:zhO} g6vdSo:|&4S!̗>HYh#:MꡲRk稌WhWE@=9sAKf0PiN(u6`{\ts$O\$`߳#p8|%I<:qyH{as:Y':4'| hE} dZf!/gb#H-bHi/ŷD1;Os#,]Rtc1ǭgE5LY4j+ތo?b|_f<_Bpm,pˌ_K Zz0%x;GvX9% EYԁzAuS 8G7˲_([O>[?BO4| XeY샻-PG~q0Ƽe$G8MƀOed9֙ΞR-Oכx|M.zX"(s@NQNύje)"@Td pHCxSifkB-tzLGA)oNf:ўuDs݋8kcBxT2si"d$KrN:ǩ7Tgfs q{yNiE@PA 'y=m^VD @*AEOi/ M9 ޷x3jJBt~<J)EMɲ#=c8=`\cɌGA#o]sO-t˸}cOA( wJyc)%$:=ƄC6~~!EWbʴ'OC6 -C\ > MHW"q_ 5J_ی{&@Hz.⭔wʤ ?uHayF%Nzk 1l_H2;PfU\3/ߐe''l}h b6$ AA!$P(JA)lukE/9ƃ e/K!8=\c 2 4Ⱦ9=lk7L"' D |h}..n)$;aӑ*cj6>?rqfpQL7A)ЦN,9_==g{5sQ=fqYxO0q-(`V%5!?n{i9E@PI J(Psك6+ӯJ4,P8^ lj 靖~5%z\:TqpE>7+?k{mROBN٧إ\N8N Wʂ[L`ה6Lq 㘑q!.~ѵ : 3Mt-hc:swz'яOۥ7Ԙ#?N@׈6\&"(@^YjO$%= ]0p!&/~L%l(&]b].=SY 81^JX7'RQfgڻ$xg<ݚ(gNĭjOҜJS@Jk<іU}irOhqs3M&O] D)v(|ҦzYePH^]ŒS(m\$IqJYKZgk^Z^0kW mHucH駘X> H7_ˊb6R,O~z.n^|o;l0{fYL'wCϋ69iuv:DLG"a oH҃B-܆`y H)Gօp<^izNbǃ,B2 z-%4C2te*.34V*qXR0&Iݙ2pb:OC( {b)X|x\-ⲙږ $DpUf- zL$So0(`,Hl,G}q J>ޔ8GMƘО63pBPc߶8E\yF>Eͽkg\&uy!Lsxdj3j6]eWKaR!g:c%Z @w :+Չ]j^6*#q"Q&PC:93GDIqc}lqPlJ&P[4SpD0L1 t\*ԅi8Ch*e :G鍡l|a]-͗jWPxGT^zDk/f 8.kOꕤ'hqљY3iGDɤI;t4&'=nGS%(M.yYH坽 F8;1mcXOD&s]xOm{G)l~qڏ3L"YL_Ո틧Nmov9TC3J?4T<{W ;j6*>b1`I4X9t+[%H[f8"fOBGw[N`oC=f7Jfw=>F ѭ@^`5zVt.Gwd Bf(`0 7O$q0enNd>  lwҞl]ވBqۭ3ٳ}pRG8+-lp`O >ח} Y %mC#H"(s D  >oQC 649MA20R1TtcmS<$Cmޓ^(Т HKrta_h?ۍRy\g;юqpƓ> _:ASm"(@~@x~VE 'p+9@z 0XYG6{Eb: ql|8]YgU}3=\X3]ppT{yOחuV uѱū@c}^{EjHK?-=IxFQ&YfϽ8Oaֽ s+R32Zoe޼ [ƒW܋Yk^}̖Yzw3_;CH-[.{2?;q)`~_ *D,0pD(p'ؐA zx|6UГJ˧OUMOӱ =a_dTe)..Ov.pVE@?tj~`Q˅_w0D2Yf N#>TtL#!YI:&s-tL|دL27^+IXE@P^U>W nd0B~?xX%|U9ڷ96í+O- QRbXB貪VfgO>d/$'xy GxQ:^)% W` -wO_y'G,d1-U`)PaH=VV4e*VcƒV&:/+yP\$ 7%3'7˯eE`6N.ȳHfC)".gN6AMͧ)"(")LPE@HHj!>Ϳw.H"HQHreObXyM~ԏb.;b-]O?=~?%=6h^?Dg ̚?6z>q]- MO1=WjγZDA=WE@PE@(@4-.+"("bZE@P9G  )nG03<=M۬R,T;tz5V PEj̠aeYsS\r{t*8ֿÖ]SHkj~xʿrA[Hǿux kޛLD:ϠVWTE@PE@X$h H.VCPE@PBC@Sv_E@P@enF]I|`1͝f߳@!5IuZObrU~S/H& mӹgwKGr  ̎uR?kê̚,{1}w@n5 y'%#-o VL%  渺("("PgTaCWE@p!Pn>d9 g庌V8Nx &ĤE"lڲ!S'z޺bL(zZ*1!z܇^4qm*q 2^Sn4>KdT_gVoMԋ%hGDk{/?f>ߴq˿nY2Ilo_nyqoy<PыwKڳlDOPj@bBU#_b9k sHU"(RF`t ⃫ %_\~Hut5 }k؞[ WY}Qv$lUm]TWw[=Da{V=r5Vfj?Xjt򇒿2߅1L7;֞ +UE@PE@P #H.VCP.z<ږ&UCtI{ʓU)I9eVƳvB/ϏONw7U"eA/Ǭ-,}{'AjxY-q!aƦ i(1/Gc;:*}LQ)bh_%/Gyϱ/C|LL0y&]]1rѫ>auwltцbX#x[0NFN(OF\҄bDTk'Df*"Bo?66`#m}/ Ǖ_=bfm:u]=N7ZzDh/o[;$ 'a7}h+"_VlzO|>L%N` ~j1,tgO6)Z]U"("(D{DQ8G粒J+"+Ϝ\͇)sU[adBάH_z ~g,%fD74n+R]-FÖR.`>'Vf9z6u'?_yhN+/S玄KNͷsIMJKqW^6މ\rՊYtlSe IDATbԫ1ld2ITL8k,G;(xv '!^i .EL.p]UGWZ:&>G+{^%`9lUƕga]/V(tϜB L OaeSwUWeyNyCjŘʳ0M<E 8eo4@rTRED=~@S &BjG½m{?di"6a`X(I^>h WPPE@PE`!P=ZhUE@)%]VtG2Fϴ=~l?GHkӅ0oLMؖY+h Oҟ/]~/;'aot=o~̈oܱ3)&xH{СWJ+]Qo3ω+Nk8nFXj?ֈT &NF6'_Xs`|eCLۇ(zח`bZ2tǏX_ۅjθ~9^Xy!;yѯJE@PEeپq|rpS"FH:?~ ~f|2𖤣LM*,5):S! vjDbЇkӳ M/+~)"("E~z"8gW|؞XnDs|$oe"QZޱ gH`ғCڲkan-Cڽ8qb鍁Lh=^L35VU$:if_#trS {rDfOϴD&E$:]ɣV@h5T7 D-|C >(D0E~>4Zg9^w2 ּ<> 3ٿݶ6d]/YpO=ۇE/{pѐ>t'}~|PBUE@PE@P2E@LSyE@PE@P INԩE@P #kOFI=|p#RskKhB!7MːlS[,t\#폄߶1UGq_i+si %h?h71T ¯w]jji)s?]a1MCsp $u"0RPEP>x&"( B"xA⭥LPg#=D9"2}/\g,kttk?f^)f>t֖=Xghc]<Ϗ^/?{-KY`fߵ`7;0K{'{m5[&t uN9R?ʄ&T>uN#58rچgOXmuHs.ٻޅ Ax0:„;c܎#?m[=z1̤ wtzHϺfmSfX iݳ k)b#^b'"bHIu=aqn5YF}[|1fxpFtfzQٔ2"(#@si)ɧVE [R=g2}^}OJ=VE@ U(A@r! E@X+Y%( Rs"ޱRtiڐH|-fįІ0Ҿ鐵Kĭ(a sA#R! RRۅ?T ׉[/|w'f3ҟ}DZ=DȪR"& n[NXK"߲r^ (.Lhϥ5x&#}Ѱ )#,n.`> oB~} m=aO&kྈ()xh0 SX" >8oڛH^P|ʎ['=O+U", >BiJ"t(ϭtܲz(@!~B\UE@PE@(h GWE@#ޏeǏ# փ5V˿Ʃv Cyv_Ʋh|~|(_Y1q|z^Pcx]|mWXݵu^2`y,vKqeH \Tek7L*i"P&q;Vt}VbsVfFԅ$M5#Zه1/_~Ѕ]묞}M4N%/u}&1;fex/Km:l`H] c#hTgʼnʣ#[xSPE@PE@ DgFي"("(EyQ튀"(s@KT| 61t:0kL|7ZlE: 3-M^|_^w?? O̊^ָ?[ƼywY?Ob[0T`>"?f _u5n`S ?lE(M"e?ҏա]vi ɕ(>r񥰉Bzj?w9Y^_kzUs-^_Y> mD;xqi-o_xBt,Nh]#eVy͸{{j ~²sN$]9W E@PE@P N}^"( u'X"ϞVK"E@X |N_rz2&! ƕH, %%l_f)?<HЏtǃ!)z$d=иڻ/[zKWD5C +S3`ߏc <13=Iy@ Ő-k@*[:DFTuEY\m+1<)x+C|m$RϤuzО%a/ +)m;+oXfm?/Vb a1ҕ>6wM§A Uds§MgO6)ɊE@PE@P< yPJIstMeg⧫WE@PE@P.R>x&…R=SE`a!z֡1|qeH'WX |vͥH71skY_6BnߛĂۥH==[:&fD f>Ӆ4e3mǬq%A~~&2ށ~p8Y?ҏa!h+R^Rq.<`wD ?Ž,Ao-܂uZ[QvbW&1/;g-:-?XgAx%(=#eˑ[ܟոIyXIk/ļeϊnE@PE@Pf LK]J4VlY^-(RF`Q0"%/ |::UFP73=k_oSCZΏtʐgߦ~f 2k,2Dǯ]aVMˑ Wr^Y{k~lun+Cˑ{`(d=ҏg!fXOx}a&:M*i#pCkpNRH_i5ΰ^G'nHh珎^xE-LDѦ>?zcX]gaU j1|_>a* =(C='¿|5Vro@F#X(^Y:|)+߻Q/wM8 ll<4)GRQ̾_3!M ByHqoLFE.[4VBLxOt==w=תz%I`eS-?yw6{.F~{`_~$:b?,C^~kcc-PhCxLitɵ.<ݹ"("(BEPSE@PE@P7#)"0Ap[Rn^̚z s}f7Tc2R>)JȻσ7y׀Eqh+'V}`9HM~'l{N"?Qte胹3Q؝RVJdw!lחYlD:5؁t:|eLۣM}cTi?\C;S{Ejh_#{p-B{mab%uL[DžU' fKў>tX }l9| my \JE@P# ӓ5֔Ղ"p?sBlӲ",4\A]PgN6KhUE`i!grW0S~|قRYor/_@B-йF Y Ob/+7~j<6"1+7a1}/{v;,w,)د[~|޴}Eek5R]VbpJwiCI ]䐈@ɠ-~ h7ŵlB#5^qŷO,->ҀvQ߃bּU'd:>܍Ty4/$ G=)c'fk= p'"O6aŢh疙5σrU("("̄B$("( f|27ϙ-5@tq__",a֕#(ah ``9R|3L U.Yjf&O cvpjC齏na(@-ބč֏ "ߺ+֞e]%-\K_,dX~=6nLce*/ڄEH-rm=6X?MXD~NjTv8Uh1R1^3as-i] |" }x-mZO`/a0pOM|pCKHr?5֍XT+{QPE@PE@H)aQ"("(@(Լ\2@S"4ϝ@X&/ #M?#M{ͶV~i5^K7<)zF0Ù֍db+Z(k'^hi[:lI+A+8߲i+s5V`†yWM!"2>(|gV"#vGk1k ש I~36N r櫖CpzCQ\aU1V/_+k6/ge{6[_NxV x- kxh|`@CG1ns*yP>*5 Ն"HsPRҊ",&](U?E@PE@P #:HzN3XpvQ"0Jw{;҅1RvHMV6cv_'|Gjscfc N"%H~o?iJ,-)*\inlxbVsK1fGE~4ib5"RcX -kDj8k"mS"#eR_,b.⋫UajJVy"(K D3Lӑ*{Q)uRPE hj>M/YISqy2iU1E`Q *yEm{1wnH7i*ևuHU5!~hi?o}xSހ_i\x!߀EmuZ7D*~̧ [ovZįjAj7_Pt'lkV"u:9a V@cˬR׼{p-^^T=wڻוM?~o\;۟Vz0%<\ ?~7l[iuOtYzs)m-XkǰBŊuhSQ YD QW5B4A-Hi4'NI^XZyTe}9?6T"(n}.c DDJP栓U0%u,V >kJ4\(WBP& @t6~r `'i.;)e+lDO7o{ xꧬgvXẌϭ !}}l4f&_!eM՘L/¬A&}HabD%HMNNzD1 7XbZ/\g{Vasbz Ҷ^sS1>=]jļO'=2$7A6rtEIǧ;hnlݘ:vW5F|.|`{h@b50EZ5)FLE߰ԡ[/3?jN>ҷl,}o0d3$K1fz .2]2zq%,+g`T.E&(Ͻp]bvcEmc*@4mG^s!ힵg (CPE`Q"=gS/JFyb)cyӽ"B34PӻyOeuSE@X:h ƵvtF}@o:6 *,8dI:Rs4 X4)_ԻnODƃHG2M mV}<ԽbEr2 (EOuU 7kLdH'sjz ~O"=T%j^sm=VX/@8 72mAt/RV@xV~) xqe3mȏtw;!CfW!$b9d{iVpn}у{Ov_ ,5~>"Ek"ĹїX~Ғ}ddv_-V ,3: S%XE+_>Ӝx_㌑xoNO)^(4}@1G~6f7%G Yu(e5 IDAT"@4$'hToD'l:ܺԋ4X/&㌝{"Ә{K{Y?cE@P7]Lv"@_\X+Eq:b/^S)r/mHҊBEG7xO: :m?> ^fKcB#{ =HuO!0݉܄a(a1;~l`5~C^/@ V2@I'՛~{{k%H[NF\p|t3V"XkH ;eq$R#}k7!(Ɗ$pY=p*N2 5_Z5"J@lm3Lo?V:xa5fV[; NqvD_ku#HcN HZ=C|עלxNCb,h (1kZof#YQ{@[+0Ԙ]uNWբ#0*ֈh?o0PgʯyKjIU`s-6ĸ`{,[6ALN$M,hM(_s\AZ#N K1p,K{wyyNiE{f<{ZP,#Ku/N€R @}~VŃk)_=S=<;qf /O:ett"Pp=7yD'GCUhPgs*$?:`յʊ"@?as) $lyHN_+,4rL>:Sa΢tOЄ=O&u3z=g[E1oEH;!M"r9&NZ~GK9E,!8ص_~ Q􅼿zy/_y$i2[J/L Yw>Ssܖm_\Lǿo# |b٩;C~-O 武 &MO+qX ]U]zıQ*?=-[Ը]:H[oAyaf?_[}H;FÀ3F4T% 3+rcRp}3K+.BG:@e,QQc{}%'X׏pꐥh%fOìh)T&B;3tR^4/u6= JA$V}X{34M]?hON E%h_EbYG8m,LwR~}+lcV{@~Ll ޞo+su̾-+O\i\z8&wWY%cEsQ`TΩx|NrOi.TWPi^ ~i^L _sTL(8UTs;R{C ZOE@X:v9뚺_Re>31U,pRu7 >x =*oGM],n,fb&k*x-8eʑΫP.9h鍧>LCcH>Tj+_V2/CUgeS?!ѯ&q2]~|h07nt?(V["6y;CE^mqɻrChãcA, &S_2 d[+(Jգ=KkE@PE`h :k贠"("(@6$L4OeH˞̓KjVP9򹳐0X]Yn>dLNy0!Y}HeRܟD k 2Iyvtiյze0_PJl\cuG`{C1VA/Z7Kb9'fĠ|rAWHv\1E BLՠ}h>+iob~h?Fj@0"MD|hvk#Pe/hSE˼uWCJU(fOE͘hk a(@4{j=b1<% p/8S(AiC+"EEz]Z"(K sCƵ_LͨM`ܚ)E@£'E@X^Y[+r} ]BF,fO΂6)֕Z!@1\[H2(Ҕ&ڼ*+S%.#?.][ 偲 IuLP5oXJ̻flo27ʖZPhIOgG)"(C^8Ke[Ju ~T.Y*׵PYB:w 8)&RE`a"P„URE@%KRR'K *u_(:L+6nB88WCq@T,R"(F`D$svUfɗLY~USy. =Z*6G]cUH|u؜4b5⌚]npes[նȜ\H./" YљNeDApVuU-(Ty~>6̦|lZ]_{o,YreU:Ӄeaڒ0b"i a2 !+,ۢZlJC&"d DamR)ftOw~oߗNw[jr{o.'3{꫓iv$mqpbi y4/^'I*O! Bb;O7$и ! B@,ND{EjJCګB@! "q_X5R! B@A,LAUB@! j! "ZSB@!  PKwnZ7^?*Xk2f;4YWF_u;+^T[ys^ٷD4|y= !,0c5^\:^{90+!\ޑ^Hmu~:o+L>ϥ\.׫LN{z'#ψXLj]Կi-'c2[]J"xF$B@!0* 4Ovoj'9q0YNl:'#ĺ~F$ Öe\5DVϕ[wvh2Ʋ??^8$*[Wu0艭g L-OLYU<{5)XTo1XeD4Jb1:= 靰w@t넧>W,uyouh/Xުrn:`un0$~vL&YU<Ъ>^j_D)~u+[5DK|d 8~^%|-soneyi_! B`] ! B`]! B`] ! B`]="#.(1iճrB@!0ƒ @@;cQOIo]_>ü^Bo&.}\^~me6.3^ak7I=B@,a_vٽ-Wֳk;jg<S'gw'oܲi3I9H~Xevf~٫lq˝TưE|EDOPB@%E zm|&y̾y$_cṿp\vOX:9}X>HV8Pfҵշ6v,3k;[0u1od:_JFXs@H<^7 YuyJLtub  D 4 VV֫3q}ux8Yna=ˏ1ߒɲ{;ʷ3qع_I23;l~ƙ;c%_iO~rDD2!  OM&#\ΈM5:ӹeMrN",CRm߫}RygrXeaݰaՏ%#lorl2윔g]y''^fmɍ}ck+l}Y V/~PFz9^D2B@,!n_ȃH#I$F Fd71Gx/`}N(z[{{%kúIcaڅmf0L m:Vw7M ! 愀}a~xć~ˆվW02Gcn [ 8eՋTrW8:.{ S'kMzFv:tͺO0vX:j3J(hB` eP^a~xBh_rvˆ.,)o~uy60/.#~om܇2rV곬Wx~>.wkr_RIy&<~R9,I7N_΃4lArDD!r! ;C`_Iek/auQ5La[;#w:9Au;y׋SGsX'Q2Ma~~+'s^e7*ÎYDtXTO!0E~į9 g.w/~9AY};~Ple-B@>!s3+e"3{l,F`_*ȟ'k$s'"<)B@! 'AӔ\v^! 7E~Y]d߳Cw2d2z?o&B`YC{|mϬW_? B{5b! EQ^~EDWj^B@! XpDDixB@UD@Z /R=~>B@! Vѕ}B@! ~>B@! Vѕ}B@! ~>B`(o1LX{y#"B`7$>U$X[DD?|sv>Vk[^vʎk58-Og.?w\es.nhN;v;D3оyHT :.jt2Ow\>=~L4eh\aN<_?)#)kFjʒd(O!L.X@I&8Z͂k\ZՎS.[θ;ӊd2n|fABAD[y@HHh $6|TqTe} ȃ#`D2?>.QB`]1>N;Z'wJ5\"ZNej9 eKh::jzMh dQvDш^ z)uȁ\% ZShKC2jn#ͦA!iH,xc,t${l6Yvw2rjo@:5pK k]k;d#'v֓жiDADm,aM&*d?&)fgJY)oUӕB@HŋiCOM&:ij]oAz˵cPT kO$OܰFZPQ{ڒ8/"ё㪣92zhgNĝԭB`MϜI/":)j?R8zެBSeI۵O#jL.|v m=''ӣs#lI(aI*e6]FB(R+@zKce&&3'Y742i6B`N giC}إn)JHe@:y*.Y܁O iIOxfbX&OHr|&[6xbzPgzdQxևu1FMB`]7:!J[ʦS-'7%ZF19y]@9˚d]0ЎLFByEeqIJ\ˇg [an|j&ٻ 4ہL ?" A2C>1x2Y 8niE (B@<@5dV{ W}\ĕ7wp^'Mld\a^~D߄=$m"/jRid12vٵG g Ĕ.i wM mژQC&[GUODI87x:O^ʰNШw T؏rL"\<%! x;"odrL\ Awvw= -i^z)T:XŸ4I(`LP'ESCI;OfJ RSNzԟt5xwID;mmB 3)rb>lBL]SB@Hp-WSyUoTھ1&S Oh iQ>p(n٦nn]wK/W4OIt}L!J Դ)иCQ;# '{BzR0I'RS.cNQ#}KW.)&GlGS(|Ej5A^enLM``K^@עvIE#p*XQ+@H:땞&'1[fWA$Nzuۃ:jpo&}ζ{TtwPoZ;|]9t)҆V UhC-w)D>24-=}K$U,qf=&4Yw pfu8R\ QVNؐB-W̗MMIO™žLEqm"PM $jIԊr<6Ƈhk`6'߁Ik1qMR!0$"CL`T$$>tiJX.z"Gģ{/K+Cݗvw[զ+-y_y)OVwy@;JJ+ \;/!cFFBIy}V̮m3A {1#|]t0b7qQ=9hNqtݼk6XF6KH;CrcOiŸN1#0CW&:N|I-qK4F>mYg=i3`?|! fRDD 1WD/[ f#I_ e~$m$oy1?ϻ;b][a`i=[x䵇} [cNIܭZDKmz -hd Vdu=,lDt@Hu,Q %*CD1!TQlzGL(;M5ں 29z)ƴ1n y׽U{Wzv{ s$Wj5gZqw6oaBP g2KiBIĜHo~a`Fk|g0amq"0cL! !Mx?5kCUz(ܷllkwAn~'dG? m~Y5,?h6IW.Ͻ b@+{rFƣ.xʸA^T<"{9skKԸfAHyA%mFS6KO쨭͒%ԀM g*P;Eb2EDzP}o~TI9^Ⱥ+ ctc.`<)ȼ"q/W2oS.7I){763*M0r&ﶺc/81с+2ahJ7LwO4Y=B(_'?1V{$WRԠ ! V }Z@8'D[AB[Zrm8Ǵk=- _칞p]9%˸g#!4d_F9.5?M.\^g9fڳvd$x)mDI(/Cc|iEs\|J$&%m#f{"A| M%/es ih"u=9ק@BDk/+ИR4LIl/:R}O57戧ﵼC?&/P65B;QIrO~&ԏϏHGB#5Re!  "<;?\} Iނ4st 8M "9u+A H v6}O/2.l"[V?r;MwnМai Fx?n! 񊴇ԉ'gEzoz-)50I*PK'"9 IRCZDz dꎫ=h%hK$ 0.1ON2GJ2D@@3f7 4&\:W,ȾM0:W<Syl)~hx &WeW3D T1@c]z=}bc޼8jI2jvU? & a~lIgx-tB쏹K:@H(Y*-[u;`GMxVhn4u]s箅%z:y"UywgގsHzv\15st(VTO˨KrU1\{\.uw$[ /-8OProf1eTw>p{0kx.J#"ǬyP{GӇHki#9.Qc\nvss$.4/5u l'JmCΐ,[G`BOiծC5އVfv`s^ԚR GMg$=x#?06槴>P#jf*'\ 1A<=@P"4GM+\s_w_u3wm:P@JHBCV(s?1jRkHO9wm bFBm˰$z\^Ae$c(&{h./#A.w90},K`#7}Xl9]?6shK3(14ԟ"kDR9^O !πdM.'$f#!hf}JC޴xFmh}\flD>k8sr?5ZVuD}1t tT2>?7vA _?`P5@ȧ-}B@5kOD7L j /z4-aׅ}81!t`1+l/OR OPHoܯr0r%t߄y؀$y ƜUxUk Qx&,@6u$\jGt(&$չd ;Kceo}밭!ء5u0F.w/!#[ D5+eyh> ی8M(IhUsĦMFb6><9J3扗7 < Oo<l<FtF&gbKq+S&.3|o?#`$Z-gӼΣi[XN3gѯ5K$) .ùO4Ԑ/ݛuB3z_w鳗c)N}%Fa:^#>م!ˀІut՝߃swAv2gKHHዃrծzՅRlvI+mMc2劰KqϸhV@D+iR ,e[7Ga@7b"\5.72.@}hWj"/((~h(-"4b!3gdtqbG~Z˻$5$,\z%?#f™rǍ\>R-Cwv|6ӗիN@UE}M9<CJë?_r[W ׈2%Im/AczDŰ$O02XYx&Ob|@i;C2E lqvM>=*! %?J=ۀm,e.˽<7@42s<ܾ%7\#y"y&{uUJe7#ojUʩqv_ IWۯb,u\g`f; Edjzba L d݂}( .l,쩅㥚ҤfD D"c$ci̹ vd0 z!F1. ˹$N2XQ /cr(r?,2ozRkHdI!ɓE,S+ęQ,E^]ż˟@;nXJhÿGi*>@ޚ#|Վ/d[<XsعciZ4Rz^31.#c66*v Bڱˁt>m C3q?'C?7|iG ]tWvS'jfdD34~Z?b29<Ą^l[tr|d"M&˓߇(7IM'̇a(eq$#VI>D*e~Ne,+`r h83TΙn! dOm؉RIRM"maB?4G`|F)xTp[e+=lmBGNOoÇ:NQ4S虺8[OVi<HBCOZ ! V9>~_s7*Črh+iwFIA&._xyD&HiKАZHDC"}ެP%#ٓ6kj` K Q&Ee]cHIiA t=m w|-qD IDATM'^; J)I< 3[Dt+sLԘ=e5[%8EЎɄP>AZl{'"9'5&U\Q⼠({y>FZDh@-U8IHލk:mgȯVQ(fG1CL: 6OZ=e6Wjx1IdДlEz>aP3Z! "֖6X&%ځ  I޾/#B vħ7~ǧTzEj;cؤ EO,{Y%:0V&M ,>w7m_4hrGjﶄ1uhO߁m243hHL 3j.+cқě&n,9ZGܯ (I=(4֖~K t" mԻWR xMJAJ('I2IBT\` &$YC5$cgⶥG-rקrOS]"Z4h\xs]Uɘݹ_gWo}Ǐn'*fj&ȨO B@kKDW|%%,oBey BuH2[=t& >$ m4<~Pl{-lA>ʣXʹAZ|1|&:>AϠI❛8#VfD8'z_eeivk)%]AFB3!4:!ӓiK˦wRB`LckMC5\gM%sɝ9!ScH4yMXÓ\}~w)ͳ#W,ڈrxmz?@$fay ?_48o"ћ;܉R3dMM/SIr$b p"5 &HzyPKHm8-PjKY_BA'$1e%~,eA ɇ =MzS_p.YK~YZr0m6m*lA~Q yjg"t=:u{*5D>:w2cb]B[밶'Ah(cRb~:./~k! 4΄K_["o&:Y tjnnUl-,U 4d9Ů;-u2 ^`(Fўa}n%~#ag4mX](Ϻ tك#CĘ71NDF:V^nBglIz:`a>8v ,ͨkGQjƒvv0I؀g Êx-h_i=&\%: ,&T=JM6DM TqVӽ.AoV0~P3㉄څ2DMsp"V$xnF^$bu̔CΉfġ~<ѯnV4yI$tRj/(֖Cnt_{ {{`! Mބ3i^Mrӝ>Xڥor>rҐu'@rsv;ͯݠpJM.{cC1)3bkPPzAEnjjAԣ]h?iԤB6:(ݍwog }(PIFc]bԀ.%$#wUdFp؋[2b@PQ'enB,P& ||x7K Kpw_X2fK3Ow0):<8/dW  R݂$5`urw\?|r;gF;1 aV:2ZN}6_uxT b RԪ@@AR m$LaI=1wn^.'*dH\f'&ڙnDbˌvgUWoj&ՂX d䗡 S6(I5 Z-q ),_ $s)cCMH UcԄ2mCNPԾfgж ZQ'LQdc4[Sz,q2kgc`-{̰@9D9,XF֚n>N)؂](HH !x) s_/v{)9}h?cjppig;}jtIGbxr5#?g'▮4' {EG%m,Ӱ19acI6&]VVݛ dhKG"ښ ؞}rjΕ\sןvuf^ rıӟ$aCS!.+d2)"C:~5 ,3Js#hJ9~RG O2{& YUX0Q,;w0x7^t3K#&@#dt#iEDž/Ɩp1 8>_$Mw{OT#!`̤FqBTGyB@uC`(ޥoq'ؚӓ w<4-xkHLedExwKAbx?qW.]~]++y7`sNWA V$ ej6> _ŗQ+Z;߇7Ț0hǽpТUx?|J[ZV=h65$Lqs8U\1CA֙ ؄ҙDXm'>D0NxG5}wJF I:UB`X{"g~̓'#5V,67+ R e-h޲ 2[а~t|ͧw: F 6;j jewk> ױw:]*@,h#_t $Y=;M|xs˂s m= {  2I5+@si8aɸ8晫K[=Z$y8[3MT Lt2jl w!|.x'5jC0^|: FMdISh@u`*{-# hw9.E|7Ff2=g l7+;ٳSk! C>sݻh_w{~Go`ӇϺ|`oeU2N>F'%i UkQr ~z{wmtw 6:1`ΏJ>mnK?? b /򴧦d[ZE&͒s8܄CZ1`JQNǟ}8i2st:"0<|uyVcԷ@:IXYDZQۅ6$ z~ǽ޸ނE!rzjIe\аȣyK $׋3wYM!hJsj]?^w|8Gr;,ElDi)ʃ&DWY o(*ߥD@t)-~LFkK t==i yVGOÓPpW֫~z9zjJK\~#ߛƾx/ɑ+߸.=~6$2(Mk ٛP=.'y CS&$Ԝrwehs yo'JG%j9#^)q/wzGNء[P.t[CM> ]xCf]e`Fv9(A=yGMjHq4a8`Yܕ>Br5AD[pPUKtV$x dԜ8[U(L;_KGrb@9߽G]Y! F4ɏs>sq9} ox4/<)1$!8ѦD햞P{.{{OI kkץN\o\jzP 8Wm|n(n>N@=K: h\"5oZSڨ̂6\ֆ~ᜮCHiv~ Im|Pr@7mbSy&\G0QD M΍LtZ=| &8b$T1n'tR贜b~ܣLG"]5.Jk*ߛfԖDRWiknB@}_r8,],ȹK]:O[2(+Y}} = g9Wp;Oaǥw!Chv-Y%r[&R(A+SfvsSq5h=6 CتHøCwuh&&M&c@4uePF,7Q7j] D~9AT{wUxOi'fx(즄>e$Hv73'l$tã/_Y5IЩ @!  ! "BӦB;J˝ KtvNG$q/p.[cބtU\k^km%_3۷wώ؝A2@|s,JbS2cyKyv 7!4prc{SҽV?ONjvs,s{VػmF+@A:A+[ŔAXfd$;ZPP@IIZ)]kB@ m.s[( Jcri:jesogC<_aMHOIi5\^ǎ~yߓ=Dio]9 sjI7Vv%BA1SxEzG-<} d LQ Om,,'M \K>!3"VlyڅM*ѝg45C! 7QEDGEl 5ۖRGIXwbj (=Ǔ9C{\d4IƲ{pH:}c)\gX.qDXG'[i$h[hh3a,cѢ4ӕ9ym0,"aFP=󡷎_kUW LMN6pj2[Qt*mHs*]h&)qN RJG&ju-&9@kCΜɣ4 ?hXED4$AӞ(BRDR 䗖o;=.7tёv$"#%–d"IliMOYSLK4 yD:MX <σG.ӾK+yj~3XJXI7\ý@'7”N :fuUi&O[T;RًZ:dGhRjBO@쩡%9UZB@xً;Y !0"rI"m㩑\L/8rlZ(qd^3D= %RFBiUA`҇)/`E4 QM͒Gě֥ijE=ܦq[!_i}0Ij3{T!0:"csDQ<&jFM3KjO`K~sP&%yr M.\r'ͺ@D7)'l=@z!~Y>Z IDAT)nPN=aF` QŖ#in|qS!@2ʸ-O,& ;/aS4dHqm/+)D,H0UC1&k}}YBm-ϋdz,1S9"Hn&tFb>5*_%iL)ȇ4ӊFLΣ3'LKt^J3+1Xx,z H. 8!]ǯ !0$"Cj׎𵰆^H R뵙prBKXPcp_NJMDx j.[8u˂xl Mz B@!vDDߎrO@$0FKD'i#ʘy0Qnĝr451D ]vt Gi3[E~~JYcfpz0ZIPiKDu/!gΤN#Ð! BD 4KMmJs; \e;B ^ql۷xM"i1TϺ#'Y3>f1nB`9g4h乁bXt8q|PB@F_" 44!gḏGm$B@! 掀!WB@! D@DTB@!  "z!S! @2Я,Yrb?N5B QD+7tXMyǵ&JD 93DDd! 愀iF݉xѽF 93 bi?%B@^$tFIB`bu jH6CilIU-! "}6k@|hB@0҈ԄB@!.؄B@!ԄB@!.؄B@!ԄXI/oyޚhy#"zOR ! Y? %B獈PpB@! 6'B@!0"CJB@! F@DtڈJB@! P* ! B@Li#*yB@! C!* ! B#VX'!~L:IT{!  ACk}Lji~M^MS! =G! k4JEDd! B@ȐB`vPK ӯlgqQmm7h.sv§ݙ#]l$p%"ZB@#/ bW6! H ! aw;k}E"\&|4V!E{4Õj ! i^ j`B@,Z_G ! B`FtF'!@ͦ-qQ+[#h4U! V}ˉ@drNB@ɥNui>|x8x<)Un'=cgG~1r{T'l^3VB@A}I!/,JDmlkkg^<~:~ñ$TmTM>vB@;%HYB/5VS+)FDaΜg[5]~ ERU'ĆeJy^xHB?ODclѸd{Hog}N2N뛲:Igu+O! D ga󞔼wIs^'G4I򞔾wc/|3G~G05hFx/ȷq$aT?%ǨRB@! f@HBv565EdS8mX/.;WHg:B@! @_iBIBgn#J?l`f}&;$+mXU[,tB@! <xg?Yo$t62j7aB@! A$s'>HB_zGt ^FsB@C LmDWJH! B`X򕯼MJjFɊkDp̎*B@! X?++O8 }7Sv D٬M( ! B@C$4tP+!42jbb+E8vq!B@!Qv-X;;u/ {$NIp+DZU[[?@Mp;/&2xh`qē@ h=` ,-pn`"AHi 8 P ΀M:h]>C` <`:A"B$D )HRt c o( bd(ʅ P%tBhf%h0fy`XV` a*G"p< o5x EbEQR(5 @QQɨlqT u5FE}ALh>4ZmvD)dt.}}=~0\q Dc20jL33yEaYX1`Y*cʼn4pV8O;;xnŧ 5Kg"*%7M M.MM M?,-VV֖66m' /A`I#$  ݄I'"(L&:#YJ LIHAMWENnH/Fo@>~fcdpfd8pabcbtee,dld`\feg2agJgd4KAEJ$HOI_95ݘo2O2oxTeY`űJZ6~fbffKgec{NbWawc^~ 2>jw̜ꜞuC\\\\\׹2܎ܟxy yxYUm}·sG?%],r3yZV@MO O]`IU@*X&'EHDA(MA0QXS8DH𺈰HHȜ(I@4RZtD %, vRqI]G;?JJ8IdII,KKKfJJ⓲:(uC꽴ttLLY%rQ9\\ܼ<||y 3 O+*(I*)*)3()PnWPW U92ʥꤚگU3PKQkS[WWPWS_(xɮY9Ee`vюw!m=TN:::)::?uuuSuo=}zw1}Dc#l%FFF獖卣[7ML2MLMLON 5k?p(kj̬&֍l lی6~3˳{Sxg6{}CC#eǯN&NN3Ή\X\|]tr-v]rSw;6.޽y߮&Gn'v/zyx>J~K m#y]{7`сn A +`kt{.>!1KѤRQM{^$DFvEDGDE~cS{-97/*8:NNLKڗ4#$]np$Ljn'M(-3ө#3633pb_r*ͪjogCN:^#[s@,.U]d}%ʥ/777]aueqo㫦M#͝WU^nn)Fsp}5E{ woܼ.^wKVygGa'}gmߺbVY잻uw۽?yǢ״~q~; v=5`0pgp{hc=GlFFF\&=72|phyȫ,Y-~mۭwl*Ko`aǥUx5ϧ5{/6(??on^o!O˟S[cXo,7 TH_ Á@V;((]Xw! ( Hƾ-LaM'e%b ]7sF,²f^Ʊe},@' tU#*V%FR]*YSg*t+ U2T44ݵws?hd8e6057 4O8ay͔D{E'xb.\;3߫λg?!@8P#");4t5,1|D:%732#*9:*&4;>0A)#q%nrѾT`˴M23&dEeGɥ*χL>v=.GkI9U}0awjSrr߾Ni.|3b3Sfef^9~GT  P<_p*tlqfҚgVWZpk my {/v]zSؠ}%~kZn owdtn=pw^=Uy}IA H ~ze8dϨؗ'MOON=瞦6<;blŎWo-u|۽G5_2q|o/;C,PLu ͋>Tr$YnFy]#':ѯ212u+,)+<"2#$Q$K㥷dVdgo+4()(ǨxI3xY_[WSn^~1l~~ en\3Au !֡"{=nPŨ?GG9DG?)GNKI\LI'uJ]j~4LӟetdV!'av9,_=r(%og1w|ēEN?--Y*]/:CSS[Q]vvU>tez+MiGVt\nn +2L]5M{ޑ=^>}y\1<=71^SgSn3C/<^'GhF'}|go3]O>c\RCgtG 0!RtH [_ˠ́MRl=P6tԒ`~XU=x ERFy2PQO( }݉^ňb10H=WZO1 ^DbJ!xZD qN+/6C= )&QJZg0a bYd f}Fe[gO8)e5Ͻ*=_ ):F` `PȈhEHG-J; 󊟔!*r)iءmc+תid(nq)sg sK}+kum[};;]|)N΅.ܞz0t]3+ uS6Lq}g_H/M{jo ᬸܙUG[],TPnTQxUtaRDXqU`wN?|?|e,s"|cZqvek7E]G>X+"?~@!<!( Ԁn0x8#P34 &>:eFx-<]`# ӆv𸝸b^IU=B`E' ėtty+DH&fe6=^V'֗lQ("9N?.9];ſL$ b5[L6Q(4*+}QPPPO8٫^]@wAaQqIiY#RG\5 ؙm_֙E-ǽunnO;lX?K ऐ=0؈F^H'LqvG%Iyz{}Spֆ)_QE*E]gKMLNs`GٌFY'r5>Fȓ~R~>W@"6`H{#c!;j6@p 5yJb x@y*B},GM1ȹ|;*O vtϚ?r 11&DobA~ XnK@ ' 2  XDE##( 3o_ゐquF2/ m3gGbc[(|V#Q~I~ϚТhE Bd4 Ƞh}.Z i0g7ƞ$h:#G 2|} /N Smt/ķn\A`H&DGd4CUfH !@v؁F s}1x47nDNNZ=l[9yiեwWrsh]zؽI; g#s~c C Zwpl*O.hߓÜ:䶩͚QGPVR~_|EXMS-G!oxxL[}G {?{WNHp0s+_.olZf]R`ݢzk򆧔Cv^p\>~翸Un3SVO\(Z^r& ޿OOGJ3k}=ć3eʰlgpXBRwcF {I}OC^RR^'PuR$=ƒX||mDt^> .SɈDmA F/M*Blٲ-V/Z7Q]2tɠMEOq'$0 i4&&^^1Qfiz!lz \rRKLpo]()MF1MdEoVmQ&_ <{vo?eܮ;:ӦMC-p`Ʊ0o+~{d ) ?ĝ\p1:i|3b(FgCopw#xǡajz۾n3z9m^àa6Xqw=cbE'?t?6==q g^o2twz cg㦇Įq)= ͸ x&To;Gpz'f:Cs-_*܀o&- F4h؀kvQSIn6h@?0}zZӻ=N\l=.U_hW^VQ/L>N2pѬ_!N'*Z]㎗!MSP3;%02zgl/0͙$5N=5uuеmf[z\T][weT]YX7$%"5!dIJU^]O% $%Eeؖ]gP;BE\NgfBϞ=˯c.rV1N ]6ʶ R2+-<=PFtTyi"6HW|*!O*_:.SFny^4]]@XB|C}mW bNR˜^,Kx:ljBKg-myF[tlVOLP<=QJןohG'U @tأkNcS1vfYnbhۊ,غx )ݣ~ׯGD2xy2Pu+țSw@?(b=8~g`ڝh0S-Q'hY,8RœO_50бIo'/߆-O4ӔS$S&uz4tly*6qb˖-?# \vI''ė_~:`ᶑk %B.)1LYRB.-YPZrr CZɴ h䮘*ޢ`_eN mv=5Zٝ˟‹)uA^ηxtN 'ҩOߊ:>r}҇}}dE/}Zextp+q77>A&Xwzi=ƠmF)ƥٶtT<0^'_EO eoR؟&f4j2t9 6i41$ĭӪ4d?f22j[ס}Ukt-+vb=-;l2r#ͣrmߑ8-:К_Fk5+QEFn$lXY6flGZdP()..CؚUFn$F}ChA/ :XĀpPoa௡٣O6X~6tKaVjMlq e'pw/Ò>2cnzQm9 |聉ݍ,.%J9 BGyp⟇w82Q$nPһkKFWcUBjܒ8=u5,j K _q;mJ*!H[T<ϾnoNnKU `[؝n[اn LEe;p1BvO]4x=yVlX q]P֬Zǯ l$ofal<Ѻq6[@b1Z7~& 2а!LdGmܸ 7Gᨗ$p ]nڴ SʭOnՊ 2._֭w}^o_qcʪza; A4;C;M21c=BAoQH]rZ\LJz!5OX z $N=( "sk8^lWc^-BQ,27|/%Zv  @w.n΢'~G$of.;U)V!5i `w1A`iY#~1 w~'qA2^/v|S蘣 gd/r&W$nș V._?m+o}NŖ]óǼUb4nQK5eqTAر5/fQ`o pƍ2.{nի٭O{o3kSutl-.E=J@5j!K;QV-&WaX z  mƀD>p%g4~$Ʊ#2.|TE 7{扩R-N ?Mp۪o.ZC&'cEG{6iɋ۸__dһj6<9ki+țk.5kɵen']L12nԸj'sʵU)!ub16hy Dg7X#jD !λ4n&ǥaт A9jnD3tY{nc7&C'0K/ɋix23^Uagj]"A`B-o-/bW7?qFE `lxڦcJ&ϱ{7-1JR=  @^\c2MM5^A 4F#A@A@3=tM#FjbC8yI   U۟`QBl%7&.o}A@A@bA؛&GfL<='DA@A@A`7"PiC7pAn4%  !PiC^y$Wh  @"PiC,!4.  T;WN"A@A@ڈ@E޺/]7;t遞ɣT,]4u'hZ98oG߁=`?d|7QzrjXq>5ך>U<=K9sBѣoM\Ū3m8Ygsx=8v<8^qM2n'ys Ll6yzPlxL#4A@A`w"[<w+{*sww`ЁCoPXX Fmڵ݈O=II HHG=1p@?%߯jxpaG1;QXTh8#x!_Re<<.juݸ-\=7OGe>h ? 3gƤW^AÆ㏙3m]µ_i q>أc ƛJ?3l}:S< ˗/" ߶}F|uSz|xmu\|HFf8L"߷IkIwͣyM?"]#F;N9s@MBUЍ_p_| 7<8Ǫkּ9Zvu7b -W@F)3[ltNW|هJyq^1gpCTȑb*_XT?F@z/Ξ3x֭ #s W8M7+hҤ1uL>nLQ= 8ñ<9W~8.ZUgTgS o9^]:Y '}i:uQ^=:0YQu W?|5nZdfQǵO^],hG+79燫_ӓG]TUwMy*ȉ< >r瀚*]chLy#g2uM}ozC^'uUf :vQZ]ߪ2{oohn'ñEVدE LnPxh+ ܹ3n*K4Fx>|1N"o.ˍ\ϯT{8JȲ $mܸY5a,--Ś5мy3E_f 7jlС76De\ung= .7n6j=ghXH:++o-[h=x|zP̳ϋS4LLbyШa#ahт]'5hG+kGw;5b0XA@.*tpj/ e:c9L_= uoX?ɉ[ T7z={Py6jrWW^`~ּ>8aı|u~TUsQeMIIQG XZܷOo4k$j=їeņuf9>8h:{ǚk:_T\[^]kt v=<`7/Cرci. Gk?Z+sLƄqd'4G9sjr҆.{nmj)4]N3=wGjJ*>Dz8{XLO)/-nϛ<ޡ{=8ߥ'&$)Mퟄ}'ǑǍGNqɅ\R\J3f u?{Lz!tHHm[?]Ssq'kkyΛhz11owkq#e֡iw;~zsH׈ I"瀜rR8_mγGyi4R(zkWLXB9Xz5y }7zfS %KGY:D!A@=;\GN[mw>X1[t]2=ݴa? r˯c>u-7^a^F 5jе @ !PiC߄-,gRw`DfSz3{*ZIDFM?s^  Jxtwgj{[i)5`!mb?݊JGA@3+=ւ  T~HA@A@3n=碵  ^@ v A@A@څ+W   ! ^wHC  r  WV  r  WV  r  Ԉ۶c>sPi.!a5o~ " T3եG =Hx8,_#UU2=JKF #*Aii)^2?NyI`ZEQ5lXRGA@0#O:i_o>[.;+2GUZ(T 4y;vλ4a8a)w :v遁7mY}fh.'t*:wyk& A@*A ǿ_~1N:q$n݆[nÖퟣs(duESoy2?/bQ* m"\YVV,wvC1sEˮ( A`AF 3N<λg~Zto@ 0jqhԫ_M'wѭZj qY$/ T {տ_ 6o{u7b8aq}I@vvNOCj{Cx !\O;UN~C/^%K]۶׷ŪiSbA#PK=hxWN͚51G'in'4 M4do]enz3qY`ܹAlBA@͛r6m܄ y( lZZ:deuBvm^WxpUא>nvM͕lP?cOp7`W_z#O8ޖ^vIj5tB^d-M؊R}t IRR&#Uk^{n_y ?Y!Dw^R^=>)YA@}8CYHLNh[5klFύ9qѥ+^^w joN%۴i܍*E+6maCW_Ci|6tOy-.^2o0ILsjZz kA9A3NO>xY† !lo]/N>qxҹ /Îb >ېvV-A۬Q{|B7p@o.4j2jׯ_O?~Cwɒۧ7-[d6nHAXJ^2Ȇ{fBбc[\$d޴aD%(W悭Htݾ}3];zCF36iܘL}Ue8d6% ˖/ǫ՝1c&n*wr#A@ɣ[ҳn5`zm>3o]XLkm֭-8 9hZ{ۤikȨϽ/2\yaдI0w̛n$]{UTV+'5rM>p&_sYgk*tA@A :p;`̲hgQ-**8.$yT_yu?p_?m|(ZbpWB,s%w o07g`A/Gb2AkФuіomCWVL[)m%Vl/$֥ ԘA@A@%忴B;ogD ACɂ @BzKOOu^+Ve*D@ *SD  UU!&DFu iH@-A _D9QCA@A@(bV9'  P r {%%%(.*Bi? ."#/=E=}ʩإgyWk<^i'Б2A@A`#wɞm[*j~ß[>:t:1%߉͹밋2S{.qԴt4kF}jl F\jE`_=]2̏lwٓt"4nA<ʇ@ }j͊Xd1-.,MQZXFk;QuAp]mljaN&! 8bSCsVX/Wزy#zHrޮLoTHͮDwH d8hVy˳+ہک/V vWQ@"ؔ H\6s]<V=|a͘>lX%%)i%@BB<4oÏA&,صk=]|>TA`u]E)2+n:FTT0}k9^mv;;kqcbt˚wW%i߈}}e*8*(>8 l*lyK>첚K?@ Mw% &xL.BN)wR.q͐V=,/v.%bKƄG_}ش>.~҄5a&P5۱Eqpev‘c-$—p&5Җ,Hur$j̾`jpBX;Mv ֭:bV'"[j&5= cO8)_ׂ ˫6&Ul×6NC^&D1`M ђ9vByUbcB@8UY&Xq UZ)MvKDqrV ׹*[:u k׮x ѣݒN*JPNtbRʺ)ms,>ⶅ\ǘ)ss5j|;n'rqI;W$cV|ɻHLHTF`Ff|7hS8T/*a94o$GUjGTbf*#uMO1Z޴<ٵ{A`7 `ja L E'!V0(>qI682+QFb54krN;_8mhݾ#f6F>E h][<4f]۳4gI8Zk=:dnjӎV SQ1j3bV;r:tݻ+MJ\x1Zn j!bsВ޽ե+:wE.8og!{okg2㖌4ΜC4'.zbc>DDU*RIݎGŪިd7g׶[P2vFhZlsLńg13mY+<,A~j7'g ts:m56Fmz(G]QOs-UejNt*zf,4XFE%/2pXt\VmmӮŗз@#íWxn|\w ޳7:w醫^BUn4Q#t _GKޒavJΦ(5B)@mhBٱ}+`iW/㏟8}/Y4M~">y5,pܱ} &ƔxAykρ~+7YsOrSǯ+_ReærIYtC R{1t+zzz:"nO׿*!q > Zprs6:u¿Jc (ڄ8dJt%S)c]]A)^1K'UD<>Kwꘅj^4|ߎmM_ kvp ͫtT8j&i2`|[3gg .@-?h= w}5\]$6BΝK9vYv,X6vo6 b^ӏ<]O|y֛Si{f~eܗ 6˹>X3<3~Fg D4"uOL6 ?[@~\AxͷG85P IDATM㴩%8\uX5̞~-GzC?+`u 1ljUL?V;#wF{&:l 7:Y3~:|H+tA繖MsuLw T.ή-sr*Ŗ?K^{-2fb?;漢J]!2dW8{i"H`TЙHe컟dDXbcI[LO4:U}b>y 5L~ݺuUe/*<t;>~deT}6Iij< ℑ's=~t롶߶dy"Ň,_w#OiiN[<GW Ix,6MseKCH)Z!熋.HMB{2/b;Om O?h45a̘1H>bg HK;Sw(of+2d̚=<5A68ɟ;wCld~a8CAť^F *< u֕xOcj JQw(0TeX23™GR%²5dy2J(S8`k7TTK8©|oP'_C'2jZh|?Z+TpL3!?yCq|W])EuFIdFTlAX:%V&x3:2vsb5t8$IguqH>AZj-j'RaSIo`Mbʔ)ꪫ[nLk:iρO-[t~zgO-6v]ΉxL~׭Kr(p?Zh W5q$'^\m4n Hv3tD~JSoΥjl2w?q^|YQF*=_ZliD#EyNi:}+;?MvC(>?沁0]F?o ZJs#U[c|-6N|BA\,#N OUC%tΦMG6S9K ;U^tj9ӇV֘y)ziԬmbVt6V',>0ZQB?ȸ3.v:юġwmؔ#>y~W/{TU6H[4oO>Gu$^ePZv͛NNNB=cIÈmެ&.^24+yg]b3> Zx"j-;7i6:)6xI5 5ƲEѮSצ=f-MO2v=mݶeQ:.QYlJj:x%w-shH*˦g LP?h ,;adtM1й{/!tȷub oIU"'xQ"*s ]M=Ѝ46x[jh77ߤ_C0k,xJ4OxV^&Qwxwp뭷*#e1n4>X1v2/6gwHHT_IHxH^I̲#h&m>O>q$xl>3aJ;hJ4nDˣYhaEӝ?ߟp17R?#V ( _$I1xW-^E'ZQa&!:o&s+Ԟ_M !OuM3z;FfMѤi# WXor5&d5xψ#ϲdG=hIUx{px߅˓3eR)d*C;/=X&ᇓt^ӒBF7YW+W?>iTv7*&UdSUʙbkt8% 0E]$^ *EZ*-UJ 7\{ ϳFrFr)9gEehN~ݦMNde$1VSbsxYD}$-ViuU}oTsxl(廤[ h芁mtƪedUo:`e ~mЦ}-UL5нwzQm¸i8dq7)7$2ת]'7*ա|):Вy!NF=0;󱈋K@^wd4 ZB.hw駓r::Fܒb'4IeiWןsO\wa.mM6Uoc1b>`7=Zѷo_Uotp=NSx!R`-{~=-֕q._Χz*g)gJ999JIhx 5G^|ia/EI'#'vIe:ƜGKa틹sj݌^:hM̱86 ŏ̳ 3Fzl@rqU_-Xm5mYp_y"Y*|$F2q1U~~(BX; }6X ͢C\tKi3ϔ9/nݸ:K5 iYBjؙ 6Ҷ۷n@+J Tu3핡2}-q(:6z6zwҁ޴`u|UuEK'L};(,5Bv +c=:ç89oǗWMOGաx k&Rf#;v,ι:4j4*SAsWXQA RM:\:]sٖXteuĉ3ctA$h|UUV8@S5CrR9s{d[6-z?@'AQiˣ߻J.h ~-{ } ` T5[4|_3e)!M}C6C9_CcJG_&砪sHCq"/UC5Va x,[3Ϙ%ǙCr ৛(Ln,J,RtŎ Tu(V!T {뛝u4ݤ2W[Ί9-eh#iOk2,6>x"~ȵTN ,XzG\yUw}0lʣJSբu1BZ.fVލF]rkˇ-!!iW@ g#oN1bywhv.֌x|Yh2d vB+*B%ybǂaE+n%C_%^fl.+TSa<}AFظn=/^}7lݽI,A Oڷx2齶ҥ\"|~h6+vP ]>9[ץ̛E5Q MA@};cwhզ=Vnjlf~ƎW$,1]N/oLc9ӏKv’ zLZjb;+s^h߱s2>qۄ<~J,^=ax\u'7FӮ3|r0Ls爴(Zؓ۬e ?D5 Ox"84wRՔw:eu?X].{<^B@33 Y=%3^}8rrV9 R=g-Q߾1 tXO \;Yy ݭ^)M¾@7tpɹo[A3KLRK ayƂ PSA^p xU71^   T     {%{]~Wfq^6WZک<4"I-=.Ƿ/DdEی*Xq˩rEE Zj;=hE^]kO+ƯKЩzdy^#In Uˑ󤺏\8_jҪ T%eO%иIs?ޥ+6*Y˖,FVzפ'H?Uk/<'Ǧ6Rǹ&Ηڈ$C\ag +i9.5b < Sz )*}yyb|>j\t|m]0*֧bĪ|9OXaW']XRm|"|7>_. @7tZx֮^#ךjQl V ,17Lfgcs"C6OEAvRݥ Cj=cwT>n_6z ,V946—e؞ Yl f*a V(Qc/b+9Bը=Pjrj{CxU,GN-ԖVqet~Q:l\YŠӗu PbUd]ـ臖 Є] R󥂝j Pe9n%րk .=({rz^eֹX4cNA+O#[!zp1e)vB7g K ,+SIv,)rT j)u1ZMk~IX !PZC\bۺo_Tk'B *"*>j;̬fYNQhPTHB,(2i:R3U)[ " JO*DAEDKfB== FOk>n_/I|Eul,~ _fmjEaW\TX,q`Q YUιʤEV*@ĕdF'<5 XV`H1eydT@d] ZC NQ%

yJ}%h]9| ;SãatMS6iZYQ}9bU z8VFqpur~^+[R:zr'Ԁ14EeBGNYa[ex,J4Fb%RWYg}D {ȞU=r 5.Bey][KJQ庬NhRYNa1:Zc7V2| ,e+Yр!;'Pu*]m9_$ P+׬Sc-k[8cФy3. og֯\M7 _障YU (Sd|QIjzs.>Pn -걮FOtꋧMy%R딝v:y1`߿iu=LSǓyx|JgJ* @9$rx椼IRD4QdI X7E] -[.&8ot`.8j߱3֭rqŊ?L~>bо3{`ɒ%lsvFݘ*&D %RE^)ITڛtn߂vm)#GÏ?.Wlެ),^0XVy? @͊e&UvNRʼnF:eSXyhϺ_V:CMܢע]'X;bS5:IӋD⬑Ίz`7YLD /x!4ua7 8TFXdFHDf ]{ (GW_#V'4Er^Vǟx.w- 7NnN-x/Vrrr0tKAq6Nv}.>^!ƂT)aߘa8>kꇴNw xBgZa޴i4:E 6j6 rh! GƎ'MSozj{J.=:0G>aG~~iAArad(Ou}5C2pޘs`W_)n*T,jׄ^}5x}>d_A9|cx7曧@qC|Eͷy0Q}@5LY,1M Cmr8֠:+LyV>Ѿ3"9Ga`m$f] ħo#Fj2rOlSIb Z]`;S׼.g>_(zVuw}~[$N_3յW aW@:vBm[DǐCo2p/*3Z]/5}|BDc ؆c C|lcfuC괗믻*/˺/kGKvCV^ʗi+sGGVBt~r8m'sl614iFߡZIm޼7= ҄ۯ>W_z׻&E&M&`KԽq&oX#h3£Ne-oa䨎%|{-yq÷#au=ja4fxV-P*:pBUI)^%m`-a?YΝ;Uv߻9YcheLtqƠ>_6ɨ|wYz0I<Ӷ1zA/}.ev0a>~%9ZШQC aㆍ&MԩKpׯǻЯȱnyhg3Fut.gGU¶0rhOy$-u%M2|2^<  3ѭKd=:?JTAhKʑ]NsE#. }3Tjժz/_C6Azq7Ӟ3(K{J[T@]?K;v/ LI<%+ j'Tk8&ݹa:Me5j&_^uXGϱ'o6 hھx^io/x…nv <֮]]xI/[)nh2K!c:8TY6ƨ&&MxSjUT"xdd¯l۶=[_tq[ȖqhkqalS6\1n,.ؼs"ׇ޽z%9P^=h߮-gM| gfFGW.;)Gk{zͦ jt:97&uԺS5 O[f+4(P C~$pxްpb>4u񩋝VE7VCE84D4˜0,o~8g2իՙWu]+/0J:}LGRG#N>XTB<69Ѹn' O_oԢF& vTUFb\]kotQ~\]XqۊOјgF4#hFQ/Q´C5F`|F}UTj-ꌠ(H_o)H<QQ4#B4S;R$,g4^LFx/FvQG>\m Œ-,9)!XPpۘKJ~F4Y8NՑ(m*Z9i5&8 ?a{aS}1P=٩v(T(_h?)gj,h!RhаA!ف'14a\L$mm<,nMMr'MwFP&BXIvĩ%ѣDyx[ A2`ՂyePV]b-m?pC:UŌ0@><)NqvEpL(=۳kT—ТtV玆C[oO|_{E(yWM'[ç%ˏ}xoɣ,AKwcG[7ǵ=-ӝ^<5r\`cvODƽMSq.W_j|y*c!঩iE[n-̙;ty4ۻA٬;n|m`@&ބGL^T^GU$?n*ױ ŲQ6Z6s^c#϶c~OwuڅӾ=j'W\.6=.amnN\@׍ ՝Sj4Yz}c C~'GUWtΖɫ0"-wmJF< oʳGpd7`Eqɛ<_GV$8^ 4vsNVB~Q]Q/RY:lWXNݍϭvpvt CWgi^6u^(qT㶿’o{ڹ1O)[ޘv:|͛3Km{H¯42D>#ѽ{,9ܱp9=TsX߮WWO*Fhu$R WHQ:d>w—+P;ns{X'nýzU[# '^hn݃_VƔ^2j0X<}jc> s-j{a5LtQ9 >V(P;tAѹs~wt;6:ri:NC=l.{ =e;8hݪecߴ;n=8!ڽΝ:`MAyA {aig~Pyխ^ C G}p{8]߮Ny#FСz?]/]g>\';KYc1q0R<ϔG(ϼIKcez76C5O?‚qŐa#߽~"ߎ_pEnNY[NkEsυƯ3E=S#-LaD(Zo|u,!PusupIk'PȉD:6`\7mcWncG:uXw ;HfN\ͬ=^\/P7[ 95.]W%Wj9ǒq8:96EڋSܴ-)&;KQʲ8_լYWgmGh{XBG"?p =p_g:@{{x)xW]\e @[ h\9Z}މOWѪaV$G[WFtP};{rh|aoK~Yؼ{?Uʼny~؆2Gl9\-l-Ѝ5k*LrԴ`+܆-_i>1& {Y:_{ Фɡ@{)j{a5m]Ы; \uRH`?aVGyaS't.oW]ATr_ZV xNAVV? x/޴)7Au`yxpOXë/='t}p{FAKV)ԛHsb.U?1R†ƿ 'NVqAA׉ۅ"BA]gţ"͚6v/yf~bNak6gƺV`:`_T FQ#c,ݐT9Y&#\s:إeg"N[I^z16朳ːiw \7tﭶEF9 _V6I"0};B.zTZ_~Z[RW/jwx#Aj="p"Hb|+}i5n]8`ӡ:^ _.l؏7h=/κlTǽɄCatsQKhsaG~ƍGf [wCm ;_V;TDZou G<؟ל&MQ7Q5(M1:D59umM%稂[6u[4hЫ Ħ'ߍ6?r$UA}LzΉ:j\zH&Ct+Ŭv4LRa+W -VI*@?v*N{Ҿ3yD~!v;AK$HDM%)KpL'"5@KrÚy圔hMv Dt QI%'tC,؇lvBv[[J:>xR%<dsx"FID8kUxq ˿_IF1 3$Cx$dx&{,[-tǭPH,׳)'iKDR:~ɰ㚊ok>݃_"؄/}}?bߨ/1jCúB_|*Vo'h,\z.Gܿ[^h?NRW£}8Y%56c'c/i;4ӝ; 2fE]AԊ%bh +cJ%FN9\8yؔuhoYFgs ,ئs7hE؉#7v2 W=-m/h0(=L(DKǸ8H)ŗکQENUvc"X^IHEP %C08{ ȌP; 5'[!:ӛ h9tHA1K01T d\&Mv~ǥ+!3#d"\H3^bٙi>}OyLʔ袗RmK?G,!ֶg#U,&H EA=xOt3T^"l3Q1;P$vajE,߿A>SUXѵkcbŃʌPd Z U ߥA"\ZfIui-GEQ7m܄?\6\D6+AMo鉷NE*rA~.yA@(,Y?ѥ MU5G_gZSfmh֢z Ӥ$VfdLoċT\%( PX~K߼߆kӾS/_ЊMFi'9Y~=HIHeE^B @OtrtqJtSP$oD@I[&|2gb]vE6BfsM6A@A@AB@&A@A@(9DRj"  `!P,헗,uR=Y$LS'@p~K UJ"Y?ѥ ծ;`ay BO5y˶ d$X`dIT|% &AJY?ѥܟVu5(晇.^]]} IDATOЪMU-O|#RlB ~D7#%Onݲ:tʕ_,SU-6 0Sc!MԪ:&">I+=蛄gJUI8gL'/)P+*A ]‘~ >>I_Vof5]m$5Ȑu9PPmwtORS}%GVLYj57TĤ<2$/PبOl4"mSEaE Dm痀 [!>=SU!77*An ݫWBXܑۍٚģ'+J1_Cr#J{Syofn/)ђ~j6J6ߥۛ=VKZ*V&xu-؂'UaZRV/ƖD")V/e'fpklVwqu¨RR9c"M΂@(ym|,ظn5駓@ށQe{۶ʗ(P|&fƉwAtU~K(<{2"Ǟ@Q'wܘRh0@İ2d]%(/s *3'w]^`N(}uPO]H<og鷌ZH|->!#mNA0E:)TQ'.Bq,"Ԓ}g6'_[~.;$w.#⇥Х2M t= Ȉ?J$pF@RCt `PO!Q! p?CCe*NrAOS{<}/جupy=p> AA%o,o(I G%Qccݖ.@܃ x5LBC; CHH}*k lG_1G.(HͤcskYo#!+W<}'P}#281{M3%5=pl 4GI1^N>:,Pk zGI."tIUvIj'I5ffzݦP. dpc6J2(\|6jB 3&Xg*;(SC҇|TVMZ /M)n҉QToddYR9rG@D&u">O].9ۜ&[IPى'+VLJM_'HaqOcbDʡS$jE '__~_}EH+M-v}P7|ReMnXA -sN{Æp݄ Li W )6]}oN4wf32!'CMβe\=j GDF_jQ<>!;*˵h }Aي߀9,91:\W<[X`eQe 8UI$kd(s1:'{oBmÅ~>} 3"CGȤQEʘE?F#x\`,HZ}E[b 0ذ~vУ{u4UpTD׋ nʍ !z*WI)qdY@͛KAG' 3^~Z 9-[¥W^ {.G) Eͥ\V FVIV.:ޓѭrϨԉ-rCZj}ЭG/h٪ EN}矇={C-ēO?._|+]>isF~Y8[hڬt|3:w ^w=ZiW^u5ݻe[UDn;,)K`9!-m`C(:@( O,%F,{BSA.]5>b$v߬E+u,^Rs`׮pu]NЪu[ݧx˗跗^|I ,>'꘤@k&0tVZ1o|hSx~Ƌ sϻ@ _OطOOI3Nom#Rs=N:y(/ N|~ #F)7oj }<֣%Vܨ:kخG  }oM{aLi<D7lVTqk&tuS*ro5k>ן {G_=i** fy,\l|6w|pD؊yo`Mxz;TE 7"wkӰ@O—ElhoݸU 7\)E$}tWsd"D#V_FDh(/^X́zRL/a[l _jM=m3>7rд)-s)K`gsU?;vbd2nΉVHy#> 4xR+W&-@N]G}_FU?A=9jeJ 1lV x9@T{&+`]sUРA5fЙhf^>eAóM _W ! x:`9pˡBrPF Q>xPBUeͷmWa|'{vYcu3cߋh(Nx}my/]F5OdwT_\ . ,kՄ k}@ա,X?+#b_xӇ$hEDze?ۡZ*ЦM+oǎo)jJPRlܥ[ئ:rƂytf<ՙqQg3UPqd'?N?¶Vl6²jUhӺ5bN\2;wo7<TͷmsZj;>G>n{)N>mgOV9\}xvPnR2TX]>VK-e>W>l|wGa\p}욫Cre $tmi*?0.xEWYH&8Isǿ 7Fa6mRFY' `*mtNuy˵m8CHVٛN*|#GdG_T%nAq+Ll9ţyп㼍7 =6=ȣԶFc]Gtjժ Մk0d*zdOusƜ56{Xqq0Uv[&8N}""d'Twx xM[A C,X~UZng3o8\|u6lhnܸ灘sYgۅ*=։G6gGSEe8 P o/B=j<ʚ++V~{|xQ 񤛦v /΄>SG?O¥ q㔛(8U/TɄ}tVKnvÍ~WV~FE^zpgM]",fШYs:2_y1,U 9QD=t%EêE=A9O'g94*upfZh|o͚uF:E5kQXc|P/F MLELd=0D`t!Euhf"D };|Ie7h W8h=[l'3_.ZBOSydݳ㯴lڨo@(ct'a1gtϠ*vQ`7XOOPVw}W58EuXs_?p10c5O:X"~f~j ?߯KQU) 5B#c5$KƉfז4#'hM>th\'K_=jE#=gd8r衇;o \̛v;©Æ}TWnaƳOsVϙ\{?Z{g'l[ɤSa=0{j;+&\{-&lG7N#z:Z2-PG%q * O';wKu2k_8(UF57pC~U~>I*9m%|B+$0 pQ):(סS.W2MZ5k¶m#L*_<2c(mõW] p;\ڵqmm}[j$c:,Xx)d^=_J[h}&?r_h^yX@0|OܲwӤj,T"xwąFۉGmor&r g&tzbGt@Hs>9R^dyV,i¨'RFE;wRyt;L]>F{!0?^,rQ )7¾=1'qFBm /p: څS%cl$9/ׅ/HWvSI.]ƐZ?'ЬPnpzb~˱ũ;7*wqУ[7Cy5>0wm pk/}CEi N}&ѭcߵ]0u:kȤO\!>ܵbуeڵ΅ǟ:v% *U|: |{ G#Q.޶0-v>z,r/ۦPmvmuN _jmK}*VەC%zY}ǸF:s;`a5ArW}'iZ!sc?&΀Typ 7<gP R[<<عsq)o@&Ofxú$tr'hm u /?= w^}Y1O76?5+F[]uPB\qYBW' 31#! !E(+LI|} ֜Ϡ~ݺj0'ZCn–fjAUƂH_pRb*Y+)[CGd$H(GJȑD](q:Ip͕@?|U5b:7朳žAW_b9 SoRe^#2Җ`S1ɓp%֌4&!c>BoݾX:^3\ɓЧnBp?t؁Vtsq:4j`w(cP 9^fZ '{ v 4hZ7͓oT#aE:_͚VVmLE.qO(b;2&~,Gs1{SO㯂fR䟵k*=٥s[k&7v>=a~2b& YVÌVi1:Eb(Ĕ8e1BC|Bvht/ÌEZ跘t;MԳm'Z+\j&9Pe "Y_D_*`)t:&CZEFZKP&qbblݺ ^yux /DX~~285g|S);܍[xne*n? zV#hA@n] ~ GMԴee ֣z-GW1Eb>GRJ-tZaj+HJ,9L7[jk͟9q8 0yd$<' D]h$*_#A'SX"2;G>a|SMo~˅I-)5ݍy{nLē 22!qP| >iP~7хԍxC'W z|L…9raucF.TM,+QX0WBDJn޼bY2HPU7^y1i#G`*  IDAT!?C>Ű"gNۿwo-Jtd:Ȥ6y#i[nҬ%t=[k!Vuޠ\&CҤ58,E ‘Iyi$۔=;?: dش⾕̈\@ )!zJ+(A)0< !)B>pc'#wx)KU"JwI I' /T))Uz2\) ~\ HPEmXLtsriU'E8Ф:UHy*1%PUK_RUtOה$&'E|O(:mlRmni(X~?hK"jNA.>O69 '> >]٣\\UUlMu;w;HZwVU.?(ORl:'ct![8A~) QhA QE3`Zcҍ?Do )+eM&[?Eߪec b @5jֆf-ZrJZ|4'i8 $@+,A~)b,C exhR(sh"k%SiWP?TnU@3V).VriK >|cd~ '~D#KvX%V%8jt0~czBS %,\ݿwOj:u깓9R.U&Wq0w{0ӏdeh~ML-[Vmإ辘(tT\t  @@ ̪ը '<ۼkR:jZ Oy%zn<9R+#)A@A V&[YGM¹kMNjEUHA@A@AE ]ڛ D  FK9ximpeaR~B WuB`F}Y0H^A@Mrl kԎvr= &B Ntn~]#_|6BA@(zhZppq.׳`!A .q) JDl ?A!AA@(8{Ol/uniV.  YdYtA@A@4! 4+jA@A@2Lt3.  &d&`E  @fnfA@A@҄@Z?/&Em C~{|"s.>ann.+Wr˔I_APH(|qg7T%^P\f\\T}P& ۶n_[ yyM>]FMh۾ To\.!PxH(  < ʔ4 D?]wIB^~'XRF+C<^C1,Mϥez kW Nj@N PeUP 8 .GCCnPx˒9BC,jϥYe&)mW%'=Ņ^ +!;ZHH-%Qz5,Ǣ](2x2S6&LPgJS`~$ Dۻ :A.dKnnRHK `B=ԙ<,KE ! 8,ꃲu-EFƔ_!{ ܿ?LπRqenOl@@C6xAl(dS,U+/m;tN|QJU?A=S+Hc9skUФEhש9׻&[,}`=zyMe'{ ){ЦMܹ3L>=T_ C-[B֭a̘1믿F Y$w!D)-k *n:Sd)n[e2 SG;w>$I l`X{+gۻy*}6M)| v9@iӦ1Я_?hժt}gШQ#u}k? $G} .7^|iKS?TּYSX`~*TEXh1m }T_+[,,]h֭__| رN?k 49r2~*ag ;j֬;֣|qȑФI8SXjVt׭_7mѣG_wXгGwqpd뮟!߾ /΄&";`Љ0ݍx%8uPW^{bT\ׯxוh3/zw,|BxV{9YN+U#$^gΜ W]uTR_|1KU߄>ݺu+\p@{?s: F'N9rY}VWu44UGV[ո-[eW+]{SosW_#ꯞLi eq=0ih"Hնy\5&oQϿx\%86e1"V=ednGam|:a&j?nw8态yL #%Q^=8(bu=ު&DS|~R3mr6l㯺C ?L<'M`f}4bF#hb90zHiMZj·_}A{q`߸q#h׮)=Ɨ~̤N P Ԅwtㄏ&8Czu&սFعSm۠9TUНHC̿U <֮]]xI/[ɲ-[4pRH [h%bŊ&>v@r?8cZzlD{zWZSN5f͂uifhv$ߖxګT}Ο|޺m#vzZAt}}/-c:XO3X' ;'HGKW,~F/!ޱ7mƺ$s}V.k?ɇנ~epp!4ѥ?ٳaΜ9z=ydH~Gj|+W\` dS,5{t n-9j-sup2~x p#A,D1zTB puSF48H6Z@=ժU:(փk.2Sh|Dd&ȟC'^Օhr"N9/sՃV ۷oW!}={dN-) /4{ti#<4<|!+a>\QdqiԨ7ƕ|bI&77W=ѡ8O}:(ԬQSZV>)xq+AGP֟DCKW,߶lM6]V.%bJu1?ضDÖ+l_Vэ8m;jmҤw~ߜu]F$Fݘխ OE,*uysfNbmuqu֛Z\m իI%M"G ̧Gkzt.* ۵m-{Ҽ;w_!^%4yU,]v-Y 5kcj/?|>|/O0b16- efc<&ϰⷀ~(I\q g֬Yk.nk֮bInm_`WMnzr)C-=7V>]N/#$bwjV"eYC,M+aן\碕f??Z:֑J;XgؙK];_o]7.lꃥf<@={Хs'“NVyo׫_yWBqrh]ܫVS>vKwłocL6N>xqFE,Vh[ēx ꉡQȏW@vn6{U~:zhO>E_i.maдiS/>PSO=YPStڞxGQ.@{n9?܉?AgC!'P}t8'3+|>%펻'戾Ѥxs!KW,~Z*bι(4fO`4[-_/uۧz:Oi(NGP83aڴiJ^0p@#:o< *M_p _R#KD)#Gmid;NoPRE8Է3[q!bq+wҽ7} =E&On >U -Z6)7lſ<>O}KC?-Ɛɸ(Vu P+ilj'&o.m_z.7lhoe,~gXP}y8't t4~ޣK/js|>o^qx_?;u_6֠O~ݳ?n8h߻7Rp1p]}<pL%Jh)#F+{H_:C!M!?L#VیuI:D?g0ӘYfC7}4}nӳgO|bZ[}xϟz]fIQ&43mm(}| xTrz}Ƶ,|4cjǢ z@~ņ9^8G+AanxGakNA"B?g> =nqXE?0t_ R㯸L=;}8 S8wO)x[r?dX]i 0uIL[>z֪ZkڹSG|e4??[>yilإ{tq-a˸K$Δ&z>5 @ G@Ck @6R2Z{نx_uz[b ppm\Ԃ{ld~*~h!WQv=-}V^~{e[4R2pk @6A(ݻO>Lkt!`x_\Q}^Ly!ötWC8r F8C LtSWєU_< 1-nO j9ɗ+9S)!58-l2MEk⤫Ma҅2Z=8.߻ǦDqm6m܄^ϝGH !HHRdW#}.M>΢>_ڡ|u!M~ݻwY5n$D1)-t)C[VmإPm qA!_C1,Mϥ۩LtScј  2eA.-8:Vnސ?v@D@C"pRTNteBj+ڒ@&]2J8+ ]%?ޑ ai }.Φ>(KhhA@A@dNA@A@RLtShA@A@dNA@A@RLtShA@A@dNA@A@RLtShA@A@R]oTM(F!%   Pزqmʪ +)R   d2&o-  )C@&)x)tHJ2Kwn F {tŅMd?i?ŏVOtcsL֞hz<.~,KΟ(l]f,ƷuO__y>[~Y?dFrtIF @E m]/.脕YSa6~;Wz_xp>t6FDæ,[zq9,f9']a>9  L|]tb]J&ԉ1' ךl;ŮW"eJ k];N;ʲM%r %_;?~4|c-CHGQӂ.@uOdˆ<_T-Ta*=~ ӥ_A@ ҅/.aUI-g)_O43LO  mE.j._NGq:CL*϶m~DQ~dmH6m:cGOdr7Ƙ&G2~~PyP_A@@&"d,X|[o,h|ˊ'6*+>4YIDOaeJeɇmR%Nn;OQSYoNazvR0϶Y₀ NtcAt ғx.꙰?[ ¢8dI7_7{KR[ dtK!#!iiՃb @I@ ]P&%IH#"iA@AHW*R   " ]    d[)UA@A@pA@A@J)}4/A]\AAA@A@bz\ IDAT uӺS:ѕ7^$A@A@"زqm$1Il]H8&  D7#   $LtN   d72nu  I" $l  ٍLt?b  @D7I$  @v# X'  $)$ml  W={ K'yL@UHA "Ģ@?[fHak_rłt/6t.3M΂ q?Ӆ)O @@&@Qt)B ;NEv"jA @c-nXG2x.TVKF#% Sq'SxgF@Vtq)/q>44L϶LX0yli2)m[֎2'nl{h|vvY?җ(3uY0Eos$wŤE `a7߈u¦B2 0 7tdC="v6ip  P4ݢYJA@A@(bd[ĀKq@qA :Sj-̓dTZ$|2QD$à|n[ʛ,-fL'fxۂLtEʑgfbn%{o\<$R=LƆXu+ b HG[H܊QZZZI45ݽD&F8@4` J&pH* pF;X ,PRGh E@&_J/bU&.vv܆¶ӦKpMXβo^2dik=d¿ů% %ՑvҌOjhbtNh0K"z9l*yol:ہp`v Wcy;/E1̶\aAzYͳ`MK&33/^d܉)A <8Im!M'RdŃx6Lt;? rN'R^_gx!9>צ|k8O6.y9m˱,ӸL?|XWq9M/cmW)涷:aT:I}[KTV@¿>mjɿ9o_>>Ej]W7\CFܼ57mܼ;>u%;]+'|Ct"N6G†!p }tsj%kK[nKm,)+L:+YzCӾW6q}K _U2F2Jnz}Im5wկ<є?G]aݣJ{rAV,s);ڎd(⢐!XA ]Ф#haOlN`zlXuЙ,iQ9v(tΗٯ._gNj__ֶLˁ6x,g9nY% v~M޿"{}# %{2-J"AdĦ̣4Ń&* u2t09PLh^m$ozeR^NsyWј9?cY<ӸNfg^avl kKQ痭E'=E]JY@T"XzrLx:3-Nf|_Nl2geil@Mͺ\>S~Lt*ҾyPx]i֫z w>S<;27+BocNڎ%dRnۗ~d:lvnGC#C;2Vk3nu6}<\nuNlnE1n^8 ܲ*Tjl&޸&%v2(QۈA^;Xݜc\] -Iu['n/+jE1/_(M_:Ns[DmG5W\-c>ڟm_i+S{g{}C'+75z7vp n̽#u:&WR>.Urq4-ΐ2qQȔR =qWMyROToi<Ip%[#>u`=@e ?{ogQwuKbk_6M!ɰHB!da&$$ CaIBB&$̚00B !80jclclKeYnuz{տ:_oں%W}>UݪS:u߻{ܺ^/}f#\<|}h3~,k!ǒ// z~A3wVS9Y Y Y Y` Y %4Iskq t3GH?Wy#'x k dri V7 LSk: TV;n6(0_ @_zц.ϵA#C~{y )evOaL־>vz$ՀMlLK X4z+?:-^ Jm?xoKY-rUV.0lũ,FzP_d` h}=~ȯ7uM@?tyь9L:o65>/L}UoXʓc_֭=igC~'lysТ /mTܲ^pC-BC↉mK]f߽-ҿ`b}{yDc鷽OgҀ= ֘h-Ͽ?ZgOOJ,ΧulnQUzl^ =@\vw5f|Niz˛rJ{Ç}:tkmw7ȧwaݺB+jj\"w_;'Q' %fi$~`EW%),pʀ|,@&y%[o}tQ@lmk]vm6ψ9 Aq|!n%ͼPucٮ#IKkQdP .sb, (P iHhh >-'op̏d-9БW$qyRiCG<Ϣb/+gٝ-]?zcy#0v.EEc%cǣml0Im,տ{=m029uYgnG]ñmQn[ǣ#Ye5ԟD1aKM5bڭۻ-nvH람o'֩|q-; ̞߳xͿӞ񶦁 ƫ7`ݑߩØk쒫crjs"p n6P%xLxQe(td{@*؁%=v0WumjN9A/r,{.u.oIo({T4, 0#0cJ<f 9hiV8z@AQdR9fPc ^I?΍ Gt H ꥏhGzt`ȯoyox#`-z1WxuYS{GV;Z;QWn:^\_\dWj<}'x2ЁO`gMy'+Y^{waNABRcB#LR,,,,xh=e01oP*>嗆<`D:G`[f386t?Q&ݼ N?s5jY~#BrYk{/[ʫH;@S]3L@%ـ6ʀ3U)/08yp'+Eޞ?6V0V? OEvP |!<ٴ6D֘?޾=8ۅe[v߹rf^6sW7$z2AY]gMtU]6ԭ(]t>~5 XS RjXk>V&\wfW[XKW/]a,|[b_ =҇gN[4y =ϸ EF3=Ɔ+׻Cz%4_f WM11|=#JGA31h|I'shהoZ.r6s"/ V[-6cCCKׯr;0|{tT\s|55rdt"]lhPuiCCFko1k#}VWs6lZX3YiXbh`dv#++<I&dsWVl OO.&n.RX&Nc놬6TG& j"NUG<Aわ[1ކl`.Dž ;bEIׁX7lq3ښtYLj$/@& TRrLML{ЫgF`vl@RLec~E697n9ϲύfk L%"{@rPM<wc~UNLf f}fC, q&Wu/9@0.lujBhmȟqf ȳ>a lܤqByN&5o!:%v{4p&p83:#s҅R S_ |\:r@@bbxǮ?KeB8g2d/#. '{ GrҬslb7:-SR2UYS颜~GL|)cwdz]=?_'}M&;,QE& ξ,+&p/N}}ڟ5FO].<lBxL邿fjV^e5cmN[owvEbnx,w[9#WD9^8A 5/:[yQ`m/]inzտmgv"`X + To^ o>nMH7uɺ\~.J5t,߆]v45JkWQ1;nHz|9e}i,z۶[~ĮSl:p,\{hnܚ?0 r1UgF2˯R=l}bb˷ޟ͟AP5ّQۼlD$o1t- xt5#6>U_ O !,exlgiKE0<.#FPwZy|h7ڵ>;\@7$pS//" nMdDžucbGռo:cYJ8+3I8yj6] f u`]Εfdr h&}qnZv4bv'?MR</9bw4 @ra>^]?È'yz/a o2'wPcS rvV[Y}@>Z CP"dpdWr@YO}y-,]D1U2=o.[nv&l+y]_st K_Yf5=+dbuϖw,,,pX `|t4M/ Xx#Yْ5T?'*坆jR9k}:Xo= IDAT*v`^^X)l%2z6r^|<`O2rb^`[/L}um< vֹ\c<@X6YAK' Oub'sz^X|EH IsMxو=cW-`EРGklٲٖF{ƴԚ?e{-Xg{N:[E}o=^V.DbK'MQ#~~C[޶1s1;6b?Ͷ0nh8ichh4N6Y[ RLK:% a9h›) BhA5jEDG0I gWxt`ԑx/ 27C> ]'-ۢa/ɇDP?\ h [5,_^.dl0rmÃ\n~=wz *wn~|(x=Bd$ $ $  ${>x^ TV@PҘIx=X[(zf2KCoqx~@%txIl!ӱ@2J&x*=etqKy ] ] @&nI@)=wa.ޢWrUѧ<6[i Aٛ˱>A\b,,,pQY],=$4h,؃E@TJ@)GYy/t<x!0n)PV4V8}.[Xgoꝅ-4` M-"vZl 菑%1''Mx[`Y|˹ēvB7<@ E6s:_<TbI]ms MC+Ioc!_i-gY;D^WqMކc} c䕱3ɂַQ,/>ou.ԫ͋sWBE'%v)OY-ye}d06Jd16bҞI cm':ۍat–X?ԪhS[6]tzcfpsJDFyL_-T?le?j{4vf-ֺklHgL}l#M߱bBk=~e+bۻnOT8c T\mq {#ێ2/\*OX(#mXP9|z+]e$wut}f;g؆ EwMk-V;{QX^zq+wc|'Y;tL])Y,, /KE}ӖXАʼS ;Y Y Y Y`,"X>] ύg T\ ̨\}:I?`^3꥗E;W,hTyf;.Xuu)&;jm'^Ш8Ѕ:jʲ˼8Y Y Y YZ|VZZ韯ZTzWQmKXi:}j>S>^Z{zUI|e/;<ͅ Q-MuGY4/*{8X,lrb̖k_pږb)[o%]x+:ɤ^4xuus>)OHHHX0(4$ThtXg3xHoz^0S*E<9V]YO,e^eyz1oMS*pB),?+o~С݂,\ IυRytRX^l59ݹ%,+{s],O3/_'ue:ѓW*{e^j[C}:WN ]7-5`h˽5n9?jK4N[٭z< *CfءTυOіT1>{\0}*_@}[* h#ELGÙJϙ)ή/6~ƫLV\Omʽ\=x,4?' $ $ $ w@tftBvH3zárՕ۽tm!jgj}"s.ZKV!ϲ|kҡZ[:Ky@@@Ҷ.tBLM]}:]Pη-P8o!m|H:nLl4B[s$6}zm= ]}kk oq +dDŖ߷3[_6>-Usvcxp0>lz6~v=rSj_}@HMv8پXOa2Wk%1kѦ|ampۍg] m_*6˶lO'vے5nUO [M;N0+7u}M˗YX̷vw׍|SSm2B"޲Bi޿~]|V`'z-}>D#˶rwӼb~<.~!s<H(t^[`!\5bʞ]Ku>ͥi4ddd)t_5pZ$䒋 ,p- (6JHHHH8/Hs`VUұi /*( `񳾾&ν9z&. /ڋ6ez2 }kVn5?@XHe?s[P?~Gliy|ds;*yȳ}B޵wN߬֓,ľ+c=7X1;N`rQj klI;ldddd g=[黆.I#iDH-|N^=祷)O6)*x l:xٔI^/E{䆃@~}]6Hm[BuFGAVNoz*N9\C6xy15-{-g_nKvО~[h훞{b{dFW]aaW_n &mÖ}߭Y}&-`Km{5۲|0k-cMV{İ.k^nc}[ZnZi!,66{Vc'|Mm.{M{tˍUm琝5|H߲dM+q;O߫#}UV^ŦG{?Btv<Qf~o4?C>;Voʑƫv@FXT_@uQ HpEr%T[6 'e//D3|1_9ӹ9A΅ڬ{Mٵ>@_Q9×э1!~Ȅ<&lWQy ˡ̇>Ja6LjeqnhG_ɞ^IKoubE˔ | 3nIR,,,,8H@ rC"-m}d 9JvQe9ՀOU%vvvf2e;h&\FؤO٫X%!CY0 _O \^%+9j9^x& H#:yRa8{&}.˼hOB+sʌv.K7ة%i_$QAG,6L]]֙觏JDˣ'ddddŷ_F.hy\N?k4Ƴ|obG}B"Sjs1Qa}OM66uX):@C|r!E ʿt\)M/Mc#l`o-P?/@s|̖͉r.:G r `u(7=* Ke3[.ђ|)l-Ǟ{4m?tU*::ENd.4WcB / n:GaY]WMPQأuex4fo,v׸Oʓ .\t#P.Ѕz9TxlV:ZBDfw"q r m+yk2>(`g[55s āgA\vOȆ\ X Zt 5sxa+ ^E.K=:>5W7 3Ϗ߁yu^Un |l\ؓabd2[V\|)F 7=S_b>99ic)Y Yұ|!S 64.~\Xr0엳βpPQTr@)rh/S|MvR Q &k.k X}_S6/*4x\;s Y+  7)9hs&۳[N%t |.q[ ?<<u+kdy}͆“;z4694^y<p> ص.77itDV"wfG?u|_Cv싏fx !1gN:.+XL% ض!#Yudvr3 S|)ls?Gc<fGv1;.D)|\^ 7a h~ְ6ꯨڮpHrC]V̆Z%>k/ *V~'mۡ:,q]mSnfwooeH??un^t?ߜ)um5^c N|bwl1'%J+&,6/hU6UD(+>nqЯ^e wZt0_ 7knyuXeqw}b߆V{*GTzr|q;ﺶywؽmb|IWLW}s~Mͦ56u>Ql:UaMD\fcqoL[yF@~ L@a喀B[suWap G v IDAT 0 =sήWKdXfG٧ oZvu?g]bta=6\ /B]xV<ܰהӓ4oA^~ī':f"zen4?AtFOaߞ rl2AVڬғƒ9mzq0˗"ŋxIs9>8x%;h{& Гe\" {YIv_ŕd= 9&[uɥe@.G}4eu|0hw? bMZ:W9xdddd-c~)1\\عH汏<{SzOU9xTw >^ (/WmS|'`2 e314Y,WOwוS9;N_f"z$`L#wc&)TѝfY]1\SY'ܹs>Dq.ƒ!h4Y}d6;w'U;/AUƞ* F9{a?UT^>ՒMu4}Yl$937A>6JrXrR,,,,xxޅ. SB p 4ʴ hkpq`p> `r]D `˧=Z@6r`\`k@ā'/Ppd3js! ;9xI7<^Ex\In.lK P"\ؗ5hyM9,q<<1^tH 9}x$=<",_^"g:ײ9 ӖgEgt|+7n8?~,g}n7+e?gK~y޹w5Br]Fs{Z|hTpO7eKx]G5IJ/?Ep)ܖ )_o˺xLG#cJՖW`:eo2?z)՗-Pl~:y[ "^u|Ԗw_rH?:ay V~D5vn?ҶSGv<m|;{ñmoFH]=rev"U[7?Xc׻W#ˮ U*f-܆O|mMl;}TajIlKBG ]̔Ks/VBqdw|MZu1˒E {>eA6ؙ6n@<XO4'FGͥd+/Sz< Ar @З::<[&szƫ1 @nQzecRY>4et~{# q3s!>{_fsp/+/nH-]W2+Y Y Y Y`IXPPBOrѼ|b ;tB</-Ǟ/CTCMdju҆Zmm>MP1ke]}r|+ yJaBe>:d7#ddddŵ@螁E]ziDp.S}{^ev dPP8\vW/ٗs\ց: 0xWQ|緬P.tmAIntAWV|Q}l22r==ouԖ7ؖ݋$޸ڞ^g˸YtO˿?ҼKLac터wЖ\x{.}~ߞKܷ-g[b|-BhOY8ċ0kl[llﲱ=;=TL޻<[ecH-Y}CǶƾoΉOP|~#={}؃]^>v澹NعǮ/_fXOgo}WLTWb Zĸ$t󟎷|$V/z!ytp WՐp .t!J] D {^v͔9$U(3GV_2/Khsϵ䢡;/s܏9z$rH{C`#In=.ϵI7}';6ϯ,CQ8<u%ecu6/?=ù(_H{qLbu":.qe{uu,0q)O\-m' |O|qɇvI}Oσ-rWRxgG,dlri+ӊg_ I1LfǴi Y Y Y Y`Q-`EUly4zꕗ-!~-cXVl 7.~79N*  hxʗ1p$;9:_N|>=M0t>J_{~ez1p<p28Xӟo 9X"[|괕a[[v,) ߷v"_55@:tceLgz,l`?{*w4rW{2/L)[߹p'dͶ\M5{t9ٿtgsGLY=A6+ypzoC! wЖeMZ/}r]?}@Yp* ozv>5`']uf 7}'-Opm|c|ٍbٿx嗮P.:jt3O,TwXlM.r D]4ծa\O;m)-M꽭Q\٩eH6ӄPF:.zzE=u^OO.˨VηͧL?}8T|57 |] 4+>IddK񿓀y8wtQ%b<\X xѺ:gkM x{drVgs7ԋ/}TFWYu'=幒h=թ?\s&(/<զ\myPz񢝏T}9/+/㚚L['Y Yҵb?ҵY cBX} >DH,k3klrT}:ok~l,2o+/RKSke^:VWr{zKO+:hHP{}Ŗr`/wh'+<|1`~lĞq-!.hKY+5ohiA敻UÖLN_;L#M6-t;Eoێ_m;tMq]ٯ~Eo}ڔ/B9~;>cdǣW]fswb==e}WZl'7 u;:%_Wo7[Hn4?|nÛ]&_o4s__71a+9ef]3{0t 엿Tࢨ \AE˗=.XdO/\W>.Ӟ\hŷ,|,:r.4s}/שMl:%>(TzóMy[ԦT,,,,-!?#]8u$_4:N@H|r\^h%u]9m~cQ.u|)3g*<2El+BWD,,,|.t t2u}T>s xm6 Q #v/ו骵fAYcR=ru2IS^g#\wMBGO>v?tͷc>/ipylYn?s1ֿ I[`H޵?9ia:{72kϘ1'myM?7I[r~A=eYAcvio.{&Mo= ߺ}TvaWؘj_ S3wߟgY8|!ݽ >; L7L蠝GF u]3<}BwJCsIa~ Dɥ_L^{y/,/&s>p·_ͮ `DW}ǞZyx̧9|cTУ ՕϘJSᏥBy&ddddct\$M. bK7@E{TW?vr|LǓ% $ $ $ , _{4I, q)q6{?K>gc[mˬm"oTl V[Noy;#ם@,?|ʖz/+StOOX;~U,g+c?nl%;wml.s)]o ˗R#B--Gu[(Ibh*,/Na&JБ~[[?ux?vYBY|xD @ݙy޷]OJHH->i|U-A'f&=N|,0sχ79Y Y Yi[kz~?L@^\ݞOS2\Iaɫg@E$kHӱ)GV}629U{=Gfgj|9 ;H&^wfg:'^.zɥC]DlB2u2fGށ?dX^ΖY=`K-D=]>1j!#.[ݞ~j='m7x4<6h2eG~7Gmͱ|^[z McUOžOn c+Gi[svLV}206h&nDZ?톱퇞:^o\g-vll|th{e|ϯ;`! #_coZ͝fvJ1]g; Xyo 8PbT.%.giH,NhQ@癪 sGeP p(&W3]v`pH{):|rP1{c. @ِm/tQa> I&Ac=؄%.|\@>3՟/=dddnt %d&(1P-@F5x<Nx|t{CrK. o]A<=vs|!ax?x>:CYzi5~r0̼8~>\KOا˙/S{rRdddGZ 6^($o rO"Xb<obA4ǗQZ㫦S:y#c;Ps=Rx\Y 4դ?=H3r<)tBϩ0}FKFF;~5Vպֻړ~W]l9Q߲;;3||+}GÍ'荒Wښ[Mvm=Tb*< Xvާ7eM\o˰1ial^ѝ{F8 q$Xg۴!GTX+ҔY\v bp;Yl)mtݱXsKlp9uB`FOX8ũ hmN 0|"CBS(G3Կ9QS;v>}0Xk2TgOĶvPL5j̅d$ g 2 "(oad6 qsr\7Az$m˳c1:h E|[zTi.txKBzP?@I墯kjC_t d-CG`n҇`ْldMУlC\uz}x 46u\ED r6Y Y Y`. ctnlП$˅#dddduKֻLKrIsfb)QI@'٩ed β[Sd軣`8+wt] `3 jGIh1+ɹɬy{unJW<ؓsB]Wc$/*/1/:8Oj$KMK|` dx800zMԑulܐU&ɬ}GCl<а)e8V@&:$!on]Ʀ<9;$ P,oY.{|:t>0 bRga]mVߞpx"kϚ7v ^bj.'1uB>{IN`̕$[@\@5 [(6da{LuyQgNF/BdWS[ʓoNvM/e͎хD,6ikmqQZu}Oc6q:xA}|+r WC<~\<-dddd c2Fp -ûPBHZrB?J2=&sb Cܫ9_VdˮFs*Wfj:@c ^ձڳh- {+=9lDְ@omYDz~UmW3x2C¹bt!h ?57dzgBd1we ?<=1G7>j#qfcxv橦t-f~b(J+[gc{E&׿t5W0%JCZR~&oR4wލZl[MaOlsS _+udžX Mgmݯ[Năٿ-9Vkt^c7־b—wmU 2i?qɥ7RR6fT-4]%JpԉR4`=xRj.@CXN7de{1S0K]3.ȸ ?U) - S}gC:.٢ 7! `x4\^Mg}!tAJ҅qcG@< ;HOwߞYۋ+3y»na487xά&&A^܀eɇqrA]t%bPJ`+ᡲ"l!x20Gd^\r= SvWˑ+0WXP@Gr]3^(á?dN}Gp QUɁDٺ}&p)9T–E^¸O>@O`_`SkcAmQC,[ l+~,xS 6͇g_)OHHHX\ L/.^^wϴl8o!𢰀4NqsYxEN^_%UKs90~散:(`Klṕi$8-=P/}ΕLق> F8hytm!Ld$׭ y c.3r]?ϒ/[Ck}J%1RzlkzBۆi[uN^˷{ӷzjYT~%Cm=O~tڶeQ+FWm˲ӣM"~|t| ux6Fg{L@`~{"LfòD^nw+K9-Yn9ˎ2JwRu~zdm[e Csu -8y#v_R0d{7EM߻7-,ocxʞ_T]+iTK%7,CRNm)4-dx0!c01!ĻKb0'Jdh)% -NrS:Nx, @\\HnYH(FidAO-!D|XWm^>(=|$P-)CSpY.K.?0.p)\9^P'CtNE(/KIzaw?I 9-r_#yf#k%S{ m[ň: 0unO{qm@XPXw6h?6zط{3=&7GS]m~!/*+aSnvftP][ﴠ5ڌ"zq u vN q8zp&&ƥk~h퍱|a匊lN82c׭t-[6+,IzY[%i,Ap +Y Y Y Y`IYneZIdY #BOq m@"c@L) ԡ @ pޗ` ? 7Y(L/KԱ^>:Yg x)&WNȆ>n2yyl%+yWM-<=fd>m-e/2bǵ #-]qw!|uS;и6{7s0?muzּ>t]axX?Ԙ?țas4N@BY:9 $:M YH.Nמr p'"|4' ;9}E7_e|l+~ÍAk?2_u :\6a>͌NgGSMЭϷpgڕ/v22X1U cR/b?c Hu?n@ ~z Kxw.'tH.{~w?{L]do@|__EVCy~uj1VT]+;| .;~(uݪb`ݽ³wم:ґ'g(v9e ox|) ?x cW3Gdhl2׵wmEsWYmzxI~eَ=i-xhNuUW|jfzxꤧ+_tƥ6KuUϦ,Yʫe\zUddddŷ@?IdR!pũX)Roѱʢ#W]Q8/]U\PNj[h.Gs^zc|'F쑬׹pq)׹n`ßn%6jۛӕ=x¼m+>L:wZ#ĨiTfk}n7[unk??Ԋz{˙VvB[#X !6edz[oZ)v0]mP x]Wu6uٖmyĎ8 !eJ)-o_ߖR?(-)CBI0epNq<ɒmɲ5Wҽ{~NFK#u9>?_-G>%OЬT,p1+<[rDB\Ue# n Bxf;/z}=R&mPz9u̅,z%N_ 3&e3m =;[q;rE@PG`]%s]}R/| tNFdɧ&DD|]|q̇msGIҒuƽbU|y2'(2+O%m_]/V>~~G#uE{]8~m^twu\گ..r2?]KVҏ s}kTA}_Pۛq_j{3 3)Ad" >귨S#!hد|_ky}_h۹Z+"PϮmZDR6F eg-n?:@E@X,Ѕ%zu؊"(9F Y}[@0rK&` M|xnk;Kj(FG9jdFǑ h]Wse81N 0cqpn*:W)< nb{?T)TaI#+|IàWE@PE@Xl(]lgTǣ("("" z!,J"^<@MKWLb8qڤMsce \q&ڇXb暰(66sAY¬ ސy2~o &1^-Z~j>DmYqa|s|a eϑ6Ew~wqEcXBQ./F8/)辂N;+|%OR )nݳ}LmV'BO3,s}!\,_pR2hOҵ8y8jdˋ]NψGwquzpD?sβ >5)!cX"OD@hFLgsDK eB ͖8lxnTz>?G!1l8A@s )LMX-z%r pBq9,Op {r>@xq |[r.>I}s{0Oyꦺ(fX"0,NO#1H( }|ݢ#[͖"36 n&WHlo' 2FL&Db]S$K;ü`\#]F[UfF|MC$O\Em\s<ī@ ,ɵDsXJq`2"hLر%>H?vJfǂ\| 0Ùe)%#B^EKQhߎ[l^pN# |_e 6- fk! jhm;-4d_+_^dWP'.v(pv ܫ89ճyi'|G\~ pg*CW1 q߼ }iǰ+/L8y`;D=K~{#}nMtn B 3)̶2yѕ?X]A t]9>m7pЅٞ]ȇQAp@h&i. #Gd6Q&/ǢW=$>|:}4~M9[fR5ml*|7B?N_sd Dr}\}3!`IF>Q1=OH@la\V$=?vr&UtXsE@P#D7@=8@.@p$2pl*CR28 &ȏVig A7 /b&2 DKHh;֦-h/egJ Kd0Lz4U$i,c~4'$!XNT%T/h"Md-~6lʏ ` -_t$̴#e68lZ-zƓd`q™``ft#LB _/q,cƱ&E@P"ȭy  k S23P,JȤ! bWyC{BP䀠aV9=PƫMo Suܟ u! $5,WB`A@,Gj._gؾ+&u m {-. >˦e_m5!I2_^0&~+`` T˃L  e: /"֗K1MeåIvfg ɘ/9YEӌCm\kV[V^Ř!Z[o-?{ZH ߒV\cl0lrcp7W_l<{N>C \7[]9+YRhcL1 uh DG+"V$FR<=AS%!R?@n1s [d)Z3҂З=Ϊbfm0)CDɷ6>ق 21af 1S eBYЌ3>t-!1"{™Ժ_i:_D8vc/2-$?ZO/Bpqt gvK?|Wz{L|l; ;g8BlX-_dM"(E@nnW灀 !tQ.3 k % [dfIuzIÌTC!*:~ L]ShU7840 a*m c(fH#^"8n͘]fKLkL})SvyP̴"Bf1ˀse$kAAxGs*0?rnڤCPdEC0'?Bx:90FA/03:4jJ/N$7ME@B=`l&Ք1X>+vdA3|cdTI|"(Zj{qL_j҇Ci\X3FB)9Q<2 1Nh=Lh_@̂4avxh#F3 !˥LÃg#m6EԨ)v)L5f4A(̪g *LOp,OK}[}ŶVȮl}}BB;:jGFLI=B:FMQc u%f c&`jaFa?3,){j^;woP1/\nY9QrˮLۅ+<] T)Qc2mOȷp0q8TY&Yʭ h{%O>PYcH{?XK$$W bR`#gG'G?, ~]!O23 3a@R $E1菙ؙ$!Y4V\H3]LX+;2j LwL*KI$-aht!|oH'<H3Y_ꃱcV|ʱ/%⃄`f 6+ Θxm0T 8yGh3'+"p,9pЪ\ BhNb ; d@k*|l!ɪs) m (Cǃ`ؗ6CAg ys8 1:$~D l622fWqX~"GpqGmÎ%z xwIvқ:` A`%LC6?3pƵ`?Ǩ<>//ϋ!(q<]?D技"(׎jWK,4 12; ‹6 T Vhg6!xR%; FR%3 y 4k6x &ʑl>ْ`ђ\!#cvK1{%zf((22|o1԰wbؘ,,^d-XJ8 l?8zwC_`Ŕ%x(؝g[z\ytA2'Be˹lO9/ WxӊKxN~DX}ڵykf0H'ae dy&XK/g<);g:˝\wѳN*l bxBq=!Yl]9|USŃ@ft?3YR#Ɍ/ X23,<=$I$.=QA2ehxBP~$3B"amǒQ-o_Ez0FKqyuپGFm}whO$3pGBm^/mEw?"M .[ &?|g֎6LnN̾9Z.9UʋKc֕yQ'wmv I@+ߵk72y-?\zG2 1WV^O1!~1kC7C$V!49]CScˊD4 I8TkIed\,<܍FŸg8D T :!h@~dlk/#-; egw%ymK&V|O(Zm.Iv}?igG z |Bp,?$}ů~ W!&$۰MC/K.щ^5_Ba Sq,&ru|ϸϡnqtx|pR̸vPf0>mqty:{͸tO2>Y.C`2vvђ,GsJH.ͣH<_7!Q7K$[,%+}XKO +dE?^)\s.0 Y g}Q,^H,dZǏ.HAp1[D~E@Px[ r칽D(R%B@X0{|_Hz}R3u!SbOr~e;BE3LSlKKqǁ|a..00K~,iC7pqtUXX-~@.? e!0hcm%6 ;hxn;:D"Q52h;ShIrev so;]Yg?8X }lJ)v$Vf-ѯ ||#|OQYPE wdFWfpa3~ʊl  YueBb@V G&DG}җeIڊ?KOS%xr>">9}AJ9rEei"K.ebSl\fOWdi5cm'щǾlï"(@n Ő/F떴I Auf)m%릒h;)}I_?hD+}n, fjz}吅`'V?7F"0u\k.j_2Iv;Xl(Ozhad׿(02ЇGu}F׋tkg86VfNU xn^t6<r巎2ck+MN=>t0C>Nc¢G gDW@]%ZND8\HD9:qVlr_$虨| v|۾,ԖC7d!$֖/s}bg69ȫ b+:}ljE@PG?#v3! 肚Z"$EvO&Q]}D~r<[.QC|&Ǣ؍P>3c 2)uK䨓>~;E@PbD@,OT/~~6:|)>H>ITE;痡\>[r?t$ c9-i#7Ee2]ciR5 8ƒ ]NUIF=Ѓ/3;f7 GwcM j%:0C|D*ưʵ3y\#=X3~B -`K%hg>钲ſ(~}h#RMW~-ԋlϤ,Sf+d,hKrsg[ϸES+@NB>26jljg I)-6G\2NR7Qyw@r}[>GWE`1"])AgM|""%ve~dѾR[~؎vd^Hw}_LeE|2p߅!Wr ?}_Ys1JƗNpggj7I Y14ޏ_˗Z"ax?| T [u6^ZGmZ9|䯞d(F!h1B߇:e.p}+W5LLNc(o;V6}bӷR?[gk%[*+_RO-YU|0k*"0:z>[,('Dw|W5XH5s|V=Oecz_>϶\JA_7ײ*' K|ׅ|Msk\֏foEj97K)&ޙɚ,r!kezNyg-s* 'D /8U"dEmo!_c6;(lǾ]t^/|"~x,ep2\;]2 Ex}=*k w^;g![D= Ano ?ڹCΏx![Jɤ$,;nxN>g*,x/%df}yPs@^ " ޗ:2_թE@Pr..,//jn""#G}CtCfAF -oo)zYmҦ9lIJ?9nDqhc_\p~6EV/_ {;Ɵ ΁`.uA|}#epP$5H[x?_9\Z&uA\P*9!Qb+T/O|mBDLXȋ!f~;;\lRxz~t; ^K,Y~;ߖ_.cEY¬2怱>'AH1?*"A'oepnx~`6UB/eeڷ׃LX]sr(ht&EnN/F0*|Y Aa2- K(_]hӉE Irja^/xs.^D/xk['oosAWO( ܓlHu:E\e"K#ȊRR'POy i->YA,an YD-h/ڷ>LQl1v?l ?b /1}r(z'1^Ȃ=`H2F9E$ D06_,z ͖`'1m7nێv技"(A 'DWfp1+: B*$Cr!XrA EVȗ>_I=AD@L>P/~ϝMDy{rM[`R=̲]D/r`Qj &Mit8'sɩʖ [H~:.dÖV`&X=@34E@Pr % 1'$Fȇ A^L !Gh 9۬hX9OJKp&}as4j2O{qr2`FC C@,'B``뗉])CE0YbE 6pN"ְ.=FTʱQc4_`{(sI|C8dvͶ_"q U9 "ĂTғ!QymWΰMގ^îM:1eus&'ox;C#wAuq0_{i{w9C0Ks# (JrK::Y"pդ%B: $˒MK:{Cb#0^pVe b ;B'Uޗq,~ B?dt@ W UH(m'ÒM XP`>swh~`BrQ/-r_&ض<0 9jDɌ:&R<8rp<?"~@64d$qvVeR?B.; [b5)"9!2Bb|%<caR5p'A:Q+D-]-  &rD`> CS7U!ٜi<`OvxOC)I/ȑʃ^`_^/lOAa |W~?`cÀb9EIr>jNцXZSBmsd9rQ'/SYPE`IJ.>p_4p!$9 $GI\ŒKZÙU $!4'[.Rr}Â%@rS,*l%+LFSZb&3fΩB'B?'qL.Dy:5\՘[LaC`Ƴ%0 {ruD IDAT>r)}ve.yT_58& fB2D>ORfsd3H]e1S:H %+HhpNcX-u+5\?/Xj}_2)6ޒV߿7s4SG"_rjP9mh5h6z߹މ) @BanK&p;=^G&͝]ks~ߦ-)GņG]9r\_OzW_@ KR9pf7> fVc䂠N5 HGd z@1c0 =l Bh$3Y. ま = .(J.5]Bқ- 8P :,${$;`f:H)o1AXb&=j2.4 ~"Bo0OG1o0l@zg{]Z`FdLv b $A4DXPE` @D1+a4oQ!D K8i RɳoCXHd1ʖ6RD ,0%ۂy—E 1SdHt*ؖ&@A"1 "W3a6%a挩& `׆|'ݨme/YUImŦ O 8I,)3$d8<#-{6Sj2[)0!R^?2>%6ώhIPE ,tVfa/',ڋYH1D@? b;"u415 &^\v OHbr%xV*]@4e\f%GHk7]~x($C=bYAΦ"/c,cL 12XGf[3&͍ږ;?g~f{R_hn4/Iݖbw4X,JVTpb>Y+2??X$,0ݳ<(6ڿ)sp}Y]Ʌ=6EɌ!_eԮ?`;p}?Ɲ^kO۝Uz.T%Hv4T3'o56wlY]@x}rNɘPzJZφN$%u=˜ZG-] Qr+D X !B%,a ~ÀGU !HM-D _Bd{d̦<8"hPlHAl'KNP1"Hl" ]GB{,jcw̥%V^8 v@S8s{kC}-Ly Iٸ^~Ȱ8b?0v$! ~xζtءOL %o# ; vc;dmn8d곡 $p㇀:uaG"\"OAa/喗v2~5@x bDFMuq:ibJcA%2cb3"NkN89Bw?wE(;!>Zߵ㻿ە;6YO>߬+n}自\c%J%RH.-%H*EN/a Y68?}H; c^)\[l䒬H} ˱bK΃`?0vR0T}{d%uB+ #{ 8\# 6Oh+"%_B^$L-B. $HVN@;(1HC,.fKCBg #c}Ž'/r,z_Fh4e#z~ۍ! AvCwԦN%>ƌcl[l_#HI>}WE@;<"!40 YT.A_,!x($Κ ׋~S%ܾ#O(Nm,D͂`TXAl9tB^6L5[*6Џ?MT,{{kRM3 !{Q-w'X:>/#N-[=wvk+H1|C+֕rw(,:n >~ε--=7#. ogXHV2;U*,r[mTr3ѠX3Q+!S/OJ= ir$2HKBĤoC\hVe(<bGeT<,v턴æF߳~X27jCE@Prܟ`" R4K[XOEF~ߨ?ѺE?rVyng+A?$@z9\F\sE@P#(sHr!(GNt }^Dh7ZR&vR6\|HoKln6gFǒ:ޗl/-[h+o;=yxW59yKڜ(wۊONWw훸ujcA^To>P:|n h̘p9K{Aƃ%=p۟b3_dѯg=y\#=X(]ԧW7 V'DFEPDs_d~WHb_Dmf">OdžM_=2vKYꐋ?]Rw!8wg6v"Cӷ: =yCC{sh剴φd%zOF|O6})}:LrR?<2э÷%vĦ=r_i("_,Qn>kZė.vtK3z,盋^7霬.[ٔM-v`S _w?Y0g"O>t2@+MhӑB)6vɏ;pg Ec Q+O9WG+]y<ЊSkh h)5V# ӞnbHC41e|cں*1±V$=g6EeNPhw@3g͍Sft.Ѓ%RNsA|}kD>sPOPYPYrDwq]::"~@>0dwR͊"(!B&BE@";_ĹNɘc[ Crپ;ܱb+vt2ܑꌫy+ 4?zMsl/eUͮMcoI8~ؠ7ØQeʶ&=EkB]@8)yt>M:_ō+sqUG("("PNUPE@P.,cUE@2s+9Xwfk'|Q wD@aS/8t~?ɤˆ7s6peܖc ܥᗉNgi} XmkWPڎ<ߕ ʱ!q' 88pҫdPZÝ2#E}ǩN+ƿpuU c C"nԵ9a|-t_ 46w#gwo@bpx50BtFW/E@PE@PE-E@P@kOr+YZΏ,|~9g @xD-pM pFו;yͺ3o *6&YaTX?Cx9p@(/2Xw߻N(/fA8 M89wS]V.,Uk/q=/x嵜>FG)Vwa^,ɿi8ʹ3"("XL~#\#f %nk/e@$땫HJfm9^/]7ܱaO/ZGIK{v5mW\LR+\wi+o*'5e'kޏ/4Nx?@N tXC*"(",%tFw)m"(,(dpR*wXH3i̜zziqzj\8Onsmz}cYWuʿtj߲m>©b|/p~BemLpl=X g՘޻QҽF @2~M8z'7q3_5( uPkI~y7PW# S{Mr׾2)6y p|g8qGN1Jo^hۻǵ,6W;y"왨\ѹ֬E@P楃ԩ ɔ!*v x?uGI3iI۟<^{a |Ċr׆oqbdɍ*i5=i3^4^&'zW~{$bƬtC#椓Ko;+-p ˙ = Ix5t!g[ +"("'5VHwW#E@XDD?syh^Azs՟カ1E +~gz2\a5ǜξN.nY+ zX ~$=RΈ!.& d1>7Xs_XU䯤9q)'789rBӵQ! QX9|s; /},gKqa9bneXBgLa/I/sm xG*W;8Zҳ`J7wrj vtN䁰䈮<E` !̹:M 2sM?uvj׾}MN6^Bw[4[a5җ;>G|I|q eܶ+0W1 /s} GM wm\]!=5~XFWd?$Q~\AԪOE88"("(E`.S#WE`r]]F \ҏs˸V{S޳w!˷]QV.~xK\K7 Q eE|/\4xIsi9(BNL7$g2뒇8] 蠼c3q3ÜnCvEżNzyz/6=׿:/1$+g9[Od9t;=[N7LI2(̓JtD"(W@TU`RA[ />^e+x/[ןQ8qGN2=yűMt?*$LE̐ .j0'vN̫QE@PE@PE`~U*"p!/ˌL;W!k?Q. hC7R0hop}ntp|kE3O_=7r]uc r~\Tmzʵ/~>^M^lmow78WrL8fshg+=zkx ŷx+]5|{JS[ha2gp}_CNɱUNXd5!)d_/(?cOlwË⾛?cKy_ DUN~5("("0_(ѝ/dU"("(@N|wNP㊀"(3Aߏ߫wKp2O^5\_RL CUN$& ~~4n{sۜ|s9`AQs9 q6`  (F>nsk.|5 D9wsHFg<-T0{^jf]aaTd8 $P#`?nY' 12ӶrlЅqIcRO] ?by,m5\QtceX<y␺("09 Qr'צ",^Hud",*|QE`9T)< IDAT" nvͮ 9'Y5\&lxڵU;9[6rtЅ{2tswUrsR.DkĪ_|QQwԵy4K{K{[].nf'7OV01OO.'tlc7e빳ebH7^.KҧUO uf {w5AGeΚp+xkitzI^k[yO=q~xG#r2*w\>x> BΆ+|"̕N|/ϸB[(#^"p"Dt#EuLVmNJ",v8ϿGSE@PE@XR,%uvu"$wc8˯a^[m>u[dlIcMg%|;\]n;~VDUSocq|܎4cqr}=˜?BnMQW^^鈫{1Wq1ݮX 1D=qw519һzz2^;??|;]yO vҧn6?렬5n^P>pcZ}=}=[q{MλOҏ^{;Q1>8a/ uN䁠3ypE@PE@PG@cE@PE@PΑ3"(@(nG$y]]smkwpm{]’'pכA\[N6{ _侎NQ3N>3e>PX%\=q;}U8nvz.~ۈ{ykQxYD5Ļ?:E*+yTVVobgJ):A[w C 뜮^Ӽ_ݵKm34 RKy A+y _[pGxMngB 9Gq쟋d% !ymw+{OPWzdk f[Ou]#ouG!,q|6Y|uՏ_M]M*WsWOP34&Ws+-і;'Y|Pˊ"("(#sZ*"#Mjx'E`q",.jGPVe48>-w zQ.qu^e\}\fEp$omp} bܥ!YΧh}47Ժw3m+o:_w kWrSBi#p绶{5[SlO6E5 Wҕ?{ 6tu)^= c>PyŮ>*|l#w Ef@w#j^ Kۣ:'=n}x+]G{Li-p"|,$ЅICE@PE@PŁ9_8/SPE@PE@ [OT>0"(Ke xA.wӮ͟qir*>Q~#Q{˵PRW]6ӏnR5 -JU\J7:~e',λGf!3eܺQ.QWN<2ee~~Ֆ-siE1)RaFThvV#N~kCOEt2%^r(97sv-N/4^;lyp_wma/rm 2l/4)F:K]TuF"}A\|knPV.'C bKD$LN6RE@PE@XgY ʊ"pLYsz"({YdT {S("E`슶χ:.V%{\l;vMT\[Ѐxr&i]jM_}Qx|%'ZR_k:9ܢ\r~PEmO\Ζ˝+i냙\9a]_cA9.P!(p Sֹr~^,{ P_(v5{ { w>~lrO}6'<˝đk._ c{.q<~Y庯I,c.%h}fk7imΏG˵O{՟3!-S;[5.}z,v'9=ݺ '?^ㅀAe?)c] N@!q(w(i/:t cx/xu-GzHZKuz3#|`>xKg~;9ճoYa 04)׮|A0W3띯8c|Nޓ#İu+g?ܚؙdukE@PE@PňOIPE@PE`ftը("uK=(Wr$ƥU) ibX-O;=U > -My7 U j9.w.!{Z~ CnOrz]|9ŷ{Wb\]m}٘U>".jp 3A +z󵍼&wMWrGqif^qd5Nמxv7~*wl0~< Cx #);`BmU]G>t?pG[? @iK#CPE`^g! WU"~,$ Jtm(@ 6N,!9 I|. M(dw5Z%wBE?<.r?qa^н\z} +S;yq.W\eC\KWp4,j YB.6\N[[Wt>qGR+]y&3uyqm[(?rt1s3C\?|jS^R+_m W㹼 +Vt:UPV'?W=NjdRz\{:aˮ`HãkCV9^pU)gqxNi>QE@PE@PB`ιҪzE@PE`(0;glAQNOWiՆ\"Dw.T]"\| .=&KDu i_R{Mn'X+Rw|a1amɗvwqW5۹d|j s]>b.M&\F_>X1?eUs Or5V "]O;GU拇𦋹?4JG'ˆʆ|Kq'|˜\;y$biCV;n"9`yM53>ta W9u5Cn6=9aGw?{cx~bGqCɛndhNpW g 0QE@PE@PB@\!9 =Yj("(D_Y[ZDXhF;6E ;90?m[VqeKG B% m띝V4jf[.צ;/  rt!GS㑋,r|f|4'i[u+h9!e<|Ϝ\OWE`!BfkQ;[BvFqŏ\PE@#Nkm3!"/gK?Yۨ\Lt=}#v'h#}5? zWHzW9,q #O}ʵ9˪l'RǴ=+]ͰV/鿵~r w>{s=rˏdI.KC[{a`k&gC!za]:'rra @!a5ԯ;%ҿ˗9={2NMu 8}q^/Ly!.,1

:OPF{:?tӕSP!0to.`/__/hh~_F*+r]z*qeG!9qG߰ݙ",NrD<%Vx2 eM|zG"p! 1 8{ (4}tc-E`Ϟ8&9OV[L,_Β Y_게cV&F¶2\#O_ɮqڤMIU qsɄ!@ H_!P˷}|ZM\3mN@KOֻ7w,s5p %aD2$Cq4sY.!sE0޻SDk_omivrw@$E&ͥo%B. Cyzg9yx˃xeO̸l;/][ݱ| z2Ç7;yx穦+?{a$g`)*sW3\/ p]yPgyT~w7mUlr:!xz꼰OvӧTÒqU+iY0G75~~4(t5q`9vB0/SrE?|YGgvll6_Lr,8@' )|r\r}\{=B ͖Fɱ:z{/'n4fOHha\e1.0[$/uE@.'ieyۦ۔H-RQpBysڐ };aC7k ^.C~ˬoPA>]>:y!mfdmS'+~7ncE3n]m8 b\/riyo1ҮoKc(2nUK1>iLr8_#~,=VPa&3;?jW;y<߻hP+Q\8Ʌ%Fbn+.. v~|yroǎӮ|y wH{/9A]~F`Mr9վA پɵ)~y]{2^{\W9e6 SV! .ʆLKx [EL|_"#GvH+C@&Ir' ?c\mɂP:X$?q }|{:i"(D@,λҶ_JHk,556x}AE nyHv-YՅrD<(9B J6 ׮]@Bu0c[Dp 0Vfzq_ɬ0f,TE@P0S._BpKT E%fjE/λ/vV3/mR=!M\!\f.3`SsE C O3g"!'*wLzƄ ޔy: saAoY]i%\-no/Lܥ`oW9'޵mLw3ގC%\E?C\&˯v0CIqy#oTMqmWFW~gƻr Ð 6 Ӓd8E 0E]G8~ Fl=)dFxMt48}O< v]ߵ9~Ȍw)D۟/^tkOnoׄGSvƵCPXV&63Qk_xOeB&/0Bo yd{(4_Qsw@]\./r!(×9Ō\,˳%[fV3|wo3YXŌ$OC$! K@ COxLfg%di8cJ'LoSU}Cx_"~ #!>/zO "(" 䈮C\e>~D,, ft|YOFr,"Fdz`O=[f2?E 9 IDAT'?+R!M?Wެ> cv`FXv]^۷~\Y#yP",Esy1/OMЉ:[;Cl6DAj2Ly-Z"%n⩫B‹/vd$߆ +O~ʊ@.Կv `3fo[c=-;w}_~ݭnB$ ,[,c` 6a`y`@c˘h"0È$!hV}ƺ]gUu+Ng9uWv~:&sN$?t'yJѿ9J" " !8;*VtK'2-q!Çs[G81>k6FS*k2ՁuH=yuvW{~qn9׋X_ߓƇM߂;I:/}!6n8<wNdg_:Ꮷ=?r6=?fr?]:2gYʟm:W?`gK_fg=l~ f/?My ^(;fpa1˅ߋ߽ܭ;[wٰN8c{xQ\i }ojXֱL3HB\p-Inf[i /Ƈ71un?:1u=̝KD~cy h~? \/惉~Qw?j2IN'zyD@D I$tc΂Z WZk:iͧtظ|s7@/7s M, ާCh ,c=yQCsʼѮӭ!BI^8Q07*" 3 ׅCYt~ V(M>-TB;isUp7R冯X+ 'f~7?h |Bָ(z>9.rܶe=UNAC;CuNס_p_ `B'.{#|5zpyCԆ1Je;quZp.L@Aːc} /;KtYpy][p. ,zYf?֗@G7ΕӲe6>?']Ӓlmu>}}Ln{{uKsbR摀ϲ})Vݏ: X q0e\\w}7_[wN!K‡.Ani)" "o!Zчkp,\x Z s;/)6\=r "OݽV;kR8_uZ[I(rqZ.n5c-AIoFC_FNX _ڣn;| _-o׎?so'j ߾pTιτu7ӞW JX+ [=w:VnvVg¶#Cs+a BNO_4(|Fx?W}#5b~zx{Wkϥ:={qp%t) b3og=[+L*.ܥaNZ%8BKwþ>r\N9Bgg{(lt_k{OLJ6|83zrmaGaӝ`uu _8d,w{_RݸZ%" C8qKo KP}x>6=)vlj`29aY<$NܽӝF4 8x'nW_s![׾(xlQ2Evs.IU'UQ)]=[ G}?|Cƍ{\Q $+G ݿ] 5Y1<qC\ A>f{pBgO#NzAxo/t8F>X=_|FB)pα6ö?{qtFEQ '1)ͅN9L Ioj{Wn0~w[cMчsmw-]n"|}к8B?N):'>̕D@຿-f" " "0.Ytc{t,/]?1"i/R@1= o`xg?MWthdW7+urFNݰkܕp>i0ZD16L/ ]>-kګ?Z,| jRgixFl\N!JxO$pC7;pSy V'tEynxջaVxv֣]#;aY~&Ρ_;녭.ao( ߾\:mm[R{4T*U%" &l':/" S 8;BD@D@J΍]Ш>ܹ#(;wopRnN`۵{A+" "|omNM3|ٳS̜7ģOp n~Z~^yήY37|ݐϾNXgn.wUΦϟc,NNߞsǓCB7*ED@/njp{)xC ȢК$@c?|mZ_{6÷Xs72C>lO/:/~t_:W.#_6o N>NY]ٰs&W'~4ǫph7p{2= Gh6{0 }]6[r/  Bw+~'O˛^ ]X^w.sJy. {:圽uC^ӡ3<5=WOdNdqTvOy/W+$*! O`anm4sQ%La7PееoȰgq%N^Yllgפ9{i|6A\>gJ@\@xpg<Ww:b~(ˆtT ,P7cR" >ng\m>FssgQ8E˫}rӨE{rF1B笸~='&o !:0^ vqY{>7e nOȍщ" "0as/tQ"\Au;WD@D@D@D@ (N_#rh[D@D@D@D` ,u9(}K/{" " " " K`nTFg" " " " 'X8'uLE@D@D@D@M@B7_%Ю ^൤o]I;Wڿx6߾ TR9 ì_$uߏ"KjײKoN1vQHpik?H'}^z~OI3g= <{#sMj엟p]^4&e}E|Ra=߈EkIPw뚄j"}"IX::qʒk_F9cn~kٝ@~7 ?ئpKJuQD`{#;QH"IY`&UF.գeH"fٸ/[«5 d]oVD@D@D@C@B71ZlV/g.l'y$t|" "0  -Iy&KRݘsr! ,h|t+I?c%ǓY@ ZtO A[R,`UBwH"" "  2 *SB! @ 8A;qaTG@B7>*ID@@n}[ SfYsLHT̒] n@N嬛 pɏpߤ:oʤyd'],z Lrfzl٫c1m&kdžK@ "]-UD@b"?yQ:N I:L;ˡExR[~]κ4Hu]7C|^󗃟_NW|%N$wMޥJf#" "4%wn78N ;A%swpѾphʘlKUwc}Н$]-" sJ({NF\\FgrǢʏ揖 ^×6pm}F'3dگ{8ә" "t&@]uۣ.Y3ZߠAꎖ=HyqF;oL/=˺g汯*[D@昀u' NMnR;8K[g?4+hE.S_3>N!Id~O*~9F :A1iS4Ϩ,pە{\~Yn4Ӡ:D@D@@\ hg]nIAs?o?ʉ3eze~{bk墤ӼGBw^%" ؊ IDAT Hइ]by|NRLl~=QGsr0QAa_^\WDbn\1~sWw K 㮃-tz΢ʹ);mOD@D9" eO\~ߚ]YȨwNlv3Z'Z~T>uwvmb"[ϕ}oߎcgq^z6/'%gdK >eYK]pZ)?&[tms;=c-,cҕm\[yq_^h=ues][w~gwNtǮhY~>e܎}ː\_x&_]m m mk|)?,O :>M|ec肈p)Oq a( K9~{;kӸ ^c׻wπuy4_[j81;<_vɵ_;HnygqV<죛^^he"JNG1*qy+[?7^vڿaICKyE@D`&=*8N{qMi/㮵[;Qޫ ڞM * dEich|gEqq|yQP9" "# R;W^_qn='=hyY$[js\MqعEXJ.URE@ 3hgtDvQǕ,6|qN6ӿy̫ xU&Dpn^at+ם=G}Q2ӭ?VXF=/Z$mlfÖ S GGD@D`C-t3ZVp|~:qs틣ie7LtS+c˸7{vE9{#;;]ebb:>:'jp#>d+=(i]<1IuP+D@L`ԇ/CzԲ&]w˯>0>rُ8Y.vbw< y"1?J"`cZͬi4Y/F-[^*]3\&7ܑY hM*4[٬9ϛ{ yglrZr`ԅ9K4_=OP;nI.C`Fu\ZϛEuu?JGխYuK:Z.5 [ZmAlM ۨ | $LΘ4˺i6!h7!d2xF[Jgн+5Q覲&4QhRiӨ'[G Q-M@H`4a/{ AZ9Ok2Q,kFs8-,1\M \Zs)rUӄȭL4LV2&^pO-+rH E \Μ3(S0V0YW[[(xTDYmQյ! je"egSDhǐX,]-4ZqimA]ș\ȭ66LdvcH5L>5YXrM<,t ,_Nv\JϰḙO.4aV[iV񵃀݅E@H_ΰׂ %0Omփav+#I<=!ۏ-4g͵\'r"E+Lee&'r[=h)rJC `ü` N.A 7qQbۖGW%y띆ƴh1nO ݩVE&jإЅ. Yw.UAm)hۂm'A֊Y ta[?LiZ.3YS8go +SziSmflq۬$"p2gM./ܒs[="0}ggDex8B6ԏV6kA]70GM[Ǘfy+r3rLVʷMYA$|* Nl e"##J!"'dY?-+EH'I";Ow21TƏkm .>bQrͅPfMSҞRXsn]iD]8α!Z굅7ۅmR VJ&_ɤ1XJrs{k߯蘵86ȕ:_ 5X.2Lt |WöwY*Yӟ6Cؤm@3 ]Z[D[x0ް¶sJ5&cv`\,r)TqYuI8Yi'Wbc4b~\1OUNj @hÊݸ1PMZ )iK' 2ɢ? ?0¾Fl=FZf+5UXt91U]؎jem=m*+usZ͔$ 1Nl~6XK.](-ﲛ0/nӨ#6<HI|G'QׄuBJzFKc tJ}bߕ1>0ZO(M"wkY[fr,Rd!i%839Qث+ K)>-^ZoU7b\fke+B\h? f=#N} ӦT݁Etaj[ȻSs/9-ub9o" E`P0h墣ވ@o$G0Bഩ2rܟv.X@Gpe` jA%Z0s=n`b9[Zy. S6YG!Wrg(rsl)-!r!s+-;oneK'{a>c`@/f!sB2u V)tύ5Xz!oVvB~Rۢ.γ7hص韥%@ 8k^N/iId.=4O 'y.$I-;) X}MN E{ta*1&3(̮aT]7ƺ)°5;| qRX.aJ]֨1~mɤJ_VhYAvD1kix!(q>d@'7 +um.brȄe5}uk\FK]+or!tk!ro" -1IE8#}2r'viufp --Ճpi/:&"0ESUY +f f =6s@PBz~sxyll>r!padxg_nE*%DSo;'$UxeE.Eo+nJXΈh9nBrZ<xb.V/.A5AہeŚV"Ìp0׫5LbT˙mFZO{>B" &1],1'H&R( `Vz6`, nv SnҿҦ[Ǭb-XiS*[zMdU:u`Uྀ%ScƤH}btF~ZMUjQ;z PU!a {Os<t}aј(a -Ë㌪PF_rj>xphna`\6l1ֶ3hv|2\ͮI'Un?\ J F9[0%i>m̵VVpa0 bVqϬilg6X 7!~w`-[qW/Y/"UMRƯg,\>-} 'wq\CF6,jBl3AaPa6 )zS"xWX`/홫V `nv0Nc'Tu,âK+Y+9-AA*΢Ey(vF#ukc 7Be,5?#! 'lφ*l\<&&+|ȿÈ)G\м㗾l%M c@vuL~w|KfyD,mZr)th 1]rVq\L= N@ଔs Hq__l1ل57(va*F"V`\|ꊹ1Vy{ ScdS鎰vO>+ten7vʬoKVW9w0G)k3ȄV280,-^\<8~uh4:?Ndz"7(;th IbD\. Ms 4Xiu`յ` ]ZdQ_pw vpIЊ0O1㆖q&cYM tuQ', ]cbcim" Vr _+Do[;,/`y/$x.*CD@D`2$tGo24f!,!ziKہz؃EV ʏ f[[is~_mj w$MVz2DXp;(oG[ǘ*e2{TE"yrp\J$\4jo½a4.xPuGP`M-ѯ:W'c_C5P-LN^̚fmC"fC :*6$Z ךMSt5I2YiBob8/tHc[c@ 7?;p;6!`aQGa95jZ)im^rk :pynf%\7- BV(m$tgfogqX)h+Cr,Z{ۯ),] *Oj`g*F5~߽GhѐPjIqimg!4fsf'Lx" +%iU<ݴBy7O#Km=+}2ERV.=A ջad 2phTKVfSpo CDq4Yf~q7fFzpBmȭ{wӀ{AaP"uŔMKuOuk֥!Nroy-V> H D-c eف|x  cxz&,-%6_;Gy0a BKNMS@$'tM XG>Z 1gUi 3gk!iݬc !DW&l\1՜`6αJg \@ki.bVJZ pSX n "@93[~Zq9V[DČ0V \XD?kuXÅŏ5ZU5uTB!} l~d6v6QxƑ>?ש%ÏhUnXh-̗8q@@]h }w~hfb˘ַ$Ϣ^lu\H{3KIIAXu  xs*ƀ+ J\u?ٵϻAn M)@L)Q ǔ1EFavB (&,ٌPd,DU(fi8UL˼s̑9(fb$;C+fR6(bє…ئﭭ?Lq?>lx3 |s6]#E% wM0F.VXEi-( tS+usv6 S( 2Y '{|H[wfC -g \@ږ^XS+kGBwo@Z7]d{k|'%vG@3:IvFU${3 +; o~! <4,wAlG!-`U!tsE۠o'13s^``En@3[~?.HnW!xDRY1mh,H{ WNKqv6ѯ,|Zp0W֬>R¢.4Eݚ{Ɔ\EYJ9@+ `tXde fg6kB_2Bnp,;0kv<]ו%0\}y02Yx)!|RA0rkV6ǪDT/ˬP@ j@(&r:bf  !Q͢B;/ŸVrk!D| ϡu?(r\oZ#4MD x׉ֳJBpO!g0>S F2kFS@PسY DfJ5u([V3 %E;m VX.@d-[Z)P6 Xk0BrjE(,H@q`Xply?C8\^ _b–F&'rU~L,qoÄVy&^GFŠeZRuڤ@izBVm •FoxpWaF}5s@K8 )g VP~‹QXiAe&uc`YXq xD()pa k{Cպ7' kqܷ>nA3/C1ZSE@D@D ^l]8ᓩo]P%TbAځN8Wa} ;soo1ڸe|wiVA{d#^?Rk'KpQ$ lk0y}Rѥ80N[O\Xjje.!Bz*^KP[u|9L-EBZ уajpZ˙JpS4. #&Pҝ"xB&] IDATPف;9|>aEԖ#B. ; s$=JN& 9l :wE"׾@%uR&7PGF8Uu17XL$w/ٿA "s}"-P  ND֏6ΓJ% ý;_ غ!AѰ\U[Ph7A!:9̊B"VM|~:w~\,{tڮABB֞lqM8_Sd!40(Z4"JLALN8rgxs!(j3zta8W+{gm\R{ Op=9hpRTC^An j 󜄢)Ϣw ͳA/'jtݠ]:bNb) 9'KRb\BVkNWL Ɖ mKo۽E7#uWJmt{u#( eOB)`urZxT*g:|fͽ+/XK.7rH 0}J޼Tj (xu:mJJO9h;_!Pm$ \aD8bS2}Y1J\ETȭW!v^ r) BpH_6%5)aw |&nBַmkE"V0Rt"T:|ưhV!E׍"; %e}aªGk{]ɺ<{G}[Ok 5w,𭢕 W `akSӚMg1^{uVu$LlzNqO[`/aU-bQ8'U%HȒeŢp0VTࢸⴸLY䣅]6vo_a}D/Vq)N^s~TnAPALM*_8IK3w>^#, Pf֍ӏhPZAvBNZ 6k[|ZTJN .2y+7Ler)pauOh'tE1k6Nh2ݨmBu,Ê=ttWؿ1òAXlaB[33Zk)f[7c?(T鷛|YXzY;]23Yktev;GXn tX bc5bV]Zy0}G7ұZ8u |lNq:ti`$ 8Kn{u -FFΈ L oUu0DMCDKX ). ] _͘Wnm<|9,M*RȑJVR|Q 2峁app^VFeW9)hiN\ls01 f!8,ww=uZ1[V_&;E*udCG_R]UF#oa"NPRQ۩ã~#pqx%gԊ4L[-rdN=fjV * ) 9w3Dk9{/VFZt!e-Qћk޼s&,xsB ]ZҜˉwVE@D@D`$tOK,0JFe0_*a@,Q s,/u9AEErZUwl E}8/ 汵*3WP('阜-E =F؉ ro)vϮz6Na>E->uX/@U~>}^SvVBqU`⵲0X .Z32E}U9ż[PPec^Okdj;C,p DV V[s(Myi[K. u. /fm7p]vo >~&PE@&B@Bw@tV2)S€"'L9sh-]ƼBowy]2 ̐Va%.n4׋\DTdb_fbX?y"ͅ0@ m6 w 59X| Sb# [++ՔvuW@r[ 9+hkK'ۗfCh;z0B3듌pkm9s$7ؿ?J P M[5 W`= s[iS3_C R+Cjm#Lb~LdZs3B;NZh\]V]Z l?nxԽ/oe0N[z/pAiI~@$tyg4-kťeJtpW=:|>m f+X?2&"9P1t8bؾ~9`Fz\T, DQsQ7 ~8&6bʘ,ˆt2(Wyxb{.³I"(nwYXL4Sr;Žf G2B^55nWq  h^ a1LT%a"Spǀ-mE~Z; qpܢ5ӃVǗ Mpet`E)r!T[zqΧwopteP8Rg9듐ih]D@F# ; 7^bbSX Cj+ZǞH_,|m9i  If ⌮ =e0խSOM&Axq,5^Q; ߻sz]|wQj3.i~ \U\ݵ}/ *qxZKW0C3<[J+9gKC"4.-"Khx%k{HpwC`ݥ/nH`c2-9ǭ^@)yLOko1:&%ZpW喝RloJS15L^a 0ݥչy5":jZo1O7 AV(m,\{>K0%4fVp?`N @Z[Cwo`nk+r[BQ[K7 ;/X 8\{\t ^U.!LCh ?UZ#hх'E1P ޾ƫz \6#]APG&쿃W~g ⮎i~)2qqǔVpA[J߆ׂ qAC[ۇ nvj_ ..Y,ݶa6ziB$?λMhvE k'Uk,V] m\ k [ziYf ^kc8Q_jͺ%4 fG[؀N홇R+>!ܮ߶+;/pUA;xm2~w$/ L>Ri5 CF7L"ި 6a[ nsVzZxi> :ѽ]HiH.RkE` o,Įwί4/#=c$LBr=kلp#˛Cw0@bR ܧ*郌ï!Z5|VZ_9#o9!󏙿 ޻3hh4xpa jBLdeU铛/1Co|7н/g ƺheĩwo`u$bcb^ڂ*sL.n4XUZ˙(Ǫ}@WZať,Or<\Z1]mN[ HMay7s5]"mq R NZVWcp]uUU. E_Tw1w{NgYCgk S#"ZS15!cjbp݇e ڕ)r nd!}lϷ 5کmc܁ĬTbօaVsʘgrU;ڤɰ`b8nC Kg`v?e[\L T+!J~. 唆 U9ֽ^'zˬwκC B61Yaȝ=5aoKp\å"W1?Xq ZiumM)g2h:8"2103V77zپ1;PlۄyfȨte a0;cFA}s\wr w׺4V0H?@4-`JŸ_D jݕ2@_}t?ÛLPoo<-bK-2J}U*@αb0WՕف7{1﵃P U׷7u.]3/j3Z7`]0 h5+r! _.,\lk5| k+(q\v[ES_80+h!V :Oyrmwb"oh@\2@0W,Shvgst-#c*`VlqլB!X+g>hN÷n úlۊ2҅8ȥ1y);3Ys0|:b&Z]ޓ:#@1il0IE,|c< .m[aYG䶭,ÊvY8ĘuLzQc4C\0D.DPRrgv_L-̖քBs`͘SHd 5S.c`c-e%C"lb>h/t[`uwZLM]]|JSf \7f{q7+ :au!:-"3 1~ aЊ<\Z59dIGPpwESc>iH53WRaMZfUgZXa c?yoEtmL?NRR[=t`F*kp\@;;!aT!ngPy ]"9k=ʼn.n܈Єma@u >ٲY 457\&D>@;)«2\  xt}ߴ& Nt#]В܀ȥ%n L8J\,02ÊY.\;& @CcFQ ^^PZI&74$L^zu\D`J$tc B*ˬ%a*t~,,vQ=/di"*fb3g0a_3%~yQVϣ@2f.U -|ΩiŦ{BY5HQ#X?wdw(4rC75*FZXJ6\Poz:&m0-s&v+n|z&.cnj~L{zw!ջW hjSA4oST̓:#rimA䒅rhoǀKMۄXz=^JU p]_NH \_@+VM~|ƺ}e';mZpϚK.I;˘-wVHN_Kp a /1!CJ`g 2fg֭%3xw!mzi}wf)Xc଺)`NC6i*~\C8$.e,`/py b4spCTޔ`5 ׆Cx2.1õ~pa?nw>tQ\8\y.pP'l؝]KT, 庞#F>@3W/}G-׬_gE8 (| y^_w P8#XGrW9JwLB}mbZ!|s(=k-[p^lptEz9cg}kAp(LƎqSj]nv(tm ^1(|cIDCX^{r4bjJP70IK_烀5N2'A;6h'" L@Bw^mkJm=b5Stضw":C\*{|ndXdT++xPHՁT&<6@GRQ"nd&5 [?1)2#pŠS\ 9.>kE ҂Fb׊<SpEFv(;Ch8>kmb{Ml]]'0u@uuw" "I`lB@,e[*Tbve JCиᲊfjjGdCaI)#eM7JMk?'f]:7pg`"aV&5NLey^@35Rifb gN FZ] r]t腘_\ IDATJg \@?dpnVQ TůNպ B wfs>.Y-$ Xh~kﴂYLiidiL$|[gbЗLBž0AX" Ax\:}b6PQozW8MZfYSZ8 je/6f  AnM8>r'eu\ȃqS\GxNGS0pK$.2mfe$;V%tEzBbҎɜGυ5Yj9f6& #>Fv < `. k!\0t `f!l cZ jk S@<9psy[pK8 /B_Zo37dDd,8zKQE Wim rъ0Zw+vZ) ^iRb"u 6kX+o&و!:s]j _gu\ V`dDetd3egx"&p: \ ^9d0.+Zx\0s~|놿"|ǝ;q;43x. 2ў>PmGOFvΘT0 7󷭺VSrF@:& C v)p7s! (HpJn<- Y&pvODn7˻ωO'NG+ÝRD@H9$BP-Ϊ^ѲĮǺ _ݶ5vbn(^^bOr?ו.ٚPo Dg\D(MeWE@@ =TLKZKV TNm;noL֪ ,[Մ5/. ڄܴRrle8dl9v2" "09NJ!gٵMh0X[/j3MFV[_)j)r1qc6ÉUgzoVE :-,G@B7>sSһms5D!A) E<Zh,=x/:(sC`Vo$tPCD@D@D@D@$ 'M%" " " "07$tR!" " " " qЍss)8 HISe  ݹj@$t㤩D@D@D@D@憀\ 5DD@D@D@D NqTY" " " " sC ;7-QCD@D@Fw~VSsNHD`7n>spHfW MH ݤ]qWD@D@D@B@B7!ZMWE@D@D@D !$trMH ݤ]qWD@D@D@B@B7!ZMWE@D@D@D !$trMH ݤ]qWD@D@D@B@B7!ZMWE@D8,|d do@ R)ÏLHNН:rU(" " " "0 Ӡ:D@D@D@D@N@BwU4HN: ݩ#W" " " "  ; ʪCD@D@D@D`$t\,#Y_F$ݨijoJs9# ;gDa0uy{d}ʉ-;mO /GύC8>W}y^`4$3Pe;A~e_;|ì{2WD@D`<w[wK⯏WMF~ud>>?W:&~OM7m;vҿ0;~nsz|Z,.}MJvᙺ.bm}n]z?:u ZW6n[Y>ݝ 90z:S'{xB]"n};-{G,0sy&ҭnx[v㎻td#" " " KN`j QgLXtە1hq9arx tmtkycA:/_Yo?GѶ, ew_ˁhdU@R Hɕ f, 4dН)~U." " " "0)"rE@D@D@D@fJ VWfU." " " " ," " " " KE@Bw.:#" " " "H:Z, ݥ# Hh)" " " "TƎP)_6OnLٷA5Z7(sA @{/S]{eFݯi02߿OؼM_ѻT̍knB DIC3({$qIV 'u)kiB& z{ \yZ KMuG]]<-!*ۗOM&Ԏk{lA9/*j\{|C5__5h'" " " S'̕K7ƮwlkO^ܶECh D a’_t# P mv t0g_(TIĭv7OX(R>6&>"pWD@D@D@A uRVqYi4\ [pKK`+`<`Ah}ry?Un qaWO{nb7}5Xrh30?vg˶%uֹ\,+`y\v>/2,d yQ]j󵜽zu\Z@77W7W̋^ݲoc><^O7י?x绞oXހS_e^n<Uǟx9uG>|˷}'[.rjj|ʧ}yk>'}ܯ'8ew[V߆nhM8 J -y6RgVg=fymA}kN48AEb`sWY?8V+by={"uHQ%:rP "98ap&TDL bV@L$EYɠ,__uWϛ]FpvPU;|S7h|rw 2wfc?'Tlg!<?ReShchC'ާ^MM7.˜j*i vz_J:O?IMF oizJR?)zi%auxRϷhcWӄIqc=90g-C!`;{Q?+@0, lKIJnӓ!QN=avG&oX}Ss7QH.b?b!^drE˹m$zu^,zV)g+:Cqz/7)1xS@+DJҕ)lgd@nݝQF{Gj 6n#i=E^Nnt-[Nz]uer*:Gw\ըQzt?ϛvy߫Uۃ%?ZZjK=F=t !`""'荀`yd5»W'<*WrUa(ގ۬9OףBhVV>nPTաǃrE<9S4xP=/["ӷ*}mxΈC<g%3P"(k^wWՆ@ Xz5}'~&nkץyxtqCZiw݅Zޏz9!Pk֬^C:v?U9ߟ61{#*g|* yzq7n1i7e +VfMSfMWsIqqa< $㷧LwߙJ˗/!CSǍ/%M}cg N-{E-qsa:_ޛ>NօsECGM?Ym@#/YO1+duey9V)ޮf-닑g —Q3peyqfp| Ue!FiL>lUR"9v6&.fbe!,JB[49HP1g%d:a! kr1eҫȀ;x񯙴hbz6pGe{ Y:];ƿ]*i5ۼګRj.MWN>]*NTժAx5k [Le'˹nL^=i<\y%T`C㎒Gv~ΜuszHc|#*WL~{+!`"o]Xk6q6ףe*<*nWS21L*k^8]3D84C#u)S]UHvH aش*%B  J=#ޘwrqz\ H.L#Dڠ!P5j`W ҋwz3m Ბ%NB݃ 6p>RdY햯X.C/@oK|VXPPPݵkR͚5$|sB,5a$_~aGQG!i+ce:N'7oF wXJvnݺuF >h׼}xuATׯ/ͷJ<7:py@AJ8;w<V]LC'2?gO -& 5O8n8(K.0dCxkgU< Ҩ9T4/^Ϙ)2__b@-Bt@@R+ -鳲3!pl_ ,O݄>dATa/r_Gy$Z/IfT|*^v=5CXI&\ɼ<&zRHvHI8vnΙdӠw>0(&г! f[اmwieaGiZ:ua . ȸ"!4~v%Y{ ݠ iwtlhR^77|M{}쟺u[>.dSJ&QLXs9gQ#Nt;H'vH:[Uq5VQ*Y㜞yԬX/.B:Ħީ7u:))˅/m|=f]kk! 0CK+1j,m:*m}j.]:2x)Ce2Ίb Em<#] sdxA.F<͙7V}%^X a:#V o#ߋ"~BH m=L# e#a~ЀI#8.AxBx3<4^$$I5(/́c=gAp~lI<;f_6a,Y(JccP*YoGSz (p<ɏmVpaC ~ea21{)K*MX1 C0 C EFVB==AmمS%d(n+t AZv@'طG *E67g)a 90$5+SȜHy_џ]H@b)d?h! 0+8BNͶjǣ U+!`!`#$G" .Q'\NַaqO+Td !=-/3*l;5a 8},fj[ i:)_+wLwXX -Y]U'@!6sTv|?gu C0 C(I׊ժRz,ȭ3,9OԂ5pdgw $*~< xh w c޼.UiϢdY-7#ۻnܶ7YoW|+WAxO0 C0 DQE7/ KEfOvA*2KMm;GQ +x$W1p(h@lxxj Zh&$.#=^ Eyf,o&jB]Sc!`@ LjL8+5;b-Z_H-I f_*);;bb!`ժoG;RWjh|:I:s`!`!P(u--\)5my!g!`!`o@W&$!`!`@.5V C0 C0 22wJ C0 C0@ވҥK {SI}#~ tqSC6l@]Ӻ-pP{6|D w 42K\xa.uMZ̙7ۧ5د ]"ϽB## dQlcK<);;IQ~Њ^ Όw-[Qng~yiM6~⤬Vj䂅w$|]?+J{m5ufߦ: $yk %/I?I6 C$⥳}9p@d\'$4rp4񵗩i&?@?-^L|&^z?a'O8F%&_CUVI{Ν:'?ޛAw݅su˩ҜOo>Q߄Iyul0&իӰW}LL}Yn3wm8u\lѢYSSO|D:vKBRJss9ӔN.XhhQdI!oϝtI y׶{]}ЁmɝT$I$&{q}&']_Cچ!`zuRgPF"s+j*^Lc_5e[&̓DW5m*?w4kRuZæ|{hw_g{@3|^?;82}&3^86- .Ggq%I$ɣ&t $JrjC(|;sڮVRxވnVZM| OGm~]Ok׮3J\b%5LҿOMVuIe蒋J;CZJߚx*5k^CIܲԂ_|ݴ$9;-7wvI̥1/FL-u㢢"j{ 憛ӯ̗4|Ħ\ƼH-[-I$>%/ƀefqnlٞCچ!PR:Dw*9c-X@ӦL-_nN_ÄnժU3]͚\e:uR萩/Pso7^/35o֌o0?Ӄ=[ H+l7_3i#ҭI$q瞲laև{x鋖zқ'ЇNe0}Kq)I(nFXd~C>X¸\m|3vu!KڟA\^t, F\!l@E*DZ52[tAi&!kz_ӷӱC˱`n[?|n^tzS ^ 5 vߝ]]?PoۃIٟv1=3~sMmlRio{5=CikU4qթ] K,hܸ`e0\ݗޘV@q+4r"qÏ;~r|Ǖ\I֭SN:1]lp0kD HOriiw.o5]Xl[VzNŗ[h7kU]s9[q܊H~X#$ڡV-:m@6r͵ 6:^}->t`M/m\6o*vm^kq'U/u.X$]?k'8>{bS\lm>h!x ےK<ɧ[NO>60sͷҏ?.KA>1c+͵ \qa)H.% $gs $NOr= C#.Wpۥ9\.pb$xhcdir *kxYA:L|u>S ;PFe|!* R+.L7dQЯR2oU坱;A[.b\~EV C0 C0+>@`>\Ͱ=x M*UUSE gj$ri['I`u[75`ʼƺ`݌2V C0 C(G*D [JrAz .Uީ>5/QDF.u,|k!7Ʌu^w[1 C0 C(c3G*E}%7*ԚMJ8PC PKr:@Xk!+!`!`eJvQcSbƑ]pKr7]WTfj3uEVWuPe!`!PsJpKXpJ% ?TGt#5Vu2]zQ9AaCV C0 C08K*u.ںm(t핟8h0хeE%.8%\dtucb!`!PP.Z&E3 R+ ] \m~ J^mlhc20Y\lNȊ!`!`@F6L5*C  j\JlݶeY͊!`!`@DE9#HUm+Ř\qOfQz"0 P9*j-:*GJjv3hފ!`!`@E@yJ!uԶfrqA.ƢSf&rEW[+UYŊ!`!`@D8ڨԺWTGf%Um8p;!-dJjWad0 C0 C"I%nKu_W_#0u#zEpUOk#@Š!`!`cZOPko'N(:skm C0 C0JVq.QqMjqڸ>N+OՉ1掻}LU/-!`!`;\mnq}wklɧZ0òbـ!`!`@B Lh݃ ˴WVev.3ژ̕E!`!`@E LN3]8~$`a1 a5ʆ C0 C09Q5<'B%h>K  C0 C0~dKZ]a!`!`!`!`!`!`!`@D[ 2IENDB`yao-5.4.0/doc/images/yao_pp_sh_setup.png000066400000000000000000001532531234404334100202400ustar00rootroot00000000000000PNG  IHDRAsRGB pHYs  tIME +5ǔ IDATxy Tǟ(m[he--n+iCvRYRZIItBWEuӾ/ ,%!̘A!Sx>q=y+H՝J2?t2_q>PGNP mxH - B݃zRr:˓?_Q66R_lI$6 kw3~ؒIw]YYIIYY U)zzΠ+ҕ?0N yC!nN(e1A5Eő#' VSFe&]UG QC*?o({2Nwgj@ɴ<(  ȫ2HF.;Ʀ*H*ož->[lfr%5B(^UD||!t;Zq mTۑwA0555Ud\O}KQV]U7uSvuEQE:jbMMp=}JKuAbł3u5w;W<^ uԸg_GaVv6\OV~B)'vcrOui58QBܨ4et=?:ҽOW,,Q*{_-fQAdkGɱ5]C )*$`(UK~WmeSkY_Lu>zt-Kjig -2罉i_[˯ iR髶vDxsd<_>vġ">-J/NQ$&WcouKTqŵ!W~${Hy >zͧ~v pa#Ԍ!Y [uMBj~N]Y.4iQ[ ;0&X=m/]/ê3rxp6tcW4!(/i64iיEiNVb88 ڋ/V6__(1Kji<xNs*ʝd~𪗜#tLI, ̹}~WQžί=63ՔD跙iݯZZ)  Br_r~6B1Iq1m /͓H:AyX X-.Jtxqv3ReoV6v \5O:(';&̺HId*ݵ<0m~Ƹf.z6O|"v M/[o:5ьs=kgJ]p~ %*Nd^4W1엙5|iNv~͌uWFȠ\@$ZHW?[L,j2dѦŭ-(tVɂDϕ/"V|A3O{zQPcIT|t|h")9V^8짮,M{9PՓC[CQ@eE?Rk؈v[囲mhb*SS6}|yd K 5'ón)qKZt;J){ol @I@fj>þ_[TTb|~zr6beGXj?Kde{jvm2J̊KtQE+M|^sիN Q=)1v8mwTL# w.>+p_ (H}|}u==.Juom5M8('=:nataa.X"4~ȴqrlxzn7֫ SD^/O㧗o޹uNse/S ؼŻv@r2SULB?NSjDKM;|ptb'뾏lr+p^ܪJPPe22^ m4],HgYx<*?Sk!wL0g,󺔘1dO7~43-_s|OHS(~ZPBGcfU:A++ڊa5j^w]׳Ƹ-TW4N D+7c֘CRqw<6z} Jc47r(LCJ65<% ]"K%qѱ N8&W!!IV+Wm8P_3<_>>>}dAZ!]AAQ|7@ z+">dt SS 駒_-0 I(\bn HԂb,gu`6ٟeGωKHy  ~q1%+A8!M`r #|.-j(b2III-r NdA݃ ?Đ:tԡ!jdF в1ypsq쏹6F'EqFV@C2,$Covn!˰W\67GMJJ޽Ż|r b, 5ۥ+lfYp׿]:Rtƍ"%%nzd@,@ep '5ϦД^zYYYC@Y//,i,H6xE26W] H!gJII;lڴIB) Q0*j)Oq2ʽd,=@ jnA,6!de˴=zD>\ HP\\ӧOO8AlUCiٳCEiJAfUTT.^ Mv :vڕ_ρ41ځ Һ(((ٳgaakF M v .mVXXh``>`k H+"''GEEwFA&[;AZ[l!O[;AZ ٪%%%L&Al@i-s\3339v  222z-郂 ?l@ixYfρDA哖ַo_ RRRTTTPg -7Z[[ρ\AIdZZZnP'HSqnu@KYYق @@~HAnsrjp 22rBãG ہRg{Zs>`Ҽ gk4Ű~z/^ܵkWTPJSw 7C2;wXPz}J9c"ڼ9M u3Ɋ̗beV7xz2ySy~Xgqlu꫶?)>w_ ^0a ?욵k֦E&;[2S {=eJtCKf{tךvSU/Nwt\W x(cH [*;"~_veǧ!DeEz3}$>4H xyyyTp8<' E6m | Zηo>s挌Z,ec XzOv"ajP ?d?0r큓=(*7?P@߼:3'E '㟳t ؛G޹@0/PEd%]5CNiq>'\@w7Ee0kGmhzeyt,9ܜ7& |_s\_N(~޳k@0o)ʣ(>Ys0G#GGG\rʔ)]t!_ }lhHvI}OQ0l{\^ ew `,'ɡe2b9 y((_{pӅs^]ZUT-z$/*̘7J.hGGѣGm۶DBBW^FFFaaaLJ9;;իoԶmѣG;::FGG}^ٳgSNEEEhH|r_|1NnG ;pO%s%H=*o+b.Rv a)I}i@3Ŧ>\/d EQoϮʎH/y@\c^zBW@BX+.fp)f\u1EWm3C" @QTYaB NBjro߾{nssseewSYYyĉ=*..nPqGBCC׬Y3qD"޽Ν;\n32ь3jԨJ5jTctl6ҡA.KӸb>HЫ'p4Fmf&hG,Q FR5\nЪ^(--wŋ/^x=ᴑ!CYAǎ[>>|S/𤤤[[['DGGoϟ?(Վ꨺?|ȏBZ}:(͠i"usF+&t5._\XXXoҷoJ?_~9 QVVɓJ/ӧeeeŸttUOC IDATt.Z:E1̤$__EmB F @~gil>)Ul'~LNR{>ȫU5b\-dffVݻ=z,waW\ꙒRGWСC.FDDӻwz" v Ly}tt/_\9cǎªW~^~-?.]N3ydcc.]@1??_UUJKK8w\^zuĉ'NܼyS@Fe``kiiaƀ .\xիB?OBBbĈݻwS$''kiiY[[_>66ںW^O>p8n MKjj'?:n```jjjhhmHfSN?~ŋ\n}sĉ3gTr4hٳg̘ Vn ZgXѱuN5B@ %j>;w.((¹:t4iɓ t:f˽pO:GaŤIǎ)<2dHڵ[lիqP0Ҭ Z _ 0jԨF$''^rqsII*ROdwF׮]W^cܹ#h""&lQVpM/|l???mmg֭xCElҧOf:͛5yy(AiR6l؀Æ MOO_tie۷[o߶_YY٥KNyڵv;rW^v`kǏ!66а2`ѣ°9Ep*IHHx+uqqn,[sv88N@@ xZ ֕544K@IIʕ+(ɂ4_@7o۷?//lll:uwUo߾oM#""ĝy M?idffzzz gjkk/]̌$I###w}} IrΜ9k׮ѣہ ȷ͛7:tKHHL2eٲeÆ CeJn߾{cǎ$ieeԳgOTAAsP@ ))9}uAD^ZZJ,,,+!IZZ#G̙3׭[׫W/T*BzBQSSCet;7lQZZJ *ŋ/6o%%%7mڄ-SPPw^GٳQؼyspp0ϗZhqaix}HHHXYYmܸ{ Cxƍ:TVV&//~ JII28~5k?۷og2( aXVSUUݺuɓQ R~AC}[0/i{PUU29rD^i*:GF4""[vĉk֬QTTl2-D$PiJKKO:|7oJIIi&gٵi300 ,--Eqt;吖ZRR2|poo3f0 Tizڵk'1aiddbPiNiDϟ?OQTΝ͛7p@(**L<ӧ'O5kʕ+eddPQi,ܹlٲsIHHܹ}Y1jԨHJJ;weA@_\OO;v{yy͚5M6 ܠN8p`NN΢E͛TAA~(Y|GϟfN޽###ddd._x.6o" 9-16V 瀀aJ.ʈجdდSll,L4UVV(^烫3Dn)# V}`pt@i͒6O.ԓ{Zۻ/$__|:n=kŅh{Kf#ѣG݋v5bĈVv`eO֗#8ْy;De?dW-|-hNNk-\ .$iccpªGQF/#Nߺu͛92mڴ얬㻔JnG#|@!_I ț5w=?:ҽOh{,!==SN :6mZddRbbQBAMCr͇l.omHrE&hVA&L|Q=z肂kk={X ]{7Vbt;Ć`Kü= N= PaoBr5!eY&$뇻$HA&l 4}&&A&{3Yی IK `I#;$pu/ђ eq5S8bLLpiAmC.vHKn`52Rn1_ZU*Ĵ]{-6Ը,|q8 ﺇ⟖7?d ^|,ɣL5 {YYޚ t9(xj1 CyRSwܟhMˆP8Ѥ<YYY/###-[e S/(`cܷ{ f.+l /Yj?]NAwOj |`??s~L!Ӎ%tK(`OBÒnnn_Js}"xyIŮ \GV]H )~}HYC>uwf Ǖg,[aLs{{C#{Zy8[H%=RY^(r?x*EclhmY#))TUUnd2QFFQD]0rS444LrV ^V7(T\^c'a:gH{LTY /A4~:LN4~} d{(ymnjh8iQ;2M#zUC~~ʢ`fy9Gϫ/JƏPzp&G潒2zr "c" >~jriS4p2@Hd;]AiJ.\J8bشiSNPFF.#""Ǝ[TTdmmrtt?#X&n:X, <̰\+.̔8@V'X,V"+6.!̬WۊQVRUbX,V\\I55*ä̊?1CoQ"6>u1h3췊ڇڷiPd~|ݠj!O6=EcmD(P4֦,AQTXX_iiT%25"龾 ,۷oo!LIEuSWY0`ih+$х%LOR+}?i7-xq9؝>9"c3^2[zwߜͺ7ucI`Luɬ)}. Ġ/@x!o+~pLQAB Sٗu] b2D:N3+HPnZ^4TRB)yqw[nIHH̟?___Æ (#Z#XfM=\\\^zm61yy\@YrĢ :Y-Q9L$ G$AgK83r7ЮmXI*h&^u_~~x*l͚ف@3 oVz_kn}Hۡ3=N,݆ } 7/hg Rv U=$uBE؜ޡv@ciKNb4W^jEQ(ؿ5UەK,w]KUM?)“%)8qDPPX[[ 4ٹ۾}Pt;D p_2%IzBm7˭!L|M]v)iOk~-Ow +-ˬY@ >{#lvprpȑp Ə HSbeee vرm6ݎjWOd$!eu&iA}()MñdtDd0y 싩`ԓ  ATa6 l"zL똰% A~YN%z bùfm3G2$I, _b/y57i1w%HIĆS/5h(8%A9z}Ea>W;JQ0>0$Ih?xHP ̵8E[l#::ZRRrٲe(4=fff4myQyRSw\ (W#h6>]"舟̀yvla_ ҭ>^7ZQesAؼ8#θGMÞ~Q1-{{7ި MG3" IXj9V;w{V/L#2n˰1\{)0N_Yp_/7u)x-ytNj Жdm.ޝs4svBmYǐ%jɋ?~\s\r(,&Lw^w^U,^(ĺ\[iu.w2y`ME@Bz&`qMz20lvoea'>cfDiR 4zjWS>'Y" $,aŠyŏBO7tK"`tP LVK6t|/ ~NPÁ?p@Ӧ(lؿ<:&l=@yF̙3A2AΝ;.]sζmΞ=54p2@Hk|5I(j5wUT>@Ru<&G3 awH*IM{l  <I67544me("ꪷKk&a*?eJ_l=B,FQ"Dh*^ : \G^;!vi>m\!;A!nՒC,!_VTP, G_wӘAf -L-![, +Y ,+f֫mR0R.ComT%X,yRo((VA N N zH< Qǂxc R+/*/ARbȋ47okkkρ 333ܖkb$1t;}AK@DxģMKe;dG 'M]b#Au!U9xD zuӘIi7aǎoѓ|/!|r(CfUsC8o[ȩcAκ= &w>(X!VMJ2TC>2yx9VCx;w.bB!BHca| +++a<+V`@= O[tR0mݧY-~ڶVx#i4 I}SUٻs_g MAwm7N A}\8<ǙwvsY *M} 7/hg Rv,!DkqUTZ;$I9hC]91iTK-ŰA64Tj=ڪuuId,dv@XLAD-yMRRҎ;LLL0>4[>}ŋ15iU_G\Veqv+ \UppӀ[ĥ?'}!b\./(*T/ "rt\.hu]Ъ]=4-ҿ_Z[Kϟ?oVRR2nܸ9s|s>Yʈ2~M60C*W*> $Z0^RE4]FIc|IM$i5},RҪ/ "7(.[i5s!yS5 ʵjIm4ՒbY IDAT>Qo),,ܼyϟmmm @M400`sCMv2d](# QUUǵW$$vڥkln7C؉z# EQ{MMMرc6mP遁WAv H%<<֭[NNN۷GAWcǎl׮]LLQt;Z ¥|Bt> I;U x)1 MK\\\TTĊ+u놂 ȯ޽{%%%ߏLh- .).QF%))0|& ȯ?WWWXnݭ[Pt;~W hhZ.JCoRpE1YGB$۷ 2077_`@ Xpazz: nGùῄ IIisAHh/Gd/pADo7- QW3>fm3G2$I, /">>d Aȍ9Ie9^ Ip8 ["F؈lMH_-Es>}Y\\Μ9AرcΝ[XXtp`K͗=fR9l(Ĵ]{-6Ը,|qxVZ[鿀`.{@ɯ{-SK}Ͽbmk^7ZeBN@~iEqǼZk{]-OLNƝ XWG фmf|ij=a|NhBQpŋ1D0رcFVV֊+pbK Wɾwn3`RyɢO[%SG-=2rP_e@~w?j-xz& k|`*ׅ?]Ϝ7STn,sxǣ $9¢;yHݺ7LfUNp9lW8/&ʢ1eddVZeEBghhx__%K&2}U% e7W[L( AMF~В"#k >()IRy:$<I67544me(ׯ@BϮ/_ۮCqR`5#T@|P[EqaX/AK.ر# -EE]v}uݎ&SĆWWs3_7{9Ky\"Y |C |LL\P}Tj\5fzg߬>mK@(2$"spzYԋ.3 )o>!fxg4U)(yKUF3N:0Ri%sI&%&& z } 8EӪKܢ">h\.hu.s/r9|hHFˆ t\j6ғ,؇zD[W^%I]EEOkp(cfff<o&&&&#Έjxjh j>eds.[OBhtX>h2/8;ݱCff09s@1`7uRRRP_ S q{nH2mڴ)SpܥK v _6}NQP 1 RTT;w. M6m۶ @:2:w :4III{{{ :sNtM|TUUQA444U&>&5$ Ho@p !6J$Lg3y}'vIeR;B@@@~~1 [[A{@[HKslv~30Ń}}vNKk#qTlve 3~nܸqM:dII\0Ar$%%o.--}SN v —Omꥻ]]]+6#XAOנoh w!\^WWsNp}Ճ^.=u)qA?@q –YNO|F- c ”du EP`x CFC'.JP{'.1 5ؚr8i&SXвXn'AZ+ ?{E aɐl܊{{uֺZw:UuURd a$䒼 T I~0_{y0tPΕ 77~Y(*;^#n)܍rdS4vЮqp*&yp»p/V3tƽ2޳iSۚMST~9rq<ڶOZ˗/jFr2d#Q?u+)Rsi^Y0Jhxk+/}tC‘"s?0ܫ㜶 }n'΋^W@j5kYB[/((H*~4XGw 6=JwPmNKǫQoC'sveRs.͜=EU{~~k-WjW &V,7.ݰ?ԁ{ǗnRͿ*﷪/#U5]hzw[ m7n:Ñbxє!].\عs/n޼yذav3hxOش~K// 9w5\v_tVeܻr3{x} 9*.l@u3= +Bi 8q?PzQ!r=\S(jVPfy̝;w3fBy*U-Z`ٲeO<@x}LԾ6/00 y0jSPM9sђq%y]k7iP-hB%\)SZN,-%)#W&͕>R$D&5, /o_ϓAx@=IΓ25 dVaNt`dRiniJދ-E(W<=2Y[9<nT-67o:t!88ֶ Vog-**8qbnn_~پ}{ I1Rz?9sE"ѻb| ++.?p- \p͙a_s EVo\cfIIIZZӧOnjooߨQ3g?aB P~~Ҩhp$111**jٲe۷׮]?~˖-TҧO7ػ?~85jEm !e>|.cǎ;wP Tv2>>#FPӧO7a*;H ;v\reLLLRRҺuz)߿|:X[[wyժUَB:thNNN%|JNNӧqBH79&&fӦM#pss5jTxxxvv3gO^~}Lvȑ'8~T27nܸxb߾}+홙{_rjժT pVZ-Xƍ۶m MNN0f̘ _L>w>}]۱c\.o֬YݺuBVZuҥxŔF¢ Zyf@@@@@[ұ\mllZhqڵH$ڰaCÆ uӧO711YjU*U*O"H1vשS%}4hݻoܸv;::fgg8p>:dȐǏ|lK. /GGÇX`QyPaD"Qǎ,XpܹcǎuJJJ]vp'/_+{E=ƍG4 [_WT3fXfNJPl߾@~B!&Bbnn>a/.))@ J:˯p\??>}̞=I&{|Jǎ{sPP#BտOOGiRzV'N@2^z5211)((? <%|\1bիCBB,,,(*;Hrw0{.]Zjկ_.!"iӦYf/^\z?@3E`<A9ӏ;b BGRqObo߮ӈPAў={ ԌJ!/$$DP\Ҡ .pܾ}R6awAb߯Rmmm) BHEstt oSAHJOO?wá!̘1c\.cb\4M[4! Ne1"O>=s ݻ7AƎ `۶m>4 F!<<\Rjޞ |JYp!Ae1|OBq8-[TvT*[hQjUJT(-( ,;;ԩS,+$$ ʌ3lMݼyb)FWA6o޼dbkj0"b0R9z輼 zyyidH1Xo~^rI&?p8tڀvr<'''9!FqƾG4*h (!߰a@K zJ*޸qfnݚ T~p8wvv6Ae3ΝcN:VVV!ZjJJJJГ,&IMo^$PZW/LҵW{2mGsM6Fb vM67έc̓0`})2'YUܓ, cvX< 2 MMM0aن x<^^g>^b+UUV͍.}Uػ1TZ=+& )xr6NtmO s6 Ʈ\ gX8F:)Fݺu5оس]1bR ң?yl7nL1l)O/$$}J=wn:7` -Dѱ0m 3IJ|2N:ccbu}ׯ_bwV]J.߿KzLLL(rHg#H1@ ܹ34Yvn>FJQAbzG\XSv4i҄bX S#)r2V [G?Hx2bccy<^z-1)Fܹ@ x"rD`-&8}}P'۟2v[_zUVשSG(R}dnn޾}{Jb) *;H=DG~u5zNt0["yҺ a#|h(F2ݻ7'j2CQA \bzyq;M!y@Qfo= DFFr8#ch(F2޽;=]XuQnTv+ro_eYFutv[fAҵ׻ݻ*SX19b Zn.W}0rh#[QV-eR)FB1R ڵk׉S-4 &% IKHBU^kCxր?|<:uy`ť yM*,Yڵkcƌi۶!2O5N(FǨ/zn\Wi>FL bH$@ɫh/=_nMTPJeTTڵkA&`NR*DL,($BQTW-xkn޽ф"GG*Ua'ثW6mڔy%V@l2NbB4v+v }0ѧ~CR>шېk6f@4#vPA1c͚5'N5ke񩰛f م_#$ +ӿ9xYE>(v,r IDAT~B|1ATqzVb.?c-J0 >@\,bqHT<»f%>pr1sHP] `㨯>dԔ!D,GFF޺uI&ޖa<~Z ,HQUd㼲_2o[%y0t)]e}Pmz D|o@.yw9ԀgmxkFLLۛ &MDFF^|}.;ִ!N(,RHӠDUJ S0 WyWk{,^8J5XUg?{UxyyQ,;6nxeBˎ|y^0zm̙H9!(a8h1)cH߲  U\_蟎aT&MxXU++:9B4TvɉM\zB'}Og;+p녭>=Q@YPƔ; V p}A3-Ţ5 @ Wbη{D<zI39% ( B6a^Yw3ŀ\@* _ R2 Cۑ̃)F1FG~WW.]VZt GM1RcY/|'O ٳ1D M^Z~49À)R8kq=y.Dj+/- xxvW !шB gyЧ@߾ةsΝ;}ͰצK1O?)!NO њ (JM/ָqcׯ_94c_5L?iYZN'ƦHr;;;XLiB U*UUVXXlX6>1\ӥ[-dxRA/%% EA1l5kEQB2s222rO~WO*;9God.W l%Qk?~Le!cs{Qxm?Bcʍ|796 zBv5dޞ5;N:={P(x<:*;O) .-TյVe]q2MMf0ªSBS H ͆EkVj5Gxk+~1wv.V`&д㏫N~/iu;۳Kxxxfh~pI4]! 2 ,/`ztq݇f뢲CG go=XLxݾ?5Cѥ_DzIn\nII 0^SW,mHg^[fEY2 ,Y`)u3@ III!!!9q69JTR!Wcl׊:%w&} ܼr0AB&nc7-[#Eɛ-}[D Hp}xA cfh]l'NsrbO lf˩ ՕWؑ(^釩cuzϯ+Vy)O<<<<8۽xCq6KБb֞\X+a1/;: ~wMmޝOW&h;ⱣGB%(77?p>lVh<MCr޹HHek߶@ bر>ZOrTtZ*;tEpƁ^};?#hC7M{:`r3ÄpM}qn|*; Jχb`jiuM{Z4^]_wvtXxut-$ȧӅc^%-7":Q3wǨ$7LLd,Ĩt&dnJ2~̜9˶7n/@6}ݕAM<-~GtEwvsk1wN>w_k?T}o.aT+70ȗ9^#h7qyo=Έ==oܻf^8>~ۥG |F4\/UK$Iaf䅒,)U(H }3zܸne3k Mu޽]SgE"Ou)-]"ѣG.] `j.:t]]e9KҚZi~yܠɵ0 羥wK5KpiEPKF^-׷ߥ vб?'{_٦E;2s|9X>oawꦰpĈM67oދu%TfUwo='U!xf8OZK"1;mՙxAүk'&˟v>>>>>Nkڂ N:eiioYXr5P,;Nhe~,ǟUn3`7wR/3v)r'[tٚŃ.r2Yo$?D&c2B(ZI[*gB'Nd4ikt{،!ō{׭-sR_^+@i j+`ɢV,-^|-1Fn[_岞/7aWc%秤 ]<6沣qN#˗MTI?ׯ/9r=[0Y%msss*;Hٱc͛y<^XXs(Eg?*LE1HdǦĦZqӞyVs7j"^ ڦ@C9/~yNg%bDz7` (xG&m6x3󙵫p#ڞYμ-1$TکZgz?{V 5?/w몲W01dl3j;˟2't$bӔ霡C&Q[]3IjZ;t#7-7>NфʿTv r9sXhQ@[P-_Oʕ<g#(ŮxPB)S;({pr-_d؀ٸ&JqX 0/MgV 2W_^7Bgh,sfl*ȸG+cXYE+f |a(UTvM|dz|}[mUKKX;8 });R)Aō7NR}׽zz{.PڡT X_XhzgG(gHYR  _C%-uж6ӂ<|+~HĝpzkSˈ@G3 'L<[= yq E3 s0R,n`xl xܷ_8 >=2v,|k%))m8ٝڬ'ɣ[?ϳN)S`ccczKP<t Lj>;Z;1bDAAA.]&NI<*\9}S8jG`?Mۥ[Q@ps%S73W/ D`یn@&$:,pj$X>" Xf+$_)\*#jW9r&q;۸GzCإok.(.Z)qΏmuu|mjNEֆ1Zu/P >E[;v^6-َ3KU6u)%\.5jԓ'O֭tRϾr-{&w2Jܔ}i0-ü\vqQ3f٢ü/#AT{u3[UB)6 ^=81br~Ơ#浒W9l _tl0"/ ЧH2{[.WsjDTv|Ji{*;t|<|u?V?vnHVO:NNNaaa-PaQ_!K?WҲV;<9-ijᛢ7܇^em]3^yHmfV*>o|3\F}*Sd1!Zwͽ/9|Neae *1,#ZbšC7nXJ/̑P?S+Rtj!`PhBG8[;oM|/vk(>Uïm\ه|,k׮p8k֬iHDa禰nQۆ>n渧WxKy'XoT48)7nnKYٺ$R١[f&|;~medzPTyyyt._ȧ#*;^#rbAoF5On259999955޹&n=򲔔)Ss5Gfg0ITuF݆5?J`ɧD7Yհqg]uN#]R0^ҍe]cǩoeG-.!'6XyuO |[;#]uLqvALe^(3~O~"HP/v`ffֻw!CT^]^%^&_y){(J|bt>wz1 ʖNѲ$VوN*~dnn. hjժ <8$$D3$]ڮx|ܜ"%R^^^~~QNO Q,ZM'(5 <Z?8:!cPx>޵"4N}r_7u}vzjԨi|B~8_݂/|(OnZA:U,QsڮV 'ٳg+nߏ9TUV\^ڟFtiǏ#>4ЍhY S9 肪ù´Gp8a<i8Qt4'Wg=H1M1/nxWسe1TOH`CEGE0e_p7BgnȓτANtb){ 듿sh+Ys:777'' ۵) q۵3'|KqQ;5s7` [baTV3By[ @q FhN}I;1([n]?_۵Yv)/Ϙ$%i5Gt,$))..{jޥ1\oyjDt|~'ޥ&n:yFS l:,k̯Ph#Xܪ}عG.\GiMT,ڡfYۍ0Ridmioajx͋0H1Rq៊ZX1|T0V~Y֥CJ7©6LԣGڎ+yV [XXp\TZ\\LGStbE,L1RnVzMpBl=pɾ: _g*;A(oȍ[Do}"G)ǣ zl6ӧOhBQ`ٸĂ$J-9&]Fo*;tI׷UVUKQlVTZW)Fb ZX's$ʊbìi ݠfΧ er}3'堷(rz>YZqԻbvES`P>Tk;,೩F2!G;1)C&c5?tdjP'-'֎w}gNVңM5N1RիT-~S+.S:>M|_^, XI\c ǖ_Κ}!cXgϞ{T*ׯ_RK;.ZzH1V[YYq|>o$i)RIG{ :4x}ZR5jxjF7Y* q_q>n]%---%%Zjt, !ĉ)Z;* c@y)))t !Tv*;HŲ311˓J!0ZXX4jԈҠ02{izNNNB4uiӆPTvJ2GAY!Yv*; O|fcz$bjɓ'젲àT? KKKH$ɲB۷ܼ( *; D%cqvvg!Be$,Խb0;FeGEtKuaL@#o͸X'Od2@@GrssϞ=r訵C7ON| `R2^d9@VBWDD0mڴ40+"+<=aʺI}yxx٪!zm߾}BBB( *; 9kچۖ+}_V^@JJJII aB>*((8qٳ'Q#=Rm0w6޽~/SSӪU%''Sg}t!LֲeKڄCq-MsᎃX+h` V2޿5D*;!hzMQPaPjwpNk6,Iի?>99a.N0B>dPb;J=D"[[[BAxB \]]) *; Nqϟ5r wAc(og!)zVd^3<kvC);J%cB;,Tv,qsKLyyy4*-ٿ"pz`3B:;w\LL'fB^ؼy3?8ڡSŷo0uC;μlG 8B*cǎ 8ҠP)blkwIbޞ#7aoL X:̄o֭J[n666Fš,:jNiWflKLL_>jBH%2l0%nW?\]]MMMhB*˗/888tؑҨPtTعf4!cҠ+___ PI&ڵ DY[[ٕ$&&R)<<\"4jߟҠ7???QQQ!rZ~=3)0x{{xԬ,JRܹsb844Ҡ=Mǝ;w( BHej*Æ DԮ]@|||qq1A<233wfǍGiPA R4!GXXL&ڵflBe1uT*) BHeP(~&L4 ں!2ػwoZZZZڶmKiPA>֭[}ٟYTT;i𠎥JbʕƏOQPA>i޽}߿}*yMooo>N[.]v획͠A( *;ȇi*,,ܽ{w>} .*sܚ5k<!cԨQҠ|X~~˯ڵw޶6l\fM6KG+رc) *;_k׮h޼Ell 1sssaׯ_JѕTaÆ999Q"T>>''e.^<##jРm4ʩ~ 6#Nv{#), H\R$U^sŧOtrrڴiK$;}3grbׯk׎NBȧT* FQNQpwk9h{ --BsAAKZXXxxxh* ///Xxq֭5?{zzj~ٺukF" ZXXAd>}{ۻ?IvsGIw+RG]QMQ}YMEME%JRg$"TK$%!b7MABh5d3oyI#K :c[Fƍ ȕ+3克S(o3KJ/2J]矁ݻ/^\ReY Z: :Aeel0 h]/VˠīW>S^𪣣3ERr?g3wժU/]tҥUȑC~@xxL8Qx_^I؝_vVEQ2= 3ZEQV]|>ۣyEEmV+c^ojcV7\u.pަ}F)[SEVm]Z| \o|M624(mEڳ=Tʬ[GEQ&~-fjkkkE1iS ={,YdĈqٲe/ިQA͝;w.\ty]v^꫍7:u*&&&""ѣk׮4iR.]U5I&-ppp(]tbb)Bwc۶midLۡeF/aL q1 `j=G{v W=ǖ:6kPA۟LML23Ƶ]ۻlTؚOg̝ܵZV8:q`ݾfx0We;MɱZ5FpcZݥِ ]^lt zRask|0 8Ԁ"_0ֻ<8w R.I`~]j@s.=qQߛX#^.*kc<]}݌F=[;٤Z*[dɒrjժ\xQB%aaa*C .@2Ua:i|?0W'K:qapvQ#rUԯ~GK[{XwCҜ}G9Y*TϛRIk:$m l~MҐZ!Çˑ888jJB%k׮5M4I>x/^*׃ WS|) ^u\_aL1ɹ>ߺu@OσFFz:w$뗰<rs~~[g6h6[k:lgFm ;v|$ʘš6c7#J 5Z+|R [f63~UZaaam8}ڵk'idM&OB6g+jʺ`k3VPYy%秮>޼iN 4h51pŸ@˹6v&+<lɭGf~:9dxѕjlZV?3++?ȑ#E+!!aݺu@۶m@16NEeop<;j~j9k+:+,uĀZ3o F0h4)4!w]( aÆغuVP!^:uBCC ,YRbߋ{X"o޼Wզ_ė*Ey{*++**YOVdXZT%_^:Ȓkժ8q">>^BVi&[nCwO[w1o|iӧOKBZF IC ¯-!۫]6pYF#i!\ddoSҐ#IF͛%!!!00PBu{xx*UJҐCgժUKRM9s&00Ҳk׮B޾ZjCG!(..nʕ@$);HitFs ICzl^X1///IC!R?իݽ{WBW믊\Cɛ7[bb #x%Fq M4;I"MjԨaccsΝ .HB۷o_ppp\:w,iH!DXXXԩS8z$!DZDEE_ӧ"eiUdɢE9rDBŚ5k>|XreT!^Y:uLxᅭN<`iiٷo_IC!^Y9L=|PB&&&fٲe@Νe);xM+V,TV4YlYlll 7o.iH!kRAaaa"xO:ecc3dEQ$);x}vvvĎ9#!}5k~ɓGC7UTRJ}%&&J Bŋt:ڵkK Rv>֭kkk{ΝӧOKB_~%888w4"XZZ6h8ydxx" ݲe 0d[[[ D!S…+Vo> -Z(!!MCWfܹsGGG:tH";[j͛7 *ԥKIC! JոqcJuEyVlk~~~Ç@mɓ'y?#""B"r? 0hѢB]*THHHؽ{N@>߿?g^߸qcF#UEDD,\h4v]CjժEt!&D7w\FSRmJ Rv(ҰaC{{pTh4~2BgVVV-Z =z"DV~cǎ،?NC/w͚5333;s̅ $!o߾|х @E3SҺˤ7R!R$':Ѽ䛅U\YBxCc~ IDATO%F1(!ϚFZ*[]qt+@B+׊i&XL̂ gΜ3g7odɒ-ƷAb.::z񑑑j>|xwܖ,YuN|YKn_G:t퐲Cʎ*; %,4MD *wO:588dɒSN|Y"kqqq'O -]ɓ\vLȖ)H1LN5rKHx*8n)}<F_^pP2cǎuvv ]hQbb(GĘYbLLL\hqٱcfIzzgbdlzG#N ̳{{Ӓy[&L`kk{ĉe˖;f4-[v [[ &888d՚6?d?3mrRv4]߳<-KYnv%oQǏoiizjQF1Ǹzj???KK,X0C|-Ӵ_O_}Ic_}3F7NR޽{Æ cFqÆ wVTƍsuu(9M{O&6ۨQ|}}m&1(1fmkff6j(77 c";3=V6~Vjg׮]cFq׮]>>>x{{WZ5chzVm,,eYիW׷";{X[Z8h޼yΝFEN<)1(1Oɸ9vC<);D+i2 -KjatTy,X >1(1.XTst5CX Ǥic,Rv%bȸr_L\[ڵkN:ƥK-'F9%׳k׮KN:edtz2UZWrI!^JucbM)(*h1kq֘|m۶;LW^ydh_նmLϭݻm۶#F5[0&05[Tpo@vL|N|x9{'exGKw.ǧge:ܛe6_{67bVXweРA۷o!ym߾|РA]tIq !Rr\b#yshaF]Rćf~uVl~ŷemA%zw8K@縠G ?۞+n(Eq,+0sup;+# cMQi'ϺUH[~}''9s'O5jK!R1wPѣGI&Bz;aDӵTI ;Vzp-zڄӫ ng}RoO(RGS/o`#G*(8lJav65Tߨ\tsqrHYu0Q'Z`cڨ%z:ZO|_ӁqƽMBdaAAAcǎ uvv>}Bz;{taVøc9گ# ͎҅ze.ubr/>#4O\fu n\S4(;&Eu -PZr= 41_ (VW‰<:D.@\?z0$^P!RJgΜ>}zڶm+]BƟyFRJvvv%N"ڂG]t03ęitt]sY${6E`tL>k1C} ?Z?~|ǎM6͜9O̙37mtqRs);{gY?  `Ucbu(DE鈳g^pfu`S|xѢE%!eȊ,hJɀUhYfmذ~۸qӧ/_>c"}ŋ//.]ȐB! ^zURo 3fLϞ=>S߿͚5:.wC ěhx#nnnt˗/5kVLL"2Yf-_\yxx̛7Oj!eÇ fccsԩ#G:uJbfذaÇXD,Bڵk-[o믿f͚ѫW9sJ2"ZfM@@PB!CɓGbRvɓgҤIv 8sL׮]5j$8h4۷o>ܹsRvdw@;˫Zj+W<}+:4`"EH8"úzMT\o߾NNNC(!d|NNNǏ?zիǎkN4M\\֭[wܙ+W޽{׬YSbRvԬY}Æ {_H2"8{+EiҤI.]lll$!eM߾}֭߇M>VZݻwٳnݺ@Xb/U""+(U_om޼900ԩS^^^mڴp;j}}}xKK:xyyB!ss-[֬Ysرc _ شiSll,ѵkWuTc2}ݵimL5~5k\t (TP+W,1ӧ׭[wuյgϞL|ۋH);9_;v짟~s֣GbŊI"c [v灼yv֭F|^zmڴqvv|k KHHPTM4i׮$#C:VOeo0`Ga36`zz5 66 O-5;ҎR(Ncr=zBT "Gi9]^6my怀խ[O>ɛ7#^ɝ;wmvС33>CdD3О__gqU1/!7㊻5e -Q[IZ7Cj,™dJ}w!5ʴA`s஦X=b)'?Nd;?~ݺuF,Yr- Gŭ[,Y}AXn x{{K!V ? lk !С.VhmY[a|P hh*b84}4U 퇢g+eLe̢7x$7%·!=r;Hx/ O.Ŧ6gۣ60r&܁x=+G3#1(P`Ȑ! .x7oJ8"57o\xOOυ 2$h"u9F5e\l;c)[`6!f-[XVl >cS۟0SRGH47iMD4YLJxGPj-wot8sѧ܎o,SǦ콢n|?= fj14\rӸ8BHaڶm>|f͚^^^K˅9Dppz1hnnޠA6mȵ9(6[{B`zJ6D{8HZ@P"qkn/q2Ny5Kw.qOh]?"[L,Jn\^؎!aGCJa7oށ??@͛׬YS/p]v*ӳM6e`uG4?h7uTޠ_;?F'ӑ;Ds[EZ (QB\'Ի֎^G(-ϩxl aam(!'߶m={۷/$$dѢE֭kܸqF$l%&&f߾}{쉎5jԤI``FSݪs{{ra w6k^8K۔&ʪPߓ)e Fw,Z`Rnџ4(֎:`/Opԁ)mzџ| N5~n>]he]wʓ'O.]ڶm{]v]vmӦM۶m]WѢE%,/,, 4h^)ҬY:uXXXH8"P CM pQgx6Wu,ƌh9^l  MϚZ&}ܐ+їQӇ֬WGm}Si98M~~:4Z.uP%'2@ ʃ"U 6lذӧO+WQFժU3Pĉ}߀`Zj$ Z #p:*W(t:mGRGD*GSˇ y]+<۷wjOO 8׆ ._C: @}QGCdRv2eZ~~~  xzz֭[7W\cu!??OMxzz~G*T쐲CH!eGp5Ӷ ===VާᐲzS9s֩S^z 쐲CH!eGFpY???`0UV^CΗ :~SxNf׳[$:O ˜ԍIRKaFlhˆ6❱UVZ[n;w… 7o޼y(JBJ.]TҥK,XLr{,11ƍ/_~iWX]&o! 94Ql!(C[)gcyK Fo@ p@ >Y7> άPZ;nJi/]kq&ha0gthOuy`L723~#n~ny4'm,'m/s%WXh"!oڴiBBBHHHPPCBB]vڵ...*TR9rȆA^|TgM>ƍג OޠŋلeGKw%b7s(Ѐ!5v啴L C/\k朠f5F|6[FᒂM)T mL==),Rc!1p$3yA)2Z]tҥnB2/_ ?~%o޼ɫggg[[L<O^gܹs[---K,i3J*qF {zz>uիʎуiiiJU Ts}|k;EIDAT{ `5`a:kYoOnl"Fg͇\ҳf3SVz(2ф)oQҪ$=aTJaAζ`L֦2ȠrUZjժ n2_~ڵ7o޾}'O|cmmz@tʕNNNNNN9s|_$&&FGGGDDDDDDFFFFFH~̬` .Tʟ?\=YRz֭{!ӷuM㝔35N0 WVS!_BX2x;5/eD#-1b4>rh Fj>Q>xo:ݦw5va kGK#eQ֕}GA *TPB5kL* 7o>'yfddVz*gϞgnggggggooTjhH]||5Bјxc(P@ۼEv1eʔSLy?:ж .u7gՁ{ h9^l >dtbFԹ8.eEfa$@dqLo%}ѺY&`M,l Y@-S2 }+Aloo9^l OӇ当~s՘?¹!kWң/jO&1ӆk= ,(a +(Ow9BdmJfϠE`mf0hOC)e@c>u:h ^x3cЃ;"wdoN%Ƭ@+^xl 7 cz5]0B!<_`*I"Bdi{.uOWB(^EBd~YS` W|>}Wg%&!RvPsr$_tny}F#!:Z=FTIO'qU15-Ʀ]y7J^QqfN-9dBdm0k\ Ү&a O^U_p9f?䔖eT*ڴcwScwq* 0ƛ˗B;S<}\\GztkUᣑOuf$5໕~Ic;v:UaΤwŵS|سW \MN4$;Nzѫޏz8RlVs'-<ǃcoE|}ڳ*|%KUa?.I-m~P[s5e1K|N|:)l>M$رeەBmP&Լstc A|.ON 쟜9Oz|6cK.O|0txj7(nL(NtJi̱6 e>EQ-'xhO%bغ,);~gVc5cL6jwpŊ3}6#Dzz>k/CR*}I,,BE{;'/-\0K -&{@>%FQ!eGe<)`;Gy]]hk,®8ks: !wkŴh_|Ч(1JYZp@>W<йL( `^5`kԿQ>ԾWBGAy~[#K̆E&%֗%F1{^ϴloR&MGMHTufԸ'W='ݑ*XE~^$1J(Rg>eI!~ ~M?Zg/i%"uo$Jb%FQvduZ-u{5R[P{yeIˁZfʂ/J(138e?]bÉh\2򗖀(X4Z 5e(1JeTAgoO/Y&+4J g+(1JeCs}[ K(1JBokaQb%FQH!ҹG H=$0Qb%FQJ4-a<.1J(16.L2(1JBb|CVf Ƥܣ@1{%1J(1!Oɝ%FQbB!"B!B!B!Rv!B!BH!!B!BH!WE2BC!Rv!BH!B);B!eB!B!C!B!BH!BlB%T0|B!ҕb4%!BrE!Rv!B!B);B!eB!B!e"K +d̥h-BH!Ȋg14f+k,E);Y.pai:jףc]\+0? $ʐL'ZWvNv=Z $"I-*Ǹm*JGM-3=s6'4JvRv!2{-n{|Pg\P:}Ӎ+X|?klf{3Fin`0ðF:= `_8>+=S-ӟ)S'@Bz8w']%Ļ$s!ނcWxP9ϕcéڂUA:2geSr(3 Lvlv~-W|h'¢eƒL E /I})-Sm7uc ɥo@DM Mjp|R ݎ@Q&#.!BdfeyKOjO|Ϧ@\w`_ϋw4yZ9M mFD#㇎LYq1`J1&ahI;"\M`vڟQn2ŏEsŋөy-n".!^h Ouo8ŢBnt:TVr{Rv!"k,B!C!Rv!BH!B);B!eD Bw#cIENDB`yao-5.4.0/doc/index.html000066400000000000000000000251361234404334100150570ustar00rootroot00000000000000 yao::home

HOME   |   INSTALL   |   MANUAL   |   NEWS

Introduction

These pages present information about yao, a Monte-Carlo simulation tool for Adaptive optics (AO) systems. Yao is open source released under the GPLv3. You are welcome to use it, expand it and even distribute it, but please link back to this page, as I am releasing updates semi-regularly. The last version of yao (big release, lots of new stuff) to date (July 2010) is 4.6.0. Looks here for the latest news.

Main features

Yao is a Monte-Carlo AO simulation tool. It uses a number of custom developed functions to simulate wavefront sensors (WFS), deformable mirrors (DM) and many other aspects of an AO loop.

Highlights

  • Coded in yorick, a open source scripting language similar to IDL or mathlab (powerful and free!). The core, CPU intensive routines are coded in C. Yorick and the YAO plugins are written in ANSI-C, which makes them portable on many platforms. YAO should run on any *nix platform, including Linux, Mac OsX, BSD, cygwin, etc... It may also work on windows, but I have never tried.
  • Shack-Hartmann, Curvature and Modal (Zernike) WFS, ON or OFF axis, are supported. It is also possible to add your own WFS NEW 4.5.
  • Stackarray (piezostack), curvature (bimorph), segmented NEW 4.5, (experimental), modal (zernike, disk-marmonic NEW 4.6 or KL) and Tip-Tilt deformable mirrors are supported. The altitude of conjugation is adjustable. It is also possible to add your own DM NEW 4.5.
  • Various reconstructors: least-square with truncation (SVD) and MMSE-like. MMSE can use either full matrix or sparse methods (fast). Users can hook into yao and use their own code to compute the reconstructor NEW 4.5.2
  • An arbitrary number of WFSs and DMs can be used, with the possibility of mixing types. It is therefore possible to simulate single DM systems, as well as single non-zero conjugate, GLAO and MCAO systems.
  • It supports Natural and Laser Guide Stars (or a mix).
  • It supports photon and read-out noise.
  • It uses a multi-layered atmospheric model, with geometrical propagation only.
  • The loop execution has been optimized for speed: the critical routines have been coded in C. Yorick is thus used as a convenient "glue" between lower levels optimized C calls. Overall, this is rather efficient: A simple 6x6 Shack-Hartmann system (geometrical model, no diffraction) runs at over a 1000 iterations/seconds on modern machines (about 250it/sec for a full diffractive SHWFS). That's including turbulent phase computation, wavefront sensing, reconstruction, calculation of the DM shape and PSF/performance estimation. A 50x50 Shack-Hartmann (full diffraction model) system runs at about 10 iterations/s for an 8-m telescope. A 188 curvature system runs at over 40 iterations/s (see the this entry for more details). Medium-size AO systems for ELTs can also be simulated, but it takes more time and RAM (a 60x60 SH on a 960 pixel pupil runs at about 1 iteration/s and takes up to 2GB of RAM at peak usage).
    Update: yao 4.6.0 brings parallel computation! See this post in the news. On modern hardware, it is now possible to simulate up to 200x200 SHWFS (1 iteration/s). A 64x64SHWFS runs at 23 iterations/s).
  • Straightforward scriptability to probe parameter space.
  • An (optional) GTK GUI provides a convenient interface. One can, e.g., change some of the system parameters while the loop is running. This provides an educational approach to Adaptive Optics (newbies can play with the parameters and immediately sees how the system reacts) and can also provides a quick way to investigate the stability conditions for a newly designed system, before entering more serious Monte-carlo simulations. Note that because the GUI is GTK-based, it requires the gnome libraries. These come automatically in Linux and BSD, but are a bit more challenging to install on OsX (but possible with macport or fink). Note that the GUI is not essential to run YAO.

Other capabilities

  • Arbitrary aperture shape (defined through a user plugin). Disk with central obstruction is the stock pupil, but examples are provided to create segmented or GMT like pupils.
  • Partitioning of DMs and WFSs in independent subsystems (e.g. for separate control of TT in LGS systems)
  • 2 methods for Shack-Hartmann:
    1. Simple gradient average, no noise, very fast: This allow to do tests of the noiseless performance of a system, for quick performance evaluation of system dimensioning
    2. Full propagation, with subaperture image formation. Includes adjustable subaperture and pixel size, photon and read-out noise, bias and flat field errors, thresholding, convolution by a gaussian kernel and image elongation in the case of LGS. Proper overlap between subapertures and possibility to put a field stop with adjustable shape, size and position NEW 4.5 .
  • Separately adjustable integration time for each sensor
  • Adjustable frame delay (in integer unit of the quantum loop time)
  • Anisoplanatism modes for MCAO
  • Leaky integrator control law, up to 10th order NEW 4.5
  • DM Hysteresis
  • DM saturation
  • Separate loop gain per DM
  • Adjustable DM sensitivity (micron/volt) to hook to real systems
  • Adjustable subaperture and actuator validation thresholds
  • Adjustable multi-wavelength, multi-position performance estimate
  • "Skip and reset" along the phase screens at adjustable interval, to reach statistically significant performance estimates faster
  • Uplink tip-tilt correction for LGS
  • Adjustable LGS Elongation
  • Rayleigh Fratricide effect for multiple sodium beacon systems
  • Extrapolated actuators
  • Centroid Gain optimization, using LGS dithering (only for LGS + Shack-Hartmann)
  • Parametrizable vibration spectrum: white, 1/f, peaks with adjustable rms and width NEW 4.5
  • Lots of internal variables are accessible from the outside of the program for debugging/implementation of new features

Comments and shorcomings

  • Dependency on FFTW for the fast FFT C implementation.
  • Dependencies on the following yorick packages: yutils (general utilities, v≥1.3), imutil (image manipulation, v≥0.5), soy (sparse operations with yorick, v≥1.2) and svipc (v0.9)
  • The set-up routines (aoinit) have not yet been optimized for speed, thus, in particular, inverting large matrices can take some time. This optimization may come in due time, if deemed necessary.
  • There is no GUI to configure the systems. The parfile has to be edited manually, which in my view is not a big deal and actually allows for more compact & clever parfiles, as yorick loops can be used to set repetitive variables.
  • Some work has been done with pyramid WFS but no has not been maintained and does not work in the current version
  • Scintillation is not supported, as it has been shown by many studies to be negligible at NIR wavelengths.
  • Command matrices are up to now computed as least-square estimates. Implementation of minimum-variance or MAP should come shortly.

Where to start?

Browse this site. Have a look at the manual. If you like what you see, go to the Installation page and follow the instructions.

Once the package is installed, follow the manual instruction, and use the examples parameter files to create your own parfile to model your system.

yao-5.4.0/doc/installation.html000066400000000000000000000141311234404334100164420ustar00rootroot00000000000000 yao::installation
HOME   |   INSTALL   |   MANUAL   |   NEWS

Installation overview

These instructions have been updated on 12 October 2009.

Basically there are three install methods (pick one):

  1. From source. You'll get the latest version of everything. Not too many dependencies to yao, so it's not too challenging. You will need a C compiler, or
  2. using yorick's pkg_mngr. or
  3. on several Linux distributions (Ubuntu, Archlinux, Fedora), using the distribution package manager (apt-get/synaptic, pacman,yum)
Yorick/yao generally install without problem on any recent flavor of Linux or osx. As usual, it will work better if your OS is up to date and not too old. Note that yorick, as it is written in ANSI-C, should basically compile on any xorg-enabled platform with a gcc compiler. The same goes for FFTW, and yao (except the optional gtk interface, which requires gtk libraries and, mostly, a whole gnome environment).

Option 1: From Source

Installation from source presupposes a basic familiarity with the command line environment. In the following, I give instructions that should be enough to get you out of troubles. The process is essentially the same whatever OS you're on:

  1. Install yorick (howto)
  2. Install the plugins yorick-yutils≥1.3, yorick-imutil≥0.5 (howto), yorick-soy≥1.2 if you plan to use the sparse matrices techniques and yorick-svipc≥0.9 if you wish to use the parallel features
  3. Install FFTW (howto)
  4. Finally, install yao (howto)

Detailled instructions are here. Once you are done, proceed to the test section.

Option 2: Using yorick's pkg_mngr

This method does not install yorick; only yao and its dependent plugins and libraries (refer to method 1 or 3 if you need to install yorick).

Using pkg_mngr should be very simple. One thing though: the pkg_mngr binary packages are not always up to date; they are released for a number of binary platforms (osx and linux: ppc, i386/x86 and amd64/x86-64), but because I'm the sole maintainer and there are so many platforms, I am often short of time or machine availability to update all plugins (in particular, I do not have access to PPC anymore). Nevertheless, it should generally work. The bonus of this approach is that it also include static libraries for the dependent packages (e.g. FFTW), so the install is much streamlined. Yorick's pkg_mngr is safe: it will only install things in your yorick tree. There's also a "remove" option so you will always be able to come back if anything goes wrong.

The instructions are simple:

$ yorick
> #include "pkg_mngr.i"
> pkg_setup

Except for the OS field, all the default should be ok, so just type return everywhere. When prompted about your OS:

  What is your OS-machine type?
    (1) darwin-i386
    (2) darwin-ppc
    (3) linux-x86
    (4) linux-ppc
    (5) linux-amd64
    (6) darwin10-x86_64
  PKG_OS (enter a number):
Just type the corresponding number (note that darwin = OsX).Then:
> pkg_sync
> pkg_list
> pkg_install,"yao"
This will fetch and install yao and its plugins dependencies (yutils and imutil). You will have to quit yorick and restart for it to find yao. Proceed to the test section.

Option 3: Using your Linux package manager

For the easiest way to install yao, the winner is debian (and debian derivatives, e.g. Ubuntu):

sudo apt-get install yao
and then yao to run it (with the gtk GUI). Easy, but you won't get the very last version. For instance, I just release 4.5.0 and I am fairly sure it won't make it in Debian/Ubuntu before a few months. I have also built packages for Fedora and Mandriva, but I am afraid I haven't updated it lately (if you want to try it, the instructions are here. These are the repos for yorick, but also include the plugins, and yao in particular). For archlinux (these ones are fresh as of october09), look here.

Test it

However you have installed yao, it should have created an "examples" directory with many example parameter files (use the command find_examples_path() within yao to print the path to the example directory).

To test yao:

cd yao_examples_directory  (see above)
yorick -i test-all.i
There is also some tests functions for the SHWFS (shwfs_tests() for general sh_wfs testing and svipc_shwfs_tests for testing the wfs.svipc features (parallel extension). Use help,function for the usage of these 2 functions.
yao-5.4.0/doc/installation_details.html000066400000000000000000000117121234404334100201510ustar00rootroot00000000000000 yao::install from source
HOME   |   INSTALL   |   MANUAL   |   NEWS
This page contains somewhat detailled instructions to install yorick, the yorick plugins and FFTW3 from source.

Yorick

Download the latest Yorick distribution from the yorick site. Installation is straighforward (see the README file in the main distribution directory). I suggest you install yorick in ~/yorick-version_number (just put, e.g. yorick-2.1.05.tgz in your home directory, gunzip and untar). If you already have yorick installed you may of course skip this last point.

Configure, build and install yorick. Out of the many ways to do this, I suggest:

cd ~/yorick-2.1   (or wherever you put it)
make Y_HOME=`pwd` ysite
make config
make
make install

I recommend to build yorick and the plugins with "CFLAGS=-O2".

yorick should be in ~/yorick-2.1/bin/. Remember to add this to your PATH, e.g., if you use bash (put this at the end of you .bashrc -Linux- or .profile -OsX-):

export PATH=${HOME}/yorick-2.1/bin:${PATH}
An very convenient addon, that will save you tons of time, is rlwrap. If you runs yorick within rlwrap, it will provide command line editing and recall, command and filenames completion, etc... I have defined an alias (bash) for yorick as follow:
alias yorick='rlwrap -s 2000 -c -f ~/.yorick/yorick.commands yorick'

Yorick Plugins

Installing yorick plugins follow fairly generic rules:
  1. Download the plugin (raw list, webpage). Make sure you get the last version. For yao, as said elsewhere, you will need yutils, imutil and, optionally, soy. And of course yao itself.
  2. You can expand the plugin and build it from anywhere. However, to keep traces and keep the original, I recommend to put it in Y_HOME/contrib (Y_HOME is where your yorick is, i.e. ~/yorick-2.1). Create the contrib directory if it doesn't exist.
  3. gunzip and untar the file downloaded in (1), cd in the plugin directory
    tar zxvf plugin-version-src.tgz
    cd plugin-version
  4. Update the makefile to work with your yorick:
    yorick -batch make.i
  5. if the plugin has dependencies, and the dependency libraries/headers are not in a standard place, you may need to edit the Makefile and change CFLAGS and LDFLAGS to accommodate these paths.
  6. Build and install the plugin:
    make
    make install
    sudo the last comment if yorick is install system-wide.
  7. You're done. Most plugins usually have some check.i or test.i of some form. Check in the directory and run it to check everything is working:
    yorick -i check.i
Technical details: a yorick plugin generally consist of some C files and yorick include files to go with it. Building the plugin means compiling the C files for your machine/OS/architexture/libraries. A plugin will install files within and only within your yorick directory tree: in i, i0 and lib, and in some cases also in python, share, etc (still under Y_HOME).

FFTW3

Not much to say here. These days, the FFTW install is generally flawless.
  1. Download it from here
  2. gunzip, untar, cd into fftw directory
  3. Run the canonical (note the enable-float flag)
    ./configure --enable-float
    make
    make install
You may also specify a prefix=/some/path in configure if you don't have root access on your machine.

Yao

Yao is a plugin, thus I refer you to the plugin instructions above.
yao-5.4.0/doc/manual.html000066400000000000000000003406341234404334100152300ustar00rootroot00000000000000 yao::manual
HOME   |   INSTALL   |   MANUAL   |   NEWS

This manual is for yao v4.5.0. It was almost entirely re-written from previous versions. Written by Francois Rigaut on November 2009. Expand/Collapse all detailled comments.

A session at a glance...

A basic yao session

... consist of a few steps:

  1. Craft up a parameter file describing the system you want to model, say "mysystem.par"
  2. Start yorick/yao
  3. aoread,"mysystem.par"
  4. aoinit,some keywords...
  5. aoloop,some keywords...
  6. go

Let us now enter into some details.

The Basics

Is yorick installed ? All set up as per the installation instructions ? Then go to the examples directory of the yao distribution; this might be in different locations depending on how you installed yao. To determine where is it is, run the command find_examples_path() within yao. Type the following at the unix prompt:

poliahu:~ $ yorick -i yao.i
 Copyright (c) 2005.  The Regents of the University of California.
 All rights reserved.  Yorick 2.1.05x ready.  For help type 'help'
 Yao version 4.5.0, Last modified 2009oct23
>

You get the yorick and yao welcome messages and the yorick prompt. Alternatively, you can start a normal yorick session and then include yao at any time by typing:

> #include "yao.i"

You can double check everything is normal by typing:

> info,aoread
func aoread(parfile)

if you get this message, you are in business. If not, fix your yorick installation. Click here to show/hide notes on Yorick.

The first thing to do is to create phase screens (to simulate turbulence). Type

> create_phase_screens,2048,256,prefix="screen"

This will create N (N=long dimension/short dimension, 8 in that case) phase screens of dimension 2048x256 suitable for use by yao. It is advised to choose dimensions that are powers of 2. Depending on your platform and CPU, it may take some time (1mn or so), as this routine is absolutely not optimized. This is a one shot run. You will not need to do that everytime you run yao, as you can, and are encouraged, to use the same phase screens. You may need to run it once more to create larger phase screens if the need arises, but that's about it. The phase screens (screen1.fits to screen8.fits in the example above) will be created in the current working directory. Move them somewhere convenient (I have them in Y_USER/data=.yorick/data in my case). You will need to edit the yao parameter files to reflect the path and names of these phase screens if you put it somewhere different or used a different name (look for "atm.screen" in the parfile).

Next, we will try to run "sh6x6", which is a simple 6x6 Shack-Hartmann example. After you have edited the "sh6x6.par" file (in the examples directory) and modified the path and filename of the newly created phase screens, if needed, type:

> aoread,"sh6x6.par"
Yao, Version 4.5.0, 2009oct23
Checking parameters ... 
No field stop defined for wfs 1. Setting to 'square'
wfs(1).fssize has not been set, will be forced to subap FoV
dm(1).coupling set to 0.200000
dm(1).iffile set to sh6x6-if1.fits
dm(2).iffile set to sh6x6-if2.fits
OK
>

What aoread() does is (a) read, or rather include, the parameter file, which will fill the various structures containing the definitions of the WFS, DM, loop, etc... and (b) go through a simple check of the parameters to see if anything is missing or if there are incompatible assigments, in which case it will print out an error message (hopefully understandable). Otherwise, it prints out informational messages or warnings.

Then we need to initialize the system. aoinit() will do that for us. It will initialize all the arrays (pupil, etc), initialize the system pupil, the various WFS, DM, etc. It will then compute the interaction matrix, invert it and finally plot (if requested) a graphical system configuration. The amount of information you get during the aoinit is set by sim.verbose. The default verbose in sh6x6.par is 0, which means you get no feedback at all except for warnings and error messages. Let's set sim.verbose to 1 and run aoinit():

> sim.verbose=1
> aoinit,disp=1,clean=1
Checking parameters ... 
OK
 
> INITIALIZING PHASE SCREENS
Reading phase screen "~/.yorick/data/screen1.fits"
Reading phase screen "~/.yorick/data/screen2.fits"
Reading phase screen "~/.yorick/data/screen3.fits"
Reading phase screen "~/.yorick/data/screen4.fits"
 
> INITIALIZING SENSOR GEOMETRY
Kernel FWHM for the iMat calibration = 0.364983
Pre-computing Kernels for the SH WFS
 WFS# |       Pixel sizes         | Subap. size | Number of pixels | #photons
      | Desired  Quantum  Actual  | Max  Actual | Desired   Actual | /sub/iter
 1      0.20000  0.03182  0.19093   2.04  1.91    10x10      10x10   70735.5
NGS#1 flux varies between 42795 and 70736 photon/subap/it
 
> Initializing DM influence functions
  >> Computing Influence functions for mirror # 1

Creating Influence function for actuator #1 2 3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
36 37 38 39 40 41 42 43 44 45 46 47 48 49  

  >> Storing influence functions in sh6x6-if1.fits... Done
  >> Computing Influence functions for mirror # 2

  >> Storing influence functions in sh6x6-if2.fits... Done
 
> DOING INTERACTION MATRIX
  DM #1: # of valid actuators: 45. (I got rid of 4 actuators after iMat)
  >> valid I.F. stored in sh6x6-if1.fits
Computing valid to extrap. matrix for DM#1
 
> INITIALIZING MODAL GAINS
I did not find simulModeGains.fits or it did not have the right
   number of elements (should be 47), so I have generated
   a modal gain vector with ones in it.

 
> INTERACTION AND COMMAND MATRICES
 >> Preparing SVD and computing command matrice
Smallests 2 normalized eigenvalues = 0.014315    1.62232e-07
4 modes discarded in the inversion
 
Summary:
Mirror #1, stackarray, 45 actuators, conjugated @ 0 m
Mirror #2, tiptilt, 2 actuators, conjugated @ 0 m
WFS # 1, hartmann (meth. 2), 32 subap., offaxis (+0.0",+0.0"), noise enabled
D/r0 (500nm) = 42.4; 5000 iterations
> 

At this point you have initialized everything. The aoinit() keyword clean indicates that you want to start from scratch, and ignore any influence function or interaction/command matrix files on your disk. The disp=1 is to get some graphical feedback. You are now ready to run the loop:

> loop.niter = 1000
> aoloop,disp=10
NGS#1 flux varies between 42795 and 70736 photon/subap/it

> Starting loop with 1000 iterations
> go
 Iter#  Inst.Strehl  Long expo.Strehl  Time Left
     1  0.000        0.000             00:00:18.8
    51  0.407        0.393             00:00:15.1
   101  0.412        0.410             00:00:13.7
   [...]
   901  0.647        0.504             00:00:01.4
   951  0.546        0.507             00:00:00.7
Saving results in /home/frigaut/yorick-2.1/share/yao/examples/sh6x6.res (ps,imav.fits)...
time(1-2) =  9.49 ms  (WF sensing)
time(2-3) =  0.03 ms  (Reset and measurement history handling)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  1.85 ms  (DM shape computation)
time(5-6) =  1.44 ms  (Target PSFs estimation)
time(6-7) =  1.53 ms  (Displays)
time(7-8) =  0.05 ms  (Circular buffers, end-of-loop printouts)
Finished on 00:26:30
69.040800 iterations/second in average

         lambda   XPos   YPos  FWHM[mas]  Strehl  E50d[mas]  #modes comp.
Star# 1    1.65    0.0    0.0       44.1   0.507      172.0         35.1
Field Avg  1.65                     44.1   0.507      172.0
Field rms                            0.0   0.000        0.0
> 

You have ran 1000 iterations (loop.niter in sh6x6.par is larger so we changed it before starting the loop in the example above to keep your demo time reasonable -note if you want to make it larger than the initial value, you will need to re-run aoinit()). disp=10 in the call means "do your displays every 10 iterations". Depending on your graphic card, displays can be pretty expensive (time), thus it helps to display less frequently.

At any time, while the loop is running, you have access to the yorick prompt. You can type regular commands, but the most useful are:

  • stop which will pause the execution of the loop,
  • cont which will resume the loop where it paused,
  • reset which will reset commands and dm shape,
  • restart which will restart from iteration 1.

at the completion of the requested number of iterations, go() will automatically call the function after_loop(), which outputs a number of things as shown above (starting from "Saving results..."): Some statistics on execution time and number of iterations per seconds, and the Strehl, FWHM, etc, on every "target" for which positions were specified in the parameter file. You can call after_loop() by hand at any time also, and you can call it multiple times.

The resulting average images have been saved on disk ("sh6x6-imav.fits"), together with a small postscript file ("sh6x6.ps") that contains some graphics. Strehl, FWHM and 50 percent encircled energy are available as extern variables under the name strehl, fwhm and e50 (the averaged PSFs are also available, together with the history of DM commands, DM errors and WFS measurements if the keyword savecb= has been set):

> strehl
[[0.434317]]

These variables contains the values for all the images (here there is only one, but there can be an arbitrary number of positions and wavelengths at which you want to estimate the performance). This can be useful in script, as detailled below.

Finally, note that you can have access to some documentation on each function by typing help,function_name, e.g:

> help, aoinit
 /* DOCUMENT aoinit(disp=,clean=,forcemat=,svd=,dpi=,keepdmconfig=)
    Second function of the ao serie.
    Initialize everything in preparation for the loop (aoloop).
    Follows a call to aoread, parfile.
 
    disp         = set to display stuff
    clean        = if set, aoinit will start fresh. *Nothing* is kept from
[...]
Tip: sometimes the document section of a function is not up to date. You can get a peek on the actual function API by using info:
> info, aoinit
func aoinit(disp=,clean=,forcemat=,svd=,dpi=,keepdmconfig=)

The Parameter File

Here is an example of a parameter file (parfile). Comments below.

// YAO parameter file
//-------------------------------
sim.name           = "SH6x6 w/ TT mirror and WFS, full diffraction WFS";
sim.pupildiam      = 120;
sim.debug          = 0;
sim.verbose        = 0;

//-------------------------------
atm.dr0at05mic     = 42.44;  // this is r0=0.166 at 550 nm
atm.screen	   = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits");
atm.layerfrac      = &([0.4,0.2,0.3,0.1]);
atm.layerspeed     = &([11.,20,29,35]);
atm.layeralt	   = &([0.,400,6000,9000]);
atm.winddir        = &([0,0,0,0]);

//-------------------------------
nwfs               = 1; // number of WFSs (>1 if e.g. mcao)
wfs                = array(wfss,nwfs);

wfs(1).type	   = "hartmann";
wfs(1).lambda	   = 0.65;
wfs(1).gspos       = [0.,0.];
wfs(1).gsalt       = 0.;
wfs(1).gsmag       = 5.;
wfs(1).shmethod	   = 2;
wfs(1).shnxsub	   = 6;
wfs(1).pixsize     = 0.2;
wfs(1).npixels     = 10;
wfs(1).noise       = 1;
wfs(1).ron         = 3.5;
wfs(1).shthreshold = 0.;
wfs(1).nintegcycles= 1;
wfs(n).svipc       = 2;

//-------------------------------
ndm                = 2;
dm                 = array(dms,ndm);

n  =1;
dm(n).type	   = "stackarray";
dm(n).iffile	   = "";
dm(n).nxact	   = 7;
dm(n).pitch	   = 20;
dm(n).alt          = 0.;
dm(n).unitpervolt  = 0.01;
dm(n).push4imat    = 100;

n  =2;
dm(n).type	   = "tiptilt";
dm(n).iffile	   = "";
dm(n).alt          = 0.;
dm(n).unitpervolt  = 0.0005;
dm(n).push4imat    = 400;

//-------------------------------
mat.condition      = &([15.]);

//-------------------------------
tel.diam	   = 7.9;
tel.cobs	   = 0.1125;

//-------------------------------
target.lambda	   = &([1.65]);
target.xposition   = &([0.]);
target.yposition   = &([0]);
target.dispzoom    = &([1.]);

//-------------------------------
gs.zeropoint	   = 1e11;

//-------------------------------
loop.gain	   = 0.6;
loop.framedelay    = 1;
loop.niter	   = 5000;
loop.ittime	   = 2e-3;
loop.startskip     = 10;
loop.skipevery     = 10000;
loop.skipby        = 10000;
loop.modalgainfile = "simulModeGains.fits";

//-------------------------------

The parfile defines entirely your system. As you see, it is made of several (9) subsections, in which the 9 main yao structures are filled. All of the structure members are listed in the yao structure section, together with a short explanation of each parameters (structure member). How to combine these parameters to get yao to do what you want is explained in the controlling features section below.

Several comments:

  • A parfile, and the one above in particular, does not have to include all parameters. Only a few are mandatory for each elements (WFS, DM) and the rest have reasonable defaults.
  • The parfile is in fact a yorick include file, and those are yorick statements you see in there. So you can make use of yorick loops, etc (see for example mcao2-bench.par on how the wfs structure is filled).
  • Because they can have variable length, and be dynamically re-defined, many structure members are actually pointers (to vectors or arrays). A pointer in yorick is assigned with the symbol & so that &a is the pointer to the quantity a. The notation
    atm.layerfrac = &([0.4,0.2,0.3,0.1]);
    is a shorthand for
    a=[0.4,0.2,0.3,0.1];
    atm.layerfrac = &a;
    If you forget the & sign, it should generate an error.
  • There are about 20 parfiles in the example directory (remember? find_examples_path() will tell you where this directory is). Browse through these examples. It is recommended to actually start from one of these, preferably one that is close to the system you want to simulate, and adapt it to your needs, rather than starting from scratch.
  • Once you are done, save the parfile and, in the same directory, start yao and go through the sequence of aoread(), aoinit(), aoloop() and go() as shown in section 1.

Controlling Features

Overall Geometry

In yao, you have to define the AO system you want to simulate. It starts by defining an entrance aperture (the system pupil). This is done through 2 parameters: the physical pupil size (e.g. diameter) in real world units, meters. And because yao is a monte-carlo code, that uses arrays to generate phases and PSFs, we will need a pupil array and thus a pupil diameter in pixel.

sim.pupildiam  <- this is the pupil diameter in pixel (unitless)
tel.diam       <- this is the telescope diameter in meters

Typical geometry of a system (WFS and DM)

yao also uses arrays to store the deformable mirror influence functions, etc. Generally speaking, there are two types of variable and arrays: the one referring to quantities in the near field (pupil plane or close to it, e.g. altitude layers) and the one referring to quantities in the far field (Shack-Hartmann WFS spots, PSF image, observed object, etc...).

The figure on the right illustrates how you can set up a Shack-Hartmann + Stackarray deformable mirror (allegedly the most common type of AO system to date). I will review all these parameters in sections below, but what I want to emphasize here is the following:

  • The pupil is defined on a pixel array
  • The WFS has to be defined (at least SHWFS) to span an area commensurate with the pupil (see below). However, it is possible to slightly oversize, downsize or even shift the WFS w.r.t. the pupil, if needed.
  • The DM actuator positions and span also has to be defined to span an area commensurate with the pupil and WFS (see below). For a stackarray mirror, for instance, you typically want to have the DM pitch equal to the subaperture size (it doesn't have to be, but it is often the case). As for the WFS, you have the possibility to mismatch WFS and DMs by choosing a different pitch, or shifting the DM to induce misregistration.

Field of view considerations

The size of the pupil is actually quite important. By property of the Fourier transform, the field of view in the far field will be defined by the sampling in the near field, following the relation:

FoV = lambda/ps
where ps = tel.diam/sim.pupildiam is the pixel size in meter in the near field. So, for instance,

tel.diam [m]sim.pupildiam [pixels]FoV @650nm ['']FoV @1.65microns ['']Comment
8128 2.145.44
302561.142.90Probably too low
305122.285.80

Choose the field of view according to your application. But because eventually you will want to run simulations in presence of turbulence, I generally advise to take at least 2 points per r0 (near field), and preferably 3. For r0 = 16 cm, that means a sampling of 8 cm (resp 5.33 cm), and for a 8-m telescope that would translate into 100 points (resp 150) across the pupil (sim.pupildiam = 100). If this is not done, you will likely end up with aliasing in the SHWFS subaperture images (probably less so in the final image if it is estimated in the Near Infrared and the WFS works in the visible). This is bad and will bias your results. You have been warned.

Pupil

Historically, yao was developed assuming circular pupils. So in any case, as said above, you will have to define sim.pupildiam and tel.diam. If another pupil shape is desired, it can be defined through a call to a user defined function user_pupil(). Click here to show/hide an example.

Wavefront Sensors

Shack-Hartmann WFS

Set wfs.type="hartmann". The only other mandatory parameters to define are wfs.shnxsub, wfs.npixpersub, wfs.npixels, wfs.pixsize and wfs.lambda. Below I expand on these parameters.

Near Field

The near field parameters that need to be defined are:

  • wfs.shnxsub: The number of subapertures in the aperture diameter
  • wfs.npixpersub: The number of pixels across one subaperture, in the near field.

For a "normal" system, we want wfs.shnxsub * wfs.npixpersub = sim.pupildiam. But as said above, you can make npixpersub larger or smaller if you want to investigate the effect of subapertures larger or smaller than ideal. Also, by setting wfs.pupoffset [meter], you can investigate the effect of misregistration of the WFS w.r.t the entrance pupil (Show/Hide details).

Far Field

The far field parameters to define for a SHWFS are:

  • wfs.npixels: The number of (CCD) pixel per subaperture in the far field
  • wfs.pixsize: The SHWFS (CCD) pixel size, in arcsec.

So that of course, the subaperture field of view will be wfs.npixels * wfs.pixsize. The whole discussion about sampling above of course applies here too, and field of view can not be arbitrary large. The pixel size is also constrained by FFT properties, and yao will round the pixel size you have selected to the nearest possible value (this should be printed out on screen during aoinit if sim.verbose>=1).

Field Stops

Since v4.5.0, yao can handle field stops (before also, but not in the same easy fashion), defined using the parameters wfs.fstop, wfs.fssize and wfs.fsoffset. You have the choice between no field stop (wfs.fstop="none"), or a square or round field stop (wfs.fstop="square" or "round"). If needed, you can use your own defined geometry by setting wfs.fsname to the name of a fits file that contains the image of a field stop (show/hide how). The default is to use a square field stop of size equal to the subaperture field of view (i.e. optimal).

Subaperture Coupling

Shack-Hartmann focal plane features

Since v4.5.0, yao correctly includes coupling between neighbor subapertures: In a real system, if there is no field stop, the spot image of a subaperture can wander into a neighbor subaperture and wreak havoc the slope estimation. yao now correctly handle this behavior: all subaperture images are computed, then added to an image that will include all spots. When all spots have been computed, each spot image is extracted and the spot position is estimated from there (center of gravity, soon to come weighted CoG, etc...).

Graphic configuration

When the correct debug setting is selected (sim.debug>=1), aoinit() will display a SHWFS far field graphic configuration diagram as shown on the right (click on it to enlarge). Reported on it are:

  • The SHWFS image. This image is accesible to the user in *wfs._fimage, if the need arises. This image includes the spots from all subapertures, including the ones which are not "valid" (because their fractional flux is lower than wfs.fracIllum). The valid subaperture spots are indicated by the thin grey squares.
  • For one spot, the diagram plots :
    • the subaperture effective field of view (green square),
    • the total field of view spanned by this subaperture (see discussion on field of view above), in which the spot can wander (red square) and
    • the outline of the field stop (in magenta).

Curvature WFS

Set wfs.type="curvature". The only other mandatory parameters to define are wfs.l, wfs.nsubperring and wfs.lambda:

CWFS Subaperture map

  • wfs.l is the extra focal distance in an F/60 beam. The first curvature system for astronomy, the UH13, had a WFS input beam of F/60 (on the membrane mirror), and thus use to define extra focal distance in a F/60 beam. I wrote aosimul, the precursor to yao, to model PUEO, the curvature system for the CFHT, which was largely based on UH13. So from then on, to have a common ground, I (and other people) used to quote extra focal distances in a F/60 beam. It is easy to make the conversion to another F ratio, but yao only handles these units.
    Note that the extra-focal image is computed as the Fresnel diffraction of the pupil complex amplitude, using the following algorithm:
    • Fourier Transform the pupil complex amplitude
    • add a quadratic (focus) term with amplitude alpha
    • Fourier transform back
    What you get after that is a defocused pupil image. This has limitations. For instance, it is not possible to compute an image too close to focus, as this would imply alpha = ∞. Of course, this depends of the sampling in the near field, but typically, one can cover reasonable extra focal distances of 5-10cm up (typical systems like PUEO use 15-20cm depending on the seeing, NICI on Gemini uses 40cm).
  • wfs.nsubperring: typically, to date, most of the curvature WFS for astronomy were based on a polar design: rings of subapertures. wfs.nsubperring is a pointer to a long vector that contains the number of subaperture per ring: the first element is the number of subapertures in the first ring, the second element the number of subaperture in the second ring, etc.. so that wfs.nsubperring could look like &([6,12,18]) for a system with 3 rings of with 6, 12 and 18 subapertures (the & is because wfs.nsubperring is a pointer). yao automatically computes the inner and outer radius of each ring so that every subaperture receives the same amount of light. The user can modify this behavior by setting wfs.rint and wfs.rout to speficy the inner and outer radius of each ring. (show/hide details).

Pyramid WFS

Briefly: The Pyramid WFS, in yao, is defined very similarly to the SH WFS. You have to define wfs.shnxsub (# of subapertures in pupil diameter), and the number of pixels in the pupil/phase plane per subaperture, wfs.npixpersub. For instance, if you want to simulate a pyramid WFS with 8x8 "subapertures" (pixels in pupil image), you can use: wfs.shnxsub=8, wfs.npixpersub=8, in which case sim.pupildiam=64. Currently, we can't have sim.pupildiam != wfs.shnxsub * wfs.npixpersub.

Other parameters used by the pyramid WFS only are listed in the structure table below. They are commented and fairly self-explanatory. Note that it is important (and required) to set a field stop when working with pyramid wfs in yao. The way it's implemented, the execution speed depends on the field stop diameter, so don't be surprised. Use a field stop large enough to avoid aliasing and growth of waffle like modes.

Zernike WFS

Set wfs.type="zernike". The only other mandatory parameter is wfs.nzer, which, as its name says, define the number of zernike in the WFS. Note that this include piston, so wfs.nzer=11 would include up to spherical (included). Important note: The Zernike are the Noll Zernike (see Noll 1976), which are not the standard Zernike, but the one used most commonly in AO. Normalization??

User defined WFS

Set wfs.type="name_of_your_function".

Users can define their own WFS, to be integrated into the yao flow. The API are relatively straighforward:

func user_wfs_func(ipupil,phase,ns,init=)
where
  • ipupil and phase are the pupil and phase (size sim._size),
  • ns is the WFS number (as defined in the parfile), and
  • init is just a flag set the first time this function is called (in aoinit()) that allow the user function to make some initializations, if needed.

The function should return a measurement vector (show/hide example).

Photometry and noise

Photometry and noise are only relevant (and implemented) for Shack-Hartmann and Curvature WFS.

All the photometry is controlled with the wfs.gsmag, wfs.skymag and wfs.zeropoint. wfs.zeropoint is defined in photons/second/full_aperture (incident on the telescope aperture, i.e. after crossing the atmosphere). Note that this depends on the telescope diameter (may be it was a bad choice to define it like that, but now it's done). It is simple enough to convert known photometric zero point to yao zeropoint. The number of photons available for WFSing is derived from this zeropoint and the above mentioned magnitude following regular equations (see also wfs.optthroughput).

yao doesn't have a concept of ADU. Or rather, I am assuming one electron/ADU across the board. So the signal in in electrons, and the noise is also in electrons.

Deformable Mirrors

The deformable mirrors are entirely and solely defined through their influence functions (shape and location). During the aoinit() phase, yao calls DM influence function definition functions, for each DM in the parameter file. Once computed, the influence functions are stored in the dm structure (*dm._def) and saved on disk for future runs (name-if#.fits files). Note that if you have a set of commands, you can get the DM surface by calling

surf = compute_dm_shape(nm,command_ptr);

where command_ptr is a pointer to a float vector containing the DM commands (e.g. command_ptr = &(float(indgen(dm._nact)))).

Stackarray (PZT,SAM,Piezo) DM

Set dm.type="stackarray". The only other mandatory parameters for stackarrays are dm.pitch and dm.nxact.

Dimensioning

dm.nxact sets the number of actuators in the diameter of the DM (along the X or Y axis). This includes extrapolated/slaved actuators/guard rings.

dm.pitch sets the pitch (i.e. interactuator distance) in near field pixels.

Note that you have to dimension the stackarray DM according to your base system definition (sim.pupildiam). If you set sim.pupildiam=60 and dm.nxact=7 and you do not desire an extra ring of actuator, then you should set dm.pitch=10 to span the entire pupil diameter (7 actuators, 6 spaces between actuators...).

Influence functions

This was the first type of DM implemented in yao. With time, we have implemented several type of influence functions. By default, it uses a functional form which was first derived by J.-P. Gaffard of then CGE (now CILAS) to fit ZIGO measurements of CGE DM's real influence functions. It is possible to use newer (but not necessarily better) forms by setting dm.irexp:
dm.irexpfunctional form
0Old, adhoc functional form fitted on actual ZIGO data
1exp(-(d/irfact)^1.5)
2sinc*gaussian

irfact is set through dm.irfact.

Actuator Coupling

You can set the inter-actuator coupling with dm.coupling. dm.coupling=0.3 means 30% coupling between an actuator and its nearest neighbor. Typical value are 0.1-0.4. The almost universal consensus nowadays is to use coupling values of about 0.3.

Saving RAM & Disk with dm.elt

Stackarray mirrors have very local influence functions. Therefore, for large number of actuators, most of the surface of the DM is zero. It is thus a big waste of RAM and disk (these influence functions take a lot of space). Enabling dm.elt will save most of this space back: only a small subsection of the whole DM surface is kept, surrounding the actuator. The coordinates of this subimage is kept, and used later by comp_dm_shape() to compute the correct DM shape. The call to comp_dm_shape() is transparent. Depending on the value of dm.elt for the current DM, comp_dm_shape() will call the relevant C routine. In fact, there is no compromise in setting dm.elt, but its benefit really only show up for large stackarray DM (dm.nxact≥10).

Extrapolated/Slaved actuators

The idea in yao is to define all of your stackarray mirror in your parameter file, then run aoinit() and calibrate the iMat, then select which actuators are controlled and which are extrapolated based on the WFS sensitivity to it. Use dm.thresholdresp to select this threshold. This is a fractional number, so 0 would filter all actuators and 1 would retain them all. 0.5 would retain all actuator which measurement max response is larger than the max response of all actuators. Note that if you set dm.thresholdresp to a negative value, aoinit() will enter an interactive mode into which you can test various values of dm.thresholdresp (Show/Hide example).

Once extrapolated actuators are selected, yao stores the valid influence functions and the extrapolated ones in 2 different files (e.g. test-if1.fits and test-if1-ext.fits). Influence functions are not recomputed in further calls to aoinit() unless the clean keyword is set (in which case aoinit() restart from scratch and recompute everything).

Normalization??

Bimorph (curvature) DM

Set dm.type="bimorph". The other mandatory parameter is dm.nelperring.

dm.nelperring: This is similar to wfs.nsubperring (see here) and defines the number of electrodes per ring.

Now, most curvature mirror are a bit different from this simple design provided by defining dm.nelperring, in which there is no gap between rings. Many curvature DMs have for instance a large gap between the outer ring of electrodes (the one that create mostly boundary conditions) and the next inner electrode ring. To create more realistic DM electrode pattern, use angleoffset, rint, rout, supportRadius and supportOffset.

The general idea follows what has been exposed in the curvature WFS area above. With rint and rout, one can define the inner and outer radius of each ring of electrodes, expressed in fraction of the pupil radius. With angleoffset, one can define a global rotation per ring, and with the support* parameters, one can define the physical properties of the 3 DM support points.

That brings us to the next subject: how curvature DMs are modelled. Right now, what we do is solve the Poisson equation, imposing a given curvature over a given electrode and integrating twice to get the DM surface. Then, we impose that the three points defined as the support location go through the z=0 plane. It's that simple. It means that we do not currently support fancier support method like continuous support (e.g. by a rubber ring), 6 points support, etc..

Modal (Zernike, Disk Harmonic, Karhuenen-Loeve) DM

Set dm.type="zernike","diskharmonic" or "kl". Other mandatory keywords are dm.nzer (for zernike), dm.max_order for disk harmonic or dm.nkl (for KL), which specify the number of modes. Note that nzer (Zernike) & max_order (disk harmonic) will start and include piston, while nkl (KL) will not (there is formally no piston mode in the KL basis).

Segmented DM

Set dm.type="segmented". The other mandatory keywords is dm.nxseg.

dm.nxseg is the number of segment in the long diameter (X axis).

dm.fradius stands for "filter radius". Segments are created over a wider area than the nxseg defined above. Only segments which distance to the (0,0) pupil coordinates is ≤ fradius will be kept. default dm.pitch*dm.nxseg/2.

User defined DM

Set dm.type="name_of_your_function" (as a string).

The API for the user provided DM function are as follow:

func make_my_dm(nm,disp=)
where nm is the DM number. Use the disp keyword to display whatever you need to display when this routine is called. The goal of this routine is to create maps of the influence functions. These maps have to be stored (thus this function has to create and fill) in the array *dm._def (dm._def is a pointer to the data). The proper way to do that is:

func make_my_dm(nm)
{
  extern dm;   // dm is extern (global)
  dim = dm(nm)._n2-dm(nm)._n1+1; // <- important
  def = array(float,[3,dim,dim,n_actuator]);
  for (i=1;i<=n_actuator;i++) def(,,i) = some_form; // <- fill it to your taste
  dm(nm)._def = &def;  // <- store influence functions
  dm(nm)._nact = n_actuator;  // <- important, number of actuators
}

Explanation: In this user supplied function, you have to define the influence functions (*dm._def) and, importantly, the number of actuators (dm._nact). Prior to the call to this function, aoinit() has defined dm._n1 and dm._n2, which are the indices at which these influence function will go in the big sim._size x sim._size array used for FFT, etc. The influence functions are reduced in size to save RAM, as they can potentially take a lot of memory space. Normally, dm._n1 and dm._n2 are defined to include the pupil pixel diameter (sim.pupildiam) plus 4 pixels padding on each side if the DM altitude is zero (in the pupil), and are defined to span the entire sim._size array if the DM altitude is above ground (as there is no simple way to know where to stop exactly as this depends on the WFS and target locations). Note that dm is defined in extern as you are modifying its value.

Tip-Tilt Mirror

Set dm.type="tiptilt".

This creates a regular tip-tilt mirror. The units in the command vector are arcsecs.

Anisoplanatism "DM"

Set dm.type="aniso".

This has been implemented because of the need in MCAO to control plate scale modes (also called anisoplanatism modes or quadratic modes). You will need to set dm.alt to the altitude of an existing DM of a regular type (e.g. stackarray) that will be responsible for the creation of the anisoplanatism modes (see mcao2-bench.par for an example of aniso DM).

Hysteresis and misregistration/offset

Hysteresis

Hysteresis is implemented at the top level so that it works for any kind of DM (during the AO loop only). The parameter dm.hysteresis is fairly self explanatory: dm.hysteresis=0.1 means 10% hysteresis.

Misregistration

dm.misreg allow to induce DM misregistration (on the fly). dm.misreg is expressed in pixels, so you will have to do a small conversion to get it in other units, but this way, it works for any kind of DM. Note that dm.misreg can be fractional (fraction of a pixel). Because the size of the array containing the DM influence function is limited to save memory space, the misregistration using this parameter can only be of a few pixels (up to 4 I believe for a ground-conjugated DM). If you wish to induce more registration, use the parameter dm.pupoffset (see below).

Offsets

Yao v4.5.0 introduced a new kind of influence function offset parameter: dm.pupoffset. dm.pupoffset is entered in meters (a 2 elements vector which contains the x and the y offsets). Those are transversal offset of the influence functions in the near field. This functionality is implemented in the compute_dm_shape() function, so it is general and works for all types of DM. dm.pupoffset is intended for large offsets, and the influence functions are shifted by an integer number of pixels (the requested offset in meter, rounded to the nearest pixel, see sim.pupildiam and tel.diam). If you want finer control over the DM position, use dm.misreg (see above). dm.pupoffset is similar to wfs.pupoffset (see WFS section), but for the DMs.

Building a Reconstructor

Up to 4.5.1, yao was only offering reconstructors created with a truncated-SVD method. This is in effect a least-square solution where "invisible" modes are totally discarded. In June 2010, Marcos Van Dam contributed code that enables the possibility to select an alternative MMSE-like method (Minimum Mean Square Error). In addition, this MMSE reconstructor can be either built using full matrices or sparse matrices techniques, which offers a significant speed boost.

Method selection (provided by M.v.D)

There are three options for wavefront reconstruction, and these are set using the mat.method parameter.

Truncated singular value decomposition (default)
mat.method = "svd"
mat.condition = &([desired conditioning])
Minimum Mean Square Error Reconstructor

This method computes the reconstructor as

R = (HT H + a C)-1 HT

where H is the interaction matrix (poke matrix), a is a regularization parameter and C is a regularization matrix. The regularization matrix (see dm.regtype or dm.regmatrix) can be user specified or computed by YAO. If it is computed, it will use an identity matrix by default, or a matrix created by convolving a laplacian operator by itself. This matrix has similar statistics to the inverse covariance matrix for Kolmogorov turbulence and penalizes local waffle in the DM.

The relevant parameters for the MMSE inversion process are mat.method = "mmse", dm.regparam, dm.regtype and dm.regmatrix.

MMSE Sparse method

A sparse matrix implementation of the above is also available. Set mat.method = "mmse-sparse". This is ideal for very large systems with thousands of actuators, as it reduces memory requirements and increases computational speed. Do not use the sparse method when the interaction matrices are not actually sparse (e.g., when using a Zernike DM). mat.method = "mmse-sparse" uses the same parameters as "mmse" as well as mat.sparse_MR and mat.sparse_MN (see table below for meaning of these parameters). You will need to set these values to a higher level than the default if you have extremely large system (for instance for a 200x200 SH system I had to set them to (100000 and 2000000 respectively).

Running yao using parallel processes

Since yao 4.6.0, you can take advantage of multi-core machines to speed up the execution time. Gains range from 20% to 350% (i.e. 1.2x to 3.5x). Here is a copy of the blog entry I posted when announcing yao parallel:

More work on yao parallel:

  • I have merged some of the -useful- parallel features implemented in our Gemini local yao_mcao to the yao trunk. Namely,
    • The DM/WFS parallelization (meaning, taking advantage of the fact that real systems have at least one frame delay (remember that even if the command is applied immediately after the measurements are received, there is still one frame delay due to the zero order hold). The one frame delay means the WFSing at iteration N is not needed to compute the command at iteration N, thus can be computed in parallel.
    • The PSF calculations, which is a no brainer.
  • I have implemented the parallelization of individual SHWFS. Meaning, an individual SHWFS can now run in parallel on an arbitrary number of "threads" (in fact, forks). This works only for Shack-Hartmann WFS. The good thing is that this is implemented fairly deep into the code, so any call to sh_wfs() will benefit from this, which means the iMat acquisition is accelerated too.
Depending on your system, i.e. WFS order, number of WFSs/DMs, whether you use dm.elt or not, sparse reconstructor or not, and more importantly, on the machine you run yao on, using the parallel features can make you gain anywhere between 20% and 200% in execution speed. If you want to use it, you will most probably have to experiment a bit to see what option should be set. Guidelines are given in the manual. The bottom line is that you should not use more forks (processes) than you have CPUs, otherwise swapping processes in/out of L2 cache introduce an overhead which cancels the paralleization advantage. With my core2duo laptop, I can typically gain 30 to 50%. With an 8 cores Xeon-based machine we have at work, I gain typically close to a factor of 2 (can be more or less). This does not seem particularly impressive, but one has to consider that a yao loop is made of many different individual operations: WFS, cMat product to retrieve the error, DM shape computation from the DM commands and the influence functions, PSF calculation, etc... So a gain in one of this items is only going to benefit the whole thing marginally. As far as the individual WFS parallelization is concerned, here are some hard numbers:
8 Core Xeon (2 boards) @ 3.33GHz, running RHEL 5, 32 bits. yorick/yao built with -O2.
16x16 SHWFS system, physical model, no noise. All times (avg & median) in milliseconds for one frame.          

sh16x16_svipc:        1 threads, sh_wfs() avg=2.86, median=2.90
sh16x16_svipc:        2 threads, sh_wfs() avg=1.87, median=1.89
sh16x16_svipc:        4 threads, sh_wfs() avg=1.37, median=1.37
sh16x16_svipc:        8 threads, sh_wfs() avg=1.14, median=1.15
sh16x16_svipc:       16 threads, sh_wfs() avg=2.33, median=2.30
You can see that the speed increases up to 8 forks (max gain = 2.5x). Adding more forks makes the thing slower. The gain does not reach larger value just because (1) there are overheads associated to the use of shared memory/semaphores and (2) there is also a global overhead in the sh_wfs() function. What's parallelize is the core of sh_wfs() (FFTs, noise application and slopes calculations from spots), but any overhead within the sh_wfs() function itself, before calling the FFT/slopes calculation routine is not going to gain from the parallelization.

The gain brought by the other, more general parallel features (DM/WFS & PSFs) is nicely illustrated by the following examples. This was run on the same machine (8 cores Xeon), with curvature.par (36 subapertures curvature system ran on a 120 pixels pupil). Look at the following results (I have omitted the timing results for items that are not of concerned here and were negligible):

sim.svipc=0 (no parallelization)
time(1-2) =  9.89 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  1.04 ms  (DM shape computation)
time(5-6) =  5.84 ms  (Target PSFs estimation)
59.18 iterations/second in average


sim.svipc=1 (WFS/DM parallelized)
time(1-2) =  4.11 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  0.94 ms  (DM shape computation)
time(5-6) =  5.78 ms  (Target PSFs estimation)
91.43 iterations/second in average

sim.svipc=2 (PSFs parallelized)
time(1-2) = 10.69 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  1.05 ms  (DM shape computation)
time(5-6) =  1.23 ms  (Target PSFs estimation)
76.41 iterations/second in average

That's a typical example. The "no parallel" case is dominated by WFSing (10ms) and PSF (6ms) calculations. When parallelizing the WFS (sim.svipc=1), the WFSing time goes down to 4ms. Indeed, now 6ms of it can be done in parallel with other tasks: here, the PSF calculation that takes 6ms. With sim.svipc=2 (only the PSF are parallelized), the PSF calculation time goes to basically to 0 while the WFSing stays at 10ms. It all makes sense. I haven't put the sim.svipc=3 results as they are a little more difficult to understand and would just introduce confusion.

The individual WFS parallel feature is controlled by the parameter wfs.svipc. The "global" DMs/WFSs abd PSF parallelization is controlled by sim.svipc (bit 0 controls DM/WFS and bit 1 controls PSFs, thus sim.svipc=3 means both are turned on).

Of course, if you want to use yao parallel facilities, you will need to install the yorick-svipc plugin, through most of the normal channels. It runs on Linux (extensively tested) and OsX (somewhat tested).

As it says, you need to install yorick-svipc. It is available right now (July 2010) through the maumae.net package source web page and on archlinux AUR. It will eventually make it in the Debian & Ubuntu repos.

Parallel implementation gotcha & bugs

It is difficult to code for parallel deployment. Especially for something like yao which offers a lot of various configuration option to the users. I have tested the parallel implementation quite a lot, but I am sure I have left some corners unexplorered/untested. So you might hit some unexpected features. Let me know if you do notice something weird. In the meantime, here is a list of things to watch out for when using the parallel (svipc) thingy (the first three items should not happen. I haven't seen it for a long time. But I originally saw it hence I give you these tricks in the unlikely event it happens) :

  • You can safely turn the sim.svipc features on and off within the same session. If you want to use it though, you need to declare it before the aoinit (so re-run aoinit to enable it). You can disable / re-enable at any time after the first init (init is done within aoinit and forks are done within aoloop).
  • Be a little more careful with the wfs.svipc. If you wish to change the number of threads within a yao session, you will need to run quit_wfs_forks() to kill (quit) the wfs forks to be able to re-fork WFS processes with the correct parameters. So, for instance, you could do the following:
    > aoread,"some par file"; wfs.svipc=2; aoinit; aoloop; go;
    [...you get your results]
    > quit_wfs_forks
    > wfs.svipc=4; aoloop; go;
    
    This *should* work. As you get acquainted with the parallel extension, I suggest you keep a terminal open on the side, monitoring the yorick processes (htop or gnome-system-monitor does fine on linux). If it doesn't work, or you get lost, just restart the yorick session.
  • If you ever end up with semaphores locked, you can easily Ctrl-C your way out of it. But this may left the shared memory / semaphore mechanism in a weird state. Re-run the yao session (including the svip settings) and quit() yorick. This should cleanup the svipc settings. If push comes to shove, you can list your shared memory segments and semaphores with ipcs and manually kill the culprits with ipcrm -M segment for shared memory or ipcrm -S segment for semaphores. The one yao uses generally start at 0x0badcafe (and up) for the shm and 0xdeadbeef (and up) for semaphores. On modern linux systems, this can not harm your machine or the state of your OS. You should never have to reboot as a consequence of using shm/semaphores.
  • Before running long simulations, I advise you to check the graphics to make sure everything runs fine. I have seen instances where the forks get desynchonized from the main process, resulting in partial images or noise badly applied.
  • Right now the dark feature I believe is broken. Be aware of it and don't use it.

Other Features

More to come (a note to myself).

  • disjoint pupils
  • loop parameters: framedelay, control law
  • Normalization of various parameters and arrays
  • Variables (aoinit or not aoinit?)
  • Vibrations parametrization

Yao Structures

Comment on notation: &float = pointer to a float array/vector (idem for &long, &string, etc...). Define it as:
atm(1).layerfrac = &([0.5,0.2,0.3]);
I know, it seems weird, but there is a good reason to have done it like this.
sim structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
name string N/A none no A name for this simulation run
pupildiam long pixels none yes Pupil diameter
debug long N/A 0 no Debug level
verbose long N/A 0 no Verbose level
svipc long N/A 0 no bitwise set features for parallelization:
0 = no parallelization
bits effect
0(1) WFS/DM global split (2 process)
1(2) PSFs calculation parallelization
e.g. sim.svipc = 1 -> split WFS/DM
e.g. sim.svipc = 2 -> parallelize PSFs
e.g. sim.svipc = 3 -> WFS/DM & PSFs
shmkey long N/A no shared memory key. Change in each session if running multiple yao session simultaneously.
semkey long N/A no semaphore svipc key. Change in each session if running multiple yao session simultaneously.
atm structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
dr0at05mic float Unitless none yes Dr0 at 0.5 microns, at zenith
screen &string N/A none yes Phase screen file names
layerfrac &float Unitless none yes Layer fraction. Sum to one is insured in aoinit
layerspeed &float meter/sec none yes Layer speed
layeralt &float meter none yes Layer altitude, at Zenith
winddir &long Unitless 0 yes Wind dir (not operational, use 0 for now)
wfs structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
type string N/A none yes Valid types are "curvature", "hartmann", "pyramid", "zernike" or "user_function" where user_function is the name of a function defined by the user (see doc)
lambda float micron none yes WFS wavelength in microns
subsystem long N/A 1 no Subsystem this WFS belongs to
gsmag float Unitless 0 no WFS guide star magnitude. For LGSs, see below. Beware to set to something bright when doing your iMat
skymag float Unitless 0 (no sky) no WFS sky magnitude/arcsec^2. [0 means no sky]
noise long N/A 0 no Enable noise (photon noise & read out noise)
ron float e- 0 no Read out noise
darkcurrent float e-/s/pixel 0 no Dark current
gspos(2) float arcsec [0,0] no WFS guide star position [x,y]
gsalt float meter 0 no WFS guide star altitude, at zenith. 0 for infinity.
gsdepth float meter 0 no WFS guide star depth in meter, at zenith (e.g. Na layer thickness)
laserpower float Watt 0 See commentWFS laser power projected on sky (Na laser only). Required when using lasers. Exclusive with gsmag i.e. define one OR the other
filtertilt long N/A 0 no Filter TT on this sensor (0=no)
correctUpTT long N/A 0 no Correct uplink tip-tilt (0=no)
uplinkgain float Unitless 0 no Uplink TT loop gain
dispzoom float N/A 1.0 no Zoom factor for the display, useful in multi-WFS configuration (typically around 1)
optthroughput float Unitless 1.0 no Optical throughput to WFS
disjointpup long N/A 0 no If set, the WFS#n will be filtered by an array disjointpup(,,n) that has to be defined by the user. see user_pupil(). Allow for GMT-type topology
Pyramid WFS only keywords
pyr_mod_ampl float arcsec 0.0 yes pyramid wfs modulation amplitude radius [arcsec]
pyr_mod_npts long N/A 1 yes total number of point along modulation circle [unitless]
pyr_padding long N/A 0 no Pad the pupil image to reduce spatial aliasing [unitless]. A pad of 1 means adding wfs.npixpersub pixels on each side of the pupil image. Typical 0 to 4.
pyr_mod_loc string N/A "after" yes Location of modulation (before/after the field stop). Valid values are "before" or "after"
Curvature WFS only keywords
l float meter none yes Extra focal distance in a F/60 beam
nsubperring &long Unitless none yes # of subapertures per ring. See doc
angleoffset &float degree 0 no CCW Offset angle for first subaperture of ring. See doc
rint &float Unitless See commentno Inner radius for each ring, in fraction of pupil radius
rout &float Unitless See commentno Outer radius for each ring, in fraction of pupil radius
fieldstopdiam float arcsec 1.0 no Diameter of field stop. Used only to compute sky contribution (with skymag)
Shack-Hartmann WFS only keywords
shmethod long N/A none yes 1= Geometric, simple gradient average over subaperture. 2=Diffractive, full propagation
shnxsub long Unitless none yes # of subapertures in telescope diameter
pixsize float arcsec none yes Focal plane: Subaperture CCD pixel size in arcsec
npixels int Unitless none yes Focal plane: Final # of pixels per subaperture
npixpersub long Unitless none no Pupil plane: # of pixel in a subaperture (to force npixpersub and bypass constraint that pupildiam should be a multiple of this number e.g. to investigate lenslet larger than pupildiam
pupoffset(2) float meter [0,0] no Pupil plane: Offset of the whole WFS subapertures w.r.t telescope aperture. Allow misregistration w.r.t telescope pupil and other funky configurations
shthreshold float e- 0 no Threshold for the computation of the subaperture signal from CCD spots >= 0
biasrmserror float e- 0 no rms error on WFS CCD bias in electron
flatrmserror float Unitless 0 no rms error on WFS CCD flat, referenced to 1 (i.e. 0.1 mean 10% rms error). Typical value can be 0.01
fsname string N/A none no Fits file with subaperture amplitude mask. It should have dimension 2^sdimpow2 square. Can be float or long.
fstop string N/A "square" no Valid fiels stop type are "none", "square" or "round"
fssize float arcsec sub. size no Side (square) or diameter (round) of field stop
fsoffset(2) float arcsec [0,0] no Field stop offsets [x,y]
kernel float arcsec See commentno FWHM in arcsec of WFS spot gaussian kernel. Default is computed as a function of D/r0 and only used during iMat calibration
nintegcycles int Unitless 1 no # of iterations over which to integrate before delivering slopes
fracIllum float Unitless 0.5 no Focal plane: Fraction of subaperture illuminated for the subaperture to be valid
LLTxy(2) float meter [0,0] no Coordinates [x,y] of the laser projector, if any
centGainOpt long N/A 0 no Centroid gain optimization flag. Only for LGS (correctupTT and filtertilt must also be set for this to work)
rayleighflag int N/A 0 no Take rayleigh into account?
svipc long N/A 0 no Number of parallel processes (forks) to use for this WFS (0 or 1: don't parallelize, N: use main + (N-1) forks)
Zernike WFS only keywords
nzer int Unitless none yes Number of Zernike to be sensed. Starts at piston included.
dm structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
type string N/A none yes Valid types are "bimorph", "stackarray" "tiptilt", "zernike", "diskharmonic", "kl", "segmented", "aniso" or "user_function", where user_function is the name of a function provided by the user
pitch long pixel none yes Actuator pitch (pixel). stackarray/segmented only
subsystem long N/A 1 no Subsystem this DM belongs to
iffile string N/A "" no Influence function file name. Leave it alone.
alt float meter 0 no Conjugation altitude, at zenith
hyst float Unitless 0 no DM actuator hysteresis (0. to 1.)
push4imat float Volt 20 no Voltage to apply for iMat calibration. Note: the default is not OK for many configs. Change at will
thresholdresp float Unitless 0.3 no Normalized response threshold (in WFS signal) below which an actuator will not be kept as valid
unitpervolt float mic/Volt 0.01 no Influence function sensitivity in unit/volt. Stackarray: micron/Volt, Tip-tilt: arcsec/Volt.
maxvolt float Volt none no Saturation voltage (- and +) in Volt. None if not set
gain float Unitless 1.0 no Loop gain for this DM (total = this times loop.gain)
misreg(2) float pixel [0,0] no DM misregistration [x,y]
xflip long N/A 0 no Flip DM left/right (0=no)
yflip long N/A 0 no Flip DM up/down (0=no)
pupoffset(2) float meter [0,0] no Global offset of whole actuator pattern w.r.t pupil
disjointpup long M/A 0 no If set, dm(n) will be filtered by an array disjointpup(,,n) that has to be defined by the user. See user_pupil(). Allow for GMT-type topology.
Stackarray-only (SAM, PZT) keywords
nxact long Unitless none yes Number of actuator in pupil diameter
elt long N/A 0 no ELT mode: allow to save huge amount of RAM and time for the computation of the DM shape. No drawback
coupling float Unitless 0.2 no Influence function coupling coefficient
ecmatfile string N/A none no Valid to extrapolated projection matrix (extrap_com)
noextrap long N/A 0 no Set to disable use of extrapolated actuators
pitchMargin float Unitless 1.44 no Margin to include more corner actuators when creating inf.functions optional [1.44]
irexp long N/A 0 no Use original functional form (irexp=0) or exp(-(d/irfact)^1.5) model (irexp=1) or sinc*gaussian (irexp=2)
irfact float Unitless 1.0 no use when irexp=1 (see above)
regparam float Unitless 0.0 no Parameter that determines the strength of the regularization. Set to zero for systems like tip-tilt mirrors and to a small positive value (e.g., 1e-4) for stackarray DMs. Experiment by trial an error to get the value that produces the highest Strehl. Experience shows that any value within a factor of four of optimal produces the same results.
regtype string N/A "identity" no Regularization approach: "identity" (default) or "laplacian"
regmatrix &float Unitless none no Pointer to the regularization matrix to use instead of computing one of the two options. This is usually not necessary, but is left as an option for advanced users. A good choice would be the inverse covariance matrix of the turbulence, for example.
Bimorph-only keywords
nelperring &long Unitless none yes Number of electrodes per ring, e.g &([6,12,18])
angleoffset &float degree 0 no Offset angle for first electrode in ring
rint &float Unitless See commentno Inner radius for each ring, see doc
rout &float Unitless See commentno Outer radius for each ring, see doc
supportRadius float Unitless 2.2 no Radius of DM 3 support points, normalized in pupil radius
supportOffset float dgree 90 no Angle offset of first support point
Zernike DM-only keywords
nzer long Unitless none yes Number of Zernike modes, including piston
Disk Marmonic-only keywords
max_order long Unitless none yes Number of Disk Harmonic modes, including piston
Karhuenen-Loeve DM-only keywords
nkl long Unitless none yes Number of Karhuenen-Loeve modes, including piston???
Segmented DM-only keywords
nxseg long Unitless none yes Number of segments in long axis (X)
fradius float pixel See commentno Segments are created over a wider area than the nxseg defined above. Only segments which distance to the (0,0) pupil coordinates is <= fradius will be kept. default dm.pitch*dm.nxseg/2.
mat structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
method string N/A "svd" no Reconstructor creation method ("svd", "mmse" or "mmse-sparse")
condition &float Unitless none yes Condition numbers for SVD, per subsystem.
file string N/A none ??? iMat and cMat filename. Leave it alone.
sparse_MR long Unitless 10000 no Sparse only: maximum number of rows (actuators) in the imat
sparse_MN long Unitless 200000 no Sparse only: maximum number of elements in the imat
tel structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
diam float meter none yes Telescope diameter
cobs float Unitless 0. no Central obstruction / telescope diameter ratio
Tip vibration parameters
tipvib_white_rms float arcsec 0. no rms of vibration white noise
tipvib_1overf_rms float arcsec 0. no rms of vibration 1/f noise (from 1 Hz to cutoff)
tipvib_peaks &float Hz 0 no positions of vibration peak in PSD
tipvib_peaks_rms &float arcsec 0 no rms of each vibration peaks (defined above)
tipvib_peaks_width&float Hz 1freq binno width of each vibration peaks (default 1 freq bin)
tilt vibration parameters
tiltvib_white_rms float arcsec 0. no rms of vibration white noise
tiltvib_1overf_rmsfloat arcsec 0. no rms of vibration 1/f noise (from 1 Hz to cutoff)
tiltvib_peaks &float Hz 0 no positions of vibration peak in PSD
tiltvib_peaks_rms &float arcsec 0 no rms of each vibration peaks (defined above)
tiltvib_peaks_width&float Hz 1freq binno width of each vibration peaks (default 1 freq bin)
target structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
lambda &float micron none yes Image wavelengths in micron
xposition &float arcsec none yes "Targets" X positions in the field of view
yposition &float arcsec none yes "Targets" Y positions in the field of view
dispzoom &float Unitless 1. no Display zoom, useful for multi-targets. Typically around 1
gs structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
zeropoint float See commentnone yes Photometric zero point (#photons@pupil/s/full_aper, mag0 star).
zenithangle float degree 0 no Zenith angle. The zenith angle is used to compute: r0 off-zenith, atmopheric turbulence layer altitude, LGS altitude and thickness of Na Layer, LGS brighness note that dm altitude is unchanged
lgsreturnperwatt float phot/cm2/s 22. no Sodium LGS return in photons/Watt/cm2/s at entrance pupil, at zenith. Modified by gs.zenithangle. Basically, you have to fold in this the sodium density and your model of return
loop structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
niter long Unitless none yes Total number of iterations
ittime float second none yes Iteration time (sampling time)
gain float Unitless 0 See commentLoop gain. Optional, but important!
leak float Unitless 0 no Leak term (0 means no leak)
gainho &float Unitless 0 no Higher order gains (starting at 2nd order, up to 10th)
leakho &float Unitless 0 no Higher order leaks (starting at 2nd order, up to 10th)
framedelay long frames 0 no Loop delay (# of frames). Regular CCD 1 frame integration -> framedelay=1 + readout & Calculation -> framedelay=2
startskip long iteration 10 no Number of iteration to skip before collecting statistics
skipevery long iteration 0 no In phase screen, skip by "skipby" steps every "skipevery" iterations (0=none). See doc
skipby long iteration 10000 no See above. This is to get better statistical coverage
stats_every long iteration 4 no Compute stats every so many iteration
jumps2swapscreen long Unitless 0 no Number of jumps (i.e. niter/skipevery) after which screens will be swapped (rotation, 2->1, 3->2... 1->last). Default is no jump.
modalgainfile string N/A "" no Name of file with mode gains
opt structure
VARIABLE NAME TYPE UNITS DEFAULT REQ?COMMENT
phasemaps string N/A none no Filename of phasemap. Z scale should be in microns
alt float meter 0 no Equivalent altitude in m.
misreg(2) float pixels [0,0] no Misregistration [x,y] (similar to DM, see above)

Scripting and Hacking Yao

Scripting

Thanks to yorick and the structure of yao, scripting is relatively easy. The principle is as follow:

  • read the parfile
  • init yao (aoinit)
  • Loop on parameters you want to loop on:
    • set parameters
    • if needed, redo the aoinit (some parameters will need that)
    • go through the loop N iterations
    • store the results
  • Plot/save results

Here is a simple example you can find in the examples directory (yao_loop_example.i):

require,"yao.i";

// check if generic phase screens exist, if not, create them:
write,"CREATING PHASE SCREENS";
if (!open(Y_USER+"data/screen1.fits","r",1)) {
  create_phase_screens,1024,256,prefix=YUSER+"data/screen";
 }

// the "wait" is needed here:
window,33,wait=1;

// read out parfile
aoread,"test.par";
atm.dr0at05mic = 35; // be more gentle

// Define vector on which we want to loop and final strehl array.
// We want to estimate performance for 3 values of the guide star 
// magnitude and 4 values of the loop gain (for instance)
gsmagv = [6,9,12];           // guide star mag vector
gainv  = [0.01,0.1,0.5,1.0]; // gain vector
// strehl array to store results:
strehlarray = array(0.,[2,numberof(gsmagv),numberof(gainv)]);

// loop on gsmag and gain
for (ii=1;ii<=numberof(gsmagv);ii++) {
  for (jj=1;jj<=numberof(gainv);jj++) {
    wfs(1).gsmag=gsmagv(ii);
    loop.gain=gainv(jj);
    // it's safer, but not always necessary, to call again
    // aoinit (here for gsmag). some parameters do not need it.
    aoinit,disp=1;
    // Setup loop:
    aoloop,disp=1;
    // go: do all loop.niter
    go, all=1;
    // after_loop() is now called automatically at last iter of go()
    strehlarray(ii,jj) = strehllp(0); // fill in result array
    // and display results as we go:
    window,33;
    fma;
    for (ll=1;ll<=ii;ll++) {
      plg,strehlarray(ll,),gainv,color=-ll-4;
      plp,strehlarray(ll,),gainv,color=-ll-4,symbol=4,size=0.6;
      ylims=limits()(3:4); ymax=ylims(2); yspace=(ylims(2)-ylims(1))/15.;
      plt,swrite(format="gsmag=%d",gsmagv(ll)),0.011,ymax-yspace*(ll-1), \
        justify="LT",tosys=1,color=-ll-4;
    }
    logxy,1,0;
    xytitles,"Loop Gain",swrite(format="Strehl @ %.2fmicrons",(*target.lambda)(0));
    window,0;
  }
}

You can do all kind of scripting like this to find for instance the optimal working point for a system in given conditions (above, what is the best gain for a given GS magnitude). We could also have added a loop on wfs.ittime in the example above. One has however to be careful: Probing multi-dimensional spaces can quickly be overwhelming in execution time. Generally, I consider that 10000 iterations are needed to give a statistically significant answer. So for instance, in the example above. that would mean 4x3x10000=120000 iterations total. At 90 iterations/seconds, this means 1300 seconds (about 20mn). Adding 4 points for wfs.ittime would lead to 480000 iterations, or 1 hour and 20mn. This can quickly become prohibitive.

Hacking Yao

At one point or another, if you are serious about simulating your system, it is likely that you will need this or that feature, or modification to the existing yao code.

Go ahead and dive. Feel free to modify yao. It's open source after all. The goal of this too-short section is to give you some head start for doing just that: hacking yao.

So, various points, in no particular order:

  • The functions are kind of gathered by themes. The main file is yao.i, and includes the base functions aoread(), aoinit(), aoloop(), go(), after_loop() and more. Other important include files are:
    • yao_wfs.i: All functions related to WFS and their initialization.
    • yao_dm.i: All functions related to DM and their initialization.
    • turbulence.i: Functions to generate turbulent phase screens. Some more turbulence functions are in yao.i
    • yao_structures.i: Definitions of yao structures.
    • aoutil.i and yao_util.i: check_parameters, and in general utility functions that didn't fit anywhere else.
    • yao_fast.i and yao_utils.i: Interface functions to the C routines. Mostly declaration of prototypes as per yorick plug_in APIs.
    • yaokl.i: KL creation functions.
    • yao_fast.c: C code for the SHWFS and CWFS, plus some Poisson and Gaussian noise fast functions.
  • Many variables are defined in extern. This means they are available at any level. Here is a subset of them:
    • All the yao structures: wfs, dm, atm, sim, mat, tel, target, gs, loop. There are sufficient examples in the code of how to address them. These will contain most of the information you may want.
    • Variables that may be useful to catch and store/analyze when the loop is finished are (loop in go() and after_loop() for more details):
      • imav(sim._size,sim._size,#_target,#_lambda): the averaged images for each target and at each requested wavelength.
      • strehl(#_target,#_lambda) contains the long exposure image Strehl ratio for each target and each requested wavelength.
      • fwhm(#_target,#_lambda) contains the long exposure image FWHM for each target and each requested wavelength [mas].
      • e50(#_target,#_lambda) contains the long exposure image 50% encircled energy diameter for each target and each requested wavelength [mas].
      • cbmes, cbcom, cberr are the "circular buffers" that contain all WFS measurements, DM commands and DM errors (updates to DMs at each iterations). Only saved if keyword savecb is set in call to aoloop().
    • iMat, cMat: Interaction and control matrices. One axis is the WFS axis. The WFS measurements are put in sequence: all X, then all Y for WFS#1, then all X, then all Y for WFS#2, etc... The other axis is the DM axis. Here also, all valid actuators for DM#1, then DM#2, etc...
    • modToAct, mesToMod, eigenvalues: The U, transpose of V and eigenvalues of the SVD inversion. Over the unmasked eigenvalues, cMat is computed as follow:
      cmat = ( modToAct(,+) * mev(+,) )(,+) * mesToMod(+,);

Conclusion

There is a lot of things missing in this documentation. I will try to complement it as time allows. I hope however that this will help you getting the best out of yao and avoiding frustration. Yao is a fairly complete AO simulation tool. It is flexible and fast. Flexibility means I can not exert too much control over the user input parameters. If I were to do that, I would necessarily impose a carcan over your creativity, and we want to avoid this at all cost. So, yes, there is a steep learning curve, but at the end, you should be able to wrestle yao into submission! I have only one more advice to give: check your results. And recheck them. And make sure it makes physical sense.

yao-5.4.0/doc/mcao-graphics.png000066400000000000000000002110341234404334100162770ustar00rootroot00000000000000PNG  IHDR+1gAMABO pHYs  "tEXtSoftwareQuickTime 6.4 (Mac OS X)tIME8/Љ IDATxypվǻgz$3&KB`@AY^xQ(y UZ.@|xb+,J,(- O/*¥Ke_x%CY"[Ȟ$_ڷ-=t1},3}9=l(b~#[ce^M-f!#H~SS +7y8:fx&|Ab4$fGq^[MOz 3ݻ%Oԝ04@@pO2ĒlWUU1-+͛7oۖN>̓GKYJWUΘ9.r˦MpHaeP}çMh@g$ܜcZ%7G(/yx.Crt_Y^Q2U('y%Gdn>iVꫵ2l غ4WЍ.,E?rH5Woa?^Zyn2q,Zh)F%9 wy租~:ixy|֭YYYǏ?v|=֭[˖-۵kW~~>%S&)͌?)S( +.X2y=j*_͞9 qܱ}:r*M!:XXl͏~}ZgEMvpܻ?c?37Ur^cfkĄf_]tM޽cs*j+X?2q$~.71})% 94$Ozʕk׮N8qYf-̘1cÆ /ƍvd_߂>tз~K3l^TT4bĈsj{HU /9D«3)>c̜L3HOݜJM *өS?*`sn~[Rٙfښ/PWTXwQLzgZJR3 lz9wjkRp ϒZKKKz)XNN/^ـHBؠyYԌt+r6Y|83~Rq+@1GAu;K'9q-6XjYU`]MMJpI)v+6|:XSm]{0}ϋ^zuK.;v$v]l7oDO wk?fOr%;RRW t43x&&Ȳu M^oSɣsH-[װ1d %6)u83jh`̔ B5+?T_\g˕B; 6,4`COwUY0iiiIرj=Zּv:dȐ "J:MΆHIsssI䓐/.?^v-͑NX쪪*!)=X*'L8on;?KIu%۝Vf"ϛݦƆPJz)' {ޥG]hсo>j(V`={>gů)}رJdɒ+W.\<{RqId_RR"dHe@,Q;zyʹܜL%;05ՇO>:WލJ\خ.Vn6'3!6`671Mյ{/ YxGハS#H6Na@|uU?2QI!}֬Yr/_sϭ^\j1ݳgO?[n%Rȑ#l2 .P&wޙ3gΊ+J;{g͚aÆ3gСC> X©hCCab?>oeErrkKKֺ_0yڴ|}>}Sx׎꟟ݥ boܼv¿Ξ`RqH>mtlgY}r3s8wͳJ/n?>D&/32~TJ2sLp8tvsҥKiinK/=ݻw/++[n kD 7=kɓ'5.]vjNૼI9%eyyyK[K~{je 8]ֻ9Qg+W.ݾ+55šX#/>|]J 1!^`֭[9>}NC=t?oرcͼ?SWa" ҥKwq|]ްǏ׶8M ~}}S@|۷f~/(qj=3[U@b;vL$~˯F-Ff6p;H4jjj%S槤Ԟcl~/_ŀm윯TpNNKtO"w 1<: j c tL xV] ` ZQmcțQ~ϠD;+IQnMרXY5"^Q&ՈQWnş]#zEX:!>UKw4jYG1lIxpWb:^GBמ{2lD %9I~Zť~%yVs5m]OIv #H(1u@x !3$ކxLھߞQq%]'׌s-@9E')ZrV5x[˯21m4G?9hFX]"I53h*Vh5 ' yG쯇d2aXjDw2|"gt|epFPY 5RE=JLcqۣbjb)rL40"^W6ץ*A#Uԣ ZnSI 4&.Bc,YN"RˊG,JbЪ_@ɴ]jh\XFN"=MHq7KBĩ["uttdIHQAb m:zOq;@ s 0o`@7lx  7`0 x  7`0 ,qގ%>mŻusyXq?DqB()*@$H:GǥwXF> :}@gڿ\ud,O"XJӂ/>E#X67 2qxŌ- XTDr"p~I7X1C-H:<\"JD],lA,m$$TF`v*Ԩ%?Ėbۨt.ܿ#%YrGfVqΊ| W/%:Knd~I-GMjixDoV,x*6d{W2ǰ3v*HTQ`=UІQƒaNo>%ŸX-W?S fb{UG.k:(m&8O^}-$@dxn0ArՒK;Wzno {=ba;3aLց*ƑVYbGe'Wu>_N 9^Ӎa>gIp2ɟaOlJ8yG@IU劋շׇs5{HKtTC 83LFTs{.R)+Cu$0N`Y3[S@6Zbmd]9eɹ\ַRҢSݖj.u`4k+5&7qΪݳyKJq`UIw?Lxq\ُ#wGJ;["[$% 'amcAWhQ)%-ڦ Ҧ?  ?qQ5*- ( Wȥ ڲ)w~v>nFogf#Hqnvvvo_{XeWud2ղk&:n j.ٟ)w}>0{]:ߓMBc_ʍWfoT/> vT?" ̄;%m[UyG .6mBӰd9<:'* ^ڮ|宗Lx^8aYTm}v`[ sh)$i p4/ oYdJԫRP*k6692yޭ لɩ*͋r]8$W<#f2>Y? 7gֈ[G7{oȶV='ĎsBG%j=k07pE x&@r>~'ƃm,Aeh)BQn:dY>+I+.i_+-il3gp[^.,j˃`8R~&֖ j1ߵ?t6ioh6uUg:AMyw9g=?c}~?-{}]Ͳ=#󍯽Rn{7a7y7ľZUǔ.onDa< !43NE|"p3J}= IRKkqHcFNn3Ky]>H6Ez`k;,Қyz͛t;Ճy΀M҂ȱB j!^>V!B]vҭ): ̔tHY*ۆa1^)Vq-h2®&$ւ%$եT2^9.Ӽfk["@®խAMj3Ah etؓ bwR{Dx~ca-ko5N0}/[,{Ȃ 87sca?zeľ~eon;6WRhI:& ]b`7Tj,|&$AzQ?`yгi:8jUU_V}aV 9[LAEWH#md57VU;t9ɖ0n^ki;39C#1J]^>eGִ*N춸W.L㓡7zVDtTbDǣxO {P›/)GrUuy0a>jFNUb\vCLFh?J-ma/~L_h $Rz۞>XT7VVNƆҕ^q , IDATC/y]gbE16?;^2B*U/,Vxd}ѣ^cԅ䄙\nlXFJ~YF{f4o2չ:B>fyLI<}PP]u1ɇ6&*)crȒV*o^oL@clF'of>1cY#/~q+}|{>tŸՖ߬j9@yZ+/f|o+a`l}rc,uًa{>\]Bx3+g3gM@c#1|K((%S s(ͷ??Ub p_8r嵦Dň2O j[A 3:7膜r^.I۬}?Ckz lA77}^[4 ȷ"ߎ&ud'* *'ʡ@n#1Z)W6FhSiډ{a4ZHAR[(ed缔 Α7Μ04"7Eh,U!$cX%由4!-#@ C/[|mSC[Lna BvaZoC_=_~Yas7kuۗv ?N Or:O_ZpCD{Ick)L>b O6WÞ|N=_#Pܸ՘v- r;0! ayFm5{Q:QY W[&=}akcc_]0LĆu'Ω~gZ1{7h<\dF]i~JMĆ Q2jC4'PD(h/ hH By5`iӠ 5O{3ǠFX5G6Et aUp3,W[ e'x|:If4rl#D}eޭe+.*4T&C ߝǵp%WK/MQZ -%WMihj*Q}6B C k7(S c$&[u-[]a ɛ]?B e6x)\m1[_)7([$]ǂ3)ƴv?[#m9s[%ُX@P~R4%mn#"XًYla!/j;_f\~3`ru'\G)zM5"v΂Rm`s祶vlaɻ5`י*Dmԛ᭿n`@K+3 y$M&`N. &`jj7Rd7MIxuژD4ux> ]=ՀS%D*`Lc>(d 4K|dT<7s81ekK#`D\6O*R몕w>c\S߶pG ֊ '5"Ǫ(Q3v|PQ`BNԀiRe]V<)KZ  Õ& (dIPTjD Dؼ䂇G6~~O ԰bYdz S%^)rSfs-dPtM;Y8"o#18l$RVx}nKU~u@kU#:4#l_a MLOH5d!C3y2{&=] .Jȸ8YDHQ/+pcqVLmSG@s[MG@!n#o yeAo0.Dof;՘M\e`ei^bE3DáB:NXMsK׎aq~JE/mG$8:B ą$Í-q3ܘ֏wͥ<% X0m`;LCb]$>Ϗ2 rhय़(9i#2؂ 9Ff#v.$ov ?WV "8:>˰pYll%hP_a4e[xl^@&L9bZ0/F22:Oop ]%C@tM^ [%V0IU"[<<"D(x;H8oqzPagOY*ayTJMM"KѠe Ki۴p7@5VXFB"2h.7FhLJIYPY +.$lM:.>VȂVߢUnlN& =f}oX}K0hj@7gODPʶ铂I-|qT<_(" h4{<˦q$겻6_eL䱌,yȲ~9.c5M{o\+t|4EC|f彌0G.j<TOtj!qr3I 26{X6jc.q[IW&C*XB0p駹lX2Qt*Y C6]:f&'Z{NYS9 jں-tT6Hպ6 ײַ:?v'wo<8Ol8{DO zgC=6'*RGΒwHe޶kC拮ylTثcT]rqea kՅ:s5Z}VFQ-/t6>pWۃ9^NiK0Jú~՝f8 ?R8Cl xkI#"ԓHRI|jjdۥ,RJDr1*! qb?x0&~y%$~_.҂:i;mh27/USf'} ysd,>n|4q0b&sߗ?w^|76t")X(kط0aq|cm8vap,5˼rByvS {ܰ2T"u~@Zt<+%C%ˤԩdY&i%9Nb} Eilp? (`OaN@Sd6(m],6ݤ^lPiVEji-9㋴9Hs=rH9vD`#rȹ[\݊|I:*_ ["m&Pp4*49W,SG_;K] u<]r'X&|q29 aK8m-*f4f@2G ٬C7Ev{V9A_FlxDѪ݀P y{厍ko=8w+szxat+ XcN+f dN-K$3f;l;Vȡy˯ϴطrn{V#I7R*s>@nt?/.k rΟ_~l9H>q:@G$1f4Ʊ7ܳߺ3k;-~K𠔿fsCs>?"I, |!ׅu i"=Wzެ̝ȴl;-"mRan}7k1Ğ'1' *T8Ik[R g _%BZŠڝTX ci)VnDVU턔]oݛ^R0b a0螼JF(: 5;DiFA<7t՜NTT [b0CjfrLA֐~aֵY##tyqi(#ψ"t?7ر0ķXikcO34w}#l'[K!5A§M[#wnI%2?uq _-]Kf]v^47I`ݓ#i>|@=Qm 5w_>zU:*ٽlb,?x!E-WhÚ+KGJ/mNR]۹z/K)M]P- zj+RCQ _=*] =ThD &בZ V3ŵ)7 !K&?O/M}M}İY(>eXsCbԮ3}OZy:Am^q7/;5_9ZJ\DG/~},وڏx&TVՙVg@]wiJEz{G$yKRwo{xC*Ͼ'-ߜ]y3r| )آ|Q`hP͚iS®P;c~BbI(!ɢ?&T2zw+g o{KqΑ^Ա!*?v1j %6"̥0`i :<`Hy>b7nR!+X Ƙ#Fm(zO)u2+هc̫Soy{{xլ!a=li% .U(&an3qxS&qs F_7w<$lB+a YYn)yzLI {ЌfZp};@66*OuoZ=5.jX^GDej05;uk/_.OJzfRZ/^ѫ* }#gCHB\ڌZO q,"nlQߥ]Rwƨ鋳=*%TMkEWnK+˝ՊYNyr?;;x0FpQ )^BK$IeϚgndeǹ gb],P[:m$p[s8d=앍siԆasrrƐة-.*[K觃f9a^ GhccnrNSNȟA+E3KdfsBӌ&vH$7? W0L4Wը/boK ?%$6gRril8>a7|,Y@&;j|8jXPfW}wF B,f 18=o'hh[ yf:MY9.!g&Ů|$UtM!o߬~SzՏ>S<ԯU`VWsPYBFՖg OR?fY=xu'rZ˴LEW޶_/0X!g݇4!bY+E+c,)\CZѸzgx=>oH{O-i h<QMHJZѿ Lhc8?bRl@͝CM ;^)0m+Lf ( =5!Џ@pz1a[{լ*%x5drWԌfhY[PAdڬMCXlG&1b ;̻#r|NީZ:2-mVbHInۛkeqd#k81:g!tL5 M%y7U{RiW~X ZTаw7Rш+͘ʜ?"9e1j~mlX^#F(NwyX(KTSRuk%ĀzV?Ұ]Fp)":'P 5MV+:0sR'}NޭH.2-ZYVVo"g'ˌJgpknJ+^!"XspOy*ϦO>bVN?԰= mH}hܠIx-~(5{sJAl_juިM syISm҄ՐUf&+TՙcOetxsd97d7OԆ IDATv^vK]=ۭhڕ\Athyr2 ̺|->y,JJVf5 zD18\5)PWgݱ]0 탒c+Ky2I6 v`YT5ΝT5dvˉL Z*7isS9EI5$o*#baAaؼ =^+\_ rS*HRpڴ )3Cf͓av;U'6>>]D}b.,6`(iuʵ,'cd0@yb4u")9fuЭ sN1i{W6 c@ALY,rik9 l {_eK*DɁ Yp'3 [ͩӐ&Զ1z *jdv%yCdA= E)*fpƐYLIs9_jEҺ>n-Kg7wxNXBזpN{5 6o{AMu='(89} pD˕cttq)~6IO$?K\mAnb#>NH9Es;?SݵꮹGI"mqX9dÜ v{i$-T5b^TWDaZ 03ARIkmU3@^ٚK,ݨy,2JdvØ7/PsǗif.7=f UDqSb8oM@PF7?ɛR[UC&dL73D$Es3fPye0iXu6jH k!Zڦ).3A@yq9@Njd5! \ [Xj Խ?>řbڟj^j6UlZ9C!"I$M_@ƍX[]|-7d/]::,O !_7)|ubDGn%l4Gʾ'ϪY;EZس-BcZX2]㗟Ě~]ai/4&cixvm~xF˰TWXWE:iyӴ7%^볺N}3ƍ|HY=]9N1R\גjZWk5faP Dr'5%E !:))QP^{M1̽;w{9smel[M:)l}U"eLh4Aܛ$Plhd$|̂+҂ēQښl!ƭ^BmŏUz侻W5םљw|zA2溥H$ h75~Ͻ\S9kJprmaΟz:,!&zaW6&T28|yEc:)4iX⩓9#*m?=|2ӭ(֯'obe4#D;~C!5!( CE .eƎؒl1mSS*Iڧ`{ۡ:#rӘgzɿR/5_-C}}w;\єAD+?2s{TY~#iR5|Tařt%II ";C1vQjd(reh{)9pڐ7yskMp,R+;-UKnEX5p P:pܤ)8p2e2Kcɹ.&:ye}A ӋuV Xvm dL@l,n8:}CSz&pozq]&{ETOg_悜td8*ٜt!exv98Tv:r6`.EAdK~N FӋu{ero ͎_@t!۬P>;EҸP6%P5`cN+RuhBJ^ŀ\ {<2`MJRV&5xf R)qg99 VR2IRPCC䭀)P;{+cŽCB[ Il$ d/v'.81D a?oiR1KF -o5Vŝf'}LQ R̉ f?""}(iG#54jEe%tJ˛if`kRҵGQP6$qGO]&%%AwINd2^V{\vY8 ,i(izᅀ[)L|pe]uU3^6$s1MZyHjd΁27O `z 3Z y&ݕ5`FtSY-/DVHۀﺃ:yMG<,ޕѓ?ţ^]={,ٚܛMqAܥЛ|BrArMUeIuV]pLNPx4ҵ ' VX^6ov&e1s '.סRWf mʸ YʹRx [=Spf^5ɖ=j'YbVY [{-C>-^Q~@ȬzBx,iƘόB)X֎v!CvsMtuR3ڸ5zwDT-'%(G]]5J&s[Vydޠɠ />%MaߞqX=,XT-y“L0n1;94w :d1^>0&ekićhX$tzq*'ΊVM 9#XIzUmi065 O8dJC|ρ-[}K^C_9^"jpq݆_~#ok%yao>ڒɇ*;,SE Qu^n.v>j]íy;.wr=b @kdeXBy5|H5٧arM3]ӏ~4]wexSnhnhX6(T_JhSW Y%n:TZ: R̰l .<*탻7-LTg |&|fwYP;]CQ({{Cʰlaro⇹x KB ܗyXҟoݯ=p+bwN<uA'3'~+.߮~r,%B;0^̂P|0ےK3ۓ/-t+>W7dG>bq־3;̩ޚ”o1|gS}~U{0ݿvR;gad[pIn|4Lb91HtU S$ҥE)+S̭n*?a]hWPqXn53*5hURmbq!ݯ> vX#z@_]}y Ӌul uC[U7yK!Ur#T:Łn\4pô׫hnj! а'O[,w_$/(C:1Ih^C,e$l=JdLb 鹦Q-9(@V"`i\y/5f es8=9P }3C-56grJOVUBFPe WXkTB#=xbs,^9ni&ђw bѨ5̶fPA2n Vm0*Yd$#8=oq|5b^XZnHaqvţN1T(ޚim`7Gw;+%w~]6s{Vl=߻o%%$"X'EטmsGG)?Vp=ɟޭ(ܻ֚mmzrg dJ'V]987Edz?DӽjHT0e d r5 Zr[^Zi H܋?(Pt`kUR)&}%+ZCQJ]XR!F(F~9Ҵi`3!jtjH}.B+:}fÿB[w{yo9ж2iߖ@ìb^0*^Z wTN.U{E ~u3K,K߉g ryZ0\if:eҌzv{t;3%Lu>(LٝźCu`0wXFk++- dasO-}WXЗ)M|ot⢘ 0OAWUWi;p_pl~W̩'D~ׅHG'gMώo0~S_M_o-sْZQ&@Elpka&N8@B98p6+г܋s赗5444 a "5a+T [ @ifSYF]_l$Ж{Զm #lRP-޷:2TnHۯSEw4vP|b dS;p ;UZ1 c=Fa,k#HPt8.I/8yN@ғշg{nٚ W%n SVG0Kz$G#] '%i7K3Od߹kRhϺwlk׊[C\9#k'֔O֓RPj vlʴQq'q?!DKg 8{YM"]NS(mIeU5E6 6"/і_Z5{W@0ǧBJNneq/q/yH0E(aS={p!{m^=Uxh.3 gUcŅ'~s%éw~QBP/kXnV̚fbwQ-N=6o p6fN/b`mO95*':vvPW0ȭ {!R){S\bh輻'Rk t]o+ViOW p@)W=h}&{ӟ_/gm ܝ?93tE'ox5/gfj'8qc g`;J{BkN<#-Ykjyphyd!gRvd~ҎH6ہ[[R8|ƽkp2K?tz;,(r' Y3[8'u &a ^&r'Eҽ|3xAq`-99-5#$&$TM$7[dǖ[ SvX{U/}&wﵤ;}Y}2ֿy '_m}rH(Fȳ7h^6ppۚ/ĵݐ3Z ۇ.͛LR21aO*E=Ge>,m%Sx'Y%rbWqARE5c+)B5 Q5˚sEgCJNԨ%]_wp6m[j&;F;\NxǰEuqt^8ZBKZoV/#oNmdg+-h~QNxhĺ@Ctb8z ;L =iLSmT{Nvz3䭉z2'? GVa11$:V9z@ifabbNڔshaw> eL9]bᙆFAwB*h>WtΜVC27ҁh;(:544 b "Q9Njt\$à mC ِ;k#{ķ2z­?kԢ@Pp/DCCC/͛nk7~-̭6rgp˲\jN;B10J94j36(LHI?\4e)wtU:]PynB,sչ,RuTLg@@%pbtuܑ#Il" < ]A! e=yfC_fO[GtU*ub^nc[ ݳ8g|a.Q_T,r-)&XqwЀ>; 3b&I5 㥙9T>qCτ;'{pv/S $2Pώh- rȀ2#${EP1y"jɝۺf.P/u}}銻>z'sew͗'Ð[ە= GT/+b+o}@>t3߼lFjPR1M _ZUUl!FeSL9;1 L>U8ea8kAOl1P_`#Q; gLK۝ۜ" }ʽB(Dy¼#:=y|$3;_y<1zU}іslquI|?r?<{ ^̝R}6򕅾u5M vy-n-ݠIh$5 z*T {7`AΠ;ͽTs  "xw¹΅{"Q)ZIhoyӡ#7e)yL$"`oMo&&=?1kτIgH=<@|SN 'I&vtoՍ:tϥ͞(~ Ʉ5AM[BBIb %4j)MElwzB>l]l֏p}=HyOrgJXqd,/mXmNMxf$oEnoԮe?ٚ? ɹ#P6.f-mscq0oԂz7*^JĪ[W!y? S9ϒNd45v)' D; Hv @"/XOhx J+6gOB10sj߆OG˾I pHLMf):1Jrd0M*Ͽ^Nl_q>'T7ѨT:Uߧwew h:o&w}aMXgP١Pwbz#M/ k't}7_N6 J5[lhʟ s^snQ5)KAi/uYdy|trvۚP34R ㅳho 4$vzc8k,wq<#|M|X`l*شMCNPZV=8Ȧj2n67flx6gHh ؚuЊ h^y_sSv|cx[W^Xoyb쩁V03~IDHeFNJrȚrD)7`<-ы4444X)Adhs)U7uIuR:$vi H'Ŭm%a WDnOsK9,i:z.N4Ym ISJm{n 4`FM 94Oov ٘zNCCd_*jtٸߟGVo,ǥsMOW1yܫZZ4 %ŚEf=2sGUv ͹X8֊9#+;ߟˎZ ϟW`H9wiә&V ܵR,փ(l4Љ44 "rX'Η#!\ci'. <2O;Jru8v2OYc6;wK_vbV;dN ) WǴqW0"x![LyJӹƂaO%nwGk`֍W<~r*q$TTc㘿whAALqiz6k#5XP;s][ou>عJF&kɦ*y" D=& =qprEWsP t5 PˁXQNNlrM2j{F B5 R򋽗~xl/Y'Ŷ+n 2^S<3qqN;c-~M^ ywU%8&`;^[k m4&M޾q/ H/Q b3y4 ĩps< >X #Óhec+&RN9{TCmFx"RN:7tSu r}%i55}uhˇwGnD5DXZ}eMogFxoPn&k][OdɎrO74r ]H4*(ww[c uȲ=MҦvkICfk6o[t);!}],t%% O-HgvLjZ' Ӝlv5ԐV)KfoK1M9oÜ|P.{U_@8dJw޼ 6<DlM0+dbzټ],IQYżQÌUkv[}fn;ޚ9Th |ӸLIgnjgoOܥ,GZԥa3 sŭ]} }QYؔb5'm EFi_L6#}#p`1s a#mǓp(iY"m\l[ͷa%-ا.`:^q-mkh,3)rܚ3 4ޅN~ 1!\`}pHlQ;0!s)ř_kNu>ڂ y͂53H$ %d>HDh(a MJ2!CFl% M={0Dۿ0d@ᶼ82c>bgW.j_BAvN3\0bRht=*b^|~p,~?fg,GcI!'fվ~Բnm;7DA *ІI(1gܝ϶UUOd5 XrZDd۾Іųm7't y&2ɹ yb-T 'rcۏ@ ^`b{;o9ӗw|C)ij?~h2n3p0fT-làFCPx ȻN!vIY‹crD8^Y2OĀH3'UHVhd_hnU8Kc''o-r8 `EޖhQ,j;, vf 4 K{`4Ξa6th)^ ;?g]1F nV{|%Oj0La=Z Ɂ`L:9Wp,v{[No}]GGyTkzf\TN-4 'x'K4g]{UUH KDZ •+(,۵3Ƴx)7˽cȻo{ )O=C*lJ".SXYVKJ9xeg#!eZF52o Z&Y)Z@ ol+ K}'dsAx s\8a~r$ѹ?Qne [o]EcBXdۦ̌µYaк]-?O1'BXm#I4|_E!o'@ak@gnH۪%"yW[uJO2kKiŒ~E=BSD&S #hy:෶t8|/JbSc޵ BҀPڎ:nU s*\ixr8[vZ^[ A<*ĆnNM;!vi 6(eK!,Bc !댑u"2EB.jY{*ĆPm98'A  QF) TxvBao7ƣǤp ۼ1VIx`GܐK*~Ch=OHN?if#=|\ANsG~S%uʁ`zE jtp b$u$3oS7m.n~04ֽͶ9.IV旀^)^bAUT+c|hq/KrNysǝ[7`1O\y`VYk Ora Wbz zwv6?=ҾK=7>I/EZ4/ڴ%2Qs)( LX__t⭉/\@TL)0Ҵt05P)ϝ_:1wXki ,]5{ᖱWJdEB%TUrMI{_w HSZ *C SQl1~F~bl[3u u?B4({07Ei_cxȨm99G]-2Po0-]a64Zjخv!VڭpO w/,^`-G<&K y%*nџ7 6h8L㺉2}HYugy3<ԫan]-H8[jLɟfOs'"h@(/Ӓ.T &_ݾx]8TZ9uQ{7Fox`J`CdM>s&۷/˴\|'s4sx54Z<e2>n .^)oJ떣w=HyljrvNHJt|闙Os^ 5:x{nYJ镚VUwms,ii5#LR@tJG[F/vmq린_ki. 5z9+RI/8xPS1ɐC U F>hߐ9#Nz77W.'634c-{P{hRz\\b;5 vŴyy!?n-|[ 3{_;{_-3*>MIkeJ>5,p`ƜXOC"ĥp4{9[bY ZW Ca4i~P}U[™@H/XDx{A1W=20240y\}XJ|s71 (䭑`Ih&;d7n3Te2z{1nɻ![F#7`e Q0 ,ba_%a<{3a|ݗ^Io+tL[{cs9s`nY_2wxp3odKGTVI~0ʝ{gzCW]euw>m//]r_uv6,0XD`V2SMK򉝓 ;ڎӥi@K`*35x`!%sa׺ܺ<@tk y*3/}g +w>GNo=ZLwo5 +gmKsMW3syS+VazV1!k͓S?Oz鍇B~3k/bg(CHm ж=aJ',?e9v~>`]*J%Rn~9 !.A$}hjGy"8 / |U7?~0ޙÓ: @AB"_|̝.|8PWܢn&qyj1wOx\,{kzl}y=/ki[& {z{І#v9+_=1u`\ y5x.g>>O: Ƕ+zL>՜ߣcFZ]slk8a܎B[^<9E[F <I޸2 lŸN`C lLbT] *䩩MF͐Y` sTmrƿ~#w2$x}u)X/M0Ve oAң5oZw悽CrnYO]dw tI^H{v|hmQ{딧& PvrH1큋jݷ^z@.(Pg_pܕ_f 2yEk3qgx ;6ᆘ Lsc/@QSlys<q3"x̹g?ݟu퓷5;ꑖ?cWQ, r V$g<[9}"gy)sI;OTf*nGN ; s> >Jg >y˜>@ d_5$)t4#ێ.{FoEJ/¨ y*BCFvdatguxo<9Rl3sA\L./p8(<^D;ĜG1yy%х\$*#Ļ1ґUMDY! B_l?-Y#Vtx1'> T+e&J$=.ozÙ3{^{uw\;bLs5_7h3p麘e:xo9%xi=o[dAUri:0tx*rS=*w0w!X ڣ{^{a1c8a'gbzoxT9R0h׷_g$y>螷'Qp x6KFYz9osɊQR㨕J9+YtRRfë}kBʗM#ڍo<S|Bh"]L p]aTocAyw8-CxG,pk .H@_]I,M/pf'@ 5$[oZ ƹ79Fx`;px^62xX繇oȟV=<@5eCW Â{fls>uc=<Ӿ>|z}6^wBۋCkC kyv 5%OAWgih :חP[Ny@SٴEm= CS sFoh)叠vi%ixrLl&$E@@NƉL)5M$H 'bgk1w}_׫6MXZ=z kMkVz NEbQ^{>]*7Dv+\xxɬhi&$NfР(S؆?ųJܮc xKXQ)"{2lpbU&|Gh.ȐqV\\qv[U'gd}.B"|F"x Y/?r;(Ak[6c :o? q *n汜k4n `?YLU=%$R@vMׯ Ns;&p,/Ya r(\7ε圆4A@Դ \9B#+&S8Nh7%Y,Bpox%xu]Y@Gy`vFz1F#HY}؃ 36<|h*a_KOOZg}{'vv>߆m'c yDQ_/J9FwDI!/9Ǥ4{iEjZn)vWʗpw jt.x rg}eoBeV9 Er)Y! yn'=(P Shu L|ouWV6cbK\XZuu)֜Oig]03ś")yv 9i,c6lی`IhؑôeF $mbb1CA&Mŝ\.^F8?|/L|xsQ !bP2Ӊy5k/r\ ӆ21^2OqX.HP%FVݞ1LvͶs@~.Cr`@ - 0VaZez66Qi' Ų\Vw75}seRpE4?fUƇȓx: m(!vɰU=ɝ| w^(pWXQz*i&FětpK cG%7_}_xWesb~87H[nFþ8䆐}Q ~_>ؿSy vNBⵚմ@:CS/v}A8_8ȋ6k2W~mjTxC% qe )ʴ}Ė ȟF`c>,XPM["BWeq19zF |کvgT3ՀSyhke"\\#/39.oBSef nPH )ǒC0AG~g4NAqqIz:srś:r|Xc%!cMO|ot'{ij?\z,3՗{Z.@Llj{ؘ&QL.D2NI$! Źfrs8/ŷgG$KP&]?Kʕ6PAb^==/_?ۗLm!dZє&[7P{74}go86g < 8Ҵ QPkV[b0cRFa ey m5S+}sҸnsjĀaSٻzYm{tT;H02֫xGUv)ĤBV &DdF'FE!1y6dp:PO5ȑ/̵\Q,$)V_ O@^d#df8\> F'l?=4c ڧ~>u@p,.qX;5NQpPȯ[%yͪVKzl\%QpR_V ǖuN,$Z添  M޿j}ҕ#E}rR*hȮt)bxh)u򕟬~{\nЊiUߛ$ ch6ۡuvR?\̮OՔ% RrϘ(#%ƷZɒ23Sز0]k{zjt8o@q&hF(vlPM'ԊB.eqOn;KUh7,l'fiF<0E.:clOT;_v..䝏"0GiNO%4CL!{%yiHYZ:47#\u=S:y$S_*B];{5]ϐdI4Rkή6.[-촵k}E p`݂IXŹeױ${Ԕ9e2P" hCbL3B*myзvIc!oX=g1"oFv4TlnF_ q0r2}=kE3 0l\(6mbta Lj\4* =^7onm1.@-%P:E_n2!Cݼ\QVl菾K(\!M|C*Ax8QڡJ1Fub"R vB J40+!!H ww ?s5yg_߃%7>ytBkYl]Lo Ҁ6MoUg &$,-DRyER6UtM^/u|&\8؃%7q;<|"EF+WX%Sc+#Ԛɋf~^CKhO$mh'{ُ+f{8 Z/F-Jzd{ jb$̿b;!ԱO4 o u@tTl7[ YlqO0e 98Y.iZwP(Kˤ L_DVw~v?R<*$|NQOX{Ч(,R,\VlR\ 4 K7YVzr,*qL#BV$Wbk]b;BXcۺkÕKz1DƇ0̵d$ ENA/h[P7bxyfs6u"&ݏ_L1kS\?>"\$t'Nu??Y<vH޺?꼰zi{gغ7O.Gs >)@2|t|}=GR{FWgiSeϖC1Ox HqKw^R?n}ţQDo4o<<Ƥ2w.tw GE5^ m^T;kZ/ܥ/#5 by{*]I.BSd'h艴rZ,$2si Y-^^Aՙ/&Յ<`Ň`'c J73ϳo!א<atmk[m%1 b:Rb)|nBrw*j %8&W,"  _flkqv0mƑ{`i R//vO2rI3tw0O;%t|JlOhE=~*1{p۬G !s*7OtK+Wn_#܆^k,?[qڶӵئ. b$OsḱjGN$Xrϼٶs*amƷoūN%#D+58ɤZNJ vdp e&\ь%70L!MR,@(0"V0hJQXtKnoY0(~8ALmQ"`>2稒G#,0ļk4^'vDgs+ j-C%}ֺ&EGҾs!XrXUwA2VJ` c2pc ;G7<.< (vp?',nK붾`KOP[$Hޯ'MT1@DF)[|a`2,;[䚛R@l^HuX4!m &km,i\f4l#νwi_Qz.yŋ; ?4]8R:q푛rH}?&D-<YKhC0RḖ? ~kvouz+PDWjMJ`%#Ư-yW>kzK\^yny{3[ϱ츟1xtEjd̋_o9ҡ*xTϜ.Ŀ,A2-/,HwS4i7rs4Ed͢3u><YMZӠ- j)[(-fIv :jp$x X 8v+zLs(9tu&_1v~率A\ӏ 6a𰟳|5K䇟:WN= uIk.dre ~qߋ'MYZM/AADm<=>j/F9F6rމ G"`>gZuN]wn9։ȁJĢjg5̝I{GhG /lCԓT sӆGJL< ɼN[6PKq\ q[2w+TNXe7c1"q/cK=T5wc'! *U9&ss=ʧ`<NۉF[$Q="M$͒|gh `yg˗uz@~:佸\̟US_5>{u3r& "M mj5ik9]Kbih0I*dLxuF'M#&Cq31Lei`#^&J.CxmnX÷jy'flXck;ԁ92^{XQr~ҡNӵ3H~H@k%30}sHEvޅ&|4H+hk5kzJWjL ە(Wf7mY-歘;c5Dc1F%b+D9v"I EƝ9\#8aӺe K|-%cҖqM+]f< d%\r4'b"L%0w'Xfe^Om#CtiY&GjZe)6(t[lܢBv%7 F ZK|V{ IDAT;E5iDĒ:W'ƬT %a"C1LԔS ^ k4ke{YxU3O )l Ho4d1 $ EjdӶ"Rk@In$}$s*4l"Ia'=%QPsN[f8\RG˴L76?Y,C vFm_Jl ԰ 4V^ؖl~9n*A. ^p` |s Z› 睧>&Iׂ++bpy0j&(Y'XN1po@t|pl[kOK)O@ bz8Y9)V!FL](b (u 8.-]eFd5BD&8rrEn 7oUQMM1$"V4җ:] X.D1 tֱͭ>\b7y;,_\&pfm|vd]H b{S /%sism>FT͟@: 1rJJyDMй3"/BeZVLoM*4($tGgܖ*^LcFzĵ:[%@h5 rZX.'Q"Yqb G'if>}ǔ<5eZ&IXU+E %1Y0&h{ʛL'S9=?q<2:H1NPTSM奄8oT,M"VHA1ɭ`g 7N!<% F,tRL獪S%iIX]rZӍuc̢㛰uH6h\"hErǖ#sm@a7v Ypxi (p|DmlrRhatN<TD.%&)]Vv,Q81oJbNp3\||yyqL1d\1J;Bb,"o-ږZU!|r&F̥-;~ N g[`7V ~`UŘ[țNqB2ͽHj >-껰)uUi曔vvn\"U'+4ھA*$ţ](F?V.2puw=uKQq{=NӶpweM+4ߩz#ֵuY*Y$"0]SK=>R(KJH D)|,9sU{N[8a8aawc")4AGCo1h66C mfٯLFQI[cDɤƙVboHC5_*(ͳB~器6t6OUc3,|:),cGR-,zL'_Ʃ9^KJp0D["+= Vk"m){<_I=Mnț ,ip4kc_-zc)-U> b{d.?œƺ~#Ik]??z<./A-5ؚ{p?UF[R|g7/~vxR>dv}^SW{3/deR0="m`szoci-$_eV di=Uy f#l."Hhd 9#Vr.f~ĭgvDI0^1G ?-JZX0Ua{,Sn??{ +S5弖*PXNZ)b@YBʤ5FM)ܴRd4#N ʨ^X \O,ʝRȔ@)kl?# us< _g".n?|m sd;lj(ͽ~gw>mgC!'j]M;LAWYxȊZ`tv)!ߌ<MqӡjvF6T"&/m`l%1Sd*%# AFTI[#}]]~ LG[Vբ}6$Թu;ǞYd;x/ՙIxIym@Lݗ *Ū{"_ۇ{m[_Sg_;;3' vE9qaVgi.k;A@\( ՙ%5vQY 5'}- ~;)@C,s»b.޿öbῊ8 q)oHpWZKGD:FڊSou:y%4g(zHob5:g}jy&yޒ!X?R+c ᭉH&)~!...sHbu bk/A3a1e9rXf{#KEFdf=y r^hI$!PC" HjM6!ژ%C &Ml@ aM.I,^MAaJrg13sG̈9YٕYYUYpo*++2Qs9oA,5;뼔NĒo=t=Rya|Q9`Q6a乗,FR%⪜_Ξ%il=?ңiVmvR7Һua=Z|&,Rlvrub1zRu^l:1+Z,/)>̙Vn4}m|p#XeC]`~wP\"ϙ7rgtRYeKqyʓ]ه z> vBeze6 ?u>L7M53Vi}ӳDdk u-֕wN D:c4W~U#ŷ3]*6O9G^yy&j'Wي[?9sQb˻za ymEl[9]e&\Y4*6ɧ?Ј$|gmΥ8Y*^l6چC]g\Us>< (O7ZXʓ[TkTbU>CڍD~ipxf$u߯2л4E?ܷݯ/~绿Zg ?{Sq*'Qo0UG?=DlZ&_zvI89~,qsB|Wd#IZ:vePsnwO_y~}on6|ZamYbNqr)Zh&vҵw瓫--PiWWq[Cyˠ:]h#Gw~?O‹rr?P49>UW_oj{Qkdk0o{cc+ztwN>O^_~q#uk~VɗGow˟p۴(ˋlym ^^)3b_:r^y{ܠ}3&JkWw=ݯ8~k}蓩[TTC_ep]/[+_kuƋ{| ou4Rx͵'TTkr ,@uĻ'-wqs˷Ouژe%2{+|x:Y i'\ >Yh 65+Yrw,^,y#e3}&R-a5d{/{٫؋}[=QJe %Bj6W^+lZ[)mf؋}6ivsnEO nubuUxo38r Zhs3df>xo6IˮV˫ Jh% n_6Rf⫥~;ůr$.+wĚco{+7J233WHWn3&I]I)JbYGʋ M: \k{ 04aΚÖK-_[$y50K]?睌y[cMv]bFUq2Wh]-ejYy9pkZ_\pIlgޮ[`)n|kiH,0\ |6`S(ha*Uz;_7 N*h]5KE]\w8Ull]yrЖf7m3jFo|{f7wz9e YiG7tջ>>y=+>ܢ>yuX6"Ȳv[r:QܯװgeW[fweg8ɍ bm7xEqy 72 @ˀx-9ij}ޝr'[휶uoiס-{ޫlEϷy5ZqS[d+޶-:e{u/V-un5>mקE{ݖ~6_o6yqEOmƣݢ{Moynxr7\kҮ5~[uGxp;Ļ-TҮ޶^kҮnE'[MN."mU☩N+9-8-{ꫫlbn'6Zhoe@Zhoe@Zhoe 9`ufjHd@$(`o/Xg|u]f{h.~2hpVg)+%WZ+vulWmŝ _x龶  X ϲ^b"^x"lsy^o~Fm _^7 o@h|uq-K5f  `+ּ3ivv[8O<+`6wr!}d[`]P!޷ >]+ʦ^^MxAFT~wswJ* v w:Ʃ<_ 3nkxҍko5YrZdXz%-3ʻ{ @t $u˧f uVy /X0WW_ q-b1ʻm9F$8{ qmg,V=M]-Sq]ʁxKV7_˲8:sAopTn7SVE FFX[:v_μJk7I^ѥ[YIwe:[ڶya1@o4 0E&zrXmckš3vNiO&ݨ9V0'7q!RT5OvHe;l7`-ֱc6k'+?3Ll6ڹ+oe'.y@kqSW$6-mHf͎?GV>PFB6'6MquLYxfZ%z1ƪS θ#lB׉D.,Í怜=l5k˵gm`yYVmyEA{ĞTv넡sɾG-0 PB֥X*%UuEA*,xh|Ľ]{[ĵ lFTm{mv *S7oUnj&زZsڂϞ{hV}ewsv+/7mަsʿ\ YMrArbvyF.VؚUhٻԦ3p^٫]; IDAT>/ܬXUY6oj}EAf][46oZ̳4Y1Kx*+\b܈hŭe#PǦxb5xƆo 5j͞S=%y9CyFGzzM!8U>6U6mqo͢Ҍ.vS0DV ʹ\f67qa,;Xp =~lf cb Zoay{kt@7*O~=֨mb@zTvk{ډT}cC'kq-wfA=oMr}喛ѫ=mhYf14-vol^-fg}_զ7qt]v_]w@!Rl Ky NCoe׽ -1/!wd([KF G X R|Zc{Pn XUn.mJKrtᷡ)DYJZ u &U'H'#R$M}K/0/R=2FRtkw-Qo=mJg`9rcx Њw@/LogZQ&;Էߢ׉;VISNIMo7KuNʹ)i@A rY+r)~>JR11Dd[-tѧZP[1ٔ$j$&`y>'B{(˞{ԑ/R*dm_h34,N)ck-+WwvO$I|@u#&a&[tRq#sgs[3]iZH ͳ@tMpxR;JvӒm${ݻ]rk|{&]HX77h:7U)=HVNHBS2%鬢Hqf=vQl7J됤>ʀ^`K)0hO<5~ 6Fyȷg.C{{Ӵ";Lp8OSꚣoȟ]޽=CKB7v qI=|*w3=2ep|LKmŖ789O)#o7:H-g;%+ +AD>MvH0wN]L'OeWR$ud`:[L_MqJw&4k[;  ;'YiwSR TQ9q0˵W;K6M =p!cB{Ș#Bq턔[]{:d/>x/ "Y#B\)*_=iS|Kb_d'Tjy+&Ys2cc{3dVf*/X%fh'&MMN#}T'$8HH똕5* dA<\Ona4kH;Uik=lБ`I @gDiX4LFn8%NhV^n2u?TSb^rZ$cڨnb7#VkHoljZ-orn ޷ʇ3-mh (bH~ܹ$RO$*(_Q24)QnsBٿDO8$I2h<94=3m"6Q@XW9[8&|NO ?UPfea<4k\H] ܧUK=!I{Un ',$OyuBO!RF|Aݻm̄'4O2pGRNH}gmBsmE}Ă7,lgmw3ۓڙ*wQ%^rxRɺ m"Rn֣4ue?Ҕ-~}_Z<;lr=1/ kmLt4|x1~Qdۄтv7nvITMe=:HeӉI=Cώį?):j o$*B񜟜ln 8OÜ_؜q6`qz(BJh 7Agڼ%++wkve%eٍ*=E Ůrv/VCAv?xK"9. IECl[pSNjZ/C7t mao:I9+ rd 璗ދ;7ق μk;\DQ^|=O~'G<&m"$PnO\U񵵹uk">s:bNJ%ǮIߣC7>>NܧQRZ6<VSn92n~D{)aE^GK_EzF:x^_-sѤQk=& &Uy&Q7u*lk\ {?%Nln9%)YbN}IyleC{Vv_n+-6Y–,yj9;2mڈuO'ʟt%[Bd];ﮉ.r^l8>UXƷdTxq<'ncdn灒/2JVG,a4蹆C3^Alݓoz!tf {^=ONcѱa喋p 㟙:iHKc$\pTKÓM) x::>;H|Q zJ@t$G}4tGfx57͂dAW4s[֊_DlsK8`-:zԤ⌱LF'n*U%hB ܓ.iR#$}G< /E-FdJăIվ54~/N"C ץ0)7>Y HU=0@;qWyn>K8!K2QmE^{-F/{& 9Dkz%\<sqA49zrB(ؙ/rwSYoKkmg!f-&sGYH5vn[IY+fgy!rm. h)m/GCcDq<\ݡ"~"S5!ratg"y?V" 8ؙ֧ċmNcP[rwjVƛě#˺ϥ7OTm?G-h~Kk gr5t8Ќ{5ɿ!=Dxuloޙs:Qtx#5ys5N?R$oȹ >[ӐxYWy%Wg{BͲn܁䥫ܷRͱv^63C$@JXIv30]dFI%@/L[\RI+UWCWZPl􆮫n㻁O"PO7I1\7ml**&fxqӬB( 6gޥٚv#7KP`4r= S|,fb\x)7- \}+w6J~s"pZT-er io聖j̩Hl,>\ۓ>.x=Ov^ICF?6阫}'IKRx&cjEFsU2G:fmdnps2^x[:z%Y4L#ΙX:.g,VdjlMJ4sf*"q$D~&ȉ78zMa4>GM7 FE`๰mE-E/֞Iޯ'/N طfyHjXGμV" /YY8Z-0CjpvS<@ @Kix3< F9Fծ 8!)<m$gB|>}Ax`t;P(c l1fCMtS]9fJH%:teR&Iƽ$O虉I.{Ya ߈D /EV#Ɏyɴ[ȟnt54˴oMg:q~d<{]RGZ/D`Kz%x/Anv# ݧm(;y pcҀy/ ^ ?7~v1؜a@<ϴ~sE:mz/HHrsw`|;)v h!衾xa:yǹ9gY@f{ tO!+\j&'l.7-wI٬9nt05|9yc`<,+12m[5i^ƶmx|Ǚ&x?brkϷCh YTp U=Tnw&Qb=sMoqOؙkIHy8|H6dT8q ٖڳ Jx~M=ңfЌ,i:d&0O il˶ƃ/lvڳpw~ }lx*o6! %Šra凾rE\ض]+=8g:f*6?A\K3FnTRNmoAV$k+ă2RVܕA\Ӎf%6O2dͤ#mM?#mH/ ` 'OLtG3$zDKV?Xn՝=etӜq:&8Z-;nU 1ׅcӸ=ptiI™LԶߗũ_nlۅwlHrzN녡YvoSϚG+jII]Ņ5ybK7m|ӟxJU6Sikmrth(R<ͪU3iSMcBk5zb. -=I4yJ_|{I<ǜ,8C\ ;8Mv8Cg{1˚9Ok /U60ѷZvl9Zs*vY9X|޶`t^"Ltx^wXl—ͅ}~/ YVw49S'5GtGJ0ba &9K W3Ni楗Mznp͕lk]KlOCf 6֣(P5Ɯ542[#u*uM$> !Ia=O .i2㕍 lqng |wPTOz>mw{6}]8-Mގ 82܅a.eKrX>7>#s݃pp$zv|+ a:ɝXu A4:W6qudsPj=omndJ)anvL;9V^),R{$sv!}~/ ]?kvxrS;*n.\n.YǾfÓxw\)oOXslh/33X [A#?c sG>7gOnxޯŋٱ4T@㡧/xmV5?%`KU,2pR0tnsc?x#Ek6Ĥ/IBOL22F䮠:.M焉ؤ$a\h}#M'KrN͑b2 X}ks{i3:Fx򝃾'X;^azEQOfP] nB#ގn!=z͈󟚎ڕN@y5 '@'N6U {Ru{\ߺkø61ʪĒڹT.z&z'ps`9WL<۩^2mΡ}7y[Nksar#6;~ixw| 5e'e8͌MgӤ(yE7qy 4v<b³#ʮVVK. b'zٕc_=G=_9bֻp%&6gx8Z!O"+crKtsKeALyN_Il}^]-Xҿ:g;v2c9ps`ǖAx|WvP}P1>@)dNv5ٔyt%`( Z]%I e/tr>XTM53mCkǜ'.kMBbBg:N.R]m> 뫠ˉ>yy[vܫXNTe,6B)_^B*&dhKdW7۹ާlKI[?6y%C*A-][;.rnӭPBzfe>J/v\1ͥ8;,Ix2͓c?|TA-멜) *ta\S:ٴ=vga$}$ӽ?~9[%=҃x"ĩf5Gb,HF^;,tؤ.gq̺u]\X[= D[Qnϰ^y ;%8;mx7njf8<ky>gܑ]?蜾ʚVsfjV&wO]jڠau*NV,|1OMI_{dƷN6 g(SWŦhMG&= u<(}WA)?xPg=&~w"\&wӵ"۸: F]v$:)D&x8E Plv_RrXgXk͵UmI6L1ݓޝφ_ yeߏϞƓD:4I?c?}5)6glG Uy#2]Uo1 T9{{K3͜NJ1l362ed^ݤϾ*I4=f;8=}A2d막Ș*zh8U;*iT4cU.5y4U C7:{.- %9o-y^ [5VQW ŷ\ȉ0Sq|v=Ǟp>ry>NyxpȘDfckϗdr ^)Eyv!Plgv'3Rd3Z&TP]pQ&>&ɓDiK,1Ot@a9 1Ys۹fLmh~kUK}[fdP9qi JHdVGF?N4g:+fgqD=xRlr\9 Fo-v6 {0R(vf~8I঒Zv n @ˀx-esT Zhoe@ZhH X<#fFo\ XZ,p- 72 @ˀxN|,) @ˀx( 72 ,7kSoZ]ŵ)72 @ˀx- 72 B] 7+[.< YRoF muyR#fp:]|`: g@v@ˀPɋ ; ZhoMf&+@zM)tG]uWby0lU^y^] 5A+XO{T˛.S^N-d淳Zb{[|%Wn_yj=Jʕ+Km7UNTlz]<2Z4u0OG>Rsͺn{dދ_`Y2 Uafl]XwP陙w0ˍ#[n6ҟʴpt?Y36̿o|yWfLG+ϐYɼ߮p[l켓8sI\{O[[LnϬ`!X9`-*7T[ ܬ|󾭠eYimގ/%*?-wx1\>ow/޼~V^u/˿˿+ލy3IEr _pk/x `T*5c_җ*^ 7oB_Tnz- ^QV7@?r)%^}IB<&0/,IENDB`yao-5.4.0/doc/mcao2-bench.par000066400000000000000000000103711234404334100156370ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Gemini MCAO system"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 9; wfs = array(wfss,nwfs); for (n=1;n<=5;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 1.0; wfs(n).npixels = 2; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.589; wfs(n).noise = 1; wfs(n).ron = 4.5; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).kernel = 0.8; wfs(n).laserpower = 8.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).dispzoom = 1.1; wfs(n).biasrmserror = 2.; wfs(n).flatrmserror = 0.01; wfs(n).nintegcycles = 1; wfs(n).centGainOpt = 1; wfs(n).optthroughput = 0.5; wfs(n).rayleighflag = 1; } wfs(1).gspos = [-30,-30]; wfs(2).gspos = [30,-30]; wfs(3).gspos = [0,0]; wfs(4).gspos = [-30,30]; wfs(5).gspos = [30,30]; for (n=6;n<=9;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.65; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).dispzoom = 0.6; wfs(n).biasrmserror = 0.; wfs(n).flatrmserror = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput = 0.5; } wfs(6).gspos = [40,0]; wfs(7).gspos = [0,-40]; wfs(8).gspos = [-40,0]; wfs(9).gspos = [0,40]; //------------------------------- ndm = 5; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 19; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 15; dm(n).pitchMargin = 0.5; n = 2; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 22; dm(n).pitch = 8; dm(n).alt = 4500.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 10; dm(n).pitchMargin = 1.2; n = 3; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 16; dm(n).pitch = 16; dm(n).alt = 9000.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 10; dm(n).pitchMargin = 0.5; n = 4; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; n = 5; dm(n).type = "aniso"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 9000.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; //------------------------------- mat.condition = &([15.,15]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([0.85,1.25,1.65,2.2]); target.xposition = &([0, 0, 0, 0, 0,10,10,10,10,10,20,20,20,20,20,30,30,30,30,30,40,40,40,40,40,-30,30.,-30]); // target.yposition = &([0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,-30.,-30,30]); // target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.3); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 30.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/doc/news.html000066400000000000000000001001071234404334100147140ustar00rootroot00000000000000 yao::news
HOME   |   INSTALL   |   MANUAL   |   NEWS
February 11, 2011
yao @ github
I have moved from svn to git. Yao is now at github (https://github.com/frigaut/yao). To check out (read only):
git clone git@github.com:frigaut/yao.git yao
November 11, 2010
Pyramid WFS back in yao 4.8
In the early times (version < 2.0), pyramid WFS were once available in yao, but I did not follow up on the code and I had to remove the feature. They are now back in yao 4.8.0, thanks to another contribution from Marcos van Dam, with some tweaking from myself. The speed is reasonable, with approximately 70 iterations/sec for a 8x8 system. Check it out with test5.par in the example directory. Grab it at the usual place.
July 2, 2010
yao going after ELT-size systems

The new parallel features (see next post), and especially the new sparse reconstructor options (see 2 posts below) makes running very large systems much more tractable than before. A 100x100 Shack-Hartmann system (on a 400 pixels pupil) runs at 8 iterations/seconds on an 8 core Xeon-based machine @ 3.33GHz! So one can get statiscally meaningful results in a few mn. It's not too greedy in RAM either (in modern machine standard) at 120MB for the main process (our machine has 8GB of RAM).

A 64x64 system runs at 23 iterations/s and a 200x200 SHWFS at 1 iterations/s (note that the later starts to be in the realm of ELT extreme AO, at 15cm actuator pitch on a 30-m).

July 2, 2010
Parallel yao released with improvements!

More work on yao parallel:

  • I have merged some of the -useful- parallel features implemented in our Gemini local yao_mcao to the yao trunk. Namely,
    • The DM/WFS parallelization (meaning, taking advantage of the fact that real systems have at least one frame delay (remember that even if the command is applied immediately after the measurements are received, there is still one frame delay due to the zero order hold). The one frame delay means the WFSing at iteration N is not needed to compute the command at iteration N, thus can be computed in parallel.
    • The PSF calculations, which is a no brainer.
  • I have implemented the parallelization of individual SHWFS. Meaning, an individual SHWFS can now run in parallel on an arbitrary number of "threads" (in fact, forks). This works only for Shack-Hartmann WFS. The good thing is that this is implemented fairly deep into the code, so any call to sh_wfs() will benefit from this, which means the iMat acquisition is accelerated too.
Depending on your system, i.e. WFS order, number of WFSs/DMs, whether you use dm.elt or not, sparse reconstructor or not, and more importantly, on the machine you run yao on, using the parallel features can make you gain anywhere between 20% and 200% in execution speed. If you want to use it, you will most probably have to experiment a bit to see what option should be set. Guidelines are given in the manual. The bottom line is that you should not use more forks (processes) than you have CPUs, otherwise swapping processes in/out of L2 cache introduce an overhead which cancels the paralleization advantage. With my core2duo laptop, I can typically gain 30 to 50%. With an 8 cores Xeon-based machine we have at work, I gain typically close to a factor of 2 (can be more or less). This does not seem particularly impressive, but one has to consider that a yao loop is made of many different individual operations: WFS, cMat product to retrieve the error, DM shape computation from the DM commands and the influence functions, PSF calculation, etc... So a gain in one of this items is only going to benefit the whole thing marginally. As far as the individual WFS parallelization is concerned, here are some hard numbers:
8 Core Xeon (2 boards) @ 3.33GHz, running RHEL 5, 32 bits. yorick/yao built with -O2.
16x16 SHWFS system, physical model, no noise. All times (avg & median) in milliseconds for one frame.

sh16x16_svipc:        1 threads, sh_wfs() avg=2.86, median=2.90
sh16x16_svipc:        2 threads, sh_wfs() avg=1.87, median=1.89
sh16x16_svipc:        4 threads, sh_wfs() avg=1.37, median=1.37
sh16x16_svipc:        8 threads, sh_wfs() avg=1.14, median=1.15
sh16x16_svipc:       16 threads, sh_wfs() avg=2.33, median=2.30
You can see that the speed increases up to 8 forks (max gain = 2.5x). Adding more forks makes the thing slower. The gain does not reach larger value just because (1) there are overheads associated to the use of shared memory/semaphores and (2) there is also a global overhead in the sh_wfs() function. What's parallelize is the core of sh_wfs() (FFTs, noise application and slopes calculations from spots), but any overhead within the sh_wfs() function itself, before calling the FFT/slopes calculation routine is not going to gain from the parallelization.

The gain brought by the other, more general parallel features (DM/WFS & PSFs) is nicely illustrated by the following examples. This was run on the same machine (8 cores Xeon), with curvature.par (36 subapertures curvature system ran on a 120 pixels pupil). Look at the following results (I have omitted the timing results for items that are not of concerned here and were negligible):

sim.svipc=0 (no parallelization)
time(1-2) =  9.89 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  1.04 ms  (DM shape computation)
time(5-6) =  5.84 ms  (Target PSFs estimation)
59.18 iterations/second in average


sim.svipc=1 (WFS/DM parallelized)
time(1-2) =  4.11 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  0.94 ms  (DM shape computation)
time(5-6) =  5.78 ms  (Target PSFs estimation)
91.43 iterations/second in average

sim.svipc=2 (PSFs parallelized)
time(1-2) = 10.69 ms  (WF sensing)
time(3-4) =  0.01 ms  (cMat multiplication)
time(4-5) =  1.05 ms  (DM shape computation)
time(5-6) =  1.23 ms  (Target PSFs estimation)
76.41 iterations/second in average

That's a typical example. The "no parallel" case is dominated by WFSing (10ms) and PSF (6ms) calculations. When parallelizing the WFS (sim.svipc=1), the WFSing time goes down to 4ms. Indeed, now 6ms of it can be done in parallel with other tasks: here, the PSF calculation that takes 6ms. With sim.svipc=2 (only the PSF are parallelized), the PSF calculation time goes to basically to 0 while the WFSing stays at 10ms. It all makes sense. I haven't put the sim.svipc=3 results as they are a little more difficult to understand and would just introduce confusion.

The individual WFS parallel feature is controlled by the parameter wfs.svipc. The "global" DMs/WFSs abd PSF parallelization is controlled by sim.svipc (bit 0 controls DM/WFS and bit 1 controls PSFs, thus sim.svipc=3 means both are turned on).

Of course, if you want to use yao parallel facilities, you will need to install the yorick-svipc plugin (contributed by Matthieu Bec), through most of the normal channels. It runs on Linux (extensively tested) and OsX (somewhat tested).

July 2, 2010
New features contributed by users

Marcos van Dam (flatwavefronts.com), who is using yao to simulate the GMT AO system, has contributed a patch that add MMSE control matrices, with a couple of regularization (identity or laplacian) and a sparse option. The sparse makes it blazingly fast (both the inversion and the reconstruction show more than an order of magnitude speed gain).

Aurea Garcia-Rissmann (UofA), adapting code developed Mark Milton (at the time at UofA), contributed a new modal basis for the DMs: the disk harmonics. These represent well the kind of deformation produced by deformable secondaries, for instance. They are much better behaved than the Zernike at the edge.

Thanks Marcos and Aurea. The code was very clean, hence -relatively- easy to merge.

April 9, 2010
Performance Boost with Parallelization

Following the development here at Gemini of a svipc plugin (by Matthieu Bec), providing shared memory capabilities for yorick, I have been working on parallelizing yao. The results so far are encouraging. For instance, I get a 4x performance boost on simulation of our MCAO system here, from 12 it/s to 47 it/s on an 8 core Xeon machine. This will of course work better for systems with multiple WFS and/or DMs, but will probably also bring some improvements for simpler systems.

Right now, I have implemented this in our version of yao that we forked to accomodate our special MCAO needs. But the functions are rather generic and I do not foresee major hurdles in porting that to the main yao tree. I just need to get a few free hours... So stay tuned!

November 10, 2008
Lots of changes in 4.5.0: new features and bug fixes

I have come to develop yao once more. Version 4.5.0 brings a lot of new features, bug fixes and code re-organization. Here is the changelog:

Upgrades:
  • Added Karhuenen-Loeve DM
  • Added Tip-Tilt vibration spectrum
  • Now accept any odd/even combination # of subapertures/pixels per subapertures in focal plane (SHWFS)
  • Added proper handling of overlap between spots in focal plane (SHWFS)
  • Added a new graphical configuration function to display SHWFS config
  • Implemented field stops (SHWFS)
  • Implemented leaky integrator and up to 10th order filter
  • Implemented non contiguous/arbitrary pupil
  • Added different pupil for WFS and imager
  • Implemented segmented pupil
  • Implemented segmented DM
  • Added a number of user functions, that are called if they are defined (user_pupil, user_loop_err, user_loop_command)
  • Added the possibility for the user to define his/her own WFS and DM
  • Cleanup the code somewhat:
    • Created yao_wfs.i and relocated all wfs related functions
    • Created yao_dm.i and relocated all dm related functions
    • Created yao_structures.i and relocated all struct definitions
    • Changed all function names from old style (with capitals, e.g. checkParameters) to new style (no capital, but underscores, e.g. check_parameters). To keep the API compatibility with existing user code, I have copied the function names into the old names (see API compatibility section at the end of yao.i).
    • Beside that, there shouldn't be any API change (in the sense that it should be compatible with old API, I have added a couple of keywords here and there). Most importantly, 4.5 should still be completely compatible with your old parfiles. However, it is not compatible with binary configurations saved with previous versions (the *imat.fits and other fits files). This means that you will have to remember to re-run aoinit with option clean=1 to re-create these binary config files.
    • One worthy API change is the addition of the keyword all= to the go function (see doc), that you should now use in scripts/batches.
  • Slow down imat display (use sleep=value in ms)
  • Added flip of DM and new stackarray influence functional forms
  • Added transversal shift (misregistration) of WFS (SHWFS)
  • Added transversal shift (misregistration) of DM (already existed, but this is for large integer offsets)

Bug Fixes:

  • "Desired" pixel size is wrong (SHWFS)
  • Bug with extrapolated counted several time (clean=1)
  • Solved zernike influence function for altitude DM
  • Merged many new things from yao_mcao
  • Can now use dm.elt with aniso modes
  • Skymag not set to zero when doing imat
  • Fixed bug in which user would be stuck at prompt when doing interactive SVD
  • DispImImav reverse behavior from expected
  • Setting npixpersub is not taken into account system wide
  • Fixed a small bug in phase screen generation (max offseted (1,1) in power spectrum)
  • Fixed mess in actuator/subaperture order. now both go from bottom left to top right, in line (i.e. subap/act#2 is at right of subap/act#1)
  • Updated many help document section (yao.i, yao_wfs.i)

So, as you see, lots of new things. I apologize to those who knew well the yao code and for who this release is going to mean some work to find where the functions have gone, but I think the code re-organization was way overdue, and the results is cleaner. Many of these modifications were the results of a visit from Michael Hart (and some push from Marcos van Dam) to use yao for GMT simulations. As usual, I have benefited from many discussions, advices and code contribution from Damien Gratadour, Benoit Neichel, Yann Clenet and Eric Gendron.

Things I have missed in this release but that I firmly intend to implement in the next version:

  • Smarter reconstructors: MMSE (MVR, MAP), may be POLC (contribution Benoit Neichel).
  • More advanced centroiding algorithm: weighted, ... (contribution Yann Clenet).
  • Cleaner display routines, separately callable.
  • Hexagonal stackarray geometry.
  • Hexagonal curvature WFS and DM geometry.
  • Phase screen generation on the fly (contribution Damien Gratadour and Eric Gendron).
  • Off-axis projectors for Rayleigh background (contribution Damien Gratadour).
  • Your code here :-)
September 29, 2009
Breaking the 1000 iterations/s barrier: a performance update

Is the performance of today's computer still following Moore's law? If so, if I take my numbers of the section performance, that date back to 2004, we should get for the fastest case (sh6m2-bench.par) 170*2^5 = 5540 it/sec. That is not the case, but I re-run recently some tests on typical cases and I am happy to announce that the threshold of 1000 iterations/second has been passed. Here are some performance numbers, obtained on a MacBook Pro 17" (running Snow Leopard, aka 10.6.1, 2.66GHz, 4GB RAM, 64bits yorick and plugins). All simulations were runs with 4 phase screens, and the display on, unless noted otherwise. Results are in iterations/second.

Name case 64bits 32bits
shfast SH 6x6 geometrical, 1DM+TT, NGS, 1 screen, no display 1020 860
test1 SH 12x12 physical 1DM+TT, LGS 44 32
test2 SH 12x12 geometrical, 1DM+TT, NGS 219 182
test3 SH 6x6 physical 1DM+TT, NGS 201 165
test4 CWFS36, NGS 226 164
test4bis same, no display 261 184
sh20 SH 20x20 geometrical, 1DM+TT, NGS, 1 screen, no display 284 N/A
sh20_2 SH 20x20, physical, 1 screen, w/ display 59 N/A

Those are all, I believe, fairly impressive numbers. Because I acquired this macbook only recently, I was doing comparison between a 32bits and 64bits yorick. Hence the last column of the table. Building/running in 64bits actually makes a fairly big difference on Snow Leopard. In average, the 64 bit version is 25% faster than the 32 bits one (up to 42% faster in some cases). That's a big gain.

September 13, 2009
Install Update
Obviously, I have been postponing for far too long updates on this site. Yao is not dead, no. I and many other people are still using it almost daily. But I just didn't have the time nor the inclination to update this site.

I got several requests recently to help install yao on OsX (I believe the yao packages have been built for 10.5, so I don't think the following would work for Tiger 10.4). So, I wrote up some fairly detailled instructions. Here is the drill. Note that I do not believe that there is any pre-requisite (beside X11 of course). I tested that on a fresh test account in my mac and it worked. FFTW comes bundled with the yao package, so it is not necessary to install it.

Note: in fact, the following should also work on linux. Just select the appropriate OS in pkg_setup when asked for it.

  1. Install the last yorick
    • download yorick from http://sourceforge.net/projects/yorick/files/yorick/2.1.05/yorick-2.1.05-mac-intel.tgz/download
    • unpack and move yorick-2.1.05 directory to ~
    • add yorick path to your default path: add this line at the end of your ~/.profile
      export PATH=$HOME/yorick-2.1.05/bin:$PATH
  2. Install yao:
    pkg_mngr.i is now bundled with yorick. So just do the following (for pkg_setup: all defaults are good, so carriage return everywhere, except you will have to select the OS: darwin-i686 on modern apple machines)
    $ yorick
    #include "pkg_mnr.i"
    > pkg_setup
    > pkg_sync
    > pkg_list
    > pkg_install,"yao"
    > quit
  3. Setup yao: First you'll have to create phase screens (once forever unless you want new ones):
    $ cd ~
    $ mkdir -p .yorick/data
    $ cd .yorick/data
    $ yorick -i turbulence.i
    > require,"yao.i"
    > CreatePhaseScreens,2048,256,prefix="screen"
    > quit
    $ ls   ( you should have your screens)
  4. Run yao
    $ cd ~/yorick-2.1.05/share/yao/examples/
    That's where some example yao parfile are. you can then put them wherever you want and transform/adapt them at will.
    $ yorick -i yao.i
    > aoread,"sh6x6.par"
    > aoinit,disp=1
    > aoloop,disp=1
    > go
    
    watch it go :-)
4 December 2005
Version 3.6
Very, very long time I haven't posted here, or updated this site for that matter !

I know many people have had problems installing yao with the newest yorick releases. Since the yorick Makefile system has been re-hauled in fact. Well, many things have changed. Now you can install yao *very* easily from the yorick prompt. Just download the brand new binary plugin installer (require yorick > 1.6.02). To install the latest yao, just:

#include "pkg_mngr.i"
pkg_list
pkg_install,"yao"

beware that the install directive will install in yorick/contrib/yao, so if you have there an existing installation that you want to preserve, you should back it up before.

This yao version is kind of intermediary. I have not included all modifications from ralf. I have however made a fairly decent size change to aoloop:

Now aoloop is in 2 parts:
aoloop,parameters_as_before
to "load" the thing. then type
go
or
go,1
to run a single iteration.

While it's going, you now still have access to the prompt. You can type "stop" or "cont" to stop/resume the loop simulations.

If you write batches in which you run loops, you will have to write it like this:

aoloop,bla-bla-bla
for (j=1;j<=loop.niter;j++) go;
This is because a call to go goes only through one loop cycle, and then call "set_idler,go", which tells to the yorick interpreter "if you have nothing pending, run 'go'". This will work as intended when ran interactively, but when in a batch, the interpreter is not idle: it will execute directly the next line and will never go back to "go" if not forced to (hence the explicit loop).
18 October 2004
Version 3.5
This new version include the 2 following additional features
  • Ability to swap the phase screen during a simulation run. This comes on top of the "jump and reset" feature. In fact, it simply swaps (rotate) the screens every N resets (set this using loop.jumps2swapscreen, see the data-structures page).
  • At long last, I have figured out and implemented more realistic influence functions for stackarray (piezostack) deformable mirrors. One can set the coupling parameter of the influence functions. Acceptable values are from 4 to 30%.
2 August 2004
Version 3.3.2
Released today version 3.3.2, that include fixes to a few bugs
  • a division by zero was causing a SIGFPE for odd number of subaperture shack hartmann systems in the angle/elongation calculations in shwfs_init (bug noted by Miska)
  • Added a check of indices overflow when determining the Y interpolation points in get_turb_phase_init (also suggested by Miska)
28 July 2004
YAO SSMP
Ralf has been developing further his SSMP (Sparse Matrix Package) and a yao implementation. It looks very promising (quite faster for large systems!). Keep tuned.

Note added August 2: Indeed Ralf has been very active. He is in the final phases of testing and has been revamping major parts of yao to be compatible with the new reconstructor choices. Reconstructors will very soon include MAP, MAP+PCG, on top of the existing SVD/least square. Note that this will also include a sparse implementation, so it's fast !

28 July 2004
Rayleigh and photometry revamp
I've just been working on implementing the Rayleigh fratricide effect in yao. This is an important feature in systems using multiple LGS beams with CW lasers. A WFS looking at a star may intersect the rayleigh plume from another star and thus see an increased background. This effect is particularly important to model for MCAO as CW laser is a possibility. First, I wanted to branch yao, and do a quick and dirty implementation of the Rayleigh, not planning to release it. I reconsidered after seeing that it was not going to take that much more work to actually make it user-friendly, so here we are with version 3.3. I also went ahead and implemented a clean zenith dependance. Now there is a parameter (gs.zenithangle) that sets the zenith angle (see below). Beware that the definition of photometry has slightly changed: now the zero point is for the number of photons at the entrance pupil, not anymore detected by the WFS. An way to enter the optical throughput on a WFS basis is provided (see below).



Figure: A generated field of 120"x120" as viewed by a subaperture [1.5,1.0] m off-axis, showing the 5 laser guide stars in the MCAO configuration and their associated Rayleigh backscatter (Linear ITT).


Below is the excerpt of the README file relevant to this release:

  • semi major changes in this version. Watch out, as some parameters meaning has changed (I know this is silly, but it's more logical now).
  • Implemented zenith dependance. Now one can change one parameter (gs.zenithangle) and everything change as needed (r0, lgs altitude and thickness of Na layer, atm layer altitude, LGS brightness)
  • Imlemented Rayleigh fratricide effect for multiple LGS systems! This was quite an endeavour. I had to modify the _shwfs routine to include several new lines and parameters relative to Rayleigh and calibration (a side effect is that we can now do and use calibration frame in this routine). To enable Rayleigh calculations set wfs.rayleighflag to 1 (it will *not* be calculated for NGS WFS as it is assumed that you can easily block the light from the laser wavelength).
  • The way to specify the photometry has also changed. Now, if you deal with a LGS, you specify a power and a return per watt, not anymore a magnitude (magnitude are still ok for a NGS). Also, everything -in term of zeropoints- is now specified at the entrance of the telescope: gs.zeropoint is now the number of photons for a zero mag star per sec per pupil at M1 (it used to be detected by the WFS). gs.lgsreturnperwatt is also in photons at M1. Instead, I have added a wfs.optthroughput parameter to specify the optical throughput of each WFS. Please set it, as it defaults to 1.
  • In summary, the following keywords were added in the parfile:
    • gs.lgsreturnperwatt
    • gs.zenithangle
    • wfs.laserpower
    • wfs.rayleighflag
    • wfs.optthroughput
07 June 2004
CVS and bug fixes
YAO is now under CVS. I have had Craig set up an account for me in the main Gemini CVS server (thanks Craig). This is purely for development though (only Ralf and myself have an account) and the main download is still from these pages.

We are now at version 3.2.3, which fixes a few bugs:

  • "~/Yorick/fftw_wisdom.dat" can now be created properly under linux.
  • I am now using convol instead of convVE for the creation of the influence functions when dm.elt=1, so this should work under linux too.
23 May 2004
Update
I have been presenting yao at the PSF reconstruction meeting in Victoria and several people have downloaded it.

Ralf submitted many bug reports/comments. Miska pointed out a bug in create_phase_screens, linked to SIGFPE being triggered by a division by zero. I did not see the problem on my G4 (I should have seen it on the G5 but did not bother going thru the phase screen creation phase there). I have patched the problem in turbulence.i and put the new release on the web pages.

30 April 2004
New features
In the new version 3.2.1, I have implemented sky noise and dark current, both for the SHWFS and the curvature WFS.

I have added some test parfiles in the examples directory (yao/examples). New users can test their distribution by running #include "test-all.i" in this directory. It's relatively fast, and test various configs (SHWFS method 1 and 2, with splitted subsystem, and a CWFS case).

6 April 2004
Update of the web site, cont'd
I have now updated almost all the pages, consistent with the new structure of yao-3.0. In particular, I have updated all the install instructions, the data structures and the main page. Still to complete is the "Example and scripts" and the screenshots pages. In parallel, I am still working at completing the new package structure. Everything (include files and compiled C routines) now resides in Y_SITE/contrib/yao/.
4 April 2004
Update of the web site
I have updated the web site, adding new performance results, and the weblog/news (this very page).
2004
Porting to FFTW!
Done ! I have relatively painleslly ported the fast (VE) C routines to using FFTW. It is almost as fast as the apple veclib (but not quite so, so I am keeping both). This means that YAO now runs on Linux! I have installed it on heze (2.8GHz Dual Athlon) and it gives nice results, although lono (Dual 2GHz G5) with the veclib FFTs is still faster (more details in performance page).
yao-5.4.0/doc/print.css000066400000000000000000000134121234404334100147220ustar00rootroot00000000000000body { background: #FFFFFF; /*background: #333366; */ color:#202020; font-size:11pt; margin:30px 20px 30px 20px; padding:0px 0px 0px 0px; font-family : Verdana, sans-serif; line-height: 140%; width:950px; } #left-column { float: left; width: 45px; margin: 0; padding: 0; visibility : hidden; display : none; } #right-column { float: right; width: 45px; margin: 0; padding: 0; visibility : hidden; display : none; } #center { background:white; margin: 0 9 0 9; } #banner { width:100%; height: 60px; margin:0 0 0 0; padding:36 0 0 40; /* font: 25pt Courier, "Courier New", monospace; */ font-size: 25pt; color:black; /* color:white;*/ /* background:#404040;*/ text-align:center; } #container { width:92%; margin:0 4% 0 4%; padding:45 0 0 0; background:#ffffff; } #footer { margin-top: -18; } #footer-left { float: left; width: 45px; margin: 0; padding: 0; visibility : hidden; display : none; } #footer-right { float: right; width: 45px; margin: 0; padding: 0; visibility : hidden; display : none; } #footer-center { width:100%; height: 100px; margin:0 0 0 0; padding:0 0 0 0; } div.figure { float: right; margin: 10px; padding: 10px; padding-top: 60px; /* for firefox printing */ padding-bottom:-60px; margin-bottom: -50px; } div.figure p { text-align: center; font-style: italic; font-size: smaller; text-indent: 0; } img.scaled { width: 100%; border: 0px; } h1 { font: 25pt Courier, "Courier New", monospace; color:black; /* background:#94A615;*/ background:#3937A6; margin:0px -37px 0px -42px; padding:10px 10px 15px 10px; border-top: 2px solid #dddddd; border-bottom: 2px solid #dddddd; border: 2px solid #dddddd; /*text-shadow: #333 2px 2px 2px;*/ } h2 { color:#404040; font-size: 180%; padding: 30px 0 5 0; border-bottom: solid 1px #a0a0a0; } h3 { margin-top:20px; color:#606060; font-size: 150%; padding: 15px 0 0 0; border-bottom: solid 1px #e0e0e0; } h4 { margin:12px 0 0 0; padding:5px 0 0 0; color:#202020; font-size: 120%; } h5 { margin:12px 0 0 0; padding:0px 0 0 0; color:#707070; font-size: 100%; } pre { font: 9pt/13pt Monaco, Courier, "Courier New", monospace; background: #f0f0f0; background: #f0f0f0; /*background: #333366;*/ color: #202020; padding:10px 10px 10px 10px; border: 1px #d0d0d0 solid; } table { /* font: 9pt/13pt Monaco, Courier, "Courier New", monospace; */ margin:10px 10px 10px 10px; font-size:100%; /* border: 1px #404040 solid; */ } table.fixed { font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } table.toc a { font-weight:bold; color:#3030A0; text-decoration:none; } td { padding: 3px 10px 3px 3px; text-align: left; vertical-align: top; /* border: 1px #404040 solid; */ } td.varname { padding: 1px 10px 1px 3px; text-align: left; vertical-align: top; font-weight:bold; font-family : Verdana, sans-serif; /* border: 1px #404040 solid; */ } th { font-family : Verdana, sans-serif; font-weight: bold; font-size:130%; padding: 40px 10px 0px 2px; margin: 0 0 0 0; text-align: left; color:#3030A0; /* color:white;*/ border-bottom: 1px #404040 solid; } .subth { font-family : Verdana, sans-serif; font-weight: bold; padding: 10px 0px 0px 0px; margin: 0 0 0 0; text-align: left; color:#8080B0; /* color:white;*/ border-bottom: 1px #f0f0f0 solid; } .trodd { background: #e0e0e0; } .toptitle { /* font: 10pt/13pt Monaco, Courier, "Courier New", monospace; */ color:#FF9900; color:#8AA627; color:black; font-weight:bold; } code { color:#50801D; color:#303060; font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } .imglink { margin: 10 0 10 10; border: 0px; } #fname {color:#FF9900; font-weight: bold;} pre a { color:#50801D; font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } body a { /* color:#4781B4; */ /*text-shadow: #000 2px 2px 2px;*/ } body a:link { /* color:#3937A6; */ /*text-shadow: #000 2px 2px 2px;*/ } ul,ol { margin: 3px 0px 5px 32px; padding: 0px 0px 0px 0px; } ul li { margin: 1px 0px 2px 0px; padding: 0px 0px 0px 0px; } ol li { margin: 1px 0px 2px 0px; padding: 0px 0px 0px 0px; } .spaced li {margin: 6px 0px 0px 5px;} .packed li {margin: 1px 0px 0px 1px;} .linkpacked li {margin: 0px 0px 0px 0px;} p { margin: 6px 0px 4px 0px; padding: 0px 0px 0px 0px; } #links2 { float:right; margin:-30px 10px 5px 10px; padding: 0px 8px 15px 14px; background: #ffffff; font-size: 120%; font-weight: bold; visibility : hidden; display : none; } #links2 a{ color:#3937A6; color:#FF8000; color:#8AA627; text-decoration: none; } .highlight { /* color:#3937A6; color:#3937A6;*/ font-weight: bold; /*text-shadow: #000 2px 2px 2px;*/ } #toc { width:17em; float:right; margin: -10px 0 0 0; padding: 0px 0 20 50; background: #FFFFFF; } #toc ul { list-style-type: none; margin-left: 5px; } #toc a { text-decoration: none; } .tocsec { font-size: 110%; padding-left:0px; } .tocsubsec { font-size: 100%; padding-left:20px; } .new { background:#3937A6; /*background:#8AA627;*/ color:white; padding: 0px 3 1 3; font-size: 80%; /*font-weight: bold;*/ /*text-shadow: #000 2px 2px 2px;*/ } .lowlight {color:#999999;} div.cloak { visibility : hidden; display : none; color: white; } #blogentry { padding: 10px 5px 5px 5px; } #entrytitle { margin: -20px 0px 0px 0px; font-size:12pt; color: #99DD55; color:#FF9900; color:#8AA627; color:#6A9610; color:#3937A6; font-weight: bold; } #entrybody { padding: 7px 0px 5px 0px; border-top: 1px #606060 solid; } #entrydate { font-size:10pt; color: #303030; text-align: right; font-weight: bold; } yao-5.4.0/doc/scripts.js000077500000000000000000000032621234404334100151060ustar00rootroot00000000000000function expandAll() { var wins = document.getElementsByTagName("DIV"); for (var i = 0; i < wins.length; i++) { if (wins[i].className == "cloak") { wins[i].style.visibility = "visible"; wins[i].style.display = "block"; } } } function collapseAll() { var wins = document.getElementsByTagName("DIV"); for (var i = 0; i < wins.length; i++) { if (wins[i].className == "cloak") { wins[i].style.visibility = "hidden"; wins[i].style.display = "none"; } } } function showDiv(what) { var wins = document.getElementsByTagName("DIV"); for (var i = 0; i < wins.length; i++) { if (wins[i].className == "cloak") { if (wins[i].id == what) { wins[i].style.visibility = "visible"; wins[i].style.display = "block"; current_menu = wins[i].id; } } } } function toggleDiv(what) { var wins = document.getElementsByTagName("DIV"); for (var i = 0; i < wins.length; i++) { if (wins[i].className == "cloak") { if (wins[i].id == what) { if (wins[i].style.visibility == "visible") { wins[i].style.visibility = "hidden"; wins[i].style.display = "none"; } else { wins[i].style.visibility = "visible"; wins[i].style.display = "block"; } current_menu = wins[i].id; } } } } function HideContent(d) { document.getElementById(d).style.display = "none"; } function ShowContent(d) { document.getElementById(d).style.display = "block"; } function ReverseDisplay(d) { if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; } else { document.getElementById(d).style.display = "none"; } } yao-5.4.0/doc/section_counters.css000066400000000000000000000017211234404334100171540ustar00rootroot00000000000000body { counter-reset: section; } #container { counter-reset: figure; } img.scaled { counter-increment: figure; } div.figure p:before { content: "Figure " counter(figure) ": "; display: inline; } h1 { counter-increment: section; } h2 { counter-reset: subsection; clear:both; } h2:before { content: counter(section) ". "; counter-increment: section; display: inline; } h3 { counter-reset: subsubsection; clear:both; } h3:before { content: counter(section) "." counter(subsection) " "; counter-increment: subsection; display: inline; } h4 { counter-reset: subsubsubsection; clear:both; } h4:before { content: counter(section) "." counter(subsection) "." counter(subsubsection) " "; counter-increment: subsubsection; display: inline; } h5:before { content: counter(section) "." counter(subsection) "." counter(subsubsection) "." counter(subsubsubsection) " "; counter-increment: subsubsubsection; display: inline; } yao-5.4.0/doc/styles.css000066400000000000000000000141611234404334100151130ustar00rootroot00000000000000body { background: #FFFFFF; /*background: #333366; */ color:#202020; font-size:10pt; margin:30px 80px 30px 80px; padding:0px 0px 0px 0px; font-family : Verdana, sans-serif; line-height: 140%; background-image: url("images/kbkbgcolor.jpg"); } #left-column { float: left; width: 45px; margin: 0; padding: 0; } #right-column { float: right; width: 45px; margin: 0; padding: 0; } #center { background:white; margin: 0 9 0 9; border-left: 2px solid #bbbbbb; border-right: 2px solid #bbbbbb; } #banner { width:100%; height: 100px; margin:0 0 0 0; padding:36 0 0 0; background-image: url("images/kbkheadercenter.jpg"); background-repeat:repeat-x; font: 25pt Courier, "Courier New", monospace; color:white; } #container { width:92%; margin:-36 4% 0 4%; padding:35 0 0 0; background:#ffffff; } #footer { margin-top: -18; } #footer-left { float: left; width: 45px; margin: 0; padding: 0; } #footer-right { float: right; width: 45px; margin: 0; padding: 0; } #footer-center { width:100%; height: 100px; margin:0 0 0 0; padding:0 0 0 0; background-image: url("images/kbkfootercenter.jpg"); background-repeat:repeat-x; } div.figure { float: right; margin: 10px; padding: 10px; } div.figure p { text-align: center; font-style: italic; font-size: smaller; text-indent: 0; } img.scaled { width: 100%; border: 0px; } h1 { font: 25pt Courier, "Courier New", monospace; color:black; /* background:#94A615;*/ background:#3937A6; margin:0px -37px 0px -42px; padding:10px 10px 15px 10px; border-top: 2px solid #dddddd; border-bottom: 2px solid #dddddd; border: 2px solid #dddddd; /*text-shadow: #333 2px 2px 2px;*/ } h2 { color:#404040; font-size: 180%; padding: 30px 0 5 0; border-bottom: solid 1px #a0a0a0; } h3 { margin-top:20px; color:#606060; font-size: 150%; padding: 15px 0 0 0; border-bottom: solid 1px #e0e0e0; } h4 { margin:12px 0 0 0; padding:5px 0 0 0; color:#202020; font-size: 120%; } h5 { margin:12px 0 0 0; padding:0px 0 0 0; color:#707070; font-size: 100%; } pre { font: 9pt/13pt Monaco, Courier, "Courier New", monospace; background: #f0f0f0; background: #f0f0f0; /*background: #333366;*/ color: #202020; padding:10px 10px 10px 10px; border: 1px #d0d0d0 solid; } table { /* font: 9pt/13pt Monaco, Courier, "Courier New", monospace; */ margin:10px 10px 10px 10px; font-size:100%; /* border: 1px #404040 solid; */ } table.fixed { font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } table.toc a { font-weight:bold; color:#3030A0; text-decoration:none; } td { padding: 3px 10px 3px 3px; text-align: left; vertical-align: top; /* border: 1px #404040 solid; */ } td.varname { padding: 1px 10px 1px 3px; text-align: left; vertical-align: top; font-weight:bold; font-family : Verdana, sans-serif; /* border: 1px #404040 solid; */ } th { font-family : Verdana, sans-serif; font-weight: bold; font-size:130%; padding: 40px 10px 0px 2px; margin: 0 0 0 0; text-align: left; color:#3030A0; /* color:white;*/ border-bottom: 1px #404040 solid; } .subth { font-family : Verdana, sans-serif; font-weight: bold; padding: 10px 0px 0px 0px; margin: 0 0 0 0; text-align: left; color:#8080B0; /* color:white;*/ border-bottom: 1px #f0f0f0 solid; } .trodd { background: #e0e0e0; } .toptitle { /* font: 10pt/13pt Monaco, Courier, "Courier New", monospace; */ color:#FF9900; color:#8AA627; color:black; font-weight:bold; } code { color:#50801D; color:#303060; font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } .imglink { margin: 10 0 10 10; border: 0px; } #fname {color:#FF9900; font-weight: bold;} pre a { color:#50801D; font: 9pt/13pt Monaco, Courier, "Courier New", monospace; } body a { /* color:#4781B4; */ /*text-shadow: #000 2px 2px 2px;*/ } body a:link { /* color:#3937A6; */ /*text-shadow: #000 2px 2px 2px;*/ } ul,ol { margin: 3px 0px 5px 32px; padding: 0px 0px 0px 0px; } ul li { margin: 1px 0px 2px 0px; padding: 0px 0px 0px 0px; } ol li { margin: 1px 0px 2px 0px; padding: 0px 0px 0px 0px; } .spaced li {margin: 6px 0px 0px 5px;} .packed li {margin: 1px 0px 0px 1px;} .linkpacked li {margin: 0px 0px 0px 0px;} p { margin: 6px 0px 4px 0px; padding: 0px 0px 0px 0px; } #links2 { float:right; margin:-30px 10px 5px 10px; padding: 0px 8px 15px 14px; background: #ffffff; font-size: 120%; font-weight: bold; } #links2 a{ color:#3937A6; color:#FF8000; color:#8AA627; text-decoration: none; } .highlight { /* color:#3937A6; color:#3937A6;*/ font-weight: bold; /*text-shadow: #000 2px 2px 2px;*/ } #toc { width:17em; float:right; margin: -10px 0 0 0; padding: 0px 0 20 50; background: #FFFFFF; } #toc ul { list-style-type: none; margin-left: 5px; } #toc a { text-decoration: none; } .tocsec { font-size: 110%; padding-left:0px; } .tocsubsec { font-size: 100%; padding-left:20px; } .new { background:#3937A6; /*background:#8AA627;*/ color:white; padding: 0px 3 1 3; font-size: 80%; /*font-weight: bold;*/ /*text-shadow: #000 2px 2px 2px;*/ } .lowlight {color:#999999;} div.cloak { visibility : hidden; display : none; color: white; } #blogentry { padding: 30px 5px 5px 5px; } #entrytitle { margin: -20px 0px 0px 0px; font-size:130%; color: #99DD55; color:#FF9900; color:#8AA627; color:#6A9610; color:#3937A6; font-weight: bold; } #entrybody { padding: 7px 0px 5px 0px; border-top: 1px #606060 solid; } #entrydate { font-size:10pt; color: #303030; text-align: right; font-weight: bold; } blockquote { border: 1px solid #bbbbbb; padding: 10px 20px 10px 20px; }yao-5.4.0/doc/template.html000066400000000000000000000020221234404334100155500ustar00rootroot00000000000000 yao::home page
HOME   |   INSTALL   |   MANUAL   |   SCREENSHOTS   |   NEWS
yao-5.4.0/doc/yao.1000066400000000000000000000063021234404334100137260ustar00rootroot00000000000000.TH YAO 1 "2007 December 12" .UC 4 .SH NAME yao \- Adaptive Optics simulation tool in yorick .SH SYNOPSIS .TP 3 Start yao with the gtk GUI: .B yao .I parfile.par .br .B yorick \-i yaopy.i .I parfile.par .TP 3 Within yorick (no GUI, but same graphical output) .B #include "yao.i" .br .B aoread,"parfile.par"; aoinit; aoloop; go; .SH DESCRIPTION .I Yao is a monte-carlo simulation package for adaptive optics. It includes fast core coded in C (e.g. wavefront sensing) that are glued together by yorick interpreted code. One defines the system to evaluate using a configuration file, and then run aoread, aoinit and aoloop. Yao features: .TP 3 * Shack-Hartmann and Curvature WFS, on or off axis. .TP * Stackarray (piezostack), curvature (bimorph), modal (zernike) and Tip-Tilt deformable mirrors are supported. The altitude of conjugation is adjustable. .TP * An arbitrary number of WFSs and DMs can be selected, with the possibility of mixing types. It is therefore possible (and easy) to simulate single DM systems, as well as single non-zero conjugate, GLAO and MCAO systems. .TP * It supports Natural and Laser Guide Stars (or a mix), WFS with photon and read-out noise. .TP * It uses a multi-layered atmospheric model, with geometrical propagation only. .TP * The loop execution has been optimized for speed: the critical routines have been coded in C. Yorick is thus used as a convenient glue between lower levels optimized C calls. Overall, this is rather efficient: A simple 6x6 Shack-Hartmann system runs at up to 650 iterations per second on an apple dual 2GHz G5 (200 iterations/sec for a full diffraction propagation model). A 50x50 Shack-Hartmann system runs at about 3 iterations/s. A 188 curvature system runs at 25 iterations/s. .TP * Straightforward scriptability to probe parameter domains. .TP * GTK GUI to change some of the system parameters while the loop is running (new in v4.0). This provides an educational approach to Adaptive Optics (newbies can play with the parameters and immediately sees how the system reacts) and can also provides a quick way to investigate the stability conditions for a newly designed system, before entering more serious Monte-carlo simulations. .SS Options .TP 15 .RI \0help,aoread will give you information about the syntax, parameters and keywords of aoread. See help,aoinit and help,aoloop also. .PP .SH AUTHOR .PP Francois Rigaut, Gemini Observatory .PP .SH FILES .PP Input files: .TP 15 parfile.par A yao parameter file. This file follows a regular yorick syntax. It is directly included by yorick to define the structures used by yao. As it might be a little bit daunting to create a parfile from scratch, example parfiles are provided. Their location depends on the installation. Search for yao/examples (e.g. shx6x.par, curvature.par) .TP screen*.fits To simulate the atmospheric turbulence, yao needs phase screens. You can create phase screens with create_phase_screens(). They might also be included in your distribution. .PP Output files: .TP 15 parfile.res After a simulation run, results are output in parfile.res in the cwd .SH BUGS Lots. .PP LGS uplink propagation is not implemented .PP Shack-Hartmann cross talk between subapertures is not implemented .PP Many more. .SH SEE ALSO yorick(1) yao-5.4.0/doc/yao_manual.pdf000066400000000000000000015133201234404334100157000ustar00rootroot00000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x\oοb cHqM9Et@5YTD:ߛiyE3o}1*KU,LuXmjZ.RNE_7;0uaǣ\'YXUVf uG\gq. U:*"4qW* TfJ@@bZR-YɓP1Xr,Vf:)! Z}hdHN2 Ikunu_oԛ#G!VfT YX1™G(Jp&Zݴ~ , 2h50(]~RWw%"~S5^4Vj"@)R 9 KBc5ye];]L%0KPANȔ=5`qxy70@qD [~Q/6-3WoU'ҾÕ(yRlG>oJVX|ǽFǠm'IX! nq-J+؄$/IOVuq&}k`KaKxӰd8{Vʻ6+9#*J?[=u6b_P͈#$@l.biǍqL<ޚ|+L솿 `vp FG2yW:J7~ˠ6Ģz%7PH5"Ee.yMO-?f9Kؕe ޘóZlH-#c7"O\sEM˸`SvsEG\ax{;&zcPa0<C {%r IG>fAG ?Sy1n5Ӝ`M>].u绸$CCZR6Ġ3DE2-MнOq&\{f5Qɪ#ڀz^t1F岞H ד\e. .ğ֎wƘ#Ɯp8J3)R/޲&5:΂P~B̼g(,t(y{ | aFAK &0I!UI.E:Ic "9"~pQL{%dg%ۡm1ko68 uVA\GY <*_SY tAyu%3V\lb2Sɫr rx &Tޓ L^yGK(9֑:C2*'/]!nuu[,WZo}k]YZ?TÅShh;#kKYe<3hv0U7_4{y9lg,r&yyw沺6 lN 6`mŇ|n3^Cy7[ΤlQq,'{Ud=3|o= B#J8\bǕ@J|`vD9 `3d竂Eb/in=a HbŰª+aRQ \!ɰigm$.ա^(1+O%Kv8d/FV,0cn_S:\V+;OQ!MU>xO^]P](PW}GiHBVkz兺.EY5S77j+Q{ILX0"J5"XQOX'ߴu_/תZ3(XB-u>4|^o>P 4$Y'G?GC|廙r]&UlV?9iS_z޵wϭkdx6[A gW6+ h?1I; HE?3Z>7sE[MXo"w 3ԓ`1''+jaK:,sfCd1(GEZXVfsD{UU;y.W3뿛@ŋ*Ny%yRDjV-~Db G~tƃ3: XXu$lDu?|0"k֖Y@6:!wØi?iXI\Ķqv83ؓIS$#H*(>WfHfP>s"*hAVߦ`> gER| RT!v;(ϯoʦ{8إ^ BEZT%:ZG8F%YNȸim9Q~VK[\'JS߰ B)ًW VBhM,.Pl("-g'ѻ㕨 A=^^%yX1TҪ5%V TBZ1DeYυ^ݑ o? EZ6AeOi[͑+yZ>Gy\6n|;T+qWrpHe#2bAG 8ZQhPHDe/ pf{^/&2ܮK3I"歹Eې &,Ⱦ$mvɆYp+-a-l a],wQ >37L)NjĈzҗL"J~U endstream endobj 5 0 obj 4796 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792] >> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F3.0 10 0 R /F5.0 12 0 R /F1.0 8 0 R /F7.0 14 0 R /F2.0 9 0 R /F8.0 15 0 R /F4.0 11 0 R /F6.0 13 0 R >> >> endobj 16 0 obj << /Length 17 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTl/]"e齷.H& KYe7D"V$(bh(+X "J F;'Nw>}w(!a@P"f'0D6p(h@_63u_ -Z[3C+K;?r!YLD)c#c1 ʪ2N|bO h{yIHD.VV>RV:|{ [RF ”"MF1L1[Te'Jx%C%_%RJ#4GcӸu:(G73%Ie%e{SC add1T4UT*TTTUzUUUoScemUkS{Q7UPWߣ~A}b}9Հ5L5"5iјi<9Ъ:5MvhWh~Tfz1U.椎NTgNΌ|ݵͺHz,T NI}mPw ,tӆF -5j4oL50^l\k|g24mr6u0M713fͱBZA EEŰ%2res+}VV(٬Ԗk[c{Îjgʮ=~mCNNb&q'}d]N,:+Uʺuv^|o]5˟[7wM׍mȝ}CǃQSϓY9eu빷ػ{^>*}7l6 8`k`f 7!p2)hEPW0%8*:Qi8# z<ἶ0-AQ#p5#m"GvGѢG.7xt~g|LbLCtOlyPU܊|BLB}&:$%Zh`EꋲJO$O&&N~ rRSvLrgIsKۖ6^>!` /22fLge̜͊j&d'g* 3]9Z99"3Qhh'\(wanLHyy5yoc( z.ٴdloaqu.Yf WB+SVv[UjtCkHk2zmWbuj.Y￾HH\4uލ6W|ĺ})76T}39usocٞ---zl=TX|d[ fEqūI/WWA!1TRվS疝ӫox4صin={j-n`[k k+x\S-ۆzEjpjh8qn6Ik:8w7ޜw[nn?uݼ3V/~ڟM~nr:53(ѽȳ_ry?ZrL{퓓~מ.x:LlfW_w=7~oLM˃_uNO=|zfڛCoYož_Cggg endstream endobj 17 0 obj 2615 endobj 7 0 obj [ /ICCBased 16 0 R ] endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode >> stream x\[ȱ~ׯhlVfh/>7v{w=,B#Qe5,R'X䷟&EI#ol`(6E~4?&Mď=rٖg2O_TV&遮@M{Ev8, 2`n ()h8Hi'^h@?/r1)0'X2I௫XyaNe{K4dȀHG%& rP/LX v< ОG`WAC&44# L ~鴴δQ s?i- /8# [N v Ny[$,9ɢ‡Q^)&#SXxED&K4Tb@m71B(͚r,إh!I!s V$*͋dXvq V&)mw{zniƓ'9^ٿ3c/[{;MIGIUN ps,<λ-p_2PMpKm m};?}͗@!&3-]1R.'k=VyG IP2Vy\Opq'( dH2r_dgWHs}'?Vf'tN6/fC'ҡ[#SαdƏ,d3֩d'yb7 l 6r4 ^~F۽ JO`qC;4aHFe+^L'8{u$89.N<]2SY1̌>,Zݧ}X-z8$mSSUS:l4G76DV jӛuVePiDCn_NUg qi& 5OX ƾ|4U^P~qxgje Ieִg߂Fذ2!T˹S?Ҏa>)qJ8qV Ծʻ+;w)?(,>>䮒&ŖN3BY0{%ŀ!y$ٻfq4}7ye_xʦ8qZa ᄦOz_%}4]7Hʧ4kIWr%~?Lyd)<S x5Y3vno$,C5 F,*uyD0YZa2 =r#7`dkŤޚfA #:ȁV( #M @/HGf#]33]a"<M[ 8hMN%!7?=FJ{U ;ShHZ\Ƥʬ YH:X B@ eTuiwxDpw4i uvK>e`-g jdz>RP8XDsR !Q%8_ ]2b;R#> dPAUu:1fg8hLdq#Gp F_΄6 R@~/sxV Npùح@-:ةͪd =i3iЏHOr> saљ:H0_1j"xM# s2u„ %o9\oa4F*yn&q30}]YN_;ƂR5}/NΣAy#rҊi+s+'( d^{Íꣂwhe~`kE X3A.@>S@T2`"]T=jD~ F*"N'h# S +#p^imAЙ:ݞH9-!7_5qkcJsnXQ%ɸgP*v-7O4KO ]-)֪ۢ$^o`hg0h"ISXyҬB-*_ݖS9ϼѲ-p!~pg־\ߕfM%,ZW{S.W5xM>b]ч\azYD'x8.f//i~:ԓgzM7PZ.JpȆzA L3E*R8YP-Y>R9&"#([MAaAuRXHHz#:.@xDBɢIʱbH{.d%Ybr'^dbOk ujl_L :YV雞NЇK7ps:8Vg<CnF̓\g&TB^:>U̅VnN]H _!VP glQsW>R(II@!/kLKH  Q 볜; [V6:R;Xz9I8OEXVl3a$>5O]S‹`cA~nwM҃Vnȝ4E 9XvB_ FO5VI6\ ;|ue2X %_as;KUPÞDݠ'pf:韶Lj8 8^ XÝ$e * } ';6F<*C%{L 9y#Xo9' d+Bv\BlB:)ϓw쮴'U``WSlt=*ҝZ]~az*]M3-aXPKU,TP$g.Jf{?+6}ˉE.Erݛ>38٪\%#k^QUTn] hk9VSGm+kK8_[S*Z8:' GlUւQp:6>IHzj轎SiwR h(HnE(*-N[Xr^֮ȞE3?ddjحVc3ZhGesJOCTͳCa:j+tOE ﵔl:n}F.oޫ1mݓ>ۈj:RJ5ŚG+ V嵥i ${ŕAΙ5%UUP`77B޻O _9fڍNv$WUmh!p t(tm3İ j\4>x'OFpPj"ԥA*1}$-;q,;k706!WENb4ʾEC7Nj9YD]~Tie75#kW1V5_~k䕹17]+xS8In:Dپ-j|#3ꧬڏf o + 2Kfrpe$ı )TS4òtإ)ZvZ#8[t{$q0$"Tk@M3%@a/GmsnF#>ûG9D|Бٝ٢< .Ks!εzs57r5hA5A%)5 Kaɽgs}e;̅ yka~g^}}__?_=zi^{ 345qx†:Šw8Ǚ&UoPaS.opѷ |=l&v=NFz ,"{v8OV3Јc<%LfZxIwO/ݗw W>^> endobj 21 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F9.0 22 0 R /F7.0 14 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 24 0 obj << /Length 25 0 R /Filter /FlateDecode >> stream xZr6}WtȵDxk'{HlZ$f$Q!)@bkhU  A?>iO1 B}AyB_hEӸ n+:=!, P)!ԑ`"򣃷a'#>HJ͢NBЗtZCGܿn=:;lޔFXf9-<AyCM\a R z!XAە_$k>!0;ᑀB"[$!a!J$' 5~EkKqRR!aQ#lLo.19U!Fi&6ΗF}]G܌>t~1|OakU^`Sw="O6E_AXgt,+)+QO$:.oOp'KF}9QL6meFCkF˸;/5l9~zof0'x>6Sl؀& E,I1NW]m'-}B<fTR7+jnd,UY<,&>'Td4 ,Y%y\&:[sh g#?BN,/e64Q>ϴyal+7^`v9~7 ̢H9^:jŇa[U zg'kPXl\Z:2/- Kw4<&EڞeX$$/$C6ws%y gR$=/hI @EdA$-q>qӬtuXo|ivjH! Æ۞J7`QeXwoXe<yxjv;a4rKc`Ǥ 6՝Wpz>;~ P%(J N: 6P(940knGU^;OcMdrWAv/ŋ{9ga{3q.(wnP_dIdTITSwK)XUe8#3:CEV*T<-wICBc+&󆷗BsSfkڡ&%33wi1+p.)jVMNH3 D_lX|A)u}2J }J% 8Dms;؎)A>:l4 y(=V:@# {@jr͈{-' {N XV?~L2V)$o _Qqp(1|"7EPq]7l6 ބȹ[խJZ`u5B QR~<}ߛ`'f: cyLS Mđk~5?Y?yk0 <‘ #k\2E8j<NWKā.!kBG,\Q f?nG)-z҉Fx蟒")m}l&EP5Y8IX쩭ZRkBeͦ0;~RAӁ#U:8Y'3ZC;C^2)pJ_+EQW7bmÊ%`h> Z z.|Y9mS)OQDiR5 e)_K6+%lE/W(/WfS^xE"=AHP5j޲[w?!(/r_qQMp>hoR=zJf}4L.P8oKn cDh#vfu鰷p-gts 7mJv~Pn#Gx]t>9g?qr){A5 = fAd-4oW\YGç36aEf36NSXM牽~ endstream endobj 25 0 obj 3108 endobj 23 0 obj << /Type /Page /Parent 3 0 R /Resources 26 0 R /Contents 24 0 R /MediaBox [0 0 612 792] >> endobj 26 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F3.0 10 0 R /F7.0 14 0 R /F8.0 15 0 R >> >> endobj 28 0 obj << /Length 29 0 R /Filter /FlateDecode >> stream x\koF_Ї(ih$F^iaP3 oF3crdG﩮j{2 Kd]]uMRRT_Fa"XQēh*S_iVdXjgEcNx|s1.T UeY1lL]G:2Ș*k$,#3oDLk25L! 痭5Iô%`1(,KBZהaFy;Y/Eh/)KE~DĦ,, ?!H"@~SbG? /`I%AdWgy-RTgHg?w8kcZ Bz5QaB{ҏSSifP }?R w?W5n&J\蟕YAk=XkuP_{?fԬy;>LOPQ aWq%9r#%`-nxFi,p4 rÂrfKD l,G@U^@lWϞv\7 ʅ_d2-[df:"" <ܾzݝZ2/VukT_IM<]{1ùz^sy VְV^TEmfkj#ә-K҅i!jĿuZ1XўfY+&kz۵5ިW}%ڪYն&Gvy{\=αb,[/b͚nsHӯ8Mz~75of'~ ߸b1ގ65SzɛLYcv#t6!(tռO[tb:ƨ! &[3p&~.p11^nV%H[ER~'r&Ҏ, \2(};mv,켭?yW%W {!]q@@tߓޒs˕\CI} br*|Ո<,jAc? XUx`7M fl 28LyIDƚ̭7ˢĮ9JܛG8nhY&֒'G1юcC; K7j5c|܈3H%g\M"\cm'<z襁MIW{|q;$(3!ލи>Sƾc\n1M~ؙMLytn0- gGϴPYO_)>J|p(3嗌( B4)]!ak$r9~P(mKU:#0@#B$]pfڷ-chȩ 4eZZ!'rΠ meHftiz tYmat.2EmZPm{)ON;_mۚ4Ng nF}bl5E -U8RYZtBFa--Sz4Fy\9O;C#$Jޓ4wplEKw➶8"fYhJ=;$9wKR+V%m+.Fjc豽{1?j?ϢMmm''ھgFp)/ٝj_q8v͊,Z ĝq9FġRHp8o@Nᥭ`;x89Mvw$=Žc7' ]K5Ftt,q<[NظncЇȃZpJ2(Q3ҾDO V+1mվ K3pbFމ>3dLDdJ/ƈblIe;K9/spoLA#O'M$p`sL.!:j(8w​rnz@I^}1is8Tr` t\DO8ldrri*r-|+&n_wmqVm] hz/zPUS IrUh5e3xP/ƅ]mʂ؟Z)d@װײ%,jJз%ѻ+T 5p2m7\Y~gssT3:V 8?E&=$㥄fHo=.ƝY7+Sպ-R÷-'ez?q/nof揺̞D̛[L]Gف >i*v[/a~Pp]I"8t(C2lpD.ga3Qf[%'_ᢿGSX)N3W4avmZ6eWcAGM!1؇_LNqW' pHbG<"AR׸Z֐Ts2XYh7y r<{~`>]I32;$*|k;,pY,:nB:MQ՞HsI{G$}8c ;svL&>[<;ߣjl+8'-Ϟ~N{jlCB^Q@LØ fbOR?/4~Qږ5W=, %sg N)pNb('_9:m˿VH?e7Ҥ gӘMr-E_?Yrq ӝoI#}zofNcxaSdƳJO$_i,|[@SLgOiG^ Fz!WQ=޻?,)]S!,"/9}cAӛә٧x.}~G[uQS=Bww̬ 'ජ!.bށ˦YΚ)|wT9;ټ3X!6fՏ/O/n5H$D(_5€5RGOu q 5MxO7,M9|fV[0 m>+Zs[wJAhѩ6Elet!Eku:dC r 0DP7m֮ޠVaU-Uxus_oy*.~cʥ" kݒf1*4yg1_(8"3AqJ=IʞAje|@& n&N=Nɕ"g!Oƒ%8'Z_\h(fr7[Y<U+ endstream endobj 29 0 obj 5357 endobj 27 0 obj << /Type /Page /Parent 3 0 R /Resources 30 0 R /Contents 28 0 R /MediaBox [0 0 612 792] >> endobj 30 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F5.0 12 0 R /F7.0 14 0 R /F10.0 31 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 33 0 obj << /Length 34 0 R /Filter /FlateDecode >> stream xZMo8W9, Q!J"Y`1=0sAX3嶔"%[vl)L@OUb_+Kbyr,%Of7 <\ J:J 7NmEZi&9cQƉEu[&{l7 i$@^ f1 )Fq OUw,\K,ͧ$nb2{ɷY^kqf[_<…_/?\/; WScTX?NN{^,-ۿnW>N`7ll0 K.˦snnzȷ^??}n߂K!Y}yc d| vf'dmrO+9i$Ni𙸿 ۗM$*C*۶U^_| |0kĵc_o ŗY0&xϋFf2:|c{H2 =~#F:e"w!zô®lǦwNi(H߮ }٬] x)C$F*SnVP$9\B8)r*e;7sSȭo1yj*J!teU"x$vYE#~%=h$M>{:{ɤviXfծyMĢQHrzzby7cE)b9Db :Oɼ5\/vf kHs쵨=g.*P梚`L,8oC 2 i.gϋز`#É|#b X.AYz=Q*@SlNI&J($f*y@MWR%R긲"z{H(ʿ=voTv8>HGi+YyjVQQe!'H&DnQ8̉<)1Di2}i<ǶشEN7ifs8ZcH2hW>G(CAD:zQ mJJ֮rfXz\ KV]D ",C(5֙g>Yӡ:@a (|2ز}dWl:= B6cE F{azrXjl~8ґ&BIs!:³1e-NgTwGO[~u N̖}>UmXOW0GËZ$ L"\Cvװ Loc+#HI}5 IC`0=+&ww=ܮXЁw]~i~͟-6%a69p9Ҫa 5vE-B;ׄ_ c\9p.iZwfؼvC=t( 6bLsM5x`F eq$,c ֛r2 7i`K:(I$2F}c@@YWJ."iJ_oי6Ӕ^ endstream endobj 34 0 obj 2329 endobj 32 0 obj << /Type /Page /Parent 3 0 R /Resources 35 0 R /Contents 33 0 R /MediaBox [0 0 612 792] >> endobj 35 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F3.0 10 0 R /F7.0 14 0 R /F8.0 15 0 R >> >> endobj 37 0 obj << /Length 38 0 R /Filter /FlateDecode >> stream x\Ys#7~_';V*}xwbLOÞhEa1J-NS(g}XYDHd~H$ʵ*ͲsMS~qk-v.wEsMMsUmV4ʺꫪH<Ӳ@%+JWUZӢn\*a)벴kʣ~fiӵ-te,\:uTmw虬w4-z XMZuDɼB<[-yʩ޶$nT1 3 UUi٢rɥt ֢j~?Oݤ,O5`\bV4.F?Q*@WѤ1le^+,틜2um%ca4a,>͠/Ӳ+EUW ڲ|wA:eotEmZ&>%.*8ǶI`an=rcV4#!F?XnXծav]lދh>bf]wMdm5V]M.b`idJj$D;X2i rĦfeZ4M}U +$]2M8p%u+\*If7l!nMTBtӒ$b!fɋ"FDLJykTD'Jj%QÌl 2=b'|;Z8u,^2Fz=Uv֬쳛$9СaͽΉ-nJaxYun/&fBb 6 ;nW߽r^Nv{w?~wi=In6m?FsF+kef@=< CeUhy4m7(I5i-< i5fXUD+F^RJZ@*,QoҾŸ+%+*hڢa-ܽu^c>ŷA":1-+` xɴQw-&'\o8u()#ve"1h ڈZ.>,[:i`7ȨYTAI*߉"e[iT*!~>_C*/Sk #[D&js8uL~'_]f+v@zg,XUӲk jiT+ ,8rsͶ) Q>1Rjٕ2^߅1:RET(?(_uV2Y1f-"1wGXY~lY!b_Кܭ=l7-Іqp 4'Z]SÜNhjRWQH'~fr nݫ&'vn>-OpڪP;wT2Kf^}tӖW%9O372+($RD2JA}/X !rqJJ"g"p6gՃєJ"Ļ7H${r®:Po'a1w|v9Ԉ o*GDb j]"dep終I3c}Uf t+0?G N.VvLjt5E"D%q PB J]c h^<o M A'AUD(y> V;,H ? 8JX !wtd/-ҙ6ZdM #X޻j[GrS,LFZ>5~^2 x2(8aD%T?;EK j2;H;rcTvEzkyQW;1^ |8I-q2}2NF# W~d)dzڱ x`Djoh1<55R`B0߿&wP xoB^HdnӈjîܷEXq߫Ub* GH<#H% OșV0~6R~"Kyt@"!nl`׶%>H;–.&Zs`^ɍ -r'^ka4Z0Ug".6F'oD:DԅXۈ!Ȕтa mi2@.3Ș"+ =L(#Ck=sr铻{HV|5$/I&T52)#y );1[l+ m:B'96CIQ@6h_'ZÜR4!LKlV󶾄F5b8Q+MT_6؈Ou["cf~G;^W>=΂e|O xwR/Y9y3bx?lq,&wI<%iV'=Fso+o2{nuSJuD*6()iyBy6"kY%eЂյ0TN1{-DA_:uiJb"Vi,CԔ2YYʀIwq+ IRg$ֳ$}g;ɜ%hw|> t1e<k;>iWoo1G}5GFֶ!^hhMXO's<+X1x;ѪT6Mi|~_4 )Ģ9zGf-CJ zyT'=ѠkFAS[۳}= Ɯ(6EHѣ?`eL P .&)GJȝ!~$4k?FF/퀨8*!1t+q dQ[n+$ Ob9%c^@0ah_T{}ᐥ۩עM2F66kЄ/Z$nT74yOh,A`iND`0Lv9 37^IXAݩI_x :ז\yee"wD,oE /ծ&! ysG]DJ ;'h|F6敔3ƉcBY* n80VTH>1!p҇ o:۱};*~@::A3X_ž3`i3ok3Pg?){% ֯lw>r+_|@R IHqp\F"C4M{y&~*VHaAQOB$q*D\i|$ߞSZ i>'eBG.>^yZ XU5h0Kfu@ a(H>!p%BxZa i&A)TO=s#O&/}R3oxve YH0 P!-PI4^ޗJyPIR_VxWxcH3B>{+o*|Ω3Ќ7`Nщp\j):\4vV<.X56 ceC+V{ʘ} Zj{|$~thxe|N 1I߀/Ψ$Uʖ"ُ{ฬP߫K>cJˣXQB->u.||xIjㅱHxNq5sdp QIVƔe4[9@Fx5E`l{XP׈}) {dKN m/E+d={8/"e+&"wnx)+/TH]'1dcp JV C% g{X )-} qyk )Xi!-xdRM#5>5a_8y_ﶟ;z&(?#NCō9CN]𛔅!!&g3Y3CL#kS'Ğ5>O3(k]=D$bAuwH ]'DfN;ɣq:.TNƫ~SܐZg?EIXUl:^bLe#z1 )F:0js@U}_5GEBPfK~82%>8G)C!w\tt _wvHG#{}\j^ornܗ|pfO>K[&hNGOŸHPP)T)B9ׄ5Hr+ ;GJ|*xgblAJ#Edt!Ki.U-a|z!r e^R.F ~V4yޔE+fmu,MCC h'hÂ9t.i0"Pv7 oy endstream endobj 38 0 obj 7152 endobj 36 0 obj << /Type /Page /Parent 3 0 R /Resources 39 0 R /Contents 37 0 R /MediaBox [0 0 612 792] >> endobj 39 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /F5.0 12 0 R /F3.0 10 0 R /F12.0 43 0 R /F7.0 14 0 R /F11.0 42 0 R /F8.0 15 0 R /F9.0 22 0 R /F6.0 13 0 R >> /XObject << /Im1 40 0 R >> >> endobj 40 0 obj << /Length 41 0 R /Type /XObject /Subtype /Image /Width 722 /Height 577 /Interpolate true /ColorSpace 44 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream x |EwW]Q!xB\eE ¢,DP!p% a͂ W8BH !9D& L=S333әykzoWW?S"D"@ D"@ D"@ D"@ D"@ D"@ D"@ D"@ D"@ D6o^+oCܼ3zNt+ fBF47>5ERW~*5OL|CRd]Qu:\y%U ! N'cmH+:S&ΞTGYM'D/& {]Vl̖ډ;u% Pʹ n9pT<08݌|*mō~iIFo=>S)'!*fqO&h )?֝H"@ R8Mm-u;\`K}fY[]D'Ը.5vR_+腣i3C7Ӆs\іHMRR6uTgJ0Ay>G2-\4^z͢U; "@,B@hCx.z?5-GC9+4[ 9SԾ:>OU<}˴PR }Up]׮(k޽y/`ܮ͞g̜;&)?`:C. ;L80$DWCWo눙yI0!~\>OU<}:mc+)v9 ?Ulw+/pј`wڐxRY"DN@@r~iߵi Xom0q؟LkSl-Q40`77 {cO'!zRd.uwDŬR)D<m%tC7an'nGlױ9eoO8Q!JMƒf)yzC0!-={`>+_!DI@:Z-X8`xo=xUT;9K̺c`űjOrjڝ[ ,:T e|U]uT2h&=e>x+^wtҳf9ؤ R^20Jd!hx~U8\k~Zu Д"`~ׁxȶ&BnKZtMwME۞bG) ZY0(ACCT|wJh:b{f i)cL./~gdi̷ͦժN7g!Yqa&iNeo̎fQ-r%&ƾpW²OP=A5r2llh9"3>鳜ݧ2ٗY9xz&ZVcJjWeg 65:k+S**ZN?,!83޾RT1&8]'ȝorYwI5neD`ۦ:w }ffeg\%YB>ء^n,krLM~O$oKX9 0+٥z:fbNվY(wp%m_Y(𕉸J0q&Hf֥RUFJ0*u+9uRd<ÇŠC2CMZ("ϢX`xJn؝X&PuҟöYs2-C9]oU\w`>1aP%q ?lsh@$ 9G:\S;|r'g9v:N⮝Vj^d,:~vÞr九 %u,28;)T~(,J5#m \R%P41T9n=dW8v3s0y۹ʅ@#2S7~=mOS+Jʏ*ND6- y"@G@i`y2[x`z)o _NRzUǽE%YqmxYF=EkkJ&&]gx:`iT7X@~ѯns~6#_1)d-~]XKqr4\ey// >j@u Y\q۾H{G+Q׌t~tJ-m )ϼϓ; 7} =FOSvg;0/bgLU,lg^͢L>3)-xBl9-ϼS@^BBD ( ,oe ,ڋ}.{h;[~H+P1sTu?Ԫ,MinQ}Wn?Xh*!!ЯGy c V+໹jJS .SqW;Kj!^nS}{Y*l `B^;nzi}+W֯iJ-m1p!>-MT9%;MΪO\y"j\' ĿѼϞs?ո㬯HX|cIWy+;HuUձ*:ZU]]Qw]jSQ j-2MW*>,ESh1\2pu5/VTwwnn0ȞWMԘ3"\lk1랋 feKX23sp*5>`LKU^=I_mn*W׌:tJ.0,[ĩ&){/[ܐا^1؞uRX,*t5}D_3.viY.G$i(p͊s )wz11ySn;xrOC#Nbi;iqgV@P>Ym%nD>oG=Q1 Ao'8SZepʢݻpw͌'ՇOeS_Nނ4 Po/`~RԪ*2] ?~2c_*Tf|!J.סay/ےfuu,JH|i;)eXۋtemL+핡=2^GZd_UQ\`GTMՀ!sժpV*mF@ʺJcP~lphF*zCkʉ4y k/USv\"ZC8 /y^L,1%kSG[}z+L# f ੁuOi.z;rϫĤ>v \O+OߌN%SAX9Y?O{*xN](RT)˩iS6غo3U>djN!Jb%Fyֺ 7>Z^T+[=/+Ra\';+C?GE*ۓ+6q*Yz di[C^ܼ;߬Hc붯zmr1ی;<`RD٘u)!"U5wh=]ډ j;K,Z:*sӋ/>O}gߪuZ19բ`X77꫏|_oo[wý5#Cyn-=^[oQQ 8okUEn ̢߹)+&ޯجSxޘm=pZHQ1K=˝G吵BC >U9%;{r0Y 5D֦`gJ 1I}ؼJ5=zkďo,&YE@S>CjYk9m4><$m.DޣmCSGD>"2C}V/Kp+JW^Q}Mݩ!]ߧ y(>)iNuv?{@\\/ RHWfbcHr6aXm]ePTsTxK9 Z^=P󝥭L+T_[jb&`aJ8:N DN@ʋ+P #,r |yUuOA^??O?p[]_%T5lN5,ڶϘsy &U8~.u9 Ѱaj34 |CC QQ1V j{4#6J-Rx`2}rJv򡆰 JŹ7R6U]s/z9 EV"B8^֐x^9,?q=T?2uŦY3 WLR}=%a"@0'e."_$CU^ xCA*4*3RVlh*[h\kYejwJ)= D)պ!:b J95M ĝϷi΀;w;'D"n!iu N^G`HUiAu}0;==.M7݄x}HFD"`e~:fKgRϝ;wϚ@=$D%PǶbEYce!#|pZwҴ4vۯsN}$H #]77pPAP`&EU&( dUu&ə3gX49V"@oEEEZXUQRTZZZTzhyW!ϢzA5aʔ)p9:t耕D"@EGx˗/ו D">.GNJM D"@MMW\c͚5 D"@";ҥ_) D"@tٲ]v\] H"@ ~HLL裏"@ D@7:o߮+ "@ D/#FѫW/RS""@ D"pرVZ5klϞ 4,"D"@,G`СׯJF"D"@LD-[&2L!D"@,G`РA8pJF"D"@LD\pAͿ;E"@ #3Ϡ_\ɨ@D"@c:Dž^xE"@@ἼL:A'DG/CD hql!Ahgg6lUǙ7\_}pUj^dc.ĉ&2L!D 4 ,8xQ?n[Ga𰕬$:ɓ'T!C7&&뮻ڵkצM믿ꫯR7;bB?[ J ʑ2BvY0""[nŻs饗)S8_c(ó*:~z_R _>p9qvvg_J béiә/}5z ~_ X;wJx*|ﶹm .7~]Y tiri|:ui^!!fNu0L՞hA~GCm&9"5g4 8_sDs\s< mٿCV AX>L:gibqzAA>SN9rSO=u=D%DLӄ!D`C7_=K']n bFX>,RCrKA)i=[8It}g -7|juISq#1u*NKHhqj<ʝn6%5-- yX+(B\Aݘ%/)ay OKFFI̽'ΝZŋ;oK.]s#{mId?:a„3g.Ydڵ[lٵkWQQ:tѪt!-@ Hk֬Brd2E0ƣ(BT6l@IO213_3Iے01 Z3ݪ|k$oQدL2~]Xm#6+ݵ+ ӥ!EhL-Q]F7OKmy/Ν'}YjԻUIvyoM~`O9*Ctcpl4VR16%/9ac[Qw4|_|;`8nn;ѣǿ>`ѢEdަE0f`N:^-Z@P@EQјh41HKdx衇PmodJi(L޾v,jcrCC]muhaTΡS@Bd\!<'llĄ'0BR[C:V]=mKC]uu+tPյui)| woHCD= oUU% 7!9xGy8 5{}FrꏠDt3@d^Ĝ6r,cW9wp.70)c%o?U Յ!n޽{=z…X ?a0̆( P" PTɁr<*&' wtu;ga8AH)mA-[ =+"5;l iXD]flGYI}zARX@]Ei!V`W} J?|i&DzV3?0&,@\d%pf<(1#X}u6V9k ÚϕJEBߗW4tj f͛7/8A)exd޳gO<Y_<< <&PXX(ktVy+T'@ɓ' yǎ o[n>l a<<<_|}))#|.2ɻ Õ A@yfD_bw/8p f9J2 C¾LJΝ;^?3fiʓ Y91~ a15 S4+RTVq矛j0!0  N~xxx^er FWz$J5bߐ#=I"Y7a{3ʍ[1A(÷xpz(.1B;.,~a0wO<@-,@w&f7kH,|WؖjȐ!$囶Aqj幹J1Y͇¾@u5 uTxmua _p`EXxxjo !j%&SA~$xoͷͮa*V_4hϞ="xx|-*j]ꫯ޸qcHaF*\|=e7-G&%%]qh p]uUUUUz E2V"Gc䚀*=@Xrk%2T vT"F***0ϗbb!>1Ν "@@5eߣE$*gD #yܩNСC82 ǎR8?=™PJb3|PUPaPmd'y#y"N#ؽ!..na]"2I z}ڠh.uiRHaIe!8pTs=W^^AnNU;HN.~ugED L g}V7U /|waZ2;PmPy9T'T*ӬGf=p#XÇIH2DT!T$@BݱxWu2"`gϞ裏p:qLporQLB Jk=QPLbafumD?_|ō7ވ#1|۷GOC0F4=zB\m۶]lkvVA]v( Fjrq޽8;ѽ{wL +@)Hh-1㧟~z5@mf y-`prGyDBdcZ o -@0|8kܸq%%%f+] cЌ4FMq߾}89NÌ3!@ ѴI #D&yeFS4P?5s!oذ!na4kj:|MǎW׮]sssAL(cx5rD|('bSNg>Xr- !B5)FTTLrK f3ƪU@ ߤE DMתʛ  >aܱcܒ8Bv׮]R̦'MmLFtaE-2uo޼9|qEjoTQ$#JCԎ:Z?X~܀ˁ8VN!ꊡ:F5 q2e$GlwD/?YI?"[\k#weeaEEE|ﯡ|iatBC8l?19ٳgAAEaoHsQ^jv ֺ|FdSi#jCPVv&Q C@ +r.tGc¨YbtHE#{k/^yWL C ޞF&`-7D>$Q+b*]xDciiرcB-[FwF$ѕׯ[pM?2tBo,Tp*J 7P=,=Xk[0^o*.m[i|d6̞[dtKc*=*̩qXcdSo=[$jZZk1b+~ԩӬY H1]Äѕ 1 FL1mٲ%i߾=NKmrBև2jM/"Ӕi0}fv7O{|LeRⴻ^G߁̖Mn3rP;LjC9t[Fc¨aF2}WÞ/|޼y^1סTdcnYQlhpþ^eyCVG먯HJƠ sUsgbrCٯuSü(ZgCuEaq{ MV$ i{hBƾ QILq&ڄ0>6k5Zq4¢E%4quC lroXx0`uԍ1l"rBIn\S"0,[u-OOYSu^w'&܌O8/ܒny'se-eiςòohHۡs\jǙ6o?wh^L(5g*:g)t}Z[͢?[UR0!ס(|i;P~-0x衇0NL'PmG-sb Y`5\j* $LހrV/`ȝ/g7,đ,ПwMFu_d 9ߒ%-/ۆlZyB'܀+*/];u }4>`!\mCF^ W鑽.q/qJ)<#tpXVX9 NKG&SWLP"bc1\ >V)6ũws<Ax/x"_j2~.u8WyzCQ莌Oň9ڵy8e>*°ӇV.ac_AE}CH]͢YEy_!p1۽'<\͢1]n]cFDO؇^XY>SH+A*\]Y ,k^)%ujZxg~ڼtG:Lm-K F-E;${j<<$t\8(H:Ԏ̙屎R. 9j0E#vb3>WFТҎ>jrѓᚐxxe@P^eǸaupyϮa@$Cj%m{܀%,4ĺG\n-y3>S(^.& u˨:5,\?: ӇiRQZ^e:oKⅡdƍG}En 0E#ޝx:tIPhi[ ="u 7HfqYA @ݼ눊 3Y166tʢ/R-(AaK*O B^m1oetu`r졬謜mt 0\33;;%!K#abJ7oiQs:N7˷3jyŘ֏0-Ljȓou]яZ䚄02#&,0N0 ج=zO6Y:jƧOmzNZlƍyZQ icNNUW]?i rlRLQM@5Povr;wˁ*껄QM0a:axaܾ}u֟ -jD%!D*lx5P!lBK/CFC aLX؂C<.h@\ 1Bd'ۤv^Odɒ{.-//wMB]C$1ⵒŁqgv-TcI^ ('Dx/B86PAn֪=zU~ѐB##^`m m6E J`Iʑ2{n|v I=0gA21bЖ!3LJ 3#:]8bYԴ k-/-?jʯڌ=luy+N==DVӤm^<4_~kڴi5i$(º\`%wfX`رO?6>Yq",qrd4rrǬ|G.OOCv9{x-,aHaCɫ0; fRy-o wJRD؂l, vppИۛQim= :݃^GSv㼔':^::u4Yx36E oPm kǏˁ)aCɫ aH50b,( \pdBtbWw7JmY4ﳤu>si[M&bY6 YYajoiL OWF $7þkluz+t0CwT>ŹSئAQ'OJܰ[ +`|t9UnHvBn$*f9&uR\1W S\QQ; }3;YbMjYBY_s1/╰t&|.zK VT|_.ҁHaqbȴG⢣#s.aT;LFNh=B rZdgHka%B$l؞i{~g*Ӌ}CʝC>늟… C@kIq${(.;]ڼբuh|<.ϲ`kk7!T \2"^\1u#OesLJ!C S*b LޗCϊWJѕ1hI,Q^ՂNm 7"DG߰ *y &fL\])>u,9x2Ce(=ux6fk` %Li_[i'5l:b>"}"cs{?Sهl+Ĝlp:SlC)/kC{)WI0IEcadAcZ D, a@H_Y^mXy!X7wƿfaait؈0pm"-˻zݗ莌O'\Q;gt`4!ېdͮX ;"-L2>/<>]Y ,;7"GbÌuG5,-UkDk"$Ǻgx}3 虏λQ'(b(\ZpH0ZYG(54:l6PM3)G1ꔓ!9d䁘F;XzIU/)fhڠÒ.r5jCgb_KJ 7P[f.O=zyw2_ 4孍Q>~7*]Kp `DWC!@ynrss;wݱn5𻑌C<@g ƈWU>u֫W6`4> t68`dXlLݻww.l5VbtEH a Okyxa}QOӎ;x @ZkәcD 5UǪ01Ao4۷oIIO'Dz J^e"}ڵc;vh+JMj,BdGNDBԞvp9R~~]~F F@yNE=y7B0n߾Ba{&Xh<PP<#R*Xܸq:>pb #cNN%\6A-P{51`m|-vːOTJaUtˮj& GN%w.vXlO-gH虆w # cFFv@ ߶:յZBG7SA^GDT9p)nGq@ݑ)>0Nd!q*tzk#>!Rj6hPoq 6װ85oHjW)1 }S_:m᱇k*|#ro*p9ƍ繵n`$Q?+1>>KWZ偌O0 6NR:|՞=r_HY^)yG(Mڼbl^h7;lgWM-ljie8uy.qnF}w[G]J h/DZ5E'o*źlszv ^T̚cXӛ…:_M4,LɘM<1 _s5Xoah36Bgz(9pzNϜA$ Ľ2593;`>{-N- cP,) <HNI]xy{wbB'nį.楾%@C:%*ffzv λ= K>\"5*.Uwt QϘX> fV^@/Qd]  ]Kmx a4idbki~aCF[ZK"DjBGXXt2[W2'>Zyǿk[^;sRQn^G ;EHX|5ߛW%3Q98Z٤NmەO7eˡ촸Cd PkHCgf%)))p9z!,k";#cS%j~#M.r?!!ozM‰[l:Z 2}uבRTױX +60 \467ŅLy1͜vˁIz(1z(!H##^vLt6BCS4VIY^ 0?)GnTX͖>i8+3o=u`,y>*$Y:Ի⻄a K:Fw~pq| "_̕sgF).d[io&\{ XT cljtjQM0a2}@06Ek% lTZ2kY5 NEĥ'G.F-2j駟ԩӚ5knv'*F $PݲeKԨɓ'i7-A$ݧQhv~{/ u|Y6]:uQM0atEum_|1|Gw5c g1,faB_rt8x(]vY|؆gq2Cq#ޖ?ħQ|H5H~݌X75;fvk_gz:)a̩/g?{-$i؝Ey^$|jv *Nd"tz$-E2g,zTV钌v0~%ģB;\ H JƅW;|AxA[* QK/ݼyS$0ҴFBZ+!:3>XXRu]sPOއ=ƱyY}/V#Eܝ7Gcѷ ߹̬*OiUE둅͔GXceVjWyUW@c ,,9xMĶQ1[%&ulT~r.:"Ӧ#;ܭAʥ 7 Co-9h]nrKalN ';kaZ*-1TF5 ÄA( w2<7`)D4oTuFA9)ˇٯy({τԴ5 Dt> vˈ[Z6uk4c'ҁ,58g/ߜnI?]{b3I>Rl{ٱ)Ul,x袑G{cuA:u*\m 3;E y۷_q3fw2<bMZVLTvZSx,~ثXcB>;`v]yzǿ9'1UʢNu[tEF†)Zst\ ahL4qb%NKʰq6OWt8 j ĝڐr0buu}mu *~64/uqcGJ'Ѝ?Wn3Rꡫ@r_WrGC}ˁy31:w¨w0zFq)ӧ{/Mi$Z:NSw "kť̲ #]2kE#taj{WQͺ1&&GČLx h]j޽c̙ _3¨g1&'?{q' ]mh |gϞzij:`5~+iӦ^ {L{陎e _MM''\ ;2<ZN܍oR"'C>G}:&e]}Μ9GIw-,~\;a3̀NmaT;Lop> L[l<0ZKal)+IXak$aO,==&9B|~2tb ,xgߣ\9Zvv<9S{]LŸÇ Yk$J0JLS0jbq٣G&N"H@M[|ڵ 殻ׁ|a޽{_uUk/^J'&{Ŋ.Srw Yy$B/Dž^hNJn0)J2 #,3f*T[jٲxu`k ȝ0  hXNg ߵ:=^NWTTԄ oeØj9kفWJ0zEG0ꡤ),,O_<kT#'!gm`I5(MF`Kouŵ I1 Ӕ'X]{$~ZR!cmB6Pئ/G } D1R`%&`Dl (8" ꢣ_ BZc C *~¢(͖ЦK1۶mk\ lf08J! cqV& FJeT!cBH@e0st!AHnfA(QYFCH1%͸"I`j֭@mHSk0-Ʀ. !< c7l8tPppl) mFW_}5$L1e70 hLhF("p+9(Xtttl޼ِcSp(\pֳTTT&[Rj%E`7@GGBB!Gc nl( !CGBbR_L@رCތ i=ĄPjó %FaQظe˖GF jZ뎀`*99Ç7b Nͅ0“0 ?LLLtFr3_M>Fo{ a`tfeenǎ5Jwſ#~"ҊDV,.ee;Dl#FtRi&;w޿o6O:T) A`tȞ9s/@YY"s8f݂.UP*w+$}x->o<t<&O cĈ>`Vb4+"PsIC]ځB߷x綑 X=e=+$C` SO=c:d.BfG}Zne [4Fl`&M]:Fa3" ❀I/"mhwkms<\￿Tf F3364$ѕ1衩\r d{6mCsYmψ<У[#2@RyEg: Y,\ ci'a ʳaG]`i裏|QW] ryEdR9_ d+VܽG.gױ`br7TÅN; NPg>:vɒ%yB6m ryEdR9_ w؊GW2E߬v=hϿ;;uT\\A,nl F=م a4yF0znjO>ݪU(_< iad-ڤW:9#xwK+CO,^RV,O^̙3oH`%#a4!Jzدm[yM#!}-cִV͜vxn8Op@z /h"Fa|ϛ7[s0xJaH/NPq[F8ӳ%xMZXXfw}74fP"ccQv2ѐGFn޼AIb%0$fǻՍ.nӸ6Jh#<[lY EG1e0QMRpc $FaފbLLͣhV$ca^ X|ew7ݥnoջK+/S9G#܏w*v d5~FC#a4 o|ܜ}]pЄdXe'1o8q(o/RtaUBͫ1S /;?:֮]<cx7glζFg"~&~asNZQݻ!yҎ:hbA$S?F{ .GG߿Ism[["hUt~ ߁yf?Aws5{,Ǩ0%!O0Q=()#$pXOj3bvn [(#g׋'k7PGWD_h{^YLNHǓg̘_Ex p>7Fr #ah"Fal3]#h-:ń_;(Lbҕq[s}sn JdQ@ [d Nɐ!Cu̙3ǝ@+ô00QuLyllNyˈԖ)K"Z9M'=wƹ+' u '/.y jh+C0``x۷o7Y0`b4O 00Qݨz9r/{-z7o?-9B|Q} LɸVℷĬEb3! 7|'0M0`b4U50“0s3ۦM`ߺu:aيel֫\#.z3Jvo~mk!t/k5|zCls$>^+C0^GRR!m n1(Çq'$lR8haq[߉_*?g{Zt .͖ry ۲zF'sVcgI>NK'> emU|#Ad)W^RR l~ix/6M0`b4U50“0Qݨzggg;;6.jŝ|qLA<^ :+}$L".3ّa'=c3Tߟ7M`?o}Bu k7pi^\q`"[8d/J|0TxnxW~ Ak=ٽ{&JI0ԆC AJ¨-[N&mG R=wNlotA|8~3qw Bq Ak0 ^ٳ i̦$hVpc!$Fa9;w.)UX amdN pTWaŊesWdQ,T,Goeofh>"8+`b/)Y:L$M-l:#1xuf_@ǯlܸѐlJl7hOhFbSFy6NUЯ!cW9""f_bn}IĊT 5,zTu%՜R{(|@y ivڅxܐlJl6hRhFZ_uր 0 ilAru^1)n6#`Wz2Gt޲BjWU#& ԚhxOٛ>$ yC=+Yh{γX r¨g1虏λb<R}</ bUuBP"t^* $uax&LD ba$0DV7cƌA7xX; Qݢ8IY$;{a߄K&6.ʠ!og%qqq:>sb{78×N NPg>:P Xz!}a/QhGa_f*^**$u~з^GAAJL0MN#a4!JA7MQ㡤_d>/}9yjNF+RTE!o%~-\ݻ{ [AOP*C"#RoG’ YQ]1i%'=V݃0> ^Nj/ F0 2!i5uDleG}0 W^:֮]A&oc#c?aCɫ aH0vR`HxmO^5٤3Mʪ B=[X3/Az^@e.p_ZZ'lj'`0B%[QU'q}._^n٧TɀvF$گ5KeP 670hڂka4'a4 !x7ݻׇ4)bz4fEٽץ?Y;x3HȺﺺ?{x*ȡAWPCor!ȍH8;`$Hq @NLOOuOLO'~oU?ʺP.Oh0%X^Lj# #h1$"B) 02ZQ? AwʎV˗ GJ$`o #СCx(1Z1.9$Q(a-B/~am/I 7HSXPv1kx¨KF0j RJڒ[(ɞ4%FVM[p}3FuI¨_~U#hKnT(lng=f^VܔD~ IIWw0@6EZ@X2C TFF\5kb̬Pf.y#$za 41>(jkr2[T eyN2ϭ:y:Ӣ6]F.W}:d!2Xc, +n]7oQQ/1rʨjaʨk;8M/j E3@1x}.FJ h7¨ O¨RC2oV^2QF_ξ]N,WE/j E3@M2^G~t1fVb(F3\߼F]xF0JN:&O2QF59.|IF  5PC 1a]7oQQ/1cP ={Ԭ QF|_K>R));WIq"6hc( ?/g(F]L%F]01^F,^&(ϕqՉilzϺ7S  I]PY%^GbbU;ENB0^%ŀъٳ_~Kv (Qҵ\ g EN~%bS%hc ÐT~¹Zn]xG%t$a$E  0܅ OS%;ńBtmî w"ϚLoXT~e J!رcp98q"bh3P!|FFPbXj(U߿C)SOR5C!*qϘmc^J߰Xj2Tc(h:x  w(?jF{a,ad,F0^RC>h'L^O(0#.˔2@ $3Vl:}] (oF+Мg¨4!aFNjTX9!U0!*<:!iR.ʧLJ֭Ѽyse1{\5=002R#|+&U4Q1~0K &m׮ڄV7ih3aԌN0Jihc8ۆ{/Oѵԉ3wyW* -5#IOrٳgc/TU0ڃc)##(e1¨̇*0c[j s GӪBD;ݛ6{c$3Vlĉ:<ڄV7ih3aԌN0Jihc8v BøqQbAk +&]3 }b '{ACRHj~*C,faRFFPbQU` *"F ؅JEET^W_vZ7hcPIgPX޽uL>]mB+ъ44Yw+\H&tfu' REL4`b4V -q?vZo?Ba Tjhb1hwfuA'UREIJeˠ[Et7odoX6YL4hc($-[bSuiZUa4mȘuWhDuR1^زe *^z*XMZ)F`o Mpo0waݖYuWhfzbޜYjz1-lWzp<*DNZN1g0cӦMz31K{tǨB݋lBgZwnr%%4⋁l }9kz-{cOq: o*a4U1ΌuWh4];Ժ*FY +WfX0D׳׍3/VnJbp$%-^l)V,5Y@( I郦cwށׁuiZUa4mȘuWhDuR1``mTDٓXNsNm\>Ѯj/gey"2Xc,qaÆ:rSwk`Ba4aa˒uWh\uRPP=&//=$C!{397,fBRj Z *(|uTjhb1hwfuA'UR}㏫Oj_ξyN,W2gs1A1\Nx:4*0FdLw+4ԺtfXj(Շ._I-dk֮EDӛڗE ǐGBb!eH 3L2HT4:3c]tRN/ =U{DFTriqLjk$CV|p7̛%xMpjudeeӴh"11ЈRә6h'5Po5JP9Ucb3sI?)U(]\%zb弅l br >Tq ݭ ф5.Kc]qeQ3K#@A0vRC޽{jHk$Ly527ͽGY/\0JAϻbʽ]k۹ޘ{\BP?—^z ^ o*ao̓kRȕ q`P|#!+1HL[bJ65m١^o/&Kzo*{KFگDQ`,5Cup\zR &t_ cP=PJ'nݚ1 x̀))4ų0!ٟ aTn[`ԔY9*׬-/cLɇ2Sw#Y ){魅֘wlt&h-"?J;$lCB1٭57, wLLHN^>2.WiVM=u6D;-?&&K`Bݍr؟ &Uk7}^Zg*~, $|jU|i?m\^ǎZuݑoUu<.Wj_l>)#mQ*zܾZ Ub:O>G5Wݎӡi˷Kvl\ljϔ`$?892nns;niNJ6YԱY#dJL[1v!gᓗXZn44D-H/h?bZ\ĩs=C7SX!|qߓ @+R6Wi6)]oX!Zz>yʍ'Wo_سjgxJƕ}-؟H?raҗj߿o%Zmڝ7+}C:cܩ^/nV7q ]k-ҰKz+l"y{׌?wK~|_~w՝*Dܥ 'vEO@'=)X֧oӎo7s/u\ Gtk g WVs=އW e\-'ٻb'Ӻ1tֺ\`5H!m W[#B Iֺ2FҗWoy^iNĎ,&(ο|/f:h0 nQkכvP9I[Fo,yrWYq}`KnY#r?@|ɵ ˇ~ X!a׮]wޮo+-*aWwu9ϼGӦ"`w=A捲, v/EfiZU_bDoCt_#?/=i޽{f/cbQ8i3gϦ̈~e']PwtY=fU$ppA[`:C+PRҰ;"{c޽Ccq;-[6DcgJf͝;WhpxyP^z!?z5>ݯ]^SesJи)F?kVDg>JZCU+pArߍ$ܾxl9+Ai0xom?tZ{gCNVZ|}Qzfzz&? U'*pdo<^?oߓ2o2,aB!Q!xS){XH>p68ΛI 9YYv|W_nugdeo[l{+7]6oyo{d9;fnA1PJ߱plR<ǴiA_(Ξl1߼ܮ gE3zl" 俋 K_xk:h{M6j!~Iqr;&xnļ՞OS^l3I9'en e*C"8Tj3M5'!uLl{AE0o{{pCpQxqu$. pg,gaW=*4wUVa}H?:4ɧu i|1;݋nK>Vɚza*"1uRJHZp"޶tN8a8`M6o=1fe3r33ŗ%tis|0mUiLR=&ᤜ,?L%Ϝ9YV)F9Qt p`"bRxTz\?KW_*^sIS%^siB|:~>LCZS/oq^H!Fe3|Ѐ,}5ܔDwϕ,OoVZG'}flj*Tc(-9$>M6ב(oi10_ζy`jUkbLZxYJ9UzӞ۞ ~)*nZ1U9E]$Lm)on9Uq33L9y|KK}fm*tDK ݻFZ&E(D_޵Ms!ח)3z7ouaU JA T/ԲeKxVz)è)KL\qO?3luK&ߔq#WF,_n]$~[_X^ǝwj(J#%܍qĮ=y`7,9+ pol;{z5:1E/We>.C\yyGvK\Ùj//K4RC>tRh?I-tofN,TY8,,>}:#nm)T `ܳc>|8z!_1^vz ҫLG}Pō߰\PhqUna+: ރZ2g## y9kJUxw0/COF2nWwKM-px%E<"yr/AɈ$4n8E\fwz5j` 5G9Zu[bϖ/\p9ԿDoJak  ۷ג"iB#-R~ټwj롖iz{_!}/cC1xIXxƍ3HT4:3etmx_uz.i(u]\ a^۫r1*ܧ6{bxA .,udaKϋF܎W2wf,6d<^0=H¹7& ӻ[q fL1c'\_Yrnmϒ>xM340{ȑЯ_?--&$""5M~7#u;P +|9;qDxXvR*> ƤGy]t V_q}h?xQ2p6&gr4?>ga^n/^3=0|Za`7·ƈ(+70D0; 9u<Qg2O\M7;7.Ͻ)\ٛ{y/Ξ=^=*8aCNCbܿ?~I{lvo7t~-]_V0aBL%|M%7t #^щ_c,JHR}y~f 0+5C v5\ z|ύpGVO»7 7MܯTN1Ϙב4W;~ב{z|4W>[L2Qf}/%+O)4RC>$;'LPh{Te@F ;$ж1 TODP* I郦cxɒ%:ڵkNӪ2ilDƔ1bWXOZ%Akۦ:.}7M^X.*/!9yp :#˿!r| /3y^\`89"Dd F$s{G ICK PF&X_}RˤvL]ѐA$ 2֭ѬY3JqMUL3#߀:0⡜[MބLNeaUW j<{"Xr S76Jxw`@͚5!%%ECZ$ vJMgq1&A6d:}]JqMUL3b*ft`^Gl}:BJ87rz!F*R=kן[U]U+`TXj(Շ*V GU2)B!-S- ybֶ{jvǂ:,y]j9FLå|p޼y,7_<;wO&F)Vs? ~9<5*M'&"ӕ2$(J+lmß@E[b{P 㥗^3(G!Vσ/P-[&..a1R9:Ne)*F]*E6pe˖)SΝ;jZH^[{Zj1s|OX͞1@R'TV :x8gPF'-qҤIʕ×׸GߺukRx\̾ Rr_֨K… H,xz#5_8Pk/8O98`du`lٲ%~8|Xi>s:Yc%fRzfʎU{aE;{/L 8Y~ajf08XzLȼ-[`#&&ƪv9ߨfY J˗/_ݡZjaOIo r`ٞϦ5RIFCi`!j뛔8._8u%Eg>3C"7aڪ!$L!*$##^VjHC1 rYQ<~ߵhbIWw<HV]2IBTWv'Ǣ1oZQ{V~;Է/dȗxkԨC7LDtSׅ?0ײ˪Vq~^ǕiߪUby0A)^`]u_X_]2 J@To1-wm@sb ґY{kڌ ǘ߰Al@uҩsCL@[+cJ%P*S)%y]MA>wH)3ϵuv3f̝;}Yh܁X>θ[A3if pYr-QL3K A,Zi"6 QA| D$G}Z%*U_p1.6qu;лD]9+mׁh@LcUH`vРARYQ8?^uJ˗ z:r:]t^6#}5˞3g}z+';K Ƣq/Tz.Y]0Z9TW{HuJ*DxE8H}e-ZxOjV*=VZS/)ۺG{>U~)"5G]0ޯƯFMZ1F-DNv)]*?ƽ^ڏ֢iT!5a1}z2rֳin7~9ߙsO.w m֬Y38aFmRRyc}.7W{]^7z̼[)f za6f&pimߍkuΆ?ǣC:VXa3OCZuv>'v!@ǃ0u|N 6n~u^KE凚 QN2ϭ:y:Ӣ'8ڵhr'÷٘ƌ4*UØI'M}rׁ%6 ~L)?pAup¨F}2j~FZbiL h{EbѿxsC-'Yvu`چaV%1~xxcƌ!-svN@.PkTKt!Y6iG(DyZ5U>a3Od3& aerEUs΅ѻwo1~E1BX*aԥN ^loS t0@.G(.tb9{-x&$,> IFb%saQ-fγbvb%Wb?0RSQ/ <>Ta~Zr)VAa!^KI\5:q*?0Y82=k$d]$$dUzDT}?ƍHɲc(Z{F]0Z=*ǂ4,WDw}o?ەi;;.e(|.orPUH2:ѣ3rbhPE_"$Q!u*U5r՜w=l9+Ol#؍@ KR'b(gy$c c*)n W*D4h;eKa):T2J6v}W6y=icܐ ϊ-jʹc^ uhM ̓ѳgO{YNlR.0*aDY)H-JIKYHCSwJLQuڙIozR:&! i@委3@,'%%J1;v`ĀQ|I/ѷR~aD)a/0*ҫl) ЙK1}9N' $wUZ7,p<-K%R8e]%[%DuV¨F*azizQ42!읾^;c$Uy,uN+ QH¨<0w^RY]7 :w8B|rʧLcСb x`:i7UHn녅8؟Hj1KZBt/*_l;1v n+9\A;ݻFOuaTL.0+U$˗[C|NK;"3+\컪y-l;F.(g(N¨Wih`T6ҫ<@rnB*f*D6+cSzv7,wݻwpG|||̦΢(GEuaTL.0,jbObIUlP^g n8;8Ɉ&L1bĈ1b7F9EqFuH `Ec0ߥK6,cT!1*7HFkvo>bw؍QE#i9Q8¨\`dMʗ/={'*D6(/A{cdĺflעE w_>b7̍QnQ:Q ҄1u`cΞ= {޽{xۇ hu ~vWgЃH `EFuHwśpƍm(;d{]8xX1LmQBv>VM "MQޥ6m0n&: ;"óB7ЕIvץ_f O?fWgЃH `EFuH3v%%%!|q] 1"@I(Lӽ.^XB/fCv>VM "MQإC}Ͷ#9 iܱ(:;[Ayu=4a F]4aT+4c:fH){u;LaDĤE;չc={ z :^A c0zArҥ4"FD $$#koڴ p [w;`TgHZa:0F&C`AdRۻDo87/ nV\x5&;} t`c֬Ybd̶8¨\(GEuK:o<QoN7ƺ[yn**wO'U/fo |?m4x} #06j a @%0j,D!%m)Ȗqx&Hݲx7Lzc>k{6lѼys?Kv>fk Z!HDRoܸc6BZdNN@}VYY@xB 8bfAVJb(/Ca70* K,+,f!ٸ6.ڍrynbBrJ֔})cc\#->`ʔ)"d} 3¨o2CY.I&8q; 墅D@(d0gn縴ʹeo p;lO>IN7e56J&!@%0 vv`foݺ#@̙3 bey^;t#>>>Z(1WH0j盌0x 6!!//)#}\ze\WOh cJF&u `r^*+`C%-Jm?j]~V)dvp7FFQ#8dї3`GƥW سct߱go 1|x۷n6¼;0j4mLB0J`hF$)Q@ piݺuHg!r& 1@27۷ooݺ5L SU\QP#¨o2C0#{E{^uZ,"A $Y ƈ%ÇG='3M% ڃQ;;IJ` P0*^z^r`,"r"{cVWѢE 뮎sEAFp/gכ`{ G@D@Iptw}(FIF A¨$%0&-Bd*U{ȱ(Q[O6 ^G=kQb(a7a :u r~= DXTpI3[lpp<&L`,1%抂 F|F_πQGbccqڨQ#1 ED@N1@cHm"p;oM% ڃQ;;IJ`wNnů""x:u I;Uu>FFQ#8dї3` "\rev%E)U'Czz~|_U UQÌ3u`uF@0j4mLB0J`hF$)Q/2³gϖ5N9] 6K.!wzHJ ")˓lYֶ,(1WH0j盌0x0{A߱0rRD5h#4mb]H;^ǀ"s;]M% ڃQ;;IJ`-mҤ %(0bH@l ˗ic֬YץQIbbbfx$$$PU(1WH0j盌0xǎײʕ;E2$`cׯ_?pŋjԨh=oKJJpXr? cРAڒG>0j4mLB0J`hF$) &'qN'B^w~aСqժU @_ʋ$Cqݺu5kք60J5 &#<4>C>}BC$ D+20tD/K/ [-x`-\ھ}0*ߋe˖%_Oodv}㮪/?3gN~ /wLssܹV1@d޽{>,^x݀ϟg;_e̔)SK.~  c'8 w`T 0j1mƗa0j'IֳgO`:ɢ!@  4y u}'|]\$G]gkbCRQ捧\S π5?u͛OfSR%DeU֢EaÆa5ì9ae0Mڏ#SfxSd GSNs.& gٺy9#z=sInU}ry1+{܁ImxYj:c~5L'V+Ij<\C-t^GY^rp+*_d 4 6L:{N ɕ>?ժUUV#FXd+]ep3vI40ƒaQωr\ic-Q 5I^z6e43"wWj1eꉕ˾ i|'.sm,J.f]}9wt>慩茏h1&MIm^T]-cV$'L㝄dOؼpbJBi Sq;9~yRuld9hk<")%1_M=Ԓ;C٤IvoO W_m۶Q2Cnܸ!O8Q$^7,p룛hQP#¨o2Cپ}0ЁyhE+f.DExs_n>aEO$ǵmpNBAȮ1U]2Bdaggsuq YAFQ!:\Ip/^r.awVNOS\tta+t_K' FXRG:upU<OΘp9ʴ0ʛW D^߿$u|# 1~!c0,:@0j02 ?^:BFF+X1Bت,8{c$cj1|>KNN6IdѩQ$1lLVVVÆ u`@` 4#%@4fo 4I͞ ,ѹsg8GfOe$0Z-QK0%&+OeFb3k> GBDICc J1|ժUBZ` ZaTKLV0b@[M"ŀ9]"ml1@RUj#F`/رcGsfQ3:iB(!>ydӦM1ѿYD-{ EtiuUQﲵeknV+` FvV QpIX~& V?!27Hj͐JXEIII0]N0R$ ppj@t%$h!`7M$_y޽{c#wcբZbQ9r#81F64!2O]D='aMn:a(e E"@U &LA%Kr. nMBd d$Yr)S`a.. 5(F?EF @&BLzzɓɈIm{"+֚Ayfo ɚ* aٳ'>}D+c(+ h&@5&$Rpv0ѲeK|" A6j m27HF񾉉S cƌ:eW"U p&dfΜ HSSSe"1|Slo t}%̙O>Yvm ~&N5 &!Lv]F xxU6UY] "Vz"7HF6uðdAe E"@U &L`saMe$R@QK 7HI-y6mo"y`+ k#@qKE;Zff%S`-*d "Y,Όdo pmς r`T0_tad,F|6mڄVu^Z2 >KMY^1@үȑ#xo>999beƐFB !Fwr 4Hd {0 Hh#s#8;v1dȐwFFSFb KQdor4j(;;[d :#BjQ#vUV FCZ`d4e$@0*aDV§ժU_"DI`X QPFs"yٳgcy+V}Q4VL0jF'MHAs˫V)FE N9*=0 #5#`c02 cFFoo߾ITV݄!D&he1@9Zmۆx`_Znh6Qj(a/1bmhҤɱcటc UKRS'{cqt_O?1aCs֌$ Ȩw81cxWۧ00FV[էo$ 펣|:p `\fdѩQ$NƸrdTf~Ts$M:0聡   XF:#70ā w(-C"T4K1$ ͣ:0yt0Z-QK0%&+LX?ˁI,ˢF#u !rr1@eo 47fТE 8G=cͲQ*)(9@Æ QV-M_B`tr'RvBB!2wUh"l cfLj @5@ L4Mn1Bs1 ftK I D_נo@L_ͺ$12IGc䄑0B@%VԺ=E9'DaSrI"cͅ=:{yNɘ|Q&gAXƿJ*coM5&$R6ƈ*X}E ]:b lC"{c`7P+x>\tK/k6n8m9$ڸ"~@#OrSUNZQ`^#UKDMb1p*]-peňKc[ĖShh"[I={c@ݨQx~~ +0 {`KX #_r:X#+a'Y|Ejժo߾@a'`Ȟe3J#s<2B6X^ 3Ұ7K>\]8_+ZrciWɰy aI-lwuOκELrW}p{notWZX{2yH^{?w&_Co7;7oޙ[\nc`ğo8TNB0Ik K_6'F<kcUȘ=g2VMfլS&a2nWq [a9NEU\nKUu֕syip!ȑwtUI҄ \+Uqi\m(v dw$`8E)M00mG3ƴmSsFQQa〇BضIFF"E#0m٭F({c0⽎۫ w6:ιyGڐ}z|˫.ո2H=ױ8ܚ%}u\vR{ܳI:*x5e5A ˂0ǰCnE0NJ]枽1@Uxegٽb*Esr/.~pXv\N1"z.̓7m>`Mm"\gwp;9snۏ~03u+~󩜬kfzްgYNO9ҞAĈadgoyf C1$GE_>Vن +UkI T^Fـ#U%30UcԂI*fNtu#{ijm⧓^9PIn^b]K3^0s/eeNd)FLkҤ ,mժUyի 'N>nU+bƈ*ס۵[ѨhޜE]L`4!C>mg}& z`mω5hh"y0Fp BȄbB0@tD&`\`A{`Ç;y!p0F-q#0Yq kqZE8Ɛ @[0P<M&ÇO aÆ+V(0&0ncDDc&jV FmF9sZǒnb_ }K.]aVU 0`:bD#DS$' 0uTElYFJG,RL/XSzĉ,Slc{[-^e;'Rhxh~FBhhN[6VO^Qɿ.9>LhlhrB@S`b-tSBd2OV4PX͚5mOXp0 9ꕊI`46gN9 @=N>5… |MOnjca1iÈ&4494@͎F[gڈf6ޙalwfLPfڙ,-Hε(Gرc&MzW##={uP,hќШOj׮Ɔ&g3dmD3p{Sy#-juĥ.D )q`UT{޻w͐F͈# NFֆʬ^ǻ| U\Za6sM'{Nm+?TJs&[0kzq엻xҍH::OfX-,w֭K/W_}gϞ0u'y0F# o9Qiv*gjD{ ):,OZboXZ?_BҤږ98٫O pROh83qJQ*k)<|pq_=GvMusX1I! dnVW>0'AMyZ< pU\Z\&d)n!w˫sN.WX ǻ( ~*(d* Fqbѽ{wx#&&&`9>z_Ȏu^gҫ(g_ʸ\G1 (&%`LMM*Qe71cӭRG&h\ tT}z&, FV1,Hp FmEFbX0ı6 ޿`|1qxA)z  d/GoX9=7Ưk>z& IR 1={L6Xz[$XU„:DT {Zduĸz?\x>O>7sdNZQbT40۵k`}mu6Vb[DxF1Wy-Buw 6 +z_ o|˜O^ Wydu1fƈXfMZj903F]ډJPPTPh`SG ̧ӯ"M';ucHTXwޙ0au!cԥ(AšP\T1*0B5T%"DlJJ/(پ}СCyXm۶ ,0C6T* U&,gU Ei "u!B  ]ZǗ-[ֱcGc[.e*,Yʼn(6T *H*ՇJDUݝ0v b fRYO?4eʔpԨQ+J+ѧhT*ՁJQY2T\`dT#u!rlՇSp2P Q0a`rǏ __;9sDlR` BT8,*U bY0L1NHKE¸K!Mu{&+`'"~wliwHIuJ*Qo'XrҤI͛7?-[b-[N<*a;aTUp,2Ps6PTEQ-vy` ˶: 1!2g{ޙžv&l{'^/ `v/cZZhժ /:utug(iKeFW_}Uep`|Trr٫(!H`Za=(^uG|ýRT ;I#:b17 *|J:dXVaXd*2Pa&!1b eX Ğ|ٿr<|0ad'\t^x|e9LI;t:FTxkg͸mڼ]sx=?X4sG_Yԥ4"*n{anP ><#!d{ #C6zRa9\<P"(_;:Yæ3}nO=ȏG.^XwE"f.7|ï^[ap9#>LLL5j&ߢŁ1?ӑ#GCF={eLN1euDRk#pqӅMT^c^C6!z8Ù=WT%I-_ݝ+x%෵u{bHz乓c\xOK_3Kz u7CuR%Ҍ|9#JJJ¤.]A?۰aCl3|sb¤z ňBh( ¢Ȃ!"2zA6baK 0JM% X^|UHdhQ~ pzc&n\='F8C~Wu`#q@(F0<{&n-\q]- .60J1bŋ6 U^]y/[x0blX:33SHn0̣(#}i"G("U0Jی ͨ>նmGz z&f,9 u|'Dw-H @L{g9ޝhxg/kC&^E@P4DaQd#^0fZ##(e1`jV\p l n ܆y_"~3ܚ9\~ !8k^ø{x-7&:`m1pnnȏ܊|G =C,^5.qk<9K ]Â"p{܆| p60$m$MmLᦶń9z4GWYFJLNN2?>wE&5UL.PXtxʆu68oX( %$9=$r\Y* VF)TDU/ T&EÕFLĤ|vn:tXPkĉ{3e<6mk_`ku9jj0AIɡO>PP[FnjO:qf:d 1R@X D(]&a4'F DA#e -OQJ. 0F] @G^J=WBQ@{\EuؙN;?Lt* LU:kQkڂZ LD@_MР$ mb &ː9=}~{oqߝ7/w={={r{0F@ @i(=!W֨Q cwT Rr%h* 0F@ / 6v,aNI]^]Õ|#=eT\ ZJF-@@@W8Gɩ^^=Y31YDJ@ FZ--T/[R{*wt]gq KD[*^D0k ~~R0PZJEOȕ54`˜QE$K8]rj^Lk59<;)㋗b64̆g惲[YP:o}㑔淈R}#,&-'/Fˉ2}"Ky}@i(=!W֨Q c^6J`Lys(mc~'=78^ʺ.jxfL^J6j-. Mtٙ{?߃%0[_0|iTKLUS8l^t-g.2uĞeT\ ZJF-:FZBA/i6^hĉI` cz6G=/dmprΆSo(-'JU0ja˦"SX pW?y^G?:A N͙ g#ױ< w":s=N}~w`ݱc1Z{m;J-U3j~f{h3Ik 'v*%c6_J@ FZu-wCLǴtH#[ ^G?o7dal4G;vKtaa waDi"'/'Ӕ:zD[lW9Zr>YJz_0PZJEOȕ54`¨gh)4xHKINJ#*yl Gv'Y!LՇ2Mځ2P*zBQF-3 = P|쀑jQ-= Rr%h* 0Z(!`_`[,0PZJEOȕ54`˜h*a"45H (-'JU0ja<ӊ 0 | Sc Rr%h* 0gT -ݝT6y3h2(p2P*zBQƀF.y|y4.Q>!v7Z+xx*6]2=MZcJ@ FZQH0Ut#](`U5fH-6RAS3(f,Z-.s|OiolԬ9a +AkTi1ɂ%$ɕP*"Zdƅ22  #93#rNJѹ6%CKePYD^cI^F 8nO\}Ik}$ُJ,_(!yyWdvޯ"9 1g?ޗƸq[z?ѽkr|[86JevgYfh $@i(=!W֨Q cv㉳J]mJ-u*1ws$zm`#UJ"yAS=%~+gTwWGnnz&qxEZV(oz^đ#R!6`5"M a^I#4KoيN:,JNZ_ʲ+xn}]4W?2eT\ ZJF-b~!y>fZ<ߗLhCƇ9%DwFX"rna_RD[c'd [A5ozZgZ8K㋖[tudhH/[HI0Ͻ_jv(./wSRZJ9aŋ%{jk.0PZJEOȕ54`˜ټL0Hi>8Fۜ諉^H?Lp1JàpuY3"lmL%GsklGEZ -DT)A# v\7& qk$3T֞*EՏHմbkd+uҽ`Қ*v-"Y]lXar; #x Gs:MQM<Mge%Rap龰j\/~)o=2Fō '6`3GŎrbKytƌ.5Utup+{zTn(I+U`F_BF`mg %?x(\+JIçHR%i X[N`C) 0fB)1:JwVi&WnS, @%Q&#ǃ]NFMY7W0zQ yeF/*Ӏ102d==\NҦvcw=ȴbز,pFHc8OV&9(JJS&24Fxot8fvJ@2 c&2ҁ1.uwI;i;tS_U9Qٝij,͓0zb Ay'AWdgalKD` JS=MƠ ~[`=ij,͓0zb Ay'AY~(ƜJ9e1'"?d@ ("%)X&cPb%h"0%yC3P)9F?rcND~%Ȁ@Px;,(1Oy`4FO,A1(1ȃO>W©S_HŀQF`T!Q#@ $C`̏[J.`L!0-%0!hzEJ?d`*$0f0gE)8N<x62CN0•I3 peLd                                  8 . ECh~*H* B~ qqMԸyQ9" y\JCpB).S< @`<O&RpO¯2&X]P%{x;@& y=_O?+HP @8 BwG??>?  P`!D Sd"PhF7V^"kn/ =G 0(&(՜Fth<];o(,#Z:*%QE4Bxt\0TEg]Lշ5rKy5Vi`i$^ҏl}I-J Yi$J+{ij ZQ|-#48m;n':8FhC<GmIWIJ S; Q~840LT;2^GWWF[ -¼Lb'0[ S+zТ-2Ѣj 'NS*_|Pv C"F؜{I:F(:D> stream xwTl/]"e齷.H& KYe7D"V$(bh(+X "J F;'Nw>}w(!a@P"f'0D6p(h@_63u_ -Z[3C+K;?r!YLD)c#c1 ʪ2N|bO h{yIHD.VV>RV:|{ [RF ”"MF1L1[Te'Jx%C%_%RJ#4GcӸu:(G73%Ie%e{SC add1T4UT*TTTUzUUUoScemUkS{Q7UPWߣ~A}b}9Հ5L5"5iјi<9Ъ:5MvhWh~Tfz1U.椎NTgNΌ|ݵͺHz,T NI}mPw ,tӆF -5j4oL50^l\k|g24mr6u0M713fͱBZA EEŰ%2res+}VV(٬Ԗk[c{Îjgʮ=~mCNNb&q'}d]N,:+Uʺuv^|o]5˟[7wM׍mȝ}CǃQSϓY9eu빷ػ{^>*}7l6 8`k`f 7!p2)hEPW0%8*:Qi8# z<ἶ0-AQ#p5#m"GvGѢG.7xt~g|LbLCtOlyPU܊|BLB}&:$%Zh`EꋲJO$O&&N~ rRSvLrgIsKۖ6^>!` /22fLge̜͊j&d'g* 3]9Z99"3Qhh'\(wanLHyy5yoc( z.ٴdloaqu.Yf WB+SVv[UjtCkHk2zmWbuj.Y￾HH\4uލ6W|ĺ})76T}39usocٞ---zl=TX|d[ fEqūI/WWA!1TRվS疝ӫox4صin={j-n`[k k+x\S-ۆzEjpjh8qn6Ik:8w7ޜw[nn?uݼ3V/~ڟM~nr:53(ѽȳ_ry?ZrL{퓓~מ.x:LlfW_w=7~oLM˃_uNO=|zfڛCoYož_Cggg endstream endobj 46 0 obj 2615 endobj 44 0 obj [ /ICCBased 45 0 R ] endobj 48 0 obj << /Length 49 0 R /Filter /FlateDecode >> stream x]oF>EcVoNv;#9!DY+3cp&9Ob@6UjՕ+gE2ՍmZ[oٺmovtiĝd^挠hfI]!sMM^ }QdI6ӦNgh)dS%,tdeݤ|sfIUS壿`j8 ^[ALnYeY c,G +*` qU*J0$zM8yTeΒr>O|V,x{^E%Lcf NWYrcYI2sX ,.~wx?'zdpKAϚdj/߿ \^LxԆ,nj zIXI=c۸w(,φFk `vez`~_Y݀Q$q[McNa14,6TPeC^۰X'~v;pJ+(:dAf3=n2Xt$ 4\'4J_>t3 {ip!#~N `{ ]IbJ+Hjd0:X7t &FzWՇB!)6$z.zq(jh0#dԮJF%#ǧpIׇJ2F-w+_o1h3aD+A:0h^Atb7 l HYSjNTC.߫e-e+3?KjەϚx0/[c.QGXQ8Mq 0DsiZuN>ŢYE" H+pCBi ?A*q}ҧzukN+iJvxP^=7yM*}G izUVːAָJ#G_{Ǟ{f6 o{RpɄ;yjjvziHoQ3Z ALA?0Ş?bɥY#2/̻ &֊9d)_ǰg qڍ:{ne2Lg[{on9x%gчo} QeTZoe[jxQp; a5x}L`xέкlI؊T3EԺ"7j߅.btr(~euR DWNђ"gCͷS)?tS8uZ[jkqh E^'4Dc6U8 CP@Rf֍Ab=K7; K?0%,> Nz2"F%3vw{X<^.^?AG &O/OGg 23J~D9)bbbڽ&5Xӳg\a9R|믉큩@#T`ٽD3[{=t FX͘ENԩ^ԶA}2y1Ŧ̾qFDt9lVOS$*׹ EMe bVi}FO* cR7Y*6c5sEUי^MLMXK)F./s_{peL~#כ)RңH2Hg4KbK'% 7=2)B,ӜH&> ~´a, W>ͱ* IJ$~Rv!9aR`xCvyXfR2xXt+sa~)ԇ_7P^/Շìmzq@oXŰ&;E\SyP\~e,eۉ‹bqα/28Cqy#zmaZD MVsOBNf s>K1BkIwy 07XB>!շ䑍r^eM gCt/owfoc:IIW> lJtrbXc-,4+\zT(ixtۭ`^V=C4W+SBa'- & N iTX*ikJ ?Ťx T1G&K!TYڦt`  ?.X %|#߉b\JwE>؎ץYBPys) #BkR낱 ^dRQBC@B0B5/yAV&W ܪwbP V)P[\ جHa6G9ppTp!Tc֣WiAhO}7F  D|yY" D, U)q>9"2wf* +mYN*)*";ĆL?<|LߴD|@ѱßLm29*QRbc}|䤌ϰB.aR RњXa(&Pbh;B*z//\o<> dFx$0TrCÑ7H py:N9חy7E x&'f.yu짠;DL9S9'tt.Cd큏:9LQ;6G aJNs߯5S2J5!$-y9]BAi/.8U]:G@ )DR-l/ej8whĝAU>琉]=R=?t{?dŏLCQ$N'ShB )r?ǐ nPw:m,@!2_82զFWP>*C ?X#|  ,-h6Pua<\ %7΢xmoT:($j@i%:m=j#dz@Yg?u-(6Xrdž|lf7QGWBUDi &#$k:I/6 y N3A+/6+Wۯi8,t'kv Ir٥euy4d60 LVwdI~膥tp+!X !T7A\QMnIlu.B{ur}!/#0xGdnp p+#t%WyH?k:`U54?]P;j03ܤ\= 6/!T#eU̓4P N1p%n8 2 f[k:#kg X&!7D =F.`Vs%ӵ 8{2&9dm@Y?Y9A`ZZZnF¶ ¢}g%4hKD0!Ho"a tm ˷ :`)wq!&o THC.Q˜ۺ_"忽Ihs%NX$h%+P6@ ބQ#*r) kKhQY~E.o<]A(| )&y/^'>+< nSi94D~/7/7IV oI /1PKh}ݶ(HWwϥQ1Zts@ "HT9]?pS3;?IW}Z. G3@gC~ci.$vZ)"a5\ 5R^P6sM^Urg=GRA__Iq24dH1xw~|f{KfѐTz>ޯ>o_پhiN1}Մ|n|SUkqkImRm.$S[Cb#5Q=mW!Gqːu0}fz`D (fEA( { ~tB[hÒF?Y`"`Sco[xjBZa lE ߍzI؂YҔvF&ohMfHIB H؈ eϠr 2ڴ_4f`ɧPT`` 0n"XbQI#0\6.m ,7QE7_y}e.[̀ D =lH,?[Nuc_5A-68+ᠳW{suAcʹ KFF&.)(c3 _blZ7i b80=w%~WZIggi׳ЃwX`+}FA)Y-dCɈH<8)r"+lPM{ Yrf9! endstream endobj 49 0 obj 7288 endobj 47 0 obj << /Type /Page /Parent 3 0 R /Resources 50 0 R /Contents 48 0 R /MediaBox [0 0 612 792] >> endobj 50 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F13.0 51 0 R /F7.0 14 0 R /F9.0 22 0 R /F6.0 13 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 53 0 obj << /Length 54 0 R /Filter /FlateDecode >> stream x]mF_0p!:gl, wFCٺhTWUw10zjd+S&E$TUflͷo,;DH{+SqS%x^s`e:Nlh⬩z&)e.f۶X7a'?yҮ0a,wcu%p+W< nq2TVq$IYYtUwt@UUQ_EEFK0ŪK)e:(']@gof2/5ko;d]A{mKCl- 1XVM2:sLz]qmc%z~iZePT~BHƵEFMtBpxW&,,~uA-/H66Qf=u^KcZ9ep ?ug\xo;>o}(S%н9͑j1z4kIFfY&Dg̎_lY ){q$}7EZmOyGKZ@-~e( dXAyVE( uUʂ m7 ݷ8+heNz֙jưup lމEڛy՛Dž0+SIUVy|{i N,,IulC96=fRf22n71~z~Zodzm P;1"ev,+[YXՙ=ZHdwYoWco%?g5lw ,趫`z__p/[]V/\BNa3i_ QZ3x̲s*/<hZZIÒEܢZ |x޻AY&Y[2c- i OEUM28b& tBQE 7" Ht\f˘_==جkɅ73f0ZqqnzZy PʢH<fXy_+Î-"ؿ;<1iˀ6 $˿U]Yx?{>ǐDc׶KHԄ*a*J.f'֌P+w3Ǡ7Pz7J93[˷oi+ |+}IbQso5DiWF]d-8KyLvv^2'x;ULx'?. !Za̭*v+SQN(׏ VLJ/ȹǐi =ozvB _bݼ-HaflXF LO\o &(P#,&v#+8%#+ %eS?b.;'6&-⺮.1#X u%~У;>$|rn#=" %k!c;ɠL!R7ЀpVpp-Gưf{xY x Q4:@d) QW6@UtNIAw]G6˗ 6=Eņ0fb3PXxC@-k [EXq"Tg}']k|jɛ+n N`AJg6 ^x$/"dvI x{`fsZE-Y " q>wEٛ[ c"\EZɤ{ kP8y | i:t{IFQ>b/ #nbڌ$_y|Qi,ecH |(J,!>VV>}IryZۚvD z$l~#+@ć*Bd:+AofgU2~!loxm,%[>=ִO`yYT78X3WT/ʵlmK7Pgڱ Mr]}0\,ȵCxԵDҠ0 |w}ٞbB81;H(sJ7e77ln=pFf|ov2ޝ!i'0ODKa!wuCC`sl'Bib%~7{x>hwj-esjY-0 45X-gGX‡Y2MesA1rmAѵ\a ? agKX$vsmk eq o_(CE!\6ϵ,#`I \C,-K @2#etx),X/s_`'s݈\nO8R=?QX#M:/,f#Z#X&I:̺jH؀}- ~E4{GXgknfzOT煎 +/@l`۵?Q6iG@M@ocڷB[Z5BPT050k $ҵ9,udF Ji{tm@RN %)QߵtmN@:tm<9h zMf)<ʇٗ"n0l-t!)R`E Aȟɲ`&lfPH xuqoTs/˚lp%FDHMwjYxZ{tKi.DKo#pޣXI!`ڶnɴFy%$>dBE!ʩJd쬘ko^fi#at UX"4G=|q`#VBHmfIP9'KG2&tPpˡp|h 9 0wS)B:1U43C#e sbaχA1 (Hbm,5AjT=4:Xh?&*؜^d74mjLouC[(Ҋ؄,,zhӈj-u@%O~>(}MAX#X~bf@72|[t˧*;(vi&h$):J۲"+kk ÎS_頽uE +͆NVMJ%bKK+kŖCVܜP`YK]5)@JWi :D3UJ[4v%+*W _Sl.?*UTh ]9 yoTȎG /czpa:ȳ3tGw1iҞguVf,YfaJ*BuG !2O{0£FL,ʆoml5t pf:.kd~3?PzƺvQ 'kZVѺFV`30gpYgM忟k D[8$8f?]Lepsk+ْ)K,qRVKN 061ZQ\%|Aq@;&3܋-L}m k%?hIORKEHܣ`V^3{6Cv d|Aܣ͆ux'_H0JP|=-T[ [FWxs\S=[S}آo 35' / xIbs8^n{Uw=أ4+RH5&#>S%QgG'_bO˄RÂ誊Z䧻5D=H20=Ndmə+ nD)Ah}{ڶ#)%pt0\~g2Cx&7f% {NQn|⊭48s%")B8eE2PR QnďIg/ TXA1XAIW y=o^~QBr,g<ޓ<*q%y2 fANjH߇vj/:ꚅ' 8f6^Ol1Qz sO킊!TxƄ5-sdK@"%J[І>iSáp >sbW -ӝLPZptqX 9%oELnFc"iw2 pml_CMP6쁽^)6xr55+`6^1U{hQ Rf5qeb@}EKC÷3zDBuJb#3t2O'oiS+ i2QN#X:뀮BGiy9\Ыtu:3}PJD r*~cXwe{^jyiUcx1?vƑxmwc5ܨpy tfñDLIs>mX:6Nȡ Q#<1D|,ܥi%:֜ᣞpi:ЍNu |8bs4Sk&%3 ?2{i8'o1dƕN=i/ ;»J ]/Juܞ]e~['>*חA{@ATDv_C;*\|^I`p.Q&Y!fIN/atONQa 6:#yDoYQ6q넀$bzqq V ?'s60}i?"n*|1qo@3BONPa]^ 7Uv^g&I ƮzyUyzƮz^>{]'{]`Zu5`.]?c8q;pY'A}sL-m~[jxR1okGj+vz痾qI"P!D"~[ߣ&% z,ֺtQ䉯P՟E,- endstream endobj 54 0 obj 6746 endobj 52 0 obj << /Type /Page /Parent 3 0 R /Resources 55 0 R /Contents 53 0 R /MediaBox [0 0 612 792] >> endobj 55 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F9.0 22 0 R /F7.0 14 0 R /F12.0 43 0 R /F10.0 31 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream x]YGr~_Q>$?aRz0DzYYG1+E@uuVVVVUԕiSgUemg0hv7cnVLۙ nMӥ}vҶ[t]weUUE)VVeZTMnO˦,M6iW+ҺhK˭9l.sbQս>3A3z`un&KiA.*xo^gj֚+ӤYYoDyQ,n^@]=Jqx'k^eޢ1 0hd2xe :-֙ \;>5!scY7E{d)\;б0x]3ocZn_% ܾtm㣅}/s=mӪ;uZW`{zvN'veg ĪK3c~{-#{+pcצh)0<]UYylMf,U%@YK|2FةDKEUeiڄ~>޼2YڛŏoK w̝Yu#B05@D4@ѷ-t1sb3seUuk1aSt0{ 숼naM\:+O[,6V0_5d;|OfM=aDfn/([YHfL󩲼~X^bA4ad]Xi?UZAZ~};U"b ,%")]?/GH 6IbYf0&g6FL߳-mW<v@ZSbGb!+d!1=doLf 윑a< و ĥm$(3{'}Q(ʰ#obKiL f-0>bu)#Z >ɨAtx@ $ZAKaM~2%,JsD #۬~IzXq(˙(2(Ű\t왝R-a2Y vVGYb[sY78| ]3͒Ͷ+!%YO,䰛B*Arb=?zÚxNuJzX;GI|T5uݵz<*~:F\)iݭQwL>N? ;g7~qhxc%PAO,n.Ҧ-Ӻڈ6x``+^ALo/~8Hw-,VZxA<Ǎ<tg<&~g@h7u$X# ncVB`=8AfAִzKoaA/8SA_ & PCA"$Ƞ{Z{' RaO5 `Vt4ܒEuVKgH#(v ԁڸ gn\m"-[uL4M?J(MGPO|BME9 0}9y&-8u/&<9Lep>KcںiEZb_NzM-fOb!G h&%˭0HŇY\ (J=ԃ< G։md/ƾ(8n&>~$!zf=|dsΌ()q$}q ﺢKP+ۦj&cE$B ēipW_6ت7)xo 6\ >&*skdc8O18CfibISp?_࠽]LSZHvPO\9SrJ(gw2OVVey[V8Di_؄ gH mAN7w ;v:ڄ}Ddoin *~kbé8gUU $==;XM(pTnH"]6Ev^8 Z|GIP1'Pކ/L:IFKg]k% wckHfvOO8QM.*9>1 :u o0>{d)(ڛ{f\P~9챺&u#-I=_6hwiۆm(qj&ޢxijӶ A 4z1ti z9|CY{ee>9l=uQ5=k@սvSoeH;/"&y1<0ł9O- ,]'&54 pfe/">`dF4;'E{:~Wb7fwYɻ7S6ylnT*XZ fw#lyI[~*x_MeA_ӾZ[((yFeZ]@*T"'qЖi`u-L( CބwZoqx,Of+u<^B57⪾1#|2#ULW+Bv۩8b3V"њ3)qs-Tq8]PܱP@\8Z3nYY` UһFiqϺ[x1*݀w=tCR60i2D~]rӜxzr2r!jԘ#"Y I f6xxm֕q9fV)rFlg8Jrb89RZ$N.JĚEAKmƵTyXi Ud$`u)C#Ym,ErdU K >TBYm^"*tm 6Qp eRK[bYORD 7UXxC.3!{NOKY pH ҦռFRQc`QRL\ 5߂o(AiPQKrG>B-`{N/{ө[uFܛ:#]gqPz̥f8'8o{Wܵɜs"|4VUM:ǞTЯҕx ߤoCVR(^@&= 0tx^+M 6! B5QڜsM88ҝ%k+;ܘ9J: %AMRx9`85# 3䥕5ʳ_x q CgrORtdd"$*DT]]Ҵ0-9{g}&g^ 2k3}!SS 遁 +ɿF) ~KX3XÖ%£a%'"%a bQfP;+eʹ}idm}%0K2NeĹPq'#4}&؏0eG?|,tY٘E%”=pM3Z/=12!i B1rNEdy|(NrPLDCa2F9߭%ԖZQOy%xz OLB7JՠR`@EY`ZQ#NN]`6\G2W'JQV0ZP  ؈ [֬Y-a͗$քW& G؎]yUB.\y;!rw6c^=J&:* i"ş!3r V8ZOvX> ,OOkkvK=<Ƴ3$,WT˭7 b)ECߣ=9DE{|_De$(‚2BïFLnn]B1}vRi N1C6]S@H#z1\)ܸW?-Ѽ#vZNrX)z{:0s2Ȓ%3'wdŇO48yg!.<2e)0WlԼksAqGoASXn`}WT/C"K[-g~.(p, ] 3rK[Wwvs%%ŪգOz&X(,=YD)u(rXnV,kaɴ{tp-uQ\QCBf1"/ҁ͕5Y}^ PT$%s尫fTp$Ǡ6wmy^EE票-k["ElS. Fgqi^B6(ɲ=x׀g{u+b{*+@;6,>[B!,7Q8+~EVD^7N%#aB6&%%.pV\yl[%(w,/a*X iDB.6=!\"3 'ńyp"ZY}-' `[c:qwQ"CNC;[b g8ExM(6fKzW?ǻ!lHʝ01|鿓/ZBİ_m9=jĈ"Crb<(yb(@K,Z.N͘sM&/ҩ/^C\ty^PET4z1a< BQ`4pK:ii({,#VˑrK{D8O~YW-  ]Bk; ܕ 0- 3GZ_ڶh>зAB#9o}h OGYct@}⊅?_a[|xS;1d8qLESr-,RK$ԏCDN:_)bC'p儎JGao#P /:;߷: Ȟ&(s *B-g?]슧'?\e]|%aPl`jks5SԒ55hGzPlUQMAUU,D:6ִGEOPJ J{j)Ydx*ٚ4UV:PEQB[*8p4OLOKl;`s|uh\_8xݝA+VTÅR* lM n_䃟B#ߋcS7# i-ݝp}>m`(2b{C8Uqx8Tʬ{q̅cWZ~w~ !:+D}':bXAg`@WL~!Qli3"9$kb!@0L557Fk~'Y Aҍ*sC=F:ޛ}e.+=gK$,yQ3ȓ4a[[;f9Q!ٌwxy~q%pGt8bJ| Jv ]FcE@i:y.W?MBKթ,II j=PrGgaXP{{Ϩvjpu4)4•M2%O3ipd7 pȩ2<+(K0N={,{/+Ќsow7ޜeƽ:|̠`?k$;-򟥋uh .04 X|?IK)򗒭@$5/$>,M#,gƂ) kFTӠ̋0W?rےl(лcp4< = \ ' Q/O͎(#%qVS4k(B_?_Uy\GbhhQ –9%'a0( CneZ+G_ K-ĺ7ZʣV8̫f":YFPkK@Q:s02h'yZ: Hp,T [ f CMC-,p~E.hSq7DA5QݎvD=v 1}(%ez@[wU2 J[-P^P|n , ̉5NF&HqMm%K1Ё: Tk*pcud^)zVZ~Ma(pf\hvYLL@:tBM|xi8ߌ,\?sу8""Q:+w0:z|+ȋtYZԸWՕOJ1[37neB%.s 6"e|sN]yKzWᮢ}+H$'~Ci_T6GЪ@2 }XRWJLzpXr2oG|P6\Z% a;Mg[!m B: j~[ Sh^ѵ)XD߆oa;\u{}Dkr['l_V4p2DDP%}JԘ7H)0Qra>Wr{sE$g1$}e[Wܟ!藝|$`kQaS<2@M"?na ،ycDI_?浒ɂ/l(}|q<ע+GS r'ԵI 8!r1b{fL%mI݆ڳ X=3o6%DX39= Hj&}Tp_Q\[rm.U)ԒM~]Ar˵٭WMePv. +3$\K^y^A/i,M{u+q~2vb$ 6־D :ք[q@`sM9-v/tZ )\X5P( endstream endobj 59 0 obj 8415 endobj 56 0 obj << /Type /Page /Parent 57 0 R /Resources 60 0 R /Contents 58 0 R /MediaBox [0 0 612 792] >> endobj 60 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /F3.0 10 0 R /F12.0 43 0 R /F7.0 14 0 R /F14.1 68 0 R /F11.0 42 0 R /F10.0 31 0 R /F9.0 22 0 R /F8.0 15 0 R /F13.0 51 0 R >> /XObject << /Im4 65 0 R /Im2 61 0 R /Im3 63 0 R >> >> endobj 65 0 obj << /Length 66 0 R /Type /XObject /Subtype /Image /Width 216 /Height 215 /Interpolate true /ColorSpace 44 0 R /SMask 69 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream x1QF JXD Q$ BbDc ؄ B p\a%bJl/s13ߝ}}{gvv}>? 8'pN9s 8'pN9s<)^~g?|}.»Ҳ.tֱ:Oulf18+mQ`v5TY;qϚo[c$*'T)lfGUgT'[P@U,Na~=aBz,*La3;,B=AOe RSvW)Ҟ<(rc U, R֞DsչɚUV|"߰2uNQ* ΩV +y{c[o+>e!?nUÆoH>*[xqQJ /-e#@MVW~@jU G:gXd(*[|:/Rcx9^wR6MX,*[6A],`8 uDJW8H+Uv)Z[|򁔫lq X;$O.Y~U>+[Dc[yO**L ֿqq+8MN ꊗINӦxYr+z+O*LÕ7i2M@eYTmquQɆ+#ކ5RPϥ!?{8o3 2%ɤ˖sQd~2wM[&1ᨵ3H[VT>EOYHJT{*|JS0,˜j]gIZ_/Au 3JH5,gJLSDK4\PgFʢ@誳ɲvdɹpԢeڎ.ppOȤDeYBrWP#ggó7ԹC)]bzMN1歨llh 3r2 &GZT[  ) nB1 M.6Z U*C%{Ƃ;PClwRO8+H! 6PpqiBʞ~Cc4\sl !:Uw`;!Lb!})f»9$`Q=p֡GBY "PKx2"2:祈;t5ޣbl8QiOŽ-I^ g{f*7!6P!eO=6(JZߠOo <#ų*CTsnP=ixc*uJ}?gogU>Q4oduM<F{pޅg}Y]BJ}m!d( - i[/!7jɹJ/Mԩ)3zzy7ړ.9ys3v 3JWqơ6Iy7T}١ 'S8?[m6'6<ɹ=l|O0TJ=)bfQwU M/Cw/Xp=on~ MٓCC`wd4>๵2!%1ᨻI+A`2w$59dA^wyO2ȡ`)~XR*Tˎ$'ZEX3P*+R19,*Lkf&CM"daۙ?S_zM$r6OfUvHrXpzCxL8+Ȣ*Իk$&a#o<-7?1~ J[*/EAНNOWDоF ٶUѶUۓ2Ǚk׹kIa_ / B~?YėG8hIh26Ћ@]0#싃y ]<]cVH?Wڣ~M:54O.r\eK|ò6Q_lٹՁcw8<އ/GKt|qRX~gSe+-`n!%xA͔Ѯ ձ&Tz70j^FAJlEq-!B ܋2?WRP~SAFq?:yzWR>ʞ"6U){k8 zISRJPتjHP}6xJx*@Qay ڶmO( ~-z<dC <=IUmcЛ-si!h;Ku )y! Al,8ve2&Ci91xx8\~1]Go#x ~߶g27UfJ/2,v7T:eE !KOeH`sosk9Ͽ;wّ$Y(~VY "5ORT!2`Hـ]:ӗS l¡bcA'rUeǓ3u7ȏ[b!<[ ]bwl rIɂ!9ސeɤbI9;_Q0i)RE${@>dIP~W]|!b:uj`CX0ۗPi&)C-9N}H;U#lZQ⛭<:}'60d3v(Y#gQUkl2{{ۧ;I@ s0FN9%5- a"F]`$p{S 2.jko VS{R0\K2 ! c(չAmR5 zyIY³qD <5!EמJ( z³gw؎h*o\2tx`t9ěٔQ[ V%o`G2mxk_aU!ag60:!omrTyoE`,84P-Õi!z]cO~Ks6, dHY@DZiad5Re1X u! ++UCGT/׾[H>)!\X*\ _?O.C}AL-";`4&2?0hC/_1y P9l:bg8^%txcIuչ$EfRG-l+w^C1{(TLђd&2dl@Aզ?!Q5YudXeo`9EuEk,X]̐- Y/̯uչ)qr2+l%t)s-ŋ@uK(ƂE*aWJe";kT$80 @f,?OŬ䞓~ E+;shQ2*XZ km&k2E᱙,HKN:[s& KZM{;<׊eU6j %q+ EF/7USfe<;}-!5>[oq؄PU\#|vSw<5% O)p{w}=.}InUѢJe۔@`+q[01 Oէq1/33\jHQQٗW_.UQBrn&ox+i4CZT2έwEd[JGfS`*Fd?2)cU6i9q@'q|C`%, bb%KWP<`v =+{ZLk 'y z;_>o3ܹLBmzS9;W̬ͻp&({wxs{ޙVvmkɹɹf\^̲3$Z '׺= uÓ:,Mf Ry5WB{LhI0l8wRpEH&CKgluN?|- ̎`|5=BK qdŗQd#K04#.8\^I\cϪB~j=3NQ*lY(3׾6,Zh϶ďb/f,%̆M,/p){Mo8$`:j?l*[xxpn24."M%04S76BhIBuՌܷ䂽/a6lb,-+/x+ - *N<<rel`bS!T@UZת LGq⛜@ó0PnrgBoVAln yX0ys> 2y\*HN{7ApJcGzV8sd[٣ܧ>[!;|s;z=> stream xM>ّOЦno Ƙ3fz_+7a6`hV Q^Zt#MR!JjZCDqBze~++"OfF{~_qcf`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`f`s.ZG:7΅=N =6K`fx nh{њÛ xΥZbui03 0 ]<9VcH4 ,jȪ" f`fu2hU5`iIos-Af`7.C[P=.Rw5R톞Bs@f`f3KP.!GEFS}p 03 }VvHTql6L-:U#V[+]֮6>`#mۺh33 ^<4 +fUrʕ꩸.;boV=63 0fv5bzo%%`XsՌ_*]NTR=`MYuU; 03]`.׺Զ16^x*aGbD**u5TJ?z8V[/\z 3 0Owm6.MIElbjAҀ%jQ] :یS*][R݊X/ú*]f`ɀŰzj`\n׎\vWì(b8סfUUUXT1V˶hx*3 0OW}5. 1*a5zD61˞eq*W77"amz/5e23 0ˀOq/GDqkcfx llU:&qMØf`>ڭ.9A.:V {mˆff`n۰N_21yef`̀2U`8t1\'`f2 hKm}fOp_f`f`f`f`f`f`f`f`f`f`f`f`f`f`fx L`fx }}3V[1/9<=!E=>q!n!.E%|2 8ω4d/πL$و='zN)D< 2S$CG?G*NAU$[#hFS){yܵlDX)%Sze SozN?tFxF%  } kTă騜x7Xb Q$8~ E.hoyx@<hrb]|" x@< es\/X9S5pA> 6ގ/ *eom49f}ZԻ"j|lW\c/Qz*M+9􆝟j*{ a:G2@c:&c^9fx@ă؈*dQš7EլzSLj F0J ,?\I 2YWZrSq 蔮Sd #`}o^P;VPA<@ .T2ăS/MI  m0EA:8R@*>tڤbR,OႭ=R jE;|{ #hÀj7ީH< 8pIEW"]HI RL

?zza:uZK5c?v68-.G&Ci@HSQqD=Tlx/a:`/ť*RMEX x02iME=d4} گAC ƫK |-U<"s|i]GMOM<nQҀt2 ik{ejKȞ,M%w.=9wi7}<<5`*eJRHE=d4#Ddj싑ҾŨB/nZORo/F#b@=ox$xjv+84g8:mpfkbߏ%:NX)`1x`,G|{Si7}<<5`*eJRHE=d4UwX:|{`=Hcpi=IE=@4`ƛ> x0 >"ME=d4η !H;cxӠŰŷc97g.8-G&*,h o+8H|Ư:5f`4Rb?_";IػV^_4}xoG_#^.# 2WR.Ⱦ ^ )žP)iޢ0 [/Qe8ꚁS4)uj]oQ<[4 ^=`:xbօw[ogl_'WtvE<G}GhggE鉶Et=DмtQ'Ĝ8\*O`*z%& 4x 0EϫRik{)#-4,hmT f) 8j(K:]Ƿc4^\{-G1*-O v.:hvD;b@]Oy` 9Eڙnl}U$tQ'Ĝ8\G Qw 4x9 UW}CJP) 8}4A(_0hlj"?\шH#(TF5R**P=6J!owU_V" Xx06A[hlA

Jq٭.> 5r*}nKtig/>n5#46r3RFNR,4v󈝫j7Q:ra:NS4ճzE<SEąNs5 ºl]#h@ĀJ7}1R*:@ăw{S;hv^ă/[vѨ` v: D=b@"Xx@<F<@:u5xe@"T-a*, Dx@nABDHn;C\ 8/l]#h@nnolq#>JIa CtỽHҩ4`@NJ~+G򿄁ĩ5~Y<<0xI,RdăC<@X$=x0&ă$r O6x< X&a8vh 5C< 8*]X #hL=H@h3c;@1di4Ox@wc;u$r O6x< XFxăqItrT aWۼ.pX*1c/[ Dx0BR=)JăvU7Qx@x05 @NzuXnv6&8W,PR[m[4M BRǧpZ\K% Ex@GeU poӷ5ku n Dx&Њv564Yqj^h [ իnz(ST{KCWh+lcx{b*e ux,D'V%$z_ދI21o@ iW2/O?ۿFYWU߸M.;T ҇-WP>TR𙖞(ՉnToa:x7&R!eBă1` =0PUq:Lxă0C<@*Yt=X/F `pFL@V͊;Sx0&?%T{4 2|@(x05 ă>ՏQ_H.b_]Ae) "ޣHpg]& x!HudC1UzZ^@kuc }ĺT)ĎeRO\`,GP-#q ٭Vk s$n #4E`b]qj@,#B<8шX$Z\QGF;3 Vk hm n #蒯X*رT >{"HudC1UzZ^/c$uc }ĺT)ՀXF*xp!ăI@v(-fZQ/xrxκ1xuRHן*X$Z\QGF;3 Vk s$n #蒯X*eHN47fg}mocy9P-_Cd}vx̹)ěZpSL x$ħ%%}ރ^"0P o?6|bFg}Ы" K)b@ 91:`% ?;8&> `l`2i >D 0{#LJA\6YJ DHIW X$lxOGH``% ?;8&> xPH|Zަ>YRP) XHgb$x@< ؏hÅB<@*|QVEAj9?1ɳbZ+L&R |`pa]MTA"s(,b@צ^ă Y -(a=X/x~"WD{Qq^X*:X3j%L pLg<`K~qL&>-(azx@< NGQI<`K*H5l$@Fq Dp7cMh#h@~;~lw{qTx`KjW0me,^y*!,s~cH @}eħ%%@o**PA몦AG*t/KzTTP"U0u"0 }L#{$^0x˾Sd|#*2@cjiՄTƒm / Z0 Ca46x/v`0xv異8>f袮_?7"dV_u;{N]0?6Z1%ͪk k |L<\xx!94)uiף}b(Gx0 ,ă11Rze`B.olzS9ucd Rã_b{eŶ~kۜT:`\>G,46tW0X*lUETxϺ1R?RͮZ՗- $.KCJѷQCKw4x% hӼC#Q\8v +2@cTƘj o *e*me9' Eԉoޡ0 {Υ60Ru u=" .,U0f` U تܕ46Q֖Cdnջ/ 40ORHXᨃcJzZoNj~s^?ͨl߼O[2aU҉9 `Aăg:HEvvuw`1RbѫU5W\̘4uC"TJ]LB!T:!jGxwҧv-5N{bSM>Uz?V0X*l2zۦQlv+޶k*ɶjjGx`Z,46X4?]'jpeT&QP)U TM%^v1Rz$ꪜB! `5HPԉ}'}J/opx lݸ.nn^ ^/^LDY[زUu"'F7X)ă>x0C XX> Rh%W/}R/~1 j׽%v)Tf`4bn+ejH~]ZouIQGjtvxB&i_;PAѸF2ѭ~5ga>ǜThۑL~ǟ#P `޵ٔ  8~#J{$^ώG\x[iu`?0>HI C<|F<8C*^%&4\ă i>5M H`EޙyшR{!h|{w$xWڱiX3b@eE=X@He4H`]ăk{x4}ChX^>7zYօ]d#TNoo7! Km۹ƴ+O|m {؆lO3x&ݢv%xlm0ORG¤=_Q/rWl|L&bnE<ă ɊN smv1G*Ѐj9x=I<@& E+S"^1U}`pS̭ =UKA@իt ;CxTx%vEM<ķk'2gF,F68vѨVӉѣoxdmR$<.S稃/\@oj9xp& x`I ]vl,?+ §SG#a}s VӉѣox~ML_+ axۊTRUjHWC`[I& FQš[.|&&ǡVvѨVҶ% ZsxëGQ`*ĘJ*ʜwW7 푇:ZӾ ߀߃7`$ޠ%öX/x7 ?5MlL$46~DDoL;m]a#Ec,48t0 ʤ7#Mx>hd),5H`]8@hă~-/`R5`$4@Qo#Ax0f2@chx@a:v% \Fqh@iV)+@ b)'ăڀ{:ed4,a83eZ$+7ŃTsFȵ!B8+(u-K<5ٮ183eZ)"ERq7UkǐQ S+:/"ꊇ=JR&5gLKʴsB<4) " w*` hW+(u8֓J!\im2-R>@J7QQr?D~]`uz&5gLK1ă79Qh~M]R" Juxԉm=RrP@ZӔص+%(VGx@< H`#x`gN6͗{۷S" ;%\#Hpx W}f*^}90|{75ZwxdӾ+(]x@?ή1T:|&zH}{݃LOhAǗ+@hx@<QR*p KwoFӓ%YcEx?\g5i9ſ^)cX_ :Ca) DM6+%خmɕ-5qq{=%ȴ)jmqv W=Q. # "X|4" 7;ݵrmi~(mu|gܘf` 4<\z2@c?1HW;; 7L.AIoyNEޟ wk"asoV2 Fa'I2o+]#EJ߅7|~>d!H~;RfP2Wf6%#awm2+vCm%%TėXWL?9T|02`:Ct_P1a:xS7L8z0X^M5uHv V c5xCRrV|{pj,vxP;щ )@8@,Z;wA<S8@"⁦2RHj7<\jx}zj_t:3ܹWv]/Z>Ƨ@<SSzq4xR]w`KƧ@<S8@&% ώz\+@2  {ޚEm]7^Ӥͧ6yXJ_x% /W!q/"p [mRsmLI a:hр <& `a:X5@:]l4~4?Q"ex0N1+)(aădă1QڳF0poLxګ=*ֹblL*jx$a|{0rX//x0N>l|{:ՈVq.1։bXT %C#h8 ă18IV@`Ÿ׀|:W*G]b'ґ0 p!jD}jH`ă18IA,eN!֩sУ.1Fv%xЗC M<SJ<  45mu.; @F x0x@<'I@< VăWwăn,od&1zx0x@<'I@<):_ax׍u+EF x0x@<'I@z$^R`$} 26HN9:n4hccJăqă-Pwv$P탉}Xqh2H`ă18IV 8Иo,W뾌VM-om{mkԄ @/k;Ar G5dfs.+Tiv+5]L Nu&L~ޚB\aۘ I;{3@P! \`}0Gx`kijϑx0:M<3(y-ң^$jC<)ăj$.[7K]vf|$9m\AUmU]UxPMe&ă+5Y#1W<|X6ăxPMzE<s;@<Ⱦޣ^`,@<DbxH@@ _!#5c|XZ%x7}܋d{\Ră*H$+xj$ -~Y/L_``joWS:ă1ExVhX ſX)گ{{ۏ^odm)m["xC{Oߜ9 OCs_H!z]zbU @ՍqLeSzwM >X/~;#\ZLVK K{!B`~SK&+aPHƉănԈB@*'%"/L?Tx>h|{krxpyO@*\Sz3jxj5wD<5uA<<'FHI }}~ hØj ~>c]ƾ4#%TDF[1ă>Wă>?%} SxARă>?ă>?% SxARă>?ă>?%} SxARă>?ă>?% SxARă>?ă>?%} SxARă>?ă>?% SxARă>?ă>?%} SxARă>?ă>?% SxARă>?ă>?%} Săxs4o3$~ZDŽ{i;L&Tu1>> o\2$/h@Lo#V "kj>dVtv0pZ⧖P2>U77k #&9ŤUʏ ־nB< Tr2Jabf9 x0& :P+x0xKh[iIEpJ{`+鳳"% 8X4<\̱^0Eă1QZă1ăm{ox%׏]~0.3$T*p.YmzNL 3u`%( xu_kiIE^V! зQ_cצ^3x҂E VcfWF@o~@|{9Lo,Ƿct+@2VTO rMfx@< xرi@SQMٷ.6g/`o3}ўv ŠVUOˮ:]5H2׀W5g ͧ u(X/?\|:|{QNR!oo ' 4&85#r,Zmxy'Y۾)kx{Cj۟Jg9dJ}ٻ3ﶮ2MQ-?x@<Av ǔ F52<9銉?TLux[ߨ)5Jp@ n3~v5&3~ n# L?x/ӑEDJRأݻjW\-xjZ +x0bvA x x9-@'W:8]5Ղ&ЊHWLEAQ@{ R=X/*pN<}ZgԀjGo*C:wRcc bơD AE']j t("dBYSE]hA< j{! x\+EWW_[k{BTU0~t fRP_+Xo#?SH;_|4 -&g15H}e &3M ɷ:%ٍo *e|i霋o, Dxp+J! -j @o *ZVN=oxxOgj]G= 2+$ƒfƊd"ZT?2Go *<7VšRu-AeW \=^ FE<U먏C]5ă 1RJ< r=9]nu(_@Jqk,X8L߇ U:W #@E~P}:>3(!ڱ8-Af@W >/a_`kFnI#fimlp)kP8-xx&w" ͳ#T L?R0:cnuN@z . m $ 8MfRV# x&jcxPoGG.X܈y`ap\AHx@<8Rp"R$x@< tx@<8E3bAşH@&4ɹx@< &eXABG<@u0r ^'L0xŀ*x0@12LJG*|L:`6ήQxPF<@u0r ^'L0xŀ*~6U^Uo ~;{#_]FfyoL!ă{ăҴ4" M?<{$޾ן|^ -,ă4-H'H`}?%AZXiZx&glGiωzk<z]Kv>L%5?[#Qr :M_TeMx?~jflMftf w < ?x+׀w6Vr z>&w/_c$`L{5<\`QC<8a=xP0/@oKPP'Xu xp"i! A/~o˃v N< zB'HZu x  _Ca|{4}N%!mx_IY)yW f6͌Jfz S KOt(Sϱ풳_ɔ~"X-+,Wf7]i†m$L?'Uۃ10 $|эă1Eă1Eă>E|{G6- k  ")")"/`Ks ăqă1Wă1Eă>Eă>?%o`\kx``LOϏx[#!k  ")")"/}KZcc}}~K<9`\kx``LOϏx[2@<@<sE<SDMp:?\3iѦouăqI@MP+ 607X x>G%ܪ>y%hU͌@gh.ăhӷH$xY&ʕ ۅ{o oD==q xp% ExY"XV/ 43V9Q.p:ăhӷH$xY&ʕ ۅ{o -A?#ny4K*EfƊ|{3g4[joLZmC[]$`\k@<,iTJ½ͷ|{N]AWzq^R%e@3cE=Й3I M'ăA<@B'jo5Wh8Hw4A.<1Mfd>:p|HhS}!Oh}шXoA%Gxs [3x@<8 ]QBv/Fp|i|{0d0> z x@<@~^MFQe qpAcN(#h8v  SKmF'$z^(!U-UUZTkM~yh\Įz"~%PyKUg yT<@ o8yeH1`J=P+~< ya_3\=+k{|uU5֯^_*}eGX*5a $ y*yЯ}j.yȃV3N C8y#>\V ƦO@D=<ȃY'x<@-6ypD81Z*y A ߃/um9LYD4@W`j,'Eރk{ GÅV3yz8ORI`m4*y\@./ngjlaoyz0<ڟM[e;&D%zFU p5a\oFqly<@ lnڷ K;: ?{y<@ mƇ |P>BGB*Є^(y<@<Я= y<8թ_<@< )NT$Q[i{>+NZVޱΗ>y-qWZKS8~%9uڭR3+vѕ&'|5oqkK(5aJ[GRW?r!+#4A\hIR}mˇuNCш4ueړ\o AUp_3mq*Zu,뼴Nׯ H7P}R1fM҄e)֑GcGU ն3r%͞KȃQ#Iwy`DNЮ1붿ML@t924в ׈Z֬ zh,K<ȃi/m=.C $yC_~5:M@(ʰÏre),qQhB3S\ 7Eyqұ ~nfNrޖ˩7FnU'?v/m\7k{%GemhS-y](!u²/ӄg,;T_&7†4<Wa~FD;h HmABHȃJ@@ȃqFPy26\rFU ȃTX'y07OyW#^ַT@fgXϖN]FP%@fg7Xy*1}4<ٱo*$i*Ш̎a uʘBDچWUT_&7^hy0.D[{! YQhW*Ԑw}I@1Dž/y0UO<^Sg\y@<ŵyP=OH@tJI7~tJ uʘc "aOqT{[ƬTk] ~ [엙Foe̞F@'dk`; PʘM1>4_fm6 ɀ3j²ʘRߵM*XIۿ~kTtզ9efPSA#M+mo,D%*0hCZ{C]?$!Yc6dw}o˘##yP /$V DyЗYBv# lH+FH=2lv"豧e^6}s< ~3jWR`V4iUc s< *ԃ<>*$jƖ1"p$b :e@y5ŇPD=]eӗ1ȃT*zCۿ4dL{Y$M 3|YBNAU싏6de5J Ȁjχ*>_pe^6}s< LWR`V4z˂<$lBփ<>*$jƖ1 )kY>0S˲GFۇ6ȑ1I`C*zCۿ4dv[f Gei5@c# pUyOIWn#jL@F[fxOg'0|@o1 UF'4 ?0*ШHB| y :bs8E_2G$@4*@F{@"C6:m6 @?6 z~l;@}V ! @FjO{_@ @ @ @ @ @ލ?35dv͉Q<N/dsO pBcg]U!3s^uvH^<Bq >΂p >1cwF?st^3E|&ߵ\wXO|{`v,q %7]LA E{[8[['^"P(E{[)8[U+zۯ??B:)j8ߥqx9KB`_E@hC9P/W5>ߝ0%P?cbD@'E w8awzʯ W-CbT+}wȖ@ߎ};#ֶת6BpߎYBb_BΈr_0#P #[~;&uXfGQag*:lqݡfV~M@w'l TW8fAw2;;ꤨ4B Bvwתq ~N1/!PM ^*% =˯.ï8 W,T . |i&PmtjRwWrH'"u~&[u55O'"uz9rN a~'u S`=6P<?1'z>Yr8cOǾ@$w?8&%&|Sqd= *3H`?& *vc2;W|;5΀g ĽF`'ZѶ7`֏}7K^r6'M, 1; @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ ʼ eu @ M_' O(o } q  n˰ Ky}; E q(MN)MHb?Fu vpLJ)Et6jJm @H iDZ/9GJ Pzudl@Fqqlv!{(v|DSlHJNt @"^]B?.Sb,C) +r@%4:uLU[jhH uFG瑠`@ Pi4u)b؄öÎ9Gϵ mӰ!@X4FS;w̱ #4u  m1-N{M8l=Sy\NggL!@shsmTm!1gO@ Z!!g7.de=78( @zǻv~†_OJ%ms@%`kcWT~1m6T~llǀ @`$дT A/%40l(M &cC 0H7H:〒FC{a Pt< (UՉ@'@|!@)A' @ >yy ł > stream x?oKqpIcJa* "LB!A""64lBA<93{{~ys;+pVYg @+|O@ uG͞yΤ:[roҊ`)29+63ArVKt8? %QliEpO7p+~Ҭ,y>{_p{lܕQ ngNje~CйݮMU䦆$6fKwó~Y63`Y$3l,D<$!NfM53`fnX|SfeTKqn~CZt>uQOǵڙE:M5?O.R#Nj>>[N.p XyJQ|f.xѸ7 vu\LeTZ)CMo3E)m;I[W|:{j֏Ëkr;QݰMuX[$)VQT/X>y*kh9qᰧ6Y_dU6{;юkIdysôYz|>8T"pޜ0ٞ:t QI*%-==0ZU٬N,Eұ҂T3)&a< pYd/NWc_KNJiV 5 1lZ<3=j~кCOQgDH+/]$Cef̔{Wkqr9!.ut~5m߰ZsĬTY}ҢNpXMgmfqd;d5HسO;,=eۙc~j͗)O!CZщq~%՛#9DkQlGș*g(p384CzVl/}#ۆfi&l92CYm?H{sT g&yT Őa6,yz~!XTnAyG')9N{ Sf쓪^E'W A1ā`56ZUPPA_\0{3em`G:-Al7 .Icɣ/8 & g){RkRd2=[+?T9X/`*l_Җb/cq"5TUjgYwBYfЧٞ$ų8{iٳ{y- 5xOaR윭O,)qBQ:TZ 6#*NW\5"з;UU{ojT~m29HBPT{0>yK}͓K*aR凓C`B9,n>k}!ESTY}YbZ쟘  UHZ4T>*Cq{ƞZcH\2óWS}NjY[ZAFxƶ'gJq6wQ:-[$FxSmCo qfxO5ZqcCCvj8 $Wnv\6On+gr vHPqrlv6yFP3`jl7 }c۸$>{2e"U'%{?,{ڤD[9>kuu pm=RaRz8vQ=d8q96P>JEϘ>.:ejbz|23f}@q?>UjHm= OD{,uqI3<U-vثM ' J)Hg;W}{ۣ%_ mOΞ<>S|pL֥|үSƶg=_;lL:{dq/k|<X 5Y }>I0Ydr2"q5h"8cɿQ^gqHz#YRǾ UzY> l#gmss'h ϲgMT&!fO/٫g'l}ă/8.Uj~ig?U/7ݰ:4Tq # K|=ߍ;gT tϱ <{8)Ă'mtb %PFg= t͞N$͓FI{usO<-{>>|[(ImW7]}HI|߃,9 ,y8-{g-'Q,DkuƸI/ҞB}W86L1D,B=K*, |BRFjqoSgԂ5HO6O="߳gG|>ɳPg<bSjwv>kv8gZ(=l,Vg9$p X֧K7"ˤ*lRɇh;>>kuYRbTI5fPBpz|)1 4QC#RITlOL*]Kk̈O$UaR% KOTFi^&DAI" 5Q;?K ZJB)J B7!(d SPTO%"wũjB-[loSvQ Rp4~OmJy֞BnoC=n n}, Q 9{>,=O1%7+w@^CsZSTOo89 50K09{{8yuJ2K0Tqe桽a=%A`Gd?`OzϞ@J!:z&A8i,GoyOx!Ŷ6rD8IVퟳ29R0K@aqp\1T2J uP qe"h2C!B4!g ba5Ʋ pZCp=크={ϛU&:giڳ4>/\&XY&1~W*C}S$'V7[썖hmz 9ow޲t"ɢ)}'h9iަg}  oX-2ψFu,-M|&O/h-Sa4606Ph4_ZYDIͫdKQ( Βo~cyer'jdQ)I!Nf3P˕ެl8ej$)/Fѯ⼐:}&EMfqR?8, rS*擸I2R;POSQoXO NֻGje 9XZ":8ːw4%K@K1@t[jϘK|]Lq)݆sOCVjDn3"s5ѝ>˵?@lPzd6 w8sDA }융DWllx, 7UgT <#Y'S,e<~S{ne TJ& *C,쩳ŝe}0ՙI V^M|oEɭӷ%[y"PY¤A8=LCi ?NuyOSag}L70NN yHaggκ@P4B>QgiuHnNj| q^HEPS&U.'iMŵylOq!IѶgT"2Y]eW@SU[T-DongYf50{\;!(z\G0*1fcUU9ےhA?x6MSEXX@:͖ Rg#|O4'*7/DE>)g8>#{cĿ,v$-wP槈&gjpJ/ QlCisa lXTn\{Q`)$88Eg}nHKULʭ K_ܫM^K+JҊ\ Wóy ` ŜCQ sz٫N%aii.?<˚+@9KҊ\l/NO(ZQSE՜ Z)b^gRX$+(s Zs'`c@"I{p7_y?g\Y+I0j|p+` ,(Y|>RvX3q]I9{Ur{K+Jrn+B#y?|+@8+pVYgW endstream endobj 64 0 obj 6150 endobj 69 0 obj << /Length 70 0 R /Type /XObject /Subtype /Image /Width 216 /Height 215 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xЁ Pa 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`½% endstream endobj 70 0 obj 225 endobj 71 0 obj << /Length 72 0 R /Type /XObject /Subtype /Image /Width 224 /Height 223 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x1 g @a 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0<0l2h? endstream endobj 72 0 obj 241 endobj 74 0 obj << /Length 75 0 R /Filter /FlateDecode >> stream x\mƑ_ȇr`qm88'n8gVC(dQpb7)H f޻_L0yQTV(kG6[ ºj;@VEaYĥ0UU4|%aR{GyZ4L4iTiQ&H62b*΋HGFaQ%4qD ¬.Hk]FQ j&IMM$s(FuX VI(#Ǚ!vgqX\UƄZ42G(6q&yYYM9<«YY`11 |a8tXܪ iaAn-_gKk/Cp`Hye$ (LGQp?.`/@>,g͖koL{<ۚz7z_n]0 qeU8 Z<̾4㧯5L]>寍=la:|nUH?n~\T%e>0%fݘ1_vfegC X5OևNf9&XQW$(88@X~Lۻf}3h7W5\LLLq=< YTuX`WvnW'ܟYu0ٮDnP΅24'~eQ E< SUaΟH뽙oNBFJ0h4H~2̋""ۻR]"w3Ȯ'+۫.K[scs?{6yiG3f%m3Kl6 0{Ek3b{f2t=fx]͇?+n2D0K,%wjm1N3@{r.0Fgt_i/3W%Y8;3cљ> .I0Iy yRyX)k2Lةޱ(DrD`Jc0Ynϯ I* # W'k+iB"Yʛ}`4Nʐc kbRoͿL-wP}C:E  ʧqہGd9؉-./v&;^qeMvjasxuڼV肃Mz!_q8 Z+L/vw8XXތp:scSX0{S?#$0T?N.%u6gl[=&qP+uZb^&}I Daj& ]s3ak[a f+pH 9jV^ӎz:^ffzU ćp},0_'#0g37F$/$_u\ :QE(E^)=^8EO{-@"Wz1cmR 4uS(WɐS-]8N->!fut]X}H؂3^AN?QmxXvωMdgBpKlh wNsvȀp .ۚ+VtSq#$YX\~qfnl cIQb٥|j$!CLeP~a6j[w/S-'Yb \\-L8&y$(q 17))$)625*QtPmO;IBj]+ߋ{3 f,D}-*Bw`oVzFstmEtkn[[f5&R 0 5Dh6NBzg_3\W mPG87Yk$D}uW `j5lV\+d,)Z\]=sZo%0nm=y:;ԐiqZov;nuxyWW묝dI ZY,O9 Қz-\%A0 Q;;؂oq׸l޲y%qH{-P (c2nU-"3*W2e4 ' MhRY qϷ[3T,S oSi5I ZI,k +P岑@嵻ҊbXBHPv~ 7ApIiWN3Jx֕{Qū0L  i9*2siίAM٘zDpAϗ6u4LTׂPzZ7綞EFRȐ%p }+-=|mNv;+8a[OꌜY;k]/ֺHFuYrLJI MMKȴρ*DeBUuqNt:N,(f֢\̎59<FC迁L*'5;s.(kK,V3v?EӜs0HIfPj1UHXa @cQ2q 03T"wqk[+}we`DD޳Obh4d"?EQK6,fgi N߽ >.ܕ[IfpPnb= aH͊_b2Ry9 Xv[ eJ8g'o}`/`JgeJ_.dV|30 5JPӖ%ݮ~7kL:/#9HLymbPKEfyB"C%t$>yy 3Ep\kn78=7pc7놋bю|i-v:WăMaGg za{̪cB]1L{<}c9?{knb2[?dGHv|f;qkXV řr >FRx:>΄p(Z#vpML1}5tta)&;o_j8]j햾._EN#.'*.>A _p ]ʋ(‹ ֒ӈp#,>Z~/@*Mm)h@h{J*<)l;(NtG{_ g= !NǙ;*eس@ULTGL`1WMxoMWGGiZ+v̤ՒL6.Ug<^tI:p@xޑ ױTw%S~j(28Tb7)G @̝& ރ˂] GB2"2qC縐Ra4J 8~95 m]wcyNI߂'dgi|Y?ҧ-]5>7xpJMid9;kmTojɊ8BgqH9/oqnZu@Yku[盭 셑QAa#B 2ڌ\\rPXoZ!PCuÌEyg(HcTDznb:V=V:s C@[`3o*q16m5pѵ[i$uBrW}CA@ΘxD瓖~"(*_BvLgs̜Gzl:^#o+ {r~ WmeV{iKf t[@WUz]o(}_^{ r*1}/p' (`Q9%nN-^JW`G9Ĉ_!Vѡnxi <`1/qYA釽z[tԅ)^P疮ڮxxگO> @;>Eو Iʎ'B)2*^qxF|S 4{Yt C+ԅRIU)qԝ:PAWy$_A...s<+`*) @'(bt*:::wZ HBQ'Uscb)<.ʤBaN9*zN:!8֊"(`F_{+_Du[['8(r_&UOX$'ߗ #vBb]`8G)U8;k au~'ֈ]4з? =2lGЪZ`5)}Oi7:zr V?](a@J#Jx.r+ý ?r%3_风:{03N3v#d"(WHu;ArYhk~<@Ǹkh2\el=Dt'tv+~cķ}<*|=[! T$ ţ`K$T "꯰nA5!ʑm#9@&Mos?,u{Qt;%^@'}hb(kdcI|£ PP^oUImW endstream endobj 75 0 obj 6633 endobj 73 0 obj << /Type /Page /Parent 57 0 R /Resources 76 0 R /Contents 74 0 R /MediaBox [0 0 612 792] >> endobj 76 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F13.0 51 0 R /F7.0 14 0 R /F9.0 22 0 R /F10.0 31 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 78 0 obj << /Length 79 0 R /Filter /FlateDecode >> stream x]uο˩8M)}X|Rq(Fw}~B7@`HBT5 ׯ_[(+gq/'nw ߯F <ĝ+.ȫ8ZsU%UV|QZKDV@hWQQY- j&4EgIǿЃ ]J@I S.2Gu.XT);.)ʪ}.@ KU,*bj#K#-\ *q9Qנ;!CdpP?,dQ']DYj{2gW/3Zu"6qeJSGl1d:__ 7o蚻ݖ~A,+J55߿Z] jhY:?JӲt8+(R݌Y%3VA_`ms/3^jRN7Z0EUn _Lbgo2k@~V'Q T('=lR坼Wڗjo^B<J:=[ qH,t1ޮ.7Wlyb (zhkN]UttkY".{:kR+Pq\0ܮ7k!m0 e-͠EIq<ʽ/|Zkeѭ[- K/{RG;}lwOA_AYp wK?fP# FvY>IR94;gm)vMA+K,ՠ KI{ƭ,X_ڳ履 ߩ2bZbq[^LMoVR;AbuPfotA ^-S{&0YFcb?b݋˼g>D߱27O37tYFe͐qX+4_ uJMw$or`!f"Jse+W:"뙽90zgt`蕔[VV ųY>4/wݭ_g}G0ꨪ XG P=cxu~'rh˃q }Zи7 R[@.7ZY`;"#lPa$K bYq`=~ _E-]KX6h|R'" gJ,dY*xt] 2'?흴-] Z3-Q&qˠ n[T]r0S:*$LnN={1Bm%ٮ$WQXT^$Mݮ=R|+hRG0-_J(o-$oEӳ0GA>\ =ʽ5+gݞR蹥U|RtoI( Iu"pkR}w? 9V ,(Xƾ"ldyh='ۼB"L)Y9۟`D+-kB*W'%`Z`uU#FKWz]j|X&JZ34_u?vA2^m&0SO[lW۴^PTѤc &;l֤gD~MlLsyό̊Ӂ8$ZUdz޸ n(L~diP]_=I?p&3/Nrkj1$N h>"N8 ol!XiԱpn"`xi烀@}:a@}:G0@}:tOX+ ':|81Ew@c&fIE7 puGKs+C2`+7r{i͑/.㶜Xwkx f cgP]_lXX[R㶪xeg|S/Sf[෍ !_~bV# dضv$c{bp}''EDhԶ9פ5*io]0UbTIW{KfL5258&_\+mfun4\ž 6}Mʚ"yEXP,U,ejB!G,tN؃t*fO_D#-A_ߐr'zAikt˞,{U}'VZz ^f֜X*̶@CbΌ$D5[cGl+ďy[epJck 1 ݸjOo!M3+ªɠ!`3nzCxjIW6feO=?Q<n4mx2|n& w6K<$d#Zx2l" l]Xx*\o8gX;hY=s]{-@^@3rlQS WfBUzO^eҜnUO/⽴,|ЍוbUOEG1< BJQxOiıJ(]%EZ8zcz>Ǡ%Ē#t3N])}pn0:W2ՠbqJN{:],7{@WMtC=+ANsZ%0V, |J?vKmܔ0_]h*`81^7֢Ph4.Ԓ6`@ѐ "@^ۡ/jUP߬ކ=ص+ "X* uV]H/RP;Ad?O,p:KBe#LQAQ=ԮTG=:pJ/:X6ft]qQ@PI@NnSl*R=Yf$/ OF{OH.Iֆ,NV1ue ok ~1E!Ay-(Dh72f )댁O@aQRRQgÀּk:ڙ:CM t 6t6f28VNcvV[!k$3&g2Y +%oa##z!NkIVIˉ^n)Ik: dz1.Dh0(@f qӈĽcklw1kE58M X6W*JXoﰦxD[k >{p'x{s'W>{s9qʱGSYt8Pp2Щ#PྡྷqЧ[G/gv<2:QE# QXaDqu<-׷npX |EߚtuV~^2)Fơ.vmSbYkD@?6Sl!rM4vnt=AjC4ݳd8ћgU`aCt{9ămř> EK7wgtkÊE"k%x $R $Xv ТW ^ip(ԱZΧ)}C mP]?6#++K>Nƒa9LG'yq4w'[ǩ:hFjA%R[}CVl0̌Id<,A92>̔EJ&F 3W3> LN =-80)ovM(|\F狣]scl˝#iIŠ!) duC# ]^bPd1d?LyӅ/c Sڝյ6>Oha|ceMLJxtl8,d2h\b X4:z@̠K*wP0Y Wg+PQmAs@i3 '2!V[%Qn$1HFRDkTNAPR"N(/58] ܩR# -u5:;L Xu2ՒQX[\("A1OZzEE}Eؠ(#h2=9=G2ǁHCbYkkZ;F^?sөݒ#>&yOj|&[^a19ALԾptxF h*KFaqVЬG*2 %Dm#hPk-dv#)o?_YS(N{v PIz_qu˖{[ʠw^6*U beN?)>:y [G+7et "ADs>)H\X6^ u=Rt(ϬY>s_NV8;꯼hBm6pZÏ,Θ59_FǘY&TC{d,"+8ō`F<6$!` uUT, Հٵt-r\gU#|#QI&"cb'LĹ;t 5/O"> endobj 80 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F13.0 51 0 R /F3.0 10 0 R /F12.0 43 0 R /F7.0 14 0 R /F14.1 68 0 R /F8.0 15 0 R /F10.0 31 0 R /F6.0 13 0 R >> >> endobj 82 0 obj << /Length 83 0 R /Filter /FlateDecode >> stream xZ[oF~/2O8{n&[nZbn$Q!\;sfxErx,P$P~8֢.ĿF|(1o2|s "NeALb8KRA0Rgq6z&DR0_fZeBZ*TEq>$N謹%7_C2Ct%rA@ Yf$gUʄhxo2foF񳔸%D/PC(u .t&!q-qOq;(cw/UX xK1=R-ͅo̓yR#o%-W杘 YؼZC%h 5*H3;f0q͚r-r(BG/b2v@\<{t_E_E^^6/受)LPQNCM_nfsq$~xͷ8=fJhS%f[~5c>^XgF:PTFpLT!ZʺG uSb>\Es˶TbM%_6E`]ފ9W|Wm9qn ^"*_A n\>jrj󓜁jY^]7` CNn ' ʍA\.]ʒD8P [,r bGAzGE#%iڏc^F գ[E/`9/e-0D@zP/7D<~⊜Q }6/sjj0I!fby W^rn[ᇌr~IH|7,'7Fm77 +˶[YFYXC" fOg2dn5dYVj{H  \ +I9O*;mNٶbӍtrI̡qRhSG͍6`=ays;`s1^Fkxө ޏum#5C1K R|A7,zI>jV oy.6\8-ȇ;Xw3풗JXR;$}PyۙWE]80A;B (h J&=x$+t?a( vTB/Y(03#Af63`(KCZČ}w&$Nqpf=PL^kf CɐS2Zq!7CG{U.8S-;jO$0 1հr? bLOT7C֤ƺجhakڥ[2`^,ȕQ5x C$dOf /Ọ/↽C }ܚcZ+xea9Ws׏ZG@9vBvYޤ !z $f-5]DL]4Tщ-fD |sPd!X=r K6? cBQy™@J}`IŮͰ&!v.w5O, ވf@vEas̏|$ |Q)VCl&\p MopJ!)dӑI dW0_`5znL;s .w37Ku};CFC !ı+oRp ";O i%}'NGScW!++> endobj 84 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /F13.0 51 0 R /F7.0 14 0 R /F10.0 31 0 R /F8.0 15 0 R /F3.0 10 0 R >> /XObject << /Im6 87 0 R /Im5 85 0 R >> >> endobj 87 0 obj << /Length 88 0 R /Type /XObject /Subtype /Image /Width 372 /Height 451 /Interpolate true /ColorSpace 44 0 R /SMask 89 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream x] Lmwu`l䟄O/BE JI@( @( @( O@[%D.-H`ROm~~n]ɇ&^z4 d 05 lJt*/Eۚv_ǶۥSd~xW:cחZ(Ajp6 6Y'w[ z[ ^(4[ў%3Ҋ$)_BK#`1B'.+QlFv(i8 @c&6p5Sl$@l#Q5\Z2t0i,y "IR0ieɠK:%Jb )[Xj\ ˊSJ JR$OUu̦~E[^vgHK8(BP BP BP BP BP BP BP 0BP<0 b6؎,0@ r;Tٖfۑz`?JYzvd(Ang*U?L=^u;T W?4SO_Yg=Ysgn!S@_)gu ɕU_yVqI2v+e.t!.I(ШS6gՍ-PsNٜUwi s欺% tQ`). $@sN'dpK7Fҩ3T~;fB%w&'3\j 6*2[/^9\σ;&'3\ \Sgۋ7|* ;v0:8ïlQUO o ש3i\`(ՎjjNg]0:8;&ՋRݬ0g2+0Y[!hW`)d(W`)jC(ЮS6g]PS6gn P]9lΪۻ"_9lΪ @sNٜUwE CsNٜU%Bv朲9n@~朲9wK0 9esV  9esV`s欺+ xʤ4hįa@wJi nO` U<"gğjA*U)g9R"> ζo?z$1ۓzyNnO@"Bv')URoa^"8#j<^), ' w95z p2AP]]Ugux;-hgis}cV?pyu}˽< 3gՇo;V\5r€Tsǥ>)؞9lΪwrX;!H߉ ;&@I9lΪ\7`h j! 2Y-UuqE 1'Po9lΪof X:"PW3$(T6{)MdZhW - U?sNٜUnXAK;p+:{˞?YNw|Up__ٮ 9lΪg\S9u9lΪ+y2H*@xs欺yC0J_`qARdpVcU, )!XsNٜUo7xaX2c͵B P,AD'S6gչWJEj%2S6gյNNGmj{0l V5bk)U.pqPXj -ߖ]тp^j̡nG{ՂlgEyC_hiu~qS:z=T[Їz~8uH)*~obuU?K>*9Ȗ~JU ۫ CE?ԟz̾w$C[t^U.pV{<2Ϲ0!/_(!ǽsh|oWջYQeȴtٴ 8HJZ# 󽽄tsh%%1Uߖ捭a* KPjd(H|TS똪UKVƊa pr>7Ք:MN?ƀ6.D;2^TU[ED >81ՔBz LJ%-hEX|}1ՔRO `?ߘk~1Q=~3V?y{2єOw %^sz0e)[UPel_ C~ӮSLYr+WZP$b8ȡs Z|#f)UP C״OY>zݴj=@o| W2rI2aKr8J?/cتszPMwrW FϰSVa5YCQUlÉ%nSV1.CQYoù%Nk:{)ۺ]UgO34WQ n6a\6CE%FRK7624Tj#U ϰtfG߹.i- 2n0\[F738'w86-նzD]@& R`Ei3Xa-'W 0HK/]Ïw}9r 1` *[S0kwz4243rWջ= T g*[lI+°ug(ԕe=݈mdheͮ]UgU0lt%mlo(﫺Qt#mEU[zPbV`1|ԭnh:j7ک܇k u"ԟCh:kTnBUAv06PYK)XSP5-,ATs()gNdUyBb;/ͪȐB `a!w 7|SVɪ.P2"e=݈ mdhI0ګd;8+N_e*9W %P/: ~] -B<y!ٓp,Qp! TOznzf2ve*qc&ėX GFQQt#.Vlwnz8ᯥ$&p0]D.4( "S{Wlm8{!~58~>2UE{ _^ܘ! --=P? "Rڷ'ߖߖ]>an+oˮ́ͯ+\G|m٥nO`j;m٥nO`j2|̲ӑj0bii_G=a( %8;׉9eU[ILjnXtɟaH[.G;(|^|qrAh|am!1:.p洞AGO~sX.q+O7b\P{SxmK*fYOn8KaN #$-_ t??ǝeie] m|!-)eOcf^9-PѾ=E<.mM(l=\}{myHSoK]=X.%-5|ٷTOrxB my޷fHu=X(~o66۲0Vp{˕ŷeWVOcS8wo~[TOr7}cW)-Ѿ=şC>y<ǶcdpK^B|S@v _1-!DEoNǜVt|[|R)y.gzrA}cq5d|[<:G"bܾhڇEdbIӍ֠鐎S m'iǐͯ8K~.ܾ[Fg7m381=^NYvSMiH$ _3\hZӁQbl[F0WdK?Lnܕ$tO-TYB2VsPE6e(`#u({wk iE ðjCmb }d\//FtJ#C#lNgnbr.]lzUKz,{Jɹb(~KGF%B2nD424ªUmih]vE J&t+χO H_^Yeyl;NSeH[`nAݸ?)3_vy9.Nr2d `nAݸ?)oKU!!-+w}A%poH!騌pvd;*N~<=ðq簾sW/BL;mS f "$a};er}zeɷSuX8 d+DDHnٟCr':9e̊Hm"l) OlHr-sHD3Y T#3b;%W*20$W_ݞx1+"trf^l\eي Yt "ןCz=s$K!Eu6OrMȐE \*Br9,ߋ/N4B R 7ϡpç_4eQյv*t`e00׉PV>)XhrR F06׉PSK)XhrR F06PPK)Xnj7^7ٮ*.*zd)XwIzTi'mlʹ0ls>26%+[Q2 q 0pnZ>No;ջĐMNA`x?_mM2:Q98^zỞ_"4$zF-kg F `%J"FWdK?Ɍۋ2`kyʀ?/Ca=CEEFFRK7624Tj#Ϊg(6>u}@ϯmqj.o;pnldh|{WջYE M9;xΦ82HM*X%q8,x+VU; Dr渮;eUG:i* JHKj{)+_U(˛ Y%/+p1Wn׳m=@tu>ejմ EAؒ{۫OYzƯZmIZ Cե{S)uo %fSWf="Q1@=KoKc߼6˷E_5r^Qϱ:9tK`DSzm5oϡOثۍ'TU/Ck>c؟Oy t1j)SU ?V0xKlWSMod叁 4`pQŰS'2 >Uի>yY1P= Ki~aN5e}mKZjla3  pAD̷82^ʮwy6ejSqaẶ6{E;qo/!aIvW-vpVs} 5R+3eͰ+$տÁ;⻞_{?.?ߡT(c=S3P]gUAZz@ y#M 0T*]#ɶMyo/!a2U.pV'0[P 8`XJgS.? QO;K94tuػΊP8T'b/܋oKUoo`mq>shk}ΜUo\Uc_aQ,`Mq朲9tl6# ⬢^Э91sNٜU7upomHćsNٜUZ ^K|[DpNI}sNٜUkqyɌ>`a%B|Uo)vXC~X!JX9lΪ4XXb`XJ_W4S6g{bu-nւNspC zW4p)-߬b[1o`XWOW,9esV}3cM fp)C:_9esV}c)E,:缈\?\Y#朲9>cyw`(rtW9`-sNٜUnֱG&Vrg10'uhsNٜU݃c0T=='| 9lΪk r+ >wu?:xsNٮwvTfkksOqTq63\rO{۫d;8[ \d2Y2x&~t>ʹt63\Aګx(w"Dog8;|,աlK<{m pT!O, ZvogTTz%vru}vU.p31 PvU.pۂulgq4=9gHo0朲9u+0Y[1L9lΪk( 9esVVS`)Z7ysNٜU?#sz֍rS6goHo0朲9u+0Y[1L9lΪk( 9esVVS`)Z7ysNٜU?#xʤ4^ x*U+,ng=1dWh]Vꞧ-F`7uqZ:m_ۏiuM\"iROſ҅v6qzCP BP BP BP BP B?t#RZYHH%[ ( tT@O;R ) c7 -*:I£wm K6.B䃣ei Lw0mP27 aŬCB+ʡh1 jM1% ?au!a `HqX2hNͣ5o`ljX5 pe%[ \ 4@|@(p2|x4M3@( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( @( ~'~U]p C;g;R@款]ԏH6 UO ѧJ]4x&ߕwMV/IH zEѻfx*PAzba<\bW7i(iA7`DK (xd`ө c ~R0% 'wi]?v]F8t_ۀNGiBHX !8ih$vzA {Toٸۯ @(*-N#<BP BP`6B]cO QR8x-\~díM r'f d}m n`jm͒Ta#KE':a0\ҐT.u-aT å6=Fƈ]_o 6zac퇭I-OY@]b2$6m@l:K1Zx.?;z fIc(^*%낝H]z@]DmHfKa<~"AvJ`F"< &Lv7ǀɓ$u=4>=0Slq "!R' g?pRa!X2<5XY2 LOJ #$Lva#mK1$ apiv(AR?Ĉs )P]?qxNr1fa<]%ih$0̖wa`DV9L' ܅%=(h7s75RBx=nt]YColOvImIO)0 SµKC%h&FM=id1!O=iHc`$4QL)a+Ê~_ _ 8m1hiOE?`)M `3Plcq> :͉)llg ,D-:5~r+k`^IF( \@ eRA$ W%>,u @( @(pz7sm K,ŖY-p{-ߋ>Bl<)L{u{NZLm]mHx ,KQa0R`#&&_=\ߋvjGv\Wo''jbc@ɐujZ ɬ $сbc][&L !K<LxF9 3!6Ʈ~c Bh# Y.ń@ChC/i̲]fӵAL-K$w :JH)K-b!K! Rh\ NhCGֱQv-[Hhrz:Sf3؊7ej%Nhh$m1h8?O-87K%dUұ%$ 4v L/MF6C "x$I_b&.4JZ ej0.6x60,ɣ4҄gidHw-%Kz*6@[Gѣ&,]ƒX(Q-8I9M^5ԧh'NԆMT{}XBG5[(d%lKA BP BP @kɦeʼn'=_uN3oI BPTjK`ni|Tuڮln#7 @(QL<[cf-- x8[8D*)DKE$H60E^X _e'1 Be,N8=0B{`'KK'X'o)Fh9H@F2%1i&8{q?eŭhG ܢXN-oCП5ĩNy>"Tf ,l,An#9 HgprK( ;WU՗ƊNn,4.Fn%46l@M0 .[Q,KxeJf~f K[-2I#]\l l|6ډܴH欗 do AC\҆K ãa*MN˥ޥb ~8ChgvSN2kH lr[%F Z!xkN7 Zx@C2JN4΂'ޯPl#IQWĢm.V@:!b=ʞ_`BP BP`H$S Ղi'lG %ІN[G`:gn״-cm  ۯ*$xZ0@a(-ۙۑ_ Yj|eK`حcւzyZjHolMmgxZL $کbs K@f,o Y27&> stream x] Lϧǒ-_E Jt: BP BP BP xT@? nqj--HŤ:[ \wHTÄة"dpgK S>ϹvivAt]es=Ʈ/Y(A28[ 8D0H'PE>V&$l.QaVr .K%Eco1HSe,a6f-f'gN5d̓ (<&.2kSld } FW@ԒY1HDgS5EJl{qN4 ?/4Y2Y !~[Ccu}RZfSaF)`< dEhyb#]*G F ~c;嗐>`@p)/ůxdGmx،aК"7ØmTL+0G 0gaYҨ @cyS1`d6{)%lHd2RfK\= 00,M ?si Y&c ɂGmxR`i L,RΰUϦQ,)Hd# ^S pL=`CVL:ٍQk` Ɠ2Q5T6-Ra$\kHFuΰU {(T?jHKS O|cahVabR~#E x`KKҳQn$ʐ[d$VCX >S8Q;h9KQ1tYq2 P.^ Q $Aaq-O;#C<(BP BP BP BP BP BP BP [aq aOAlܱY"| ZyAj_mioY /h!-z?b|97eUasv]$`朲9|u.*0u"D0S6g׃NЅU朲9^sz PS6gՋP`sNٜ]:A Tsz" V`)W'BsNٜ]W/BC 9esv=](PU`)E`(0X9lή_  9esv] +)a˰CP`/JkpBs9CFw8No?gOvE*aۃH.>\py"fppSlqi a t~[./"ܡ;Dn6x`oIܒYrY3]d [NCmHΞLf9|;Kx.^ !aw~}8˭-!3g z%:8Ӈ}+9""ci< B 9esv=[(PW`)Mh(0V9lήޜ`  9esv]  *0؛l@]9lή7!X朲9{s-+0u&D4S6gcoNu朲9߄csz PS6gP`sNٜ]9 s~" U`)7'BsNY_wx.G oߩD;/`xA :O?GDǔ=ӱYty!VoG><) x]҃EUx^ $si 2bcsY̿˳,`n'3ك}]?4kG9R՗dG5jv}Sl6%k ҇,*NK 9esv]y?MX0Z_`9lή jZYV0dZHZ,j :j\N|D[gkuÐnL۞lg {q2W2xH " 8ՔA^]iPcX1ls0o~M5e8ҿK?ƄW ] wL5e8^?/`t3SMtp|Xۢm)>Řjp(suzØg;|c)D]U|X5 +`DSFwz?xP jYl= St#b-c5 nw:>9Ŕ%D jPOļrvP-iS^>exyK;~( V/'UOYHur]% j8J>)+k]ԣ,oyA G;T'z^;exm׹zPT6p` S3>q);.\*2_Pñ-Ύ5|):~CaP[R-12%%KiQ5b2[S]A8r/C}P2n0",G\CǔՏQQ隟[Nq4C%M\p9i5d;}]y:˕^nu_h;9ݲI1`PA*:TBS0wfpCߔmp_gEV>TRC%afnL΅akg0Q+Ye\ΦERWCߔMu:n`e00P8Y >})*_!PNVUdHO00g;_ >})TU 4};xrw/Q!9AT9[kQM@ u:^V"CsrkQO(s<ܺJyJB Sא큎;Oq<)u} $ ""$!9wj;yQeSrf I4DkDXlt|ʤ<~F !\}, ðqװ>cWwj;yiemaYAFYkX챫;Oq_F.;w'DǔxKgi A.$RþDr I0xzbl\ @_GŦT#5-as@ ` cd'/rZ snc2u5= Wz/CZ_0FFy9~2.Ǽ m }SRVQ{)Yw1JW cd$e\yw#m }SS UX@^i٦@zX'DEoKۑu)oJǷ70Ώ3}uo> YySq 瞴+rWzEJ~(^Q2Ʒ3-]]?V7:]/B|[noǷUo׮WqCIsTeP=:8ӥ?,RJMdtބS&*Thۢq|?eN<_>ڗW@g_q vڗߖAcefd J,:ķef0Ӗф& @mC|//`!-7z mcwkPb.5ܡ[b+oUX]^,GT/m:;5\^rdm麸U|b;فҎKuxA ׷[&/q2ŷE|//@~i0~VPnι(BǢ?-(wm{Ӽ1]8=W:->)L= mup٤1g8.d|[<:G baoٻ%F5d蛬bH¬o6ہȳ,`Jy]6ː^0FFl!j_G7exuԜ̊ږ+12;q9[Pm HoR:ڔ̝`X]]<+_E] (8__l]w`nc蛲^)] 4B <ꯡp‡4ePש|!pe#DD(!ՔA^]]D1^zv)SumCM2l&$0lɐTSC뚮KWk`3Ű!#i2]EðřƷ=몶)o]ZdlS ߹6]eO"!/cEDnjcN둮#$4|)CesUߡHj(cV} YZqKؼH+g*˭od7vIrJq;r@f)[z{׵2`wfhM^rznLoi^@3Cߔmn@_9͚.$TkjoKU`*LBsvqD+_ aQ,`M朲9޾Ņm#좖^Эw眲9nj"}%>,;0u yoh!Ω9o)+NXqi +p|sNٜ]7\5yYҸz_ ?Y{6K7V{(0,-į+=`){ƺgkAX9esvB z׵?4q)Wt5VYb[1te0;ke?眲9}3cM fp*C;޿szm.Un$rGrm7{1V:.? DDg(Uec)WuI洕\Q FlS6g׻α/Nx$'b4?z p)W5V9-UÇna]E/SuO y8w*5yzfg Mf@oGyyM[ }S}rQ ܦMl~8#9M_ ϺKS֭}k~6 5Wt ?a D+M[.\~PJxO]TTz%rEjߓr28Oloʾ)6gO: 9esv+2P Z%4\9O?-YΞ.*UBkt  5D 9uʚB0KEJ jAfG vT_)sKfɡC;g t5n9up9!9{ڪ2m,g( z-:8ӇS/ƶlflϤwF0pLr|SV䈈t!2*0؛l@]9lή7!X朲9{s-+0u&D4S6gcoNu朲9߄csz PS6gP`sNٜ]9 s~" U`)7'BsNٜ]oBDC 9esv=[(PW`)Mh(0V9lήޜ`  9eG CDE7e#zX2Sαr28u"m5b4r>݄2> Nc2K~9D}U`H?!x @( @( @( @( @( mb/5L%TgCP`S@2 IN2 1 bR䦇j^fL* g,96lm<ƉtKGDcSai (l1,kHlYE/ րl~&uNZmOSL%*' Fj=P0?` q_~qA0P92PL'U|[Fz( @( < lvm<%GISo 3 DSB'Wɝ : ~ d{6%Suن,A? vY*8aD?b CJe;]r/aP\S,j?`0FRyfaٯ6)!~Y*T04b2!6Ka䭆:5chBRm%aC>zHK0F"`DQ;z"`,.%W F`doFjz D7cI R 9KY5)840ԔxRsOp+؏($GSt;u g00aG }RZHY$`U1`\%Ԁ_ ,M4mq.i?J!O!x`aC>YKR:0D0 F© 15 Xe``0N%r %ؐ)hv4~ZJ#)zpҋ cTD%5d<%HP$)=eש"b*QSz ,KYa0Rb#MM@=\?FjGvX_';2 N1cD`:V`f6H8Ql]jG 0.Ɛ>  `YO)ʜ!6%5oC.0 0Q%TlM,e) ,f6udK1U e!!%YBa؝ `R5. @vu 5›b,nBC`辊:Ag͹lsB]˖,ԏ(/Sga6P!KV+q8ů aDZ CloK$ZU=sKHtW#Ć5.%`0d$HIi, x!!0`?He,,0 0,]AX]6 Æ$d)Pz,tK#bأ~ f!b0& K/cRӔR̓ef@v,À*&,0 h.K@g] aSqvhvwqrY"7Ű0K l6 )X< 6 ,I5 d!bFvurz 'xXԩ(,`QٯNNa[` m`g1Ҥgi`P?Fŏɒ%<[Dm΂ XTŹY2 1iy Xրwa'6eX&*& ag*{c@=[(dyJ: ٍ @( @( Pԓ- ˦St_.lsl7zk L(pjKböKUB5]I #77 @(0P(b4/G-++^-!]0 d$dx54'/9OTnnԓך%`Y ui\ Dyv,Qѵ3))x5FL= H'PZN],=aa[sAnBlc 8c^/xN%4Y, /M #Vd)C풇sb;5P#&"K ,S#7ٽ)[e/R;D\`]my0 !N|EFT&,҄ZJn9 H{q:8%9a* wU-Cl1Rq֗Vr+ec*Tiӵ4٪tw ٨앥b2| rVPM9O/py"i處%@( @( Q@~s_6tNٳnm5nꄵӎզYVH1xYOF#`}C?? Xl} P1LCae=)xyiP 'k3gr]"j/7,8aY*S 1ɂř>HNb@0\fh/ Sa'M#7tYrcx&]pK&d,%gi( +F 2)pԒB a VhQJnʓ]W0c* 0 [ ,*y\Ij7֥Ճwj|/s)1~u"pnи-t6xRn8["X ,[+ X.KL~݋&KSC-6*9dMDT ,6~JakgykT[دHK$"x7)KRcxV*opXN%(4QCDlxc;Kl%h43А!h)1`lhoM7RϹfwҪ 08YlwbK=~8GTE=d&e8Ysvw>;W>BP BP x?}Khj#[U%V&)uhg>|/3¶ΰ B:[ 0H1 e;s; 4KWBhl-דRU wlǷ#L¶rgxQjs0uR/<! bc.٩[h4É XcS%rK~Hat~ٯ0Aa)%,Њ)Ye~Ƙ1Xm &; Y d/Y} D:J %F|_, !p"l) !5$l1`)*R ^0ԏhKȅ-8|_f]۩*S;Sq! /'ͅ_4@b8*Q.vʀ0H^†*a'lfk.c`3Xmx4J ,5tԯyKx0E=&9E HxA) `6T̏hbQN%1ǝقsaI~0$X"T_1<~^*&!4~ r2N {"Iǎ;f@Gt9WxF`q+&E6 £`S?% 046i"ڌ {*;gq,aFX*K‰t1a'5x)7eN6ҐT<)Rʩt> stream x1 g O@a 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`307l endstream endobj 90 0 obj 755 endobj 91 0 obj << /Length 92 0 R /Type /XObject /Subtype /Image /Width 372 /Height 451 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x1 g O@a 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`307l endstream endobj 92 0 obj 755 endobj 94 0 obj << /Length 95 0 R /Filter /FlateDecode >> stream x]m7_A;9[^rl<ngaRkFR$=Ū"٭ыs8VwbTHfj~3yf,Ebլ̗b3ݙM{;@bn* FQYĥV07UU,Kd\o2M:QWY6I<68J򲊹7(⼨׫oQTTe:- {!G#+sH.8$hmA^ApK,Ӣj<*՚ڼʣl\ƾ8M~E# b[ mH(3"7Ծh) 4~ n͗ߢ ulWnol`o{wl\(|[T]Oh#~fV?[mq[3ze`(q;zk?Xn%6KayVwLKl57x1gܣ%7Zr0NWI ҲQ,ȊVQ<{4-GhU/7vX=37ME*OE){Ź"]il@ %eѩqq^5zCE޿1h;Z/!7ܿk.eEdhx3o'aVZմ6wL>nmþ/(m`U([VW";T-^C(imPIe=okvg Ai 'l fgm]Z{fo&^fjIl_3Å 6h%W=1wY{=B,qjJ'FVhu`8I-K ;J沯j;P(OL;:c1h^3yb6< &{h<^B[(*&I7JLUhu ԛnY]ɠaM fȨK~Gb*9U[R1qv{톶fJ*ɋv#45zt@]4Mltl{ۮ44Tr=z nQ4{^OG Zf6͋,Շ hu- dP]6!Li"7X C8K`}Gon X<|כV87EZ_ot6N[6K=oKT8gp}ckh:٬wolh68C-oo-WA̪@q P"Wqv=.Odeei>A6>kOLkX ᷐]!l!8\XkEm`adxdD#O`5A8{bZ8MDO})VQ)ElcZZNJ͝rOJksmڳ\U)ǭkS h@֯<1N׫X[{{oܔsZZ۠TJFsrth߇9tЈZtWH;7RrmKKKW*=D{z Aa;#w;YF}x>JqUI{Ȃ!ؿ읩a`6 @^[^"v[4\F.voX'd{m*gIoS IBX!&oI >nu$ ]G_m`KdQ̚X!r]>#>XQXM`p (ݟ(#1? LF{G*.Q1~d[+2C]7ƌNLPqql 3O uWY 9GeT].n12a,q80K; 0a3fBHZ |?|oUD*(A@1ڙ%9<[FP?tjZ8~eU6b5#BspgD5'eDFTPH?nŻ3ޚ-?{6оqiєO!G˜6$2?Iz8ɢ~5w,G۽rN0>.hivDWu_讥rZ;GF Co0Cťaid%I3:(Bu'Qc=~mG)SZ%LKCK蜿w;Y-@s֘5;)B9t )@9lȹM qqܿf`FTCfV(m|(!gSV=z: lR=Pg-@փ^.ԤqՂ1TTK{D]r]n֭}ߵ}<đQ.TڧWT>pp\UxJ8zeT6 Qh{J )ʱrI_(,CXJ9HQ.+(KO;NYKͯSapf!YB3Gn1+y~pG# /&R <@p1Y#OY4^qU\#(#z$,©dğFˆ # }ŭ3 0HD*4ob~F?42>lg8m ] irn(cLch Gi">33B2<)R Lڭ.nhG}g Y e%9"aWcWd2Q͍<%a@|.K`ܛ ?,"QF^'7zvn>ZYy[$@Ɋ() GE<9jFS=٩x7ur= _Nc/'w؅/'|5_A̲$3 ㋿PQ!gTxĆˤ,X ¡[tX %2~~\?l_VSJ;º `RS ¤s;ZL`oZa,N?384+ !ʂݨqKJs#WWS8!o 'CLe HHҴK*tfpІi` u HcD+i_?WW7)@f9GH6,4VL e^Z`rc$t;QW0*^V✎ |6H+mZ%+, ;QVɰMzXCpQG1 4k ;{,u`h z~CpŬ.M i sNC=;9٥<69[[,Ͻ@_leQX| Ga|TdEl5a_&u)"VJ{LQ9vXvsZ?Q]ފ״s(zN"9u' <K(qlG9=~Zn9Z17 ‹j9?Rd?$lnN< F3blLC'a- FumS#8BÝ<0Ϸ٥<6b F:azXu"G:؏lh|wJб(췩S56|%~IC%dtp vbVv'<99~9$X}JkOHmD]f!HJ*$%@~LI`9?X'_'JV'Ͼ~'].Y̑r;\<^鹯_?>ʣXxv0Et?(/I6sN<|iZ/ftqm=Jύ`gŨid nJ]kU.=v\(.T h3}Ͷm/fvqH.'LAZ/[%pݺn VLʽRU1iy}Y* aڮ[ҚZURVۥ{}6DJkyU6*W`MkL+O-gtt8#M".+!`qr;" ocZ!$`\CRTЍ"s3pGEG69:Ӗ?q-%F5kH %6ZDVS >76*A9)9fҔ3_,B@3g1m|_4fOT-ݨxs3٨Uf2w/4bGdfi#X!rXu?k'6qd55@ 2Ҙ)yrѧ缾Uh5zΖj\ DZ$R>wZ]ZyKVV^)jHuE`[]ߴUu*r<wb4yڽh(Er;*V Jkr:F"9p,`ks ni5zƴ_LE4iJ-፾ĀZ9hQ&˱+%|{ 0@=:;aC('? FSdkAMA9~(!ľJLR]J)AR1.t7ywoɴx_('Dp] 4(v !p62d>R#6fFVv'uC.ENr|~u:58^'x̡SaAh.N|ay¹Q+^GEslqrL`k\܍kc>qvdwQZSq2:᤾9nP )xȐ!<} 4>J=,k2yl?ג";P~4rwe8/ ȆK/nIɺn7.bE7#but6tY[r}i*&5~niہUJ2rwXT}h_As) n|=E!n2r.SB8L#~!Ь䖇:%:*h[.Y4ET')X SG Y]:[雧;[Lm![E>Ҝ,.5,9k—Xs4]sUYe:2 Y K| r鮞? eT`X儻3ʗ>b/'ͱ3˗.{s9a(SEǯ]:]A` U&3 nBH 4myMVhI1K#AZN4ԭ\ٓ;)N)$Ixbi endstream endobj 95 0 obj 7176 endobj 93 0 obj << /Type /Page /Parent 57 0 R /Resources 96 0 R /Contents 94 0 R /MediaBox [0 0 612 792] >> endobj 96 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F13.0 51 0 R /F7.0 14 0 R /F14.1 68 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 98 0 obj << /Length 99 0 R /Filter /FlateDecode >> stream x]{Ǒ>E# 8ؒ88q;pɕG!(pzzգGԕiSgUemg0,͗/7٘lnt'13MMUmv4ʺ᫪HSB =>BUާu]үjrM4LivmWy0'A1]\עoӮw7pcdٝ[ ٵy֛Ӷ'/ހbEv9a9|ȒMהM6%Δm0&ß*;ssfI c4]V}[˗eEi xߗ!dU쫔)Rv}W,RB!c,2ZEtmh$BK׵+>o{P<.i@cA<{Se"G;(@h:P+ӦuS7:w̗ߕiW33y ?'Ö/\|{]Wu*ۦjĈYV]cMYVcEx0cr{n0]7?<3W Vvsg=I=Qb".:2,^}`7 jLnmd&aiɎ5bPVf%0Yi,$oȀ\, W_~͗d#mg IQ %Lju;'X;m0isӺ &vkG"eXLdr 2w,4\*#(eF.0=.X Ə{t }.C1g7^IWnKb[TXBF_sTU0ǴN*zWV0Q'Vu* y  Zl-I3Unu1Kv du _zb<]c;ɐr4lqeֆ̟ǧͿ^K#]?3Pn tXw洹W0)oփεYcxtՁlYzHyei)Yji]ՒkUަy[fhD!B.tuԾXȓυ| uNd)!\]@BlaMcLSThka.ڶۆcV@m/[jEi ۱B5DYg=P2Vs[E7WUF1k]vSim^Dwrl8PY0'WgXMQI&= ,Z2@V`s8e]U6Z=9Oqls-`gFh&lO Ok7hlັlzkE;I[~SzC`*,l!'UtEm-ȳy SF<%b b<7ibxí]AcSWzз @2y/=ITkC@҇a`׮2- bS#;šD*xi: F]ΤEFN,ݞ)x[a39f2Uya{qʐ\kiӱ"-~ll?>͠?gp0Onr ??^LAM+#GeYaO-OhD:$/q(ey EDTLoԹp'vj\ xco\ s1;Sb8-s1`LԉLΤV=15>$7<̢<6h8A;$UTzX}rw ,ƴO^ͳ>7@ 'B[sAɪ98`#^_jf@AcYLpƛzP"+x,t?)693Խ;u&;9kF@ DPоD lHiƐ,Έ{3j趩uP(nǃ5:_l>L? ~Qu1- 8pzNPlHDSR(0cݮak1+]1c}-I˖4ecJ,NWk9+!biPRf%rH=p }4wQ8Sr,FFץ)frj1 \B_R Ӈ XDZZ]\4NLҎ g!uڕ0hNI1*BM w'\GŲ Q=JAηܠLZg`-pR5Teqξϵ1m/bqBaɐp̈^>oľh-0+nr \ \2>x6s1`$~` f84>Nr+bnޤYITN'sj#q慺Mkd|MЦ%H>iӳQJ/܉ |T~2AlIXj[<7s+'s Nfo;7ivM IMjhÚ>pq #XtB~639qD1Md:ߋLT`̷|`/nSِc%QӮ:m'n868/1ӧْpa4Z0C&gPZsҒXd^21+ F"_:H6hXbᢏ q@j<9]zr;%$XSՈj}h!B0ܰ 5`=R!5s^L 8sDjhg:bO>C oP[ϐiYᐿ% <*Z,j7@𭃋J[_c"z Ӂ"zU氼`vlcƠz6qܾC^Y|~ 1>2P( 8kԢWK,dĈ$VF瘥I/)@=P䀁.);\M#]zv[9,;^̽""4 f/=]ڲGV)jmƵ-L HBIGTsKA 2y0CRqmM'|#=>СBז/YHFXA? c>m|Aa|X*Kx!ٶ-fʶG!8rA 걅DG2_3M'&S`9mK|-d>mK< )t8˱(g)a+f>45V$/еoTc؀tL`3f-¯  {ڈbQ"UH=ЄPQ\P]+~[h y 콌s .Ôih,H_jM&$Z4vo4K<[ضPdldNP 2(YʠP_k[$2 /@_7B ^ȸ7;錼Y8Wm"S"} Iq͓(a0qs87(^Y+^1G&+ׅbieTN``)- Y,V7mV Ŵ 7q\7^)kH)ۖôrVfr|q-![^![6]Y j-dK;˖ Җ-mClܲG*|Mr8j={^@Veby:09-ź#Hdϛ>y?чXG[pJ2GEB7яNFpÄiynK_Ջ/fqhw}AJC߂DM7ÞJ.t{w=1b8g|q= 0_  yG #CP3I)"EF|Vja}whoF$s17W[JMƊh%_&4a`n9lb.ٹ dJ[wث"dMT5T- hĊO9"b'QRFBBʀ| $1= z@5&׬^/7ߊ%F0Y$s" oa_m\LfpYx7_a?, JW~dz"z& hjYHٱ#FkWOSߊ~.Ĩ)x}7_ \@IfF d24 GL^*WQ8>Y|lF_vf}osЧN|,cg 'oёA*9+;!"zB:; 62'ϋ}PD2)wHpZ Lq}l.);I=2|,'4*]-4靐JgI$kj 踒{+OW:\o 9;{掅HĄ[+8a!''2pe> endobj 100 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F6.0 13 0 R /F3.0 10 0 R /F12.0 43 0 R /F7.0 14 0 R /F5.0 12 0 R /F15.0 101 0 R /F8.0 15 0 R /F9.0 22 0 R /F13.0 51 0 R >> >> endobj 103 0 obj << /Length 104 0 R /Filter /FlateDecode >> stream x]koG_Q nb1؃,fI.dRТLJ=Ww5۱$UNUޫ{ԪkUYw+ն:nku}}* wڌz9@7]e6_k*Ϻ茀ZeŪj$ˬ\kw[jV*3<_ZNdx8}aJAITA6unF3 jt=\uGR!5U.V P@5)@kaFJN.ez'0.{'DSGȑXg|RzG65jcmNe6` }1'>/STF8]`D'Uj?:;½_[ }8ܳؠ -ƒ}TMN9ag ;"zOWMzر>ںz"8w9u'>AҐp_CAޞ7WatK *@dyUQB"H\SD?32I0uMGEb@'>ypS\[̰*p C;ƶ+I5"0lwMc1!_3^g11'}8ٹ{Gw O'> -7[+^.ƿ'{\-Eqo\c?)x8v}ҀMZ3KP1ve,Oь!$;>}\@YKiGQb-jW)v~ }+HŒ^|S)aM2}NFҢ;|W)~|`P@ 3pR4y3h"> B !X-&v\0|| a$b1bT͔ܔ躪ύo6&+2,dk컭d#-zO&?} פ­ s;=A%>yaMӮ,z_G(zE@ڈxs-fu$kYrxuҵQTuᄽ`ӅKFYk`i߬ku|mcb繘uc>H e%=5m{J"*;SU۫kOo~dőz9}vzv?mX=Fu`?JWmLFz [s3OCΪ34ۤp!="efYjmU]c!XI=l|عZZBSItX `˟'9"͈[@:/%##F1aBpˆmwҷpE9'6O8iHFU4mj9ޞ64)8UUc55i2O\cYm}8'H^_~baH61j'B]r$Bi. EMgSȵ>+ƥ(EOYs|~ot>lN]#:F=.;6yl!-Vf/I&H{ Ph=-̲Inm=: "EEZQc;+ VcC70ו/DN C \0ms,{MjALF#/1nz垱.#bc bcHI}ʦ̦TcK*漡 n7fKh)MŏUE‰D857mvWJV_qp2g-ކIYM{4uF"-0"+Mb-hw9ݳƦwdaN͔۬ lsZ30q=홴r/؎.ǫZjXx.?C`̩U:v}L{՞VAݛxey؂iaRK<dWHO%BpcX\taPwMd~q|/) TmVI9Nf.{F \vS9Mx$R;'Tl+q B-)HOCّgB]O<!$++g:&cIܕ@;;F?H ,z9]VR8;kQFn):g3ylyIآqs0sGX  /&bay!ie{C?1f~Qv#-*o3qE'!吏M؄ڒA} sax<vK}m10)\jXGKrC Gz+@=;ynP`}{?/?e h3_X G;|wM;M0~ :kwpWr;8Ϳ̍写QPcbBzĘ_oWϝʝ=6aY}֓A}&F%{uDZ:0WXQO24 4mHRM KC7T`_9azC1!8m^Ĺ,seDFj-p.q|qڨn64GlfG˲c^䌥6yyǾfp.mRvy0k"%{C-|g=±QIr&yFJ2Q:E9x˂.J<{%pUNW֔X[DSlڟbfig,? (g+FTbMaNX!>42b(2:6ߡ%;ārCl&#o\HO;]c2RovwfކVZ`IGhL]^0L[Z+Y̆ VrW ǫ/sB ~ p/ C9|Lۅڤ::~{5EL^i|(Wc2R uu>#ޝ _$ |D> /g`>WY|eӱh]QWՉ`rhy,ft1o}0X +Wy3 uͬyPGy"ÊU@o4z N@Mfy3.hLIdKɊxzs{6p8|?e*>b/.['V; u$cA7^7ICN"4DVYҟ^rZT*|Y+R5`/˓F.>= A_T"LZjw?0ރףfWBfuqM%ptf|h<3.#p'_~sq@8.A.v?KѕxoY{ʷ~:!vÍ*K笾S endstream endobj 104 0 obj 5635 endobj 102 0 obj << /Type /Page /Parent 57 0 R /Resources 105 0 R /Contents 103 0 R /MediaBox [0 0 612 792] >> endobj 105 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F15.0 101 0 R /F12.0 43 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 107 0 obj << /Length 108 0 R /Filter /FlateDecode >> stream x\HrE h~p.v|]6eXoYCV#%_l%G`QWUEWޫ"WU8⸪UYت^|uJ﴾ps>@UQSƍqTIelT]GI 4JRך<*:IUQJY7UqTUAb=&O,p}F0yC1AD5EԤq*͢8`}FUQQe}ͽz&IlO*\=ß^?Ysͩ=?S?WviE'4%h+n ~G7+}taۅ@.guIjq&ER2^]Fboۻ#}xGVyTgue0}/ر3ueI%)xKf/c|":hb ՏJk%WZ>ъti6H߶|ꄕ-;n[\ZfǞ$Q٤H;g͆+@[FꇶUFcRX RDžӕ|R;`@@ ,˦ҼqMpUˀ(ӲťW2ƌhKkO ki$gm'EedipNq}S>kyorjo&nBӇN^1 qAY:WYT<upGh-ʫ4KG%'x.ʃp"@;%$>e%U8S:>i(Ȉ˥(1r"XO l3m1;bK#ݷJOHkl5b]ͮBmذ[A048d=*:wzDc{ {b3[&Lus^aWk$Kg)4`9ɘ[S*ٶ[u:"S{ ٫6yGy͈錣7Ymz{ÞU%q8e[q:s)Ya^:cl\\sNj@bZr>n 3Zm o{wyA^G +⢮` ȣ "&MLG`#T(Bo8*T!.zhʢyLtݔU?j! Xq DAez`y<P!6f/BW'e\Fؚg*sA3: ADٽ%q7MLOO,}ETUXe!$v;6l;.a>r)BdW co(4|}gAe*Fy9k2pv㺝K#ك98cn|#5 ( "URRrEok>{"mЂ!ˍi#;k{0S@Uv:R4gHa@7j6FԶ]Θw}02QfT5TYZ;чlU+VatvWs=Üx|}l8 9L.<2 d'+,y# Z Wh6lVBC Y?Vʢc01͛!\79J J=[Źf3>v7zLJ򃮏0mp:r{(V 4>W7'W>D|G'/ێL/-bbT)J2cOFVGM,b꧍e{w_X-oZjeiAs!Ce`4ocp;G&Lk78QQ6;pM92-ҞZceh"c6Jj}}A4}QQh1^V mT 5,Џw+Yxƫ'Fp괽cb6GU^V eg1W*^cqI6U7df,_((H9{{(g>1VR2%SBE/o,5>1v#3A_>s/G6'xea{rtV~^+YkuBa(Ki VWEi,`5PVdY]NF}@`;fD_Ǒy~Зfm' dl/+nc_pED $+քT"Pޮ*I];SoEꆯp {M!v/#U5Y8?qI:t022۵aʪƤ.3 +a-f"KAnM'$Y Mc7q> MVe}y\Ò|8Y'2Zh>w$&f GIW(?Qp_ԉ.\蹕!2CG wäGaKv(E*ΰZW+⯂AW_K&kxoe#2@5i g/`uM2H-fXi7M.#YT32e ypu6%T`NSVӄ 8H6QS:Kǣ)L ԟ]#`AB.[Aiu;[! w.mX׈ 枤ҁC{\!쭍6TH;q\A⌇>d5KL ƳQ;)x¬ISTȋ?So9GT~C.^Zdx-M N;ƅt]_w(D$&\ﱎHbwK,N9`DT2n ԫwPU]fӕr:2S=> }خ4 AV6^Q H`K K>Ԡٮ%'(zwAɬM D tp[vs_z,\20}2c4IJ4C#ܽ׏v ^ֳ .byM0kbj֋]ͦ:o1}0(;NY,Gf @5[nǸR 8hv|r^7}7"6͝dzfi|w~U+gO$O B,lׁoG2JtfެX`ɘ@GVߺ(.=r~C8^ntwg%ULG.?b53o\~*8:&feg鶉 טY4d"(, 1aKvC;uTV^`7Ύ_NJkL].N~rlLEak۾/wl=*pKf-u{(3f>jIkEןP2o;~GvT^ \UNoM7˷e(ʌO\ΗˀB=Ҳݯ¶]*{O>04-lpzGj#|Gl6 )& α`h,UvEF+kCQ{n@vg:枹$sڡ:&%{Oضy}6#X`G¤xvH=Beׁ&+Nc~CU/h AQ񵮧fA7G1BbOow;CL{.=&cZbwNAf&p؈M]˗悵 đ8(Qܚzme7z2>~+ _xy)w鞐zsE9FxFBpg̳:kԢ1'spĢZt{{ 1[<%H=#ɠ;Zw wtCk+J)F5s#U ε._19^#J%pX5~ )#|BY_XH[L/WC_Q@ ·Ҵ'K: endstream endobj 108 0 obj 5130 endobj 106 0 obj << /Type /Page /Parent 57 0 R /Resources 109 0 R /Contents 107 0 R /MediaBox [0 0 612 792] >> endobj 109 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F9.0 22 0 R /F12.0 43 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 112 0 obj << /Length 113 0 R /Filter /FlateDecode >> stream x\mF_O2ΦI ^|;dw"kr3H޼{_ȦZ'"쪮I}~RuFyy۩)FCݩ/ZT뉦ت&5˳)Z!U]ݪ|UY7KUV]QjժIښY_EԸ?V5ktVԀPLyVy_ KO8 ^mVcHCxZ#rEOP P=TUrU.ַ/ 7uS.8U_e^-O Z-7tby| %wjysUZ~}Oq.SSiy,seI,h8:,Ffyك.]"B脚by0ij -Km'рʶʺUhR~ ;Σݮ.2M:񤠆qM_ٹ0$|^)Ρ,/iWFY4Yg_+ hzssT&cx:* RBCe7Ͱ-1foLwUt.|MrȴkyR>lDv؀-H =Fl/=|<'<ڐX $jQT :M0u*t+.6Ww K٣+na]UY߶AbLd^w5s K ?YS[!59b+3lUWHxUHTUԜ˭n Pa0H?kx'7 E|bѽ;oϜBX& k[uB1j,ĸݛ oįڄP <]}{=^10X)`{X{źMѽɳ#7U(;7Y\wEp^*QM&Sj*tMן70]1',)!skOc:BDY (|) c%H*l .R}G {r&;&gpM)w'&qGk~ s.EME_ў鑏yP,_j ƈ*`GW _ F7/r Q<:CTgVjK¡~+#bS~drK& OB pتyy{+LPQ(`3.`$iteͺ3Y#-gLb:-'X>aROwj5Aʜ'P;~Puwy+?M㭺T=f0z7UVJ#(k[6KOx>7Qs!ĒBbFB=5XRFǯ c/ `bTsRG&6_l$csmL g5 c._hLuZO:*79`7TŅlbB%UT P똑Ñ J9asqzs5^gBL; Y=h?ACCAR-ʂ5˜Jl(yp8U"{]dɮπ It,ݝ5]ֽZP$sHޡH,1.kڰCE|V? >l|KIU .y$P4lhI:bʟCfH?=Ía.S6YH(Fj "F#597\f|aX(Um6؇').l*c1kURܪk:0ϤĦ6.xM((Jl:hyyE^~$=JiqЃڗB,FH,Xv#6GТ4!>w AlV ,X2'iFf{I+V ?,%eul ~4BNrS_Sr.4dLOeԛޕi <rSɇLP@ CDbQ,>jNըY󪚬3am^'vBiԙ!D„Ch"f:Ywq Ƙ߳,kH"iY(6Ò1⬆3q9z_:a~k 4x]oѧi;Y12K̤z< yK? q-NV8Ǣ!OU=ƨHu6e{iƦ)p;fk{vqS^ V/>p˵J;4[X ɤyKكàyh?6>c5 d3'CbDd_.""ƨ3?>UAp ?;Y1owׇLF̼evnbezYK9n#O( 4`0g7Ņ)`ŝe"`7lNGڐ-dك7wN>VzIb"Dxb21R{GCP1i C5 4Kfnx!&JvtFc;n_/ƀ!_v@ƛ؈ L[(ɕQXédm]3r~DQ8q44J S[ލXіQڡu6tZELYSQƒ3ιRz[|`yO_>A LIPK=?0/{9ߋb$vu5@}s+끛97bM&#dSb4fR.O/!ְtDy31q"0 sŹvݿ4~L2[+61g5^1ə gC\^w q2fFp52 j P3}EQ#tB3Jf\6k*hG%^<{;Mm0X2%Vu#(!SJ:aI'~24NmMlۨ/TL%uGNNK֐gTYm-"r}-roLMU^햰Y6wz$4]EGgMdzB-J'9 .C/NG>π j0%xcYiODo-{e >"3vV荐HqBxqƻ/Q=o{cfE߀(F~lovp#fV_)}.V̄ Cw6̆ ÉF2F$D&:5A|[HEizkGHbm*s >m)j@}5b3s[Qm$b[IePϋ\fMv|N zeH$%Bq(X~ZI"L#1C=9h_ I9Ot0λNP^Z0qY=6G/+$#VWVRل9R?+₍ ?XF>h Qs5h2 @gUv!(Ïv!&:D3icx!cξk,D?K&V]dz}FZɷ]뀺:`{KdC D" Ț!K]Ҕҗd((#.S9KSźg>g+iKPa L?Xc""dT if+Fqe^`ExVF`5Pf Vo\#(!u y`=].\>fJ% N9`!2 BCS`/q.~[L/J(-X!ꐇJ*=Zlx^3ZB[1r_h ãOD_I|P!O c d 30c 30.4w\Ks'cE˝AfFǬ~"M\Rq#taccG#|;!?;!9R?;R9R%/n4P{:AUW;V՟CDEv0u;G~ Mƅ(9x" #<b[!XH BˠTyl8ӹAk* = , b4 |JO+"+NZ` Ŧ,]^6 8a_Ɓo [E lH6H⭺d[Rt#@W~hLҭNA/Is9ǓcEX~Ll(9PVĴMՕަ'Dm} `xgq.X× ٽr;23>aNzdWlm4Xx&+/eZUc7[vaCR[]b7n@mMGX[|1eU-4GǼA3s|5{[UzjÍg endstream endobj 113 0 obj 5524 endobj 110 0 obj << /Type /Page /Parent 111 0 R /Resources 114 0 R /Contents 112 0 R /MediaBox [0 0 612 792] >> endobj 114 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F15.0 101 0 R /F12.0 43 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 116 0 obj << /Length 117 0 R /Filter /FlateDecode >> stream x\ioG_џ*sAN v"BH$$8ϙ&{F "ޫkV<oEUUZ&iڴs][]&;ɿ@UXM:M-`%6ڢH|YI՝KCʤj,UmSt4qMbܑIWfYSW?|q%4-:I| L3+X=~/ʓʋϼ8cOx^Ig]_p*ڴĞ߹~Ǟj >@$\ ?cOx['utÙuV+qWݙS^s#H+q31c[9+#nFdyVe/O⸼\ #oW'LڢmB2Gԓݜo` <"fw yJY>;*ND3* |_]7f0ma]^_ yIJ#X~P:mwkctk|m6Ȧwްp7N7{:ڙfYRwy R߼jbs=9 @h(:Vo7jwdj]eB "iV˯7G0 ԽnaW~"%A'86vhOy4Bzǀz}7vTXP0v+i\?=_>^oWr[1*EkAcBA "ˠuCA y+rvk^zEQ#H.!fh*r /dKM !4Ol~史QT dԭ 7Yjgb,.XjD3UmG@'L -io6"8ODR/X^RUb-`:dڄ ؤgR{9*j+mw{A.,[ F[_]j6cB?OɵQ9 u.tw~N?i[b=} J(t'I@M؝4OXKVC[i-pQ?:"bhXx>[f˵ $% :Ť-r*_Hiz'8aX-;,{pΈ (j\9j\ze!.Qc'Yt&*6S!GP@=lce/sL YeTSbƽ:5xp"D!U~"6b ٫1-pn%ZG/%(L R!!RsX#2lkxqaUN@ȹZoBFoz^~xhJDuUibKt3< (!ؚS=F2o4LtCwr䲁A\IЎCbP 3 ֭u/WK  1J. "&2rpfxPR YB YUѯ'QJpy}TL`:o(Ol&^ Ns"_ti.Kdol_Ik啮@2D?t u<:ٹ,fۨĪ[geѡO'6W}W̊REX 6@]'Jŷ4`'NKr`A$Y~Q؄M9HSl2,or]7ĐW.nH>-C&n6YbȝZlʘ+/yrj,:l?=kӋedžqcN蝒*jW٥>|*c7>&ۏ2}_:}*82-re3tP)~aODuMcך~T .&?\)HsX~IKB@. r>(̡φDhn4 h.$!iΗ4狻W07S)X՘TVRhYB<[t QH((g,Ӳ˃4JI܏+puƤ,x%H/sdIA}78fAI7 [5ݐv0TZE&9x0~ao{B>ҬC6S;tE(깙"R5C=)HF2CCb=ơr2tCs̆:Ǟ&IV* 9tY:vQ3ݘc07~bb-eG-NpK|AzUk|/+~&sxw~1oeOX)R'#ϗb>Z(\sJD1@Zӌ9PW(I(6xdEK{GLtT1>q w nDGzrLa_I3\8m(ǂ.}W…ܚ: NN˛a'o.nRZ"{%`2KS'/zMa##1Ryw7j{ۙD!Z}co0WF GA3ˌ'䓼񫁧Gޭ9gب6tTTI\WPpҏukTY 1h*brHvB)TSOҨ_.);79ث7_rnf+QcљEx -`;wx,*PB bJ,^yw:#;Vo D6~J+/b6G+G;֋ c`#&{g+kpaT#kǪ{>3z `a@dBx%_򞙥<` g6ˍ9g-u#Ʌ)YjNUɝ#](S*r V}uA xCT|Qf ]PW8 vdzOWcϳ\x0Q '~dh=Đih&=t#BVI443 MKEVQ'{*DƱ&YFc76',?,4r0N2[}uj;-6w*w&#2D弱rv,]0|5J2ʊ/XOC%v}W{i8$6 Ϗ2+b6Etv?2F!ӏiwh&gT8QTڸ!QkAG;փē,mQm/06֦W)=Z#|}Q9Jp= A <EoJP#ܔECr m2dzٗE_kkg)/Y#i|땁|cPRtGU?Qi^ܬD[0=?K endstream endobj 117 0 obj 4692 endobj 115 0 obj << /Type /Page /Parent 111 0 R /Resources 118 0 R /Contents 116 0 R /MediaBox [0 0 612 792] >> endobj 118 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F15.0 101 0 R /F12.0 43 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 120 0 obj << /Length 121 0 R /Filter /FlateDecode >> stream x]m6r_$U*g_w>sĩjvyw$4H̀\i!RrHht߻IWQNEŶW]WU/XGU^DgBu}>tŠ4}orKA7MWC7weiC۾TWVyYw[UI*U]m"v-E3^hͶ"CS2yC_4neqnۼ~ | 'nĘ UU R~(CU4Vu^4Vߨ/O6o+3?No߂ rzSm'[c6' !9"^m~=>wjVq8ηp=yZzՐ d" .x 6x`.ǺaWMbfkt%VdNoNt=\Zq.b1WԢ_Ye K+2,gY9leJ뫼/3ZxpEhDW7i~a8":yv~bcQԫm{  s" #^)q;sg=yqS絃]u[bA:Ni7u^pg|̨]ۤ!j\?A~,ܵ 0LQ](. *+)GἋhB4z0jwvvz.ޝ~ڼ1*yw(ow0V-u8m;#;Ja:QgH1&Q/65q#)6h.4e5HcTа>f>F|󌠞-5bJNT{H) ֹ0kmf9$P1P#-3";Y\F(;Y2̈́em .D֞n{! ehm NsY&`S48ΡP4n* ;aJz'HfS6^Dw&t4FnNf2IQ8:F^~i / |r::<f2ot Wh}vywt- S-ʥQ{6{R\tB^\ΠA6T SDs zZy Q[?Me&j"$a+/KG,Ax:/a6:".?>6!H9p8q<*GR=(5Iy ]$OSLFQsezz볔aXO(I۪ɫ- U}P]:wBz`g xVw?w7tr&quǓwm-!ˁzY֠Ѐ6kc,Z0QC{kڟ=\qܔ@`ѤY FƋ!6Q֜|O^_Lw̵=Dt'k2z*`y{eGUh-&W_Vc%6?"* +t4S_x?BxJ3 X߸όd)1iްjqy(ĎgmmnwdGfwl R DFȥI9 gE}+c=N[Q^YuΫ_GгyçcbuӷgŒ厭n&Ex\JVa:6nBP"TLJ2Đ P3*^wK|N&/<ҿ85G  p~iHue$AB( k> Qee!zs6qoO5wb3Kw:%`[zK*s yI;0x[U/RJ,$v8$Nb!G1µl|Ą&"Ⳛ5.IH\B7JLn %J̟c~LKƥb]ycDF.*NN X Dzp}u_V?n1 M E܉̣QhZ"0V f2ބ0Kf}es:=鞃EU]e6ōrG30Hoe8x9,{5F/s a?lrpXuZlqTnz}I|+N:?ӽUKſ3V߭mZ [&d ^D˓nDktMhvUnڼ,j5l| Um.+7*o-UdMR%R%˥J#4fA$ FR%~DS%痯Ea?c$R%uaL(o;coz1k !GGÑpά>xSȴ#}A N2mF џ%!z],FCxq FEhgźJ~Vzj_~0ܼ~%6XvVtH`Fa3]\! Fb^s:e^ } #xv`|7lk)Hs ]aҀxȅrY^^,,%E5#5.!=(i)i9[̵gJY^.eax='B ْ'¼p:LK%S&h>ʼn GmN\ʿ7:uƉːMIHepќ e 'ǑPQcfm ¦eNZVq/Smy7nI4}1[G8f)ϧl.P~=20]b'|ZV Lk6>bk'9^( G G:ҋXH gRHX_~XA >b̰$A|fxJi͌|BTBzMJIryw[HJ9dw Y IdN%rqQGErU&tM?&sYxڿ=+lnٵϳ[z84"6V.b۳[haeG(:έZ0z >DjȨ}"m9WAz9NB=6,]8=!| m6V3sQPpq^l[{BD@碮զ2g(.|,Vf #/-<70|*'sk8lL4zzfp4Psu 0CNf1, ۏ| u yyP`aKY¥?RC1=5:ŶS!Sp IPB5>ܷz a)BsjtHN C|M|[FՐ-0˺=߂LKW.pZ-h.`>-Hf.w@[KXob|bUi 8թ7g9_g%z'z[FAq __~Mۺ zKW6FXݰ)3R"r~/9V-sH+nϘox؟Əwb"8޻+IDa麶2Go@B|g 01ң!XK ?p/~49wPJ&mK3!c2  .<|-8%gL4+dcmjRj;#ػ`o NJ3=7YMc_6DPU5_W endstream endobj 121 0 obj 5119 endobj 119 0 obj << /Type /Page /Parent 111 0 R /Resources 122 0 R /Contents 120 0 R /MediaBox [0 0 612 792] >> endobj 122 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F15.0 101 0 R /F12.0 43 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 124 0 obj << /Length 125 0 R /Filter /FlateDecode >> stream x\oɑ}>P<#af7H:0hjd3D5뮪~ 5eS3AI}PeJI'IݨԮST*5ՑGoGUUUEuV5M6yjEY[Z[eݤ*mRO<vS7EakπimieT߳l1Hl*'Z@]UU$nuU`cw1 yU[Zf~z6,£}&iţW 0 YrJTY'ER՝͵z@T]TUYA'Ut}fqojnyo7wv ELG3I+ݶq9ףZ۳4Z,GfmZ F=ΖF7t1u7yFT= !.su 󴉓JY3@ߣscQyNAI@ΈMLFQA}녹؟G  -w't%3mC74őͭ|4,fќ9>> #M( &:k2>_7V_ZWmgEJ,|Q')XxGԸ?E{<~FE20|ic"ڬ[6kOf q="3-P#O\K-9G|{0&| {sy?!LXG8by(Ifw-#ܬeεAB7鞅O,7@΄ӤG>+d~)qGv8Z~V ފ}iH]dډGcPzGWzAGa,F:#VwqwxrDb2ϿGR#wC(Ӹ)73C]>\~<_TܭĘ%i,eLF'"/xR9Ok=@֋@ٓ7Whg H62aÆo"3gØ] vC<ԏbژZtTc#nfiN@xnl-ˏ&BZ]9T"Q-DێZntguD6^6@P?SWͦ[g ~X1'5͑’$Fɀ*RVfTpcMJTaCs;$v]G.xF1LT?tLh_y^ QW6o}v\%4ШF<2$eZZKZd!2r:`7 #G|u'8ʢ_!h:hXXz֭cP_Svq8 Bwݱpi&+p'';A؍  W/ 0E@y"&;CpaP(l.]G|oj{uD'h+vofhf/q?[̈Zoi|߳"U$ 7?Isꓷqdc&-P<[R$ްB@jE36#M“Q =݆N%sl"+`>1Q Z5x^'ҍ0c7{?HoDi!ߩI3jas*~ϔȴ_ nb)M],p g(npx`{X;SҩP{L?K2$%6)b|t#axOW.|EMz~Gio}b{ЩQmr>=:CV͵т IB1P|8V\I^qr@}.i& ׉'He`bMb,B >%1IbD Ncd1ifsfq[HzT$TP2S萟W N9-jZ0L:XQ4 Y:0xxZOaGf> D3,i VaD2cXaǔ!ІpěG\ްiq&7 J&HM1qEנHFYZ(' ~Z0 JopE%<o0zȔ#. G+4@#ReBm\0 o77K2/vD{}"mlto{zAT"ࢪ ⻗\c;JN[Q1mf ˯̨Hߑ@!ڕ_oK؟ Ĭ E'FC~G P%Tը;-R O4RwD5PHFTUwrwO ~&l*ήv \kc5&D`P9SzR165u_jZBn7k<le/Y!6ހ7[jFxl?/^9+^9:"Ont|vN+Ͱ]#)قi1U9p^~5Z@ej{T6LHO%$\{r̈́sqRUq<"z#wOe)2VT3 цE_[N -R.a;QG3M؆as"" 1(eR!\e(Z9UFTYAgs ^k-jP *g~\Э}7Ӣݑ3T|w2p=RqH)TCijk*tEڤbS+.ò @QhYͺb vݷi1ǦCycGa,N$^Tʯ!8Ot('E>t V| Q@Qk#e*؟)E}TFh>`ı.}Z 0 #40%WS)K~|0 A,8GF$F NqU_u$U9>K EA3VUչ=dDbKAN(!zr >AN YKڨ}wPdz2^C)g{+^\y£]@Uum ݥ>a- 8kijHD [S6Er趬qqh<"vy^ВE"JN QK o `'/4()ٓſZ.ĞSLAQ5yquIkJnk[L 4tKKݲDЖ< 1ݒ>w,V+.='Y5ex%`stAq}'x -1NT5%ؓQH}qp\CFGf,nD\n2zu哩~P~vb AOQ#V_FylץExzEvow|ǒDED%[qtYfJʛavݠv݇]wq8, K0> %ZVU[vNP.ɽ~܅'NS.Mvw2KEKR#zd2Z|TًW_\ۯTW|y)8Q=4N剽[Cwz._fyX>ãi|>.vg T ^\(3o"+]wI?3 . POMh<_]hnj<"xgM5%|Ɵfu'$j{wi endstream endobj 125 0 obj 5214 endobj 123 0 obj << /Type /Page /Parent 111 0 R /Resources 126 0 R /Contents 124 0 R /MediaBox [0 0 612 792] >> endobj 126 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F5.0 12 0 R /F3.0 10 0 R /F12.0 43 0 R /F7.0 14 0 R /F15.0 101 0 R /F8.0 15 0 R /F6.0 13 0 R >> >> endobj 128 0 obj << /Length 129 0 R /Filter /FlateDecode >> stream x\{oFa`1Ynr{b (h9DG=w_uuM=(##uY]U]o7G*MTE祙J@JڪߵZDkdnx <7MTX,s,s>7ȓ|4K}/WaQygnz!⹙'Yc@5 sla6*r7rn}ӡsǀ Pes,5YLVEw8KQO\߭ǖ'&FjQ[y<, $ߜ%3q}BKhu7ʡT&8(ˍ;~yqsQO](jKuRTݕZ-URx>iF 797ڮyi[~_0$ |Gq]YTܩbrԌ?Q\ ^b/]-[6KɹN {J;efV[I1( >}b]wt_W+e9޲MĬ8 )*_r+Q6@ ӠfhQMٕVM,e?b2fa QCWUd'>GlȺn?!1*' 9.e 'hȉ/0]@ 7G!RŬ)ga>yh4ԙrD7'&X_ 2E4x3ɫ*:Um,}CCLX\EjN^ы5EڑTH`LFTSPOūmUB?Zw_^='xőd,QS?ۏZOUM]vQ أ\8 ~HHz Gǡ~cw{S74AJ}B4W5((Tvsտ5xljїDxt2ЂC iׯsa4BiAF~63r.{6C6.MBK*Au[ʦSE1̀'@sIRL 0B~ĞNajgҧ%M[:ʰz"kꏉ\>`?'OE"!%ýItRzSH =-}2|>1ߋ=;\*˂0>FI"|w"E9dBE~Bʭ:T!# .CCbv١3lkBޛvϠn37x7[RLGMbPRx>ð٢#ܯ12y߹Ws?=D33/ Սj l72l%5˙ 1jɡŤcfjp?ANkLv\Gy, EFw-)@nF+_t*.qBH_f߫~bN>5nPA"i7siMD=:_my8aC,ȟ6xJakW*-rU6?29;?/%&NyJNK9{B! /,3U Vh(EM|XqorYe2R F koсG%d/m@ k]䵹ʿs%dzr*Q]7nVe9G]Q®~P߳=ftMPlN `3uEΈtƆg/I鵁# 0"^YqayZ_yMcaTdd4YWڠ# j{Io:faTc2a{86D;bT$ZMI_h-8ePEҲ69?Cp-VO!?`P]ZĄk`(xD(jIzQg5_d-SleuA/e#G+FX'>4>D>Sj, 4*25LOM( "M'Ig KA^T /BYqo|vGBWgBBP&O63N]F$07̟!PcFR\$&|9jfihqfs.;L = {^_Kq>ƦO' y[yV`6COM?lvNi4o{3Y3FِqW~wz;: 䐗8O`kB(第 %7LђAZ?JroLbۧY(?Br91g'̂d5A$r=bi6UYnd^m8ea8ǽԋ~jB5&2d07 uZ4{ a1 }tat mw}v㒱 gjKS[^;uxfi>t,8ӧ*SfBkJtT{ШL>)h'N<surBgG+)}b:w prGV< Gg"0,⤔JA#jx/N;餺qwd ~O>g8Fɰq>l0U؁2"2 -}_ƗxcS3&v9 ^`/vWF|pa+f|W0gOh6:^-|e.' a a!^F=y&sa q7VU_r@8X@l,z;6Sg", @x29ϟ;=tĵҳ^ gڳ5ggɥbb2I3Y(cx /$DdLQtRKiуϧ~䂸5n%fQhC'ŋ0^ LV ʀl{2j .[$0ۜQ IhƑ2'$T vˠ۠f2(f"HalN&i"w'[DwYTɸ38~# (3EGEw͂EٍxoT&JWXA~j/Vn ~YdW`HzY`+0~DlO6  4@F ,0[6(n)`+l6Y l9UXN)%. aKAd9<#ȗ ~4Ï} KM/-XF}6 {ߏN3e 4=](!BĄ`c;٨\# ڢK@(( -RP C+aLH [vm7SlG.`g endstream endobj 129 0 obj 5377 endobj 127 0 obj << /Type /Page /Parent 111 0 R /Resources 130 0 R /Contents 128 0 R /MediaBox [0 0 612 792] >> endobj 130 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F6.0 13 0 R /F7.0 14 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 132 0 obj << /Length 133 0 R /Filter /FlateDecode >> stream x\msHr_1TYu%eՖ&AY JIU&t7l>0ueʤnLUefә7fm~x1f6f ]G@0UU&O(kS4I\W).:.fZ&/[?⬭Z,&kH*S$u& 8m㬬Y_\$nҲj_EvO⪩kLnWnMEۦ%-2IMqbU_ $fb)(o8@+-Re-&ꢴ} M UQ#v2 Nmdm 6IRfDdu.^KAinG4$VҦHCCZ :Rz 5<>s_u.zc]7aqr,^"gr\ZYfGF'3Eι`qSPAIg`iB՞`3bm⩙n#[qZ ∝EG $dsD2bzt)Ă Ess,̋#iQ禂ʴU疷Ӈ ݥvAv| Fy|fFRR89Pg>|Aa3}ÐO8H!0Tj|ɦEs2>rD [1ta %lܰ[SY,c4YP6 f$?d$<<^ɣY'`92بD}#.lYPy;DY/îJjmn!vE(C1@gŻǏk;.bTV5霭)패>2>KE `ގF80seMP_${V&IeHr9ʉ;kwF 8 f rߋ5~@5Zx BٲBHHBX"JF7B=_~UMb/,wmOnFQJ3OgsLs2c‡HS %3}O@JP_G6q࿝i$|RRܦKঢς&HRv+O7!Aۢϊ2gPӭgbF7Z'6pm| I[s;2:Cџըr HY5VG9ٞ_%b~;>yz5Nmq'w{Kktvgyܿmtݬn#ӓahʔ(SeX]ŃM7u]@DP>^m7͛W)hykC`L:dh˧qZU4ޏ3z̈́fws[H(eGS l/4J^B䑦ᆛ$#+HoPVL"),l+{6aןAe6;DG©}ӠQ`Ph6]J$y9H3g\@[ZFQ0!8 *U6<^ tlq;pyF GnjܳikI 4(pREaJW.r"I<0BL)\pѵ?0hn C.0ߓ,kF)ȅ7=D9TsПPQR7Crz0ʸn?zܩ- 耜8!:ȗ g՚-$!Z ^݅xk6DO Q;3l=D27(zEC NEEsC-l=?d I&gXa2랉A/]2fov!Suǻ/}tYۊEkz݌$;uЯfBj0(x~ r1nL.}(%Ҟ7H-l3hڰVaa9"O$K(,9 ;Ǒ%5Qp0gypT.X8ܚ[#}LT^=.{[,qp3*7?\K\\@k~o^ϋs|BJ 4_O-,s|πҵ,MB| \2*t FLGBfaț:厧K!sn/g3:P8A"n |Gh?#~ ^#&(T($\- * /RkJ{CQvR`%0cKߤ_KC]쨐.ȅ7JbEW->bJز+S\%]6HI2d"9?#O׏H: ZԔhWwƥ@-{yPjdjA0tNt~g[`RK-iߞbl*{HGW#}D20V* v~!k^E%S~qBxmB d6}l T\V*\ȔkC*R@1 ?wyys=8DRBw)CvVBc,FjAr6shyԂ'xX>' ?#XZ7cɀv"x4Mf!^Nu+sQ3eZ cR1!Co c$!x,{ː7'Qԋs'Y揦??M endstream endobj 133 0 obj 5539 endobj 131 0 obj << /Type /Page /Parent 111 0 R /Resources 134 0 R /Contents 132 0 R /MediaBox [0 0 612 792] >> endobj 134 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /F5.0 12 0 R /F7.0 14 0 R /F8.0 15 0 R /F3.0 10 0 R >> >> endobj 3 0 obj << /Type /Pages /Parent 135 0 R /Count 8 /Kids [ 2 0 R 18 0 R 23 0 R 27 0 R 32 0 R 36 0 R 47 0 R 52 0 R ] >> endobj 57 0 obj << /Type /Pages /Parent 135 0 R /Count 8 /Kids [ 56 0 R 73 0 R 77 0 R 81 0 R 93 0 R 97 0 R 102 0 R 106 0 R ] >> endobj 111 0 obj << /Type /Pages /Parent 135 0 R /Count 6 /Kids [ 110 0 R 115 0 R 119 0 R 123 0 R 127 0 R 131 0 R ] >> endobj 135 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 22 /Kids [ 3 0 R 57 0 R 111 0 R ] >> endobj 136 0 obj << /Type /Catalog /Pages 135 0 R /Version /1.4 >> endobj 137 0 obj << /Length 138 0 R /Length1 13444 /Filter /FlateDecode >> stream x{ xT̜^^&9$$ rI`p)@E[R݈ Qثm|b'~)i>93syo3ٶe{2 uզ>_Al-|:ۍ}k6|B\˚;W#)~5yZhWqnvkn_p{cV߼okSOrgnmF?H%^(A+"$#-ApxO~Ns7cch{kgƏ__0hԚ];37?>9cR}|'rqbT~$:fS^SH?*Czӕ!=pڧ:K9}̫K9{*Q9y*G9q*C)| [{,Q9~,=W1LZ~(X/)—#zgo#//ϱ|w>i?c&7۔X_ӕ?B _. Bx 쟮>6eK~qEb}OcS}ÇCaPrpУ^ڠMcp2=عOϱ#X^[.g>/(W~RS~Qޯ$zr+{ʵ-Yi kZ[S79IL2 fi6l1IDr&IXDebEU#֊PTSz9@BT3D)T&*M8fo@ 1{Ku0pQDͱ`CLjZ6]#=1E7{MDz8>E<;^/Sb -mX-ܓҎpmݶuVZWװDGn ԭ}G9P'_9@nPp;<6] &D#e*j ĮBZx_ߝ*k_'~ߍ܊wMx;^U C~zѷΠ'b 8mX@pN"?^WU<}Ftj5 [Ћ[sԆp*< |=>y ߂L5YHH;aW1]8=~abFgryt+Z~ʜarN h-+-).*, O sef>%5%ٛIpMZ&AcQ< Bs'IX1ci8)TO^_C؜@M-0rİ3(رF{}n],;7j/6$(:FCMǐB#P}x,ȜPj 1p Z@8zZȍ^1&&Ԯ:(Ѡ;ݵ-tQQj02Z_q -!nQֿlfTWXb`l.9we/3TYաËn|}=!ߐjsCu뫁ҞpnO;²Y7tG޵n-0kh;PMVZ;(9|u@ɦ՟DkہxZrz%: uS}Vb-/Ѭ *r ފqr79hZ&[ sD ̉ E.N pCP_]Fmjah76H{L3T4Uy6#^m"),a@7jmjbhI[F˭Pߩ 'FiChyS<|QE+ﱁm>pOF'SO sM2WL̼gݎ3bxsԴ1^BJВ!32rVp@LƸQoeOk 4,h ]x$T@]k&XTAp\<-m#2BmOLjaD.yeːE.AaC#@j/Aރ^^Ek^^C B9(w!}mⶡl=! ;:6}q܄ژ.9an~?'@8hncα/N ? Q&Q*CDm-(}hib9#˹v1# " ?]6dGV$4yP^Js/JF)PJk`pGi` A= eD! ` |T V!&t Xg(I$cI6rd>&0B]L/Ig#634Y47l1Y-#7ַ\ymN;VSJX3'n k@i|k+]x!V&1p?G, +%U"pJ!$TUa&XS*!d!M/ky*P#n |Љ;^Kzy2'|`V|([J)DUU0F3M],'v`tdd\|~V&}[oOٳCcOjss)<xNMS u61M(2QGG>GbGfY(z6A/KKEdt<3FFM*f7TV_wJ-;`{FSvYt+RgI9UH~'~H?!R(CI"ဃN|h#(v7YdUEd3FXEa2Dx.@\j#/nĝcAk'hKt)QV DG8_EKfЀp0y{/a?f4{\h~̽XU'y&<Ôb88b^pj|\ I(mₒR` ~s 14: H&c‡y$+ I> aGq$6օs?ю>j& ^ 4'@r Su^1W52b6g'-9ĝt:3L^ |/mO18A#j@d 0Xhfmk˹e_?墜e\[u<gqfV Q:wWBC^*f5%6wjf&onIZjO>.T<'ݦl&9BUŇ}$NuXk`::sZLR\d/ ـ)lZ8mt.'%;7u7nhꕸo'ezoo}ӽU7ݧtkJFNFʢP4g'/𵭯_T߰/|mߘ^}HZ>rZ t<0j0(u0p< j !Ut^`pxAD+FrZ+4ΰwO\}jwB3ʦnU0BٞnV䷖VV{l=U {,\wxx. PgЖPXlJ ApILrSu$zKnTlÇC|<$eC%`caXg'H hUnoAEACSPQl6;#4 Ӂ%oP8-(faݦ-q-Ծs xd.<,J'.< m%%fArW,e^`[}K~c__gokO n*dmYC޺΄Ytx r @}[m$Do8/˄VXƷ mfH0@ Yś0aXJ3 #{ r~ȐՄI1aNL$t]G).-D h/Fq<>::(<~JZ(iƌ)3>Uۺf5^ ^s_qm"?S{E򋀥 lBԡV48Hkv[ʩ$T*6{j2ũ~"0Om%} 7.R 7.gq__ݸ7-hգ㷐6/iٲؓ3#wsz岁"ߊܯ/mM~HEe.~e㹲2uOvhdbʳ2%ԏrBhwj#w390^9'bTĘȋ"g%ҏ5#35y1 ǪBݔh2> R >?>&c@mRM('BR'n"=n"PvJ` Fĕ΀%ՌuȺnډ0A=Mt@Gq@ሣeBF1[*Ji$n1X$ML76OJ/Ձ6bQI)ׁ[hĂK!K3  |8|qaJ8- [Du1`ڂbˆ.ĂNWXvtuƟ#D x} P@uɎE}'gxgjPπIOq_kB- =3jP*;^c de)٠36 cToeJ' Cklr&ph#*6,K;x5"$F0J< `^rg̀@t]B{` Z[ %X*[>cKH' //2$Ƽ@7v2D}檉-jvI<&i;ͧA~&~~ůI/=㓯NN?%WÃ[*sfȭw}SZ[ ?sm_qqji՞t_;ѦǠ/ R%K)YA)3uxwqatqkŽ|Sْl S ?x >i ܛdKґSS'*- ,) :3l`mIp'۶-hҧB0!HtJ_-ur4XFG+[Zot62ce]vv`^ghZY7=MjWf&8|/PԞe[gNJ^dB@!5 GyPp?ƒ$Q0ZPC1< 1rA kZKc5T7M 61+fq{lfs,#n 0fɪ\*C`;*Z #Ŵ }5xA\<}##0z5?)}%2`]h;~XjdQ,%ja+0Y=?R8{:;d0 j~FBJ)jKlP61v&M\.zIN\/VwRa2 ɽi^U|9Q̆ErqT`(1@w^R J2P5Dk^Bgo3]s 뇵h(,~y,qv¥\Wr5xs+&n ɓFktaz G^&sm ^|lq8P3`1MT:@ި"ZQ  rVbHxİ"C`҇4,X TQdGtk)Oؓ^ aO<K'^`]ZεzPOnړ7poؒݗkU{jN8g< +`kEAm,/(HW z5I=/S BB%&OZ[қ4xKoӍqWCro@M;3̻,Ł g= ?|``J|dn [/:/>/8*"1߫2uq ۠,S6({|LYN+jx[蹠AVa*XNtNWSN"t&=ӳ8,jTSωFˁNf W63ШIЍi &}>BWE0{{NX"wᒑ9 s y =r\kYa'v f7O,3s"$4~@!ܪ+t8`l ؀|'کȣ_e^wznkSr[Õt -A?ݵ42M ?t rj_2YmI'AC!4ԐBCe-3,7HQg4a)ALMN6%HqUD=erK{]J d0dۙWѩ!m`;687gez)gpj0_4C8qcK6oٸ$0>>|xUM EYlz5II-LNsAjM+~^bS)u(. EW>gah}vk_hx7kWMձLUg?3SsZ; ̇L7e܋rFܑu{]]FW'x/gZOx xO$o4HG;σ{}J@@DaK͸Z*8βWrSrӱxlcKņ~%y׻>@Vܳ쾙fN)wݵsGۿYNHuqO2N;jÜÊ #1f`zW =Q5fy BjJbk]-33zBV{mXZ&/s?#0!^mh =lC*^7X>_Xvƹ87B/A4, aAjIpZ%T>c؆v:M+k,h|u_-ٜgNuhPJ$s6:p~0xنwu^c% bXl bdn%"]R/ tB c \ZVk{11C쪱1v0=?$<Sfl"q$-ylJF 3,aK-(u>vŐLaC"ŠU~pE\^m] n%f"L 80->]ҡf ؉HQ? 1mk{x觸 W;DqN͗8 NJmL;᠁ӿOEг# DG`\M`l{jxXK :EX9Ka'p;UpnU2+1]1M`ߣzJkͿcKO95v+.[`WRX!։lX*~M> endobj 140 0 obj [ 342 0 587 0 0 0 0 0 543 543 0 0 361 480 361 689 0 711 711 711 711 711 711 711 711 0 0 0 0 0 0 0 0 776 762 724 830 0 650 0 837 0 0 771 637 948 0 0 733 0 0 710 682 812 0 1128 0 0 692 0 0 0 0 0 0 668 0 588 699 664 422 699 712 342 0 671 342 1058 712 687 699 0 497 593 456 712 650 979 0 651 597 ] endobj 51 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GMYUSQ+Verdana-Bold /FontDescriptor 139 0 R /Widths 140 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding >> endobj 141 0 obj << /Length 142 0 R /Length1 27164 /Filter /FlateDecode >> stream x|TU?~wꝖiIf&BR  E@H U( RDA 1,.]tW`AQ܍(N>?-:u9w3o1<7L{w1vzUqa3g9'??9z:I(JfHD b[qIٖ]9Z )n盋ƟOK3TTf2% r&K4@3h.C\ 3r?!Ks\_n WM.N~?+bͱZ䖊[ҥL)KI$3)mMƓv~YF֑a|[CCΓ_337sbZG?ӓCz~GsaNGz7Cp&rNq$;-oMs |*ypFT@ F=~`.Hy92eSB@rR\NݦY-fѠ*$ <-78eư3q gg1a~f^W~Ϫ%8&w *<:x^J8Vi=)M:}[N=)`D?Na{ aS`9^l VN'4}Uգ#`9ld62ejԨnOgvWkP^uiߟY*G4vq!::xd]O^i)Z|OkY8-~qQC}^]f\ zK/Ń[!?;Ch֨R<{{֭-C`v)zk8Owa}7ŏ׬|~"fehw͞3Px `; `k[<{.;غ_X߲=` L6k{;v|b `= `m X\Xvu32ZEx8"ɰHTbEhBQ#6b'n.G$$r @H &$Öik@era!#lB VNt#Y܂!Ho҇2R 6dr#H 2/|(1fۍ #(r ~>]] 5VN7LH'f1A&NrP>8vv<8̸3k--YYZk֖l+]͙kIWs<~5cyS=9w'J%$K(4!Ơ?z:t)1|c!5%6cڑt%}SzCƍO*OOeU &\=c *JI* =ē=Pk*-]`+RREl!?BrGӹ6Ć$mD)~r?Jnhy$3h׷ DX"vWp7_IqQiyG?jѢlIJ_Ӯ];YfQN :¶8[oye݇mʹAs1݇ -.&X #&J<'$77جT%5jg <=c|'G.y5 ./z[ ZL'SUU %h-.&X]&LNpđ`WONvD d` V">bw,Ƅ$eR$'S{q^rY$ bDdѨ(2z\555GI< .}z4zJ& /%{s=lEm"> N!GϠCv0r*+>w\_]Nűͳ͉}wǺ3+Om%YAUUm pTK0T 9 n_ڧ%[JOIha CAcO_=MN@M !tRS f5zJӛOyn}O܂1ௌA tSs㍊+! P^^;tLL eYKoLw/ߑ^O "w(Cvzet(s踶A-{.=ztf9Z\ Ű߹S\&Ba2i$Wmu B`L&,r y8* 8fNZZ.' `zb:uܻT:Q2:nYutU1yCG83Psb^}aa_8i߀1몫N,1C^_W>翬xW̛r*d.J#`'b8P6N>(ZT=~p h%c+|l$ɒ QJʌeQ(@l5MliĮ,0 [AswTh'i.I\Ncǖ>d={hJgmw졏?=/)ըZUgi7s7K##&E5=eG6EmC v#bΩN\jf O-}<|t{X?cjw1g;Vhb#D5J ٤l*QgHR;(Z&kgy%+LF3U*$S=)<GhVӦneSQ:rl\KL*Cȡ]DOsdWL%-SI>-6--է7l 57$=4T9JUT$ULGD_a]![Uh+ byby&nz|MOƘ@@>f ƾި-capsMd;:nXpTk؂1;b:*R\6EwQ,\=w1$xxW[7j_QCHe԰vrWFLLbTo㽦07Ϙ{7Oѥ}7<'%Gi MHE>sx'> tލAfJd]nO^Ockv {\$:#f%I|{(4*Mx:*ߡL1MNMgs{&aְӲ/ rФ4%:qSM̓,-lv&&dICx_1>!ps67D%l\ͶK|@4ze$ep.+}+{ӚEPtv$ؿfr@ 9?śt}>; M!I<>(P^ >F uA44 nIXf:ׁJAJOfUԒ;uR`ډ:lK5 }n밫rݥ:#@(LEfzt1]JӕrGǨĩISn&.LZ 0?x3ߩ~LHUOIaOޗ S顈Pqo a?c Y:I4Xw1q1GPk2{nceJy teKaSXffd";o>5Iٓzעov?̔{?vx{N wQ3hmS>~m (?NNFg9exc3͗\V E,b7_.sF&!s]sdk ޵lwm+o7q)xVN`-I .oHIjrMIP(~UMc-S;1C|!!_;c=k f!Q1Q5&0 $f\21>nL֙9<JSeGg~ML`&,[ &#D.qsL4X\w,j½Pgٳw:xވNWbn@vEGl8B}:RXdeIsk7kӬ <NeugU3Z/9g_<}f+CT_ d2P x}acA-pP H0B8|Utx)kb6l8;oF=w[%Vgpi ?.Vnwq6[u7#;' tO2Ls\;77LMv5ۘ%bLxx;%|amL҉R|1TM fGbC2/2Hp>BC‹J1h9̛{۴Etەr@40JG <36!ڸB'g:lpzÇ:;vؿ7KݼnG}著rL[>_"7.o?v*zx6I{A'#R]TuP^,TjKKˏ+cggYTU;4X|&CyB U@f>{}f ^64UBb~]P bE(˖b1K]`1%QZүz7?>5?jC5:n͓e!}̧J9"L8" ҳ)K3/"wY#dP=4_?=/''fg K>,cx*UpUzUƴv3'dOȻ fg%J̅v\XPݡ 9Hr}jtL♤3t}! 9!b`㲒V.?5i㼊!_ԧyYCz977WF[ DhkvQIw¯e?AJxr|ډMM4q#K'Ϝ;v! wMs2/v|cnͩO};~fw =mu2a@2rznW8C5j=<㱵mG߀E]*uU=>kح0 x7$LV@5xd"2sM#8 A@Xv]SL]6?VGbam~P{?T 7Q/~)m/ ~=BΗM(qy,XL-%tLG===-%=+=7[Z?e ;ɺl{uNp'lSA⚢$v  kj2 9S^d$dy*"7b8^z7oz?C?L[Orߖ= :zLLsdDT3222m5l5n5fxЎ IdM Ija=yB\<>n`"?"gY+(&e牤D9Y1c0E*4r|7b]@L;mF8 6C (T /4apHi{wOY s zf^Sg@\yRozi$tgqͱܽGj؊)&#6-ംXrV #g%gȧпCpjC3$y:ieGyG"ſIfYYޗwU5W16E{w"\Q y}=Clc R2DD`t!͖'lZplboi=TM-m$EP} vю/"stݒ)sM+ D tETRi'HjIV~]䩜(@p8N#i٭jq=4?<:Wi"y2p@yW\)I.f+7 р|`=% :f'5&]C@ hNl'NɚW뺊v]=Hc[G>;rz[C ~ͱq"mb&f#bP 8RD%U%c51f_t Ҥh,_`: #n[tyxE'p.>fğ3BP Ahd!C90E:J=߀8.¢W xp'ES:< Q$|i~nss HtQz=repP>%|+\P Y{r;/T; VT 9dLsxU|c䙲(L<#J2oyQGZ%#N$4B e/n1&f'KN(-Pi6z}}'h$ncx } o"}[' "Q 5tg HcKBSOd+4h,UoyR#<*n4m6Xv ;=ݖC~(-KR P+jxsE,4c},L{Th4#?b"]%-FfA9(Y-DX%o99\1~b(Y YOF “B u4 [*`#szkyJOZS%dgݧE'҉DEIk==C+M O zY~`M,(dڍF`@8<^IUG2@fAie & ezs62wlSf&ekeݡ ƾ4M6ҊE!z i} AEO~C܇wQ;;l9sOF%zIEWee¹4aeٹ& [[7}.o .HMED>zZ@Xhg?%doJ-&$ʤ),"t./ Mבutΰθ۷#ul_:.˶;nCR:%Q]r}J$` oIRtQ/= hVoZ+xzF=htJ7vu\8i4w:)TGJ6I (Cͦ~ $K <^Z2|Yb2םX`8S<tCǝ-v=O"/$w_V2LsK;W9_kC۱ز/k谍.1,ghANQCCÇF84&zkY8#"0iRfA1yfWM5n2xo(B4s*&i]!62fj498#(b]AWz,WzH[j1fzTE!v]`xLTmhdOOdVu75n3`hHA}fFr ק3|z1nm՗CwH4[=3C-rkF|OuyN`fpiFŪhrN [huSޞ[ ,wH xsBb j7LDAH#"OOGT;_d4oT-q;l@S\(KOR⿖F5N܉@ĽX,^YzfMy D<-,!L]3qR)fK.=p쐖إ?n}&ye7=zΧ~z{?4fNy7?chGȝվ| }$fF7R]'\Q0du-ЎӚ =Y3IT %wJGɥ0~#}eg0to/ ox%r,O~_Fۑ .3v|r\ HXrKdsA2Lئ<3RE @3N1{pF9[.#˲ hBP(ĪB^5Ch !ă#xpC nJ݅H,XCzS<:33Jle%87 :ۃ+|e&+\@velQzue ZkYv 8Z1+jiï%:TmmB-o#9yqg"uBjdC⟹?I_+TG%TP|& ȼA110K"fNAE$PGԭꋪC [k KügU:2f I=xfcWfsgqhV1n)f3qwGn0EqC~&Gʈ*Zb~JZͭ淊[ܳ~&E#l})/" aQ4r %"49piM>r>Ф 3<_$5tZ`I WP:̑ ͯF;}[ ET2>⾁MD)eGYDD#GJN+C{4D Zeah1>e^< p_E;Aq8]v񨷬FXMU0B$ءSVGLDR25,H=lx>#[)ͭuq]"nJH1 yQ0 :'FdY1HAPw;ID1O]ځߒ5j;=hbuz`?Snzt4@"_-"V7xk(VN{@4Z5,ġ+6a:fȭ\g&' ^U? f"|=?דl-a7$w㍘+aO;$4ܙv̳H̄.0NmUzt9' %^0K|$H$߁xUI; j%;l~R.Hac2;<+19Ŏtކ|VtiNӴ࡬# w]^]8B;EnE?| gv> 7#f}%aq#Y|Q]O=r'OSHT]FR!rF._hy'՛ۊ(WS(Zv/ǰ->ӁeWa)DDD?׬Dt9%!R Qfء78a{v-P5o q#(.C4K,vnU !#'yvCPioo+S**pMyhU!n"3q/Ϟ'&qכ;jb 1)"S*[["iiNޞE d!`iV"' i4?xbq1ok^FU}4؏ΌfЃ^n/\Р~*"+ n)3XIB `&=|Ao}y <ĨEE5*Jp%oVY'&v 9mLdя&;q yU^9|~r p#>y925`'m+ϚX%ۉSFT"Q#cL x(r9)WL̝OI%;]+f!ŝM$0LM$M6$t;o`D5!$ic$~lOwrI,9bBz !B?؏j矛ccT go8m5>i71wg?##@>=&U$UQ3ASg\UTI&ڷ>삭`iD0HpN9z&=~ڬ#lO/Nc sE4`gt&s6ߋ)⃇{{)L8|G y^l(,<,ֹV?I>A eRSØ5ޘi-Kg=?1`MI 8X}޲8]Cq"p ?+3BNCPrl!IrdQ#C"Ybȋ'fvrz^jggg 5qM.mOhn6ѩ- ަU4T]n7V[o7ۇoKOl|6{&CJ(V0Fox }W/Y3] &nXx#ſP3Ⱍ1MxIebP i3jpܷ:0')z ԧm*~;A.7g|sF5=דaO,ߏ60Oe7ߊZx/Ǽ*p#AÚ~g? T z86H~ V,5 @uVXeZKPjIE%3)L!8@V,e]ݕ=U7έ{w323{!4g#54d "ei4O䗉IψHg$cD7K7TZ[ޭ^BhYFِA\SZ'!+rsTli *], jsӀwL mkGɂئNK^)#[da b 5uf%BN--B_1pbrt72 D}IHȇD[ry6uQ`̡p`Ca99V)Rtid[]BT;ds.)p{>}x777׎ێ99%s[3m-A>-,ɦ0&&rfY6[YuQϫaIuؚjY,jY,)` >IL!#& }6/F7|K< ƾi}m `:0V[['[B>|wf+ܴ&' Zxx^A}YV=%ƭk kYIwvk@lO87:.l9f:322Yc]RB,2ә\k:E:\q@w*6P]E1{kno1S){L>B"Q02+ǂ9.汖1RiY6 xfU5fpt i/kI9סͿosU\P njiE ™!8@)Psp6jֵ*O7&F*VOZ?bEwݰBRÈ'e48@lz}{.]tdd/Gh]n90!AJzvgΔ;wu<;^؟ጊj!)M6XMR1CZn^.O) @n'SSS,SU2|[{=``#G~JJbf$-zNvLb !~qf4_6Ɂ1FmS7+Oa&!B q-`1KIЗ!:||"f54ي]ݛOt!(#E5$i|ZhK,Ϧ%C8#=KψDwr 9nN5҈G&%Y^.-VdoҜ`0WpSYg{Y[үߌGi/ #j\|#W!GM@KKMMb>cCdJ>^=}0b5&`*c.,Hv4t9a{:N;I. elFi9fL|}N-(ڮGb=kb(*#S"k"'O\W]ӚWжF7sއ­`6DyM"#Y/Vp#t 6o䂨*`7(jYiC1f3eD@ b9pAh4A!gR3?G۹Gz H[6''͌ߦ 1Pټsy[|Zq OMLPiU^췧v"s?32Ԩ84 XFэVLFYEWk ^k- ?3ɂ fRFGrX̰5UXXlc>k343Dxy&G+QxD+bIZo^^<0aAS9*=EEkā&9vO[ 2:r6Y-/oݲ9iJ g}I_^i'fJrR$OD$NNa#,\/OoIM䖊;ŏoHUO[0BE=Wjelw$ӗcD~l!}{EwWXI0ӻ|Y0^&e%Zj~}#?&=&?Ap\<%]* H ynLvK+GI(# `8f9 nvD$gDQ9MH:o@#+d0$:+a`Y"2 bA 3*MA].(|j~%#=}߲r'GGq^ĺS^׋idz_8`X \Wu!Ţr]˸сl2Pwz\ #s,}(l~q`2$u.l&$L7iyrr `iwړdZrNdv#%E{Sf&/u~3p0Rb,/Rh| ź&PQ_e )UZ³94>);g5J1V Wvzlj{>d[P暵cpAnaGn]cxMGtJ W.ljJeػixo-My 1geLjIK}0 rrPkUE]q,Rq5%q\'ɅI{3:F{rUͱx/_4m Ź&'<1V :RYM6 >=)\,GԾU؏k֍vzYעx;b8.y`l8CkB1&#羃G/bMPQLpHSk2)wZD1D=L־82Ry#yQ&2:D,^p f %Ѯ5J?_W6qNE,́>=h3[+κ5wibs+}a4k{a[ {ѰmطᝌcX/1l |$Vؿ3;~[z7v0УH N@*P X X8 h (&>4 _ (&>44 a 9u& P8B@)````)``;`?(@# aC8-+б퇮On?|~ui_O~=-Wof?\7%]}[wnU\}}uwnIk~}yל/nuݯ/nuH\s#nu_@ ^"b׵`Ë)y!%\a,9븁۸xfF4 >#<BKf4NZ7/0 endstream endobj 142 0 obj 19157 endobj 143 0 obj << /Type /FontDescriptor /Ascent 1000 /CapHeight 780 /Descent -250 /Flags 32 /FontBBox [-610 -421 804 1223] /FontName /DGLKBS+Monaco /ItalicAngle 0 /StemV 0 /Leading 83 /MaxWidth 606 /XHeight 561 /FontFile2 141 0 R >> endobj 144 0 obj [ 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] endobj 14 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DGLKBS+Monaco /FontDescriptor 143 0 R /Widths 144 0 R /FirstChar 32 /LastChar 126 /Encoding /MacRomanEncoding >> endobj 145 0 obj << /Length 146 0 R /Length1 5372 /Filter /FlateDecode >> stream x8kxՕCOK3#YlY%!3ƓrjL8AJb"vyC ФipJ 0&@)}]%GPv6 ,P6gFv-ѽ{;ڶe{?РnN Qoal-$|nh,no}]9 `~m?rFm(þt`۲mͩfև .ݜܟ}m3ԇ_0[Ϡ*n3 r%h/1,uC5ܼ dӲt^aKZqly-R\i1 -ӧվrȯ /`Wc?K_{@Oh#+AX#c(}L,}0(8(p >hI: $Dl3TT@)iw"|ptCR ImHzF  ~__#ÒaA<>=4ŝ"ӧģ8({#ᨸg+ƺkCkTwGqǵ_-VWw {o_+`' ]ad1S%MXZݮ*1檂@%W^,-J$sŢWwx |˝x!'̱9&%f Tύpj1Q*=BS0 U "a,cfM+J4W'tv/e hsK`fZ R5jnO왤s\$:.$}WD":ŵ!BՁoIJu֭[uʄU_o‰wHi*mォI= z'wUvdn n8r%g۫ Ohߜ3}tQs=l%/rIr/EFH7l&^v'b1(K$R@ I7a(5eH~hex !x9'3Ai.Le1n}I6499u_3 Z5ASS&B'yX )}qNS'. t#+cMH)Rl@J#%UpԗґlmO kwL"莳>:nt4-i._͕uD" ¡ƅio$]@f]ӗܨ1(7t3Dc1O*)T ުF+uwH1t][b4#$k]ΥVƔTƠW( bLI׳CS+i4&oto8 :>e"/Fʹt?f(2v=N+R{:NMNU$^IOtvbI\+?ϧOh|rAо4#v͢!!1^@w\Z5XOБqF8끄ۄ{<6GπGIk#KY\@q?:,dz\r O*9W2f)ak̛gZd R3Et߬{3{G;Fd&U[s#~.g*-kį( *`K(Na"{͸݅r)\NL8\~d=__az:R -碑 I0ȖVSuƆhm^~^^W+%&iچƆƨ`i˼??ES[7W74t,98npG95ݾ@ӺT<=A<;ϻPBѹ'w?*/f(<ޅNÙ!怉afW 3aުZtj|"-Otvf"L-a&.^5b?'A5Sq^6T`;l&vwS-e[*(*TXQ cyy"Hr SRIZYWLDsM )i/|2?so,)س~ʊRYҚ2waF:"}31*;FVf@( 0~K&je옟7v5<9P)A۬FڡZb6#=9 AL=5`edV XKq!;ecv壭N%,fhC_? =QOAq8ž2> endobj 148 0 obj [ 342 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 724 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 682 0 0 0 0 0 0 0 0 0 0 0 0 668 699 0 0 664 422 0 0 0 0 0 342 0 712 687 0 0 0 593 456 ] endobj 8 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GCNFAG+Verdana-Bold /FontDescriptor 147 0 R /Widths 148 0 R /FirstChar 32 /LastChar 116 /Encoding /MacRomanEncoding >> endobj 149 0 obj << /Length 150 0 R /Length1 25484 /Filter /FlateDecode >> stream x |T?|ξdfLd I&! $0lI V **.u_V[J+UK]j+jmkZjZBf~Ϲ}Ffw{s<ڻa2b!;Hkz3^,зXo"]fr} d˺m2ϪءoJ|\ۻEV q5&7-Ck$Oy]k/]ö{mշ܀Wz6,KO[q?d!YDbA:I Qmd1sL 2G3/UO^d_PWĈ'zAsZ*;g k_򏶣dq-@Qy@v`恞;~:`:~HjZ --ºfIfJsf{i)rhT+KbAir,K-MK+-+h+UF+ߪR<2Cy UG:x'^u m> n볃ܪ=)RϚ-7o[Uތ*TPץfT4o~}*KWEt瞫ҫw_Ǯ]dtT77zʾ_؉OO_jJ8Z]}!-u;wvHl),ܵҳzɗ1UJ>wq)]'9qS=qrV' ><7o55ţM~&?='6zbϴyǂǎ|ia=[>G,c; ѝG}%u 8CUZXYDAD)#tHI)s&=l,7wϞtWf_4gVǴ~_m$Imݸz]Jn#۰ [DP]WAI6+KB&u9w+ي[L>)סudCo'$mr%'oFyӛr}sw8'N4'4kAk~ogrޒ{@&={f==sbm= Par6Faֳ_2 ^DӐrryJ@~l^|!73.9_&{wcxa?!^Z/Iw \A--' בJ1>FRm<#.&wrԋ?1N6J/ط>`4|HI1Qy)^ޡA7d4HJa kjѲʡ_zR:F~q3(/qj2=cYhւE,,@`AXAb0ъ-{ #tތcF찯N")Mk<7tڂ?i}G}g2*23LY7fC`n0%%ǜsg@+_l(\Y8Pt[љs&LV p?a FAg(:S&g'В&_wii"2!Ch!Y!YJ3B]˂i~xvFQ1$?_Z>yYte}IQ`wyE nԌX D*1D*#8]mEV?]%R bT~c>ׂrq{v>9Y^POHq՟ +hZ,P,Iw/1S4;EJ2hF5G$#)قl, 4L-fX{ݕZ_4RۑHwG>xzq|ovJ( d|'?8V&~•۫tƢįU6V&>YL]݉= k7ݲޓX^&.`/AiMSSMii"5TbmkyVJ[V漭ͣYYD?(EH҅ѳRL&Xl bS!82̆;H},ѩ.8vy;u+heUE7goPq{+ʫΦޟ8~:5ױɞ=?݉$i8"ڼ32OYVtfԬ溭yfu}sֶ =1*J[f՞X8+L-3ifjLt7gNΚX:vf]J^kʎYYP:8Wjx8AEo,dVKqQܑ>%#I6ήw[}KouBV`~d 21|#؉aVUPE1( (\LOuUUu>'*-[ַ.mxɲ'9 ni[^K}^L TB+uEwtմtF*۱v{[SoshwЗ죋 Ϋp`ggkWo\ktda[jUd@1{ uw'Ex4 .SR"rS ('iVGݢyd#5iP,i 7:ha]g[-JeԲM*[V-H=^ǩp3NC᪮0 +M=7XmSHt?OߢMOmOz敯Mt >Wk5xDOJ>S=S&j)S=3ř)bgVY{R6=.*Y6ITGNb7n'fTǗo߻C0lz]J ? Zu 78m|YPx9xT;iw}O4Op s'Z36PftTL[A,ssm nvaѼfdNYP,J4S$݂P{?E N`iƬ9l(fZhPKɨhǬT0]pRB)rA) 1/Uk O \-qxyK@Wzo{čHRi@ Y5@04d8^턓p4 9 ΠX{o {p2v!>!|Q$Q-GiX4`ڄn$gy$'!SLۍ4"f WQ-q΀榓r3i;HB`7:n2a#q}'pXGURJ }$}Enͳ 7e)=ܐ C{ړ3u;uS`3̇NMLĩFjg_֎ssҽ݋w&%.;^z%ݞ|d֟~x[8i9>AZUx=ZT(&6P;Y۩nجb 1q#E=oif6@SZ"*,BVwv12@au [Y̞H9?RT[kGTFݓs&G6Ym^Y]ż9^[7V7Rh8Z[VjuN3Bj.Jjq:{7( Qq1c?&X~8~pؙZDxԀE+u^ 6d)-D9R(y^leMnz~f[?7dTiEii Ȩ v0grô/!hcS& 3dm& +,)۳p4Z3z [ZPJkǪX`CsiQ Fk#Eu "ˢA՘$b"A Ў }AO)`2Zf´Q;zK]+1DL .ߖ[8&+ִS yHw;0eΊJ_?Ny=4+Nz_l dqM1^oR}jXFMjs:hMde+ NSlS 'МEjسjx1'$,#_J%xSX2g 2>Ri3(w҉l#]tI x;fyK+KJ,jk3>1 +>qJSE˕-3ViaD$UV?U"?mbZk*FWT7M=γ . nmEY))ӲDD\ q>mq |ǚ\cu 1,:-d,3W( cKtUW"O"aӛݛ;T?zYd\?C3s;|ulT3abͨscCuP/NO3_W E?veҀ[hIÐ-  [ iʍ$$ [VdQP_ݎDēS58GC\gI?/~Uxa_<#}~&<i I5U|(Lcˈa"4L6JÕʂʊ:Ĝ 2tJ:Fϭ[ݩ.-q-I ulmvm/R򽦈$fMuBД1YěH*-Vviͭr=&9 x<ޜXUn+D(*)HpyЍ/XN6 S0 FYzi^ VXI- "S0_J7'^~W_e#uMj` 5;IKgm/XUb~jdz ꏖ=U mYް56eҾExsF߷zwuеCq!ӵKUJڼptɣZ=t{ݙU.jt+YI ulF CL u.}<[Z|1Jj-ZP+FTK0(FU :Q-=㓮j[0E_?nkZhoY6&&vUZI>⤧Ola@1e].͞ ȿ2IҦH8-FӚfYK[$M[%rtfZ/uUߒ~~ǘIn!p0)ڹNzp'G]PK$Sj}pecӔw_Mqɍj#oy_WuFw~?m8#Dɫڝ$l23l] ~)Sg39?1O(JHF$37'PE&N5dd<2*ಂ{3z zkz]SuMmskj$͘ϲGg=^]i`k,!m}.[T}Ls D*@Ã#/C'ǰFpD1> HÐl ,gluVGh jJ4dLz߳_>3/ [[?=ώε+;R-u_c'7lܹNxiZzU nK๽ZݿP[0X6xsE%Oħ]Vxy}6IOMvI2 JV{#("/F`@Ax&^' M0zRoF*#I ءl4bIcIc1]SI4MHW([P,@!YIU E^&o "UóPrKCk CE|Kڃ!ELY Tݑ88MoKt'A4 $Lj.XZyt,fIlCV*VTU =wZ&=!l/˔ yba }8"e69*wA f7Ϙ=E~9'運Ae.۟Ӂq݆aM%G_xD/סl Sx`=þFsé#[ r<ԃ;9oL2y+:ֶ&85%caW{Z>o+7hz[ޙ:m%Q& 6TiWk*y!̈́=LaCaN}XN #~ He-fǤ 1?&T./>&c9Gxg^H졽Qvݶwm }>qxa H~m*n+`TpWsy`Cp r i!NډHTs[&XAQ.֝NR|!^sޘ9]4]Fos|Oo&ϦkAbFpqM3tx9b`z&V20pg9̘ S8^s$:^=p/ "|~?SAt~J&|{5 # Jјr adXbuט-ܹL|&ORetIғepsd3>ٲ۫E[b2_ ^+NQ[vqAatq٭sMҍ"cB4J^7.Bь557Fcy]f@@H{3H ƃQ%& I2:4"eσtQU kDFEK\>bri-&-ޞAjG+)1?}˟Wߚ0 F'yumW6[2tTx3ĀjE>Jzed1=΃6>!| <ͪ,dy&:F#W :ԇwc2nW܄)6 Q ]ҘKepvXb[*ʰaCjIhoy[m*Xdo @|J'K6'6wY^\u:xJ7d"HÚf1 z,CaYv*(~Q*:er.ThbF^P U$EP[zi%@N V;Wsoc3þfs-H:2oTd("i%~0u]W֤5gE o86&Ϙa=`#$g:a#>(.9*Wfqt.:PKEZD$pJ%J%5Η:̭VgGʜT՝`|H[=BFGVMi4>Tsfxg!|UrEmJ.<1 jC;/>xJ͊IJ;qcbE.~8P@`CE9v-m[t[C tu.jo|/8UxG$^Z|ҥ4p0 XrUqHH )U5白r@YMevCz%18 `L4FG7=hd=+tJ3s|6e|~LVXPH7ܬDR\]@*JS%!5idxlB~Œn?q~c -.۾{\4T/3(Jj=cC?#pl5W>[LڭOohħM.H7}K`4 }^ciMVݐγUBidA8 J{/h9L C|$ٚɔ-WzVGK2[频GM7g py TՈ2X !&ADBі$2ߐJw>0kJ+Ûg~+F~dc5K[Mx-V`VM744{ɺvVc;Os~J­ͅ9w^QĊu0/lp;5V0lWoMBX7 Y3wKmiEG^ZВO/nAokI~ѹUx=ϿP;n\OkK>jdeL[5I@7 dNol6d!^7񗚉qIZ ͙@mswsvsi ?}p+j&N8ڵ^jaWfJ |eQlK$Qr:^߈ZBdaR֓il}(XDrbX-2qt!s%As#*+e2 ~G}cݯJ̱c*Bj iUZƙZiiZa.m4،ntJvL%5Ae}#/T SBMWA`BEX@E@SLo[U#Vk)5Jҡ(r`BY?8?(p&ODCB~^C%poY&]B;n! *yE[TBKBCԠQM 3 +ɫJ:OiS)UUecrSI/j!QBz bcF3S$!1g:n @7e tC~@"l3}u&l̚7q9\4t`lΗqDz?~D?M7 [Ķrm5kM FҦUU5_Rf AFf̮ ƍ]en ɀ$ã4 >=HC3kf.Hُ4E'Lԣn>[lB* " 9p78A|M0e֞t)$i5q]b]k=kj׌lٵ/@:&p*mI\&>% b20d'Cƿ}lJwb?&/+dV9VM^3uSD^-V aQbL@߮,h3y4zc% ̀҉DMb/?6/@ta&^}CavLB 9}D&^قsD'_YAWimJ7yBRIRK{mVUάuM=YKLZ8̩936g̴X@=QfG{ M  VF#YfT<y⤤-Ihee|Bp)c4b[AEE_GQ*ר 8Uk"=BaVٌ9nAfrJ ΝҳL& =at(+Dˡh hn gN~^Oo)l}Kk-wvTiInVwK>9ޕ榾[JKj67-Q= 2jD܄;%kd(djH PVT)Dd ZFkI,Ge@2_n>Cop=^ >ᓍ/۟)sك&|!d5):6$;Ί gM.n<-ǚ;ޓ\;o~Xͥ(޺Lx13:&372Y5W |$h9bonXFi의F[l26Jq81 bhN,<f(+C\S3\ލ0k'-F2_qN//,WgQWf9"NTuEUBb;>8 ӼG~k6G<)S|-u1U''78!k )hy1fߤ̆@Rq]TpimX=I69U/G;79< bbD@6?J` F,~]NGxrF J] -ΦrV9 >*ogҢb~Y; F &s0\##8W:+ijtfxojt-Sos̻7M9VR7Ι>3{zH0~۩ y[=)H?yF+ȗ2i6{dm^`]mLbݖm~=s;@z7 1;4} b:2.Hs:.WuwN g߻BAiq]:I:,12ކ9FKM- t偼R*ᯣM'&>J.Y>&m͊ 4ڍ6<n*hʆgٝĦY6/Q[ɓ6blieN`q1k3l;a pLm c<V8c~`ewo]K$;xlYؘrN5WLcmdQhMD+2dlY)ez񤒦]^]Mȫ;䞀3Gv=Z^ f&ZGM U.;X4 DFhR_u_+\|Viz<>屹H .WN1Z4/= 2oš ŵwg-A u5'Sm?mLwPvM[S&>F \r%M|zUTp^Ƞ W>lU+'ǞAVK+l`e:)EQjU²_XçANEKgYqUr?CVJ@'kii:c17+Wl1o] )`Z\yXvx>AP47Α!=dzcM3qX뱥\1cw~qq?GpB! "O.- `O *-X~phP+s$F"zOH*㨚I$k :C@i!;{ԑᶿK9FM519yh 'Г6GNNj!4 ;!]6ڜJSLXɖq} a_2ԠpNSjvs71p:oqa:/`˫wvff9A|zttXebZˇH!qc]x‹KL ^C#8,͙gʲ_@iPQ4R,ǣYZJ#2AW ([L}kZ`- 2V_B-{Ni\5@4\JD.%" >h$]ip(-!'Fp]/iIšT`Xok= - C_%mǎ 臽O-|O+@{?LF\ CA$ş9dD2g`@sb4"|@\Y$cp+43Z+-6ΣyL5uRa%SGRiYV:T7_a*RQ4fP)Yq\ )$1 {?fgZOˑgL>ـK3 .f98/u:~IOcW`gq!-Ȕq>c(~aeO $ƶ.x tcn3 KAu񌒝ˆ%3j;|3+#oqtÒê{rcH=fΛ|k(䌛h 6;CŽ]QaǴK af;[:[D;{!I^Zmߋ~M=rHm[Bq bBoet|6ruq9pY7kgtTylu:wWnj'&}. >%#+(sMøL tO^/8сs6I1:ݞOK\Qwd=ͤ/s# 't6x%vKF,a4cdu H|HSFӞ| = B]iZKo|ħ|?߃G(CrrS,4z&M@ݑiFdIF%&D[OI\v 8J~;dа3N~`l;XIFk][ _w@Xȅ9S'ecM~'^5&L {>gڬDMo?̔\+< '260]lMɜ`,84 1:oZIqIWY-R$;]E.$]o(X?UWs&X$Rlr];n<Ԉbכg >!l e/I\܀؅nbu CeG7dGq :&.C[s@ģF&j AL%W.X6ΒayYI"1d<1T\5NJ=.)6gM2AQv= =Awѩ\k6$ -llGegEI]JYlNqVHu?JT0VCa?>X, Eb/as%'FO[6yyDVWM皷 ^uqi9†o @PLHڇ;P8l:>}(l"mc z陴%1squPɦbwgf<- 9Ot2bbTTǛ&Z']G34gП..[ -fVa_%wCv1Lm4{Bg288"$YBތi :2Ɂ; V %a+5,VpWexIÊ4pK/]`rf-w2`Πo6@5uoTPiB_ 9@?'OsR=4xL ɚ(.Jң(F (t+g`2!СHHh"0yiZӄi\dr%hJe&"'Pn,:x{fuϾRi}I*|ZĤb-j&\Ʊu,VME\S{TO&(2O&7u>,\P>dm m[v "FGC{S3z"> endobj 152 0 obj [ 352 394 459 818 0 1076 727 269 454 454 636 818 364 454 364 454 636 636 636 636 636 636 636 636 636 636 454 454 818 818 818 545 1000 684 686 698 771 632 575 775 751 421 455 693 557 843 748 787 603 787 695 684 616 732 684 989 685 615 685 454 0 454 818 636 0 601 623 521 623 596 352 623 633 274 344 592 274 973 633 607 623 623 427 521 394 633 592 818 592 592 525 ] endobj 10 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ROJOQN+Verdana /FontDescriptor 151 0 R /Widths 152 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding >> endobj 153 0 obj << /Length 154 0 R /Length1 2880 /Filter /FlateDecode >> stream xuV}PT? ޺B d% ,6]>jE` BVƤitdc|(V"i?:MjL:mgGgbgyHM/{s}g{|P|Ez!l3'y a[w̆;^ۑh{<(CmGI P.onhYGЎj.<d'lG}նOp>9BHgW"eb" Z@=FFk_+P޽Ѥ)oeʕw:ÑJ*\!ЊP碃чC+-8CM38#ڀ_t@ | I yrM=_O5'sIkYMmIdϭaX1N8团/3͸T/4R1u U0QJSI$R2)-URkMY߁i1GK5LFbK"l" *R$.)^4ںe#V6b6T$k6tvC~vac 2dd2)ӕ:=u5r⭃_η7pGr ކ) [4p%ooqY G,wMxE[VAF?\Y oK";u8 |H@Mn2`<ݰ "kd b+[h!Dڒ+K` b{!8:Q  g\G,3? GU9S @q]*k ̷p+czF&X#&9yr̙.!>.Fg,H\h7z~Fۖcg M[K۽)~ ś$a&IFh3 Iq`0jBۤn5zwI5 HƋ'^Abph#@Qy8m8qU~Ì^GiLR%TҗzoO(Ȧ/H]K9!PapF{&f5G-H/'饊 %`}TԸJ8j07)B3h@$=3KhaA|~^R$?/^"D]R~YQfD,HG5G}~2tփ~f[oyK'S/eg N\z~BEDO:~hn!ǑmΝ;~q%Veosg1x}(h͙$ZI1fv2xK\RĥrFrNMrբ* :B\܈{ηXnL+rȈ (tk~B I"!qBp3%/v/&_i Q .pkA JFdnHKM ܸ07 %"?;9 %u!sl̎O Ȧ.*l5<5hI  7UuULm]-) endstream endobj 154 0 obj 2145 endobj 155 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 894 /Descent -210 /Flags 4 /FontBBox [-495 -303 1446 1001] /FontName /BMHUHA+Verdana /ItalicAngle 0 /StemV 0 /MaxWidth 1521 /XHeight 670 /FontFile2 153 0 R >> endobj 156 0 obj [ 1000 818 818 ] endobj 157 0 obj << /Length 158 0 R /Filter /FlateDecode >> stream x]Ok ~9nIzlYȡh`t;t = ϑ>|h0׸EqA8o]La_3.}"(%#kNO.P7rH>p Un`^Lz5 wK| 1TᚌE2aFFU ut$VQ3u Zxd7"nSP>}U)2oo$p endstream endobj 158 0 obj 224 endobj 68 0 obj << /Type /Font /Subtype /TrueType /BaseFont /BMHUHA+Verdana /FontDescriptor 155 0 R /Widths 156 0 R /FirstChar 33 /LastChar 35 /ToUnicode 157 0 R >> endobj 159 0 obj << /Length 160 0 R /Length1 6408 /Filter /FlateDecode >> stream xY{xTE~w۝N'ޛN:Ny@Ґt GHhB /VM䑁AѕA;zTtoWqFGN%~ ߷7]UT:uwNսYf}2nD`Nkec?/ּ-!Jo窵>(gviǠEMhZ  ݌ԨB< Q,nbx{ 7 rj^!^|C'4i 2MzdT2>4֨񯟹>5 'F[/w^[HBzҋ<~ AQAppS&K <^}Ĺ)C}wKڍDwRp$N`,~+~aq/]*.ͻD6uW8v,WɝrO_ _Fͮ ~% 2 Gx,x,t>'' ֞gì?/bqqp15!5Kn.Hu].$n*IHq - I\!/9\V2]&Q23-HI5FKfh2huzJ1 k@2\7GU**Hw*<ԅ ;44r&j-ql.|'4^.ںEwEV4ʦE84:چܙ`zYnڵg@Kfo>p BEW ?wUᱮ7A~7<ȷ֍\/N*+Ax ´ G?VxB_<įߠrq韖୸7 x%^ nȷ =:.b`؅XbNIA:/Ra< }M)B;4P ѣ(8gr<]@@'Ae}5 ߎ{H͠@΁+}*Fje)u݁fp1G\Zޠ 88PTXfgyܮLI2Ӝ)d͚d1heh <,;)jSHC^=W,?rPh G|\YjWexU*$[eDfIs`1MBr95U.^(؏i97b[@Z[w`sQd6YuP$Ns[]N N(IJO"'za[~y̆9DD ^v~SX ^GAfluWs{ A)|GH>Fa26=ɇ # nl-d~ljbPnF>BCaH [i-9U_@p$n*0p~F Upg?+BFdB2CBpXkTu:O](s LA0FTHHf ߺYt'f.@K38ak"l$Vv9wk59F A#W:GO0׫I9]3G7#EE_1T1R-‚(.1a ۬ (*MVXWfVIqiY8˕R̥]_ӟWZnp$JW/*YSuZ=WrlĞU6yZ+jMO8?2??KΨ0c9W3Q6t) bfkfkgT9kE­)K4e2Ӊя6Zj;Xp2惽kgL/[ z fͳ{M3~25蝥\X%-V[cXJS-,!Cd{L6ߠ:s9}7 3^jn ]vg)j|j&͛=N]c"JCܔO*9]i6.-p.WݪYc먍uuV+2-͐r# iдhjX3صZ{:i;NuG8^%]"2Hܣ,L\3k.LnzgKx^s[=; p\8׬nVe  1}6ט9BC**RNc6pW)#fĹˉ{`@ $K6@t7nskP[f_9jXxu=0P-Nk?7G4 ]z/Y\>NgگJjldbp~\ n brp~UΞm$:7sW&7e?M6cqFK3^Et J*ᙖ#K+)[v*@|1ÿootwGAė"d^&DMIMD$`jQ.yHjDuZSBEEXD;D!P"<'UNle$%P -)j8̦/ ϒ3M5cF}?&ԝ_ e]]qSoOޤd?!c8w?@z|,T͵mosqDy:RSOy^9ɰVS$Q:5FGY&  \N@V(V(QuS%,@1io߳)4*m%CǙ_/ L\9ǬNѩRU%HRoJRS6V˙vGA{4'ʕ:p>vgN1K6^zkҜЄb~yޠykj'3SɗgM XpR1)ɡr\A0] GZmnYmЭZf]T'sv.o5`60jknUf wqZYhV4)?|&7)fR$Ps砀GXcOo]xӹ/pY!ʈi7ZE\!(zVQnFU@3Q _:TB3xiR`{@<*ViaۚۚZAi?M endstream endobj 160 0 obj 4625 endobj 161 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 750 /Descent -210 /Flags 32 /FontBBox [-544 -303 1707 1014] /FontName /PXXYKS+Verdana-Bold /ItalicAngle 0 /StemV 0 /MaxWidth 1777 /XHeight 666 /FontFile2 159 0 R >> endobj 162 0 obj [ 342 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 668 0 588 699 664 422 699 0 342 0 0 342 1058 0 687 699 0 497 593 456 712 0 979 ] endobj 101 0 obj << /Type /Font /Subtype /TrueType /BaseFont /PXXYKS+Verdana-Bold /FontDescriptor 161 0 R /Widths 162 0 R /FirstChar 32 /LastChar 119 /Encoding /MacRomanEncoding >> endobj 163 0 obj << /Length 164 0 R /Length1 5024 /Filter /FlateDecode >> stream xX}xSyϽGW%YWdْŕ6YC{1<`c;v Lbh8PV>qptIiet%q!etm:wi2p]039=_o8^@8L |~pNnznp^=O N xbp?섯3d5P;`7A47M؄& [a?8zQt쁯wlG7'WU‘LR8'. IN0ìJܶ`7Q,|G8 GZuuvG+gafENV5,}#x$K•ȿx+5ǵ]}#qA+iBY[5`,`KqOkoԴOG+gFac*d 45 >dJ|- ?e?>ʡlQ{y4X P*uV2˞WnOre`hZP7-%Q?nS1}X\ab<1V]E, 2nbr*xl6>Fb9bK؝G2m6,딺hl*{uEpY!Ll2e*{MgkZlM,V%MlAe2T+_B%䐣A$Dk;'$:I2JRpay]m>|qyypd E"5E"\΢(鬨6?@^Ztd:]GhObmmz1GS[9o~O(vˋ޴/Z\C>Ropӝ#'<\P X&n^h^>T?&pg QMja eQ:0_cf($iJdp++RF7 !rFM% cKeL @R&JxyX V1LN&U;?Y;2FSlgaF ,vn;7a-:2_wulz%c+6;ϑd[JV<|_×aXxJo:3WA{汕PfKj>[4Ȫ<(rUun_ .$z1mQoH"s4GzcDYtr\/׼&>iǷ|iꨰwՓʵM7ꄽ UBMmmOu:GIt2,Q EWQ(Lͅ4@lƦ04!&Y0F1n0"y޴)P=&̙aܥ t'&it0b05U|2%XM?|Cػf%sfm*[1<kZ]Es&LbQePdVo 8g}0yYtobC%$Z` :1gY)ux"6󌄹1eQBO%́&Q֟a9T|tzKLtDBpPS b-Po~w~>;R|{k²ًoFS}Q轘WuZ(\fـy[_ />nBqCg0 ܄WU<(9mMSA.8IQփO%A{&>|ik?zXeym̱*Kd)fޛ-[joDfob/ zCMtOwSVI뤔/Ifh(݆*výq,=8"m*(P`09 H3B\oRwgv3i!Qj_3%"&CwC Sar|͐$$ B?9;g^N^3wos3m] oQ_kcC7d_H?:&VZڼ7pqR endstream endobj 164 0 obj 3396 endobj 165 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 750 /Descent -210 /Flags 32 /FontBBox [-495 -303 1446 1001] /FontName /TOKGHS+Verdana /ItalicAngle 0 /StemV 0 /MaxWidth 1521 /XHeight 663 /FontFile2 163 0 R >> endobj 166 0 obj [ 454 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 601 0 0 0 0 0 0 0 0 0 0 274 973 633 607 0 0 0 0 0 633 0 0 0 592 ] endobj 11 0 obj << /Type /Font /Subtype /TrueType /BaseFont /TOKGHS+Verdana /FontDescriptor 165 0 R /Widths 166 0 R /FirstChar 58 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 167 0 obj << /Length 168 0 R /Length1 14336 /Filter /FlateDecode >> stream x{ |Uキ^tNg:R$Ih  K$7$@eGpgu0::}|| yVg骺nU={oeH6")s "{/\7"xίB _z@sg 8É:.cjpH-3خg|>z%υ#|J߆]fp銕jNf= C-Bq FS".yΑfl_=Xkԛ?qb -\8rqlw8s<0ֱ{r8{{ȞNGmC}(ay(~?K'r\KccǘGO?w;>@}y}}LX9W.x8{8}xaNpaC+~J8 y_c^=S!];j;wd:zvT9ö#4qǶ[][mwlMZ>d+xfcZǦPC8dc(ӱ* ~GpV6*jVڶ.GlLC]l˸s#'ט1df3 i2&; $}\|>&֦7[zlt1,CdF#Qè~a'FЧ#$LGhEJyCoxiIqQaA~wXn';+3#=-՝r: qlNҊX`q`rZr WLwW~ESOM=b}bY5jPad ckѧ`U UmpG[vk~vE1I[定AǴ%(cfV _v >7'lg° jZ,Z\ m!L-0_:Yay,gqnmf4YcI7@ [k3s՝΀?p@^ {w5/iիn ;Ǭ8i}R.zMKKK\nGuFչ98onURM[Bڗh? =;}ݩM3tUOoF^VjF[O ^-Z\~jAjϴF'縰vqf7<G=sS;9 si Vw߷Ǘ<ç?!Xiq;kzZ{f8=jk{Vxj}s'v5;[rk;.S \aw@jPIa 8މư7AcB5O@]*T~-vska2 h8AMp>/(pRQ= /ja/,T31h#_>wOBbPxt N4 A U,CN@hC; xQ- Ԛج(F#l(nԒ%tHBɀYȅR4hJP6@-a  q'<÷+$lfeSx>ÿ$ hE"DjU;' %÷xKrd5-6 Ml:z<)eTC>_~x0㶸acxk$O5\OjTQ>rQQ*cECio xZP{>r稊Qu(|TIw'G1xR.$LjP=V=y0OgqJzl.,B,pqQ; 8[XP?2؍g\IUSƶ3v$\vzfd/D[Lnh.ݔIM m\¯^@]mc~AJj0V/ !i% | CVj,餸\Zb.-FM[9ej s6, ³l6D7t5qj/J4qYlTL,αY$Xc5L\+}./E$0]XSk`:NFw6hq/M<vw~E'"NMy HDͼŢsU[TE3"F'8)@a/DLSaB0o*u1ȍ$HRlxDt-x*෶~}>ȍ( B\t5Ln _"^cF!pLxs SB.E(#B!Q_*z=}GL@|=Luk,c.ŁOi_9[Y>w}5ٲ#_ݸz xyn7? ,RND$苸h7YK}0!xqF$aK5&`* P(Jc*V]ĵ,MXυ P\(!)#an$&DUoKa@Ş33f NzO߻;cfjz[:2誷[~ۑ WO(9q˶};+}@/?ƁLEkrɮT4yS8$w6[\\Ͱ}} NItGJbf=7Uh*3C"-Xq>2Kp1ꔥͭki'>+][|lTY_513vO >%&%{xWʠ?p ƃFSzC 7/fQrkZkzkپ-J^ ֔Yٜg(K,L+,0:TIZKY,<" #0bw{V3'zb=WxB 6}ހ1| :-U ͊%$&-}_08=i2hZqQIi0HӪPm>؍m-yZ37)y6 _su͖;u֬_tN&ςж8;m,W0|E`y7r<'j nQ   >%NaE#!'sNᲹ2 'ZQg8䭠6CnO~;+wG^q1n$ f^,l,Ӊ@V".Sո&:)/-%湉AV BeE6&Acq=:P8٧LJI8!ّ\&<G;jE®9S uo.xڝXZ0xvIw7|v=́ǝ?{UZv뛁HQ5d",󃝗!HI"0(i#V҂ZnkcBZ! %ޭa@Ԡe3B s@\^DK3"k~73ǹh=- Λ$-Cm"Id96I !MpiK|Be:_M|':D~MXAdZE,;2GŠvl"XwwxD1AZ›>o$qn^~$;y\Eu-S_g2z^Ʌ$&ǢVi992^g;3K-o/E (),)RdjAi{E&NG9}`- JP bX %ɸ,)_IՌ"юf3ERZbWkC}v5Y2:I"%4d=6QX#zh1XFUR'/.M Ho> @3/ 9z'a2/jlaaW0O3#AZݮta",$Hylql [63}D* &,C&: zK-SŃ,ǿ.L+q\ѯ/sg+l/)?tiN1Gb5OSdTHHl3/I e=H#[bS%KfY|/6k}hZMCioXHR`ce+%NDXSXBv^oovccge5{EZIYoX '8gRP_,`:B4RLRSj3eԕrP:CKI݌tqw:,/ɸ_7ZmN8I/75w&)^q?#+>>-f ob7G_}ʶxǒqc3 Ta~6 p ܳA1_)૲'$<]f~⤆󧟜jn+ኗyM>jm&ũ7dVeڸq) ِ&hZgVۥ.bPkIY*%~H:' g7 OpHOZQ&ϪeĀ5L.!)[:h Cr)=t:2~ྪMڏt6<0mG;]>=v5}ؾfSC_u2f`5OK RlfdJ:ĕ"rY-٪KKV:tP9P'<_YtabVJ]ŢC _c;6]~濊':c\xx뒯뤬QZ=Iq׬ ~c'Kܘ4`Ic8d2i:U9%Jz u{ 6ԛO|u Xͭ,69mRkڵOI>wC!M'*eqsu\1>: ]L} kWEY{4. a ]<ܩsȗRn.6͍N3g.*.*eRsȼ|7U.1w%OepȘ?V`QH % =Si?A>D_~9m+~cӟVF߈8v[=Fë9u[[)w\t?LfϢ$>?,?;{vu՟ٍM qJksSM1Xpu(|Rci0qUe͊Y`hYcX Ƌva:k4Xl.j2Y?'̕bh0q{B~lFW?_LW50!ũQ&,]r];{PsbN?eфǚ>|5Os:n#!26]8ntn*+Er]0Fͼ)w6(*b,J(B7p[*| =FO`½wtt@+2a% x&M.SL-]Р4SV*na vqDm$qRP%hiXW{ChWsŜhb=Ng i,n’)( ktnYSp@bdزϢG| -CBɏR]_ 2h01WD H<ˌ…Hca@TL4&Wԑv+Ì*{P&f-M),.3|SAJ"YtJl;m}kx[v{ۻ_l͆;99NKq8]NtN~"of^0x}tgltv897[|ܫ۟#.#guS#ǩa Ad~;w{^40N.DD{r}kaNI lsOWgƴ G+bnT].bMn:uϐoǣ 7dYO.'OR@P `W)k<-0A&1Fu5™ˈ6v|^\ɼb:yFCg)Ϣ)uuxxIY֛[x/ykޏc獁Iu;6n+x#,F-#~RAĕ)ANHZ^t鬴U:k%fiS"C%nɀ%;.r3꭯1 *X=jguxxS1ѝ * '~}ނYl敖۝VdGjFKx}T#MX$AhVET,lVŢ_l;DNX-e* J"u*ZHhS6ȟRz y8(9_ԇOJlVZ~K6pW`,'@M>MIcª™1k\8wk+PXjÆ"MB.W$ +B-H.r1E-"2sqcDňЈAG]ƃuXJz~Q T5U.*3 P_\e6ȻڿWe,R_Lkt6q Wc$.^Pe̸joOm o-]Й9rDKeEH+gKb.[",|&:|k!9:Tlŗ6dN+c &Dw(nŃ&H(R!URX#OIA70e!5f^7Bِ]J+oZfպ{jOԲCHqc5w̫8+2I!<:kmkV5Mf3NAiBNKjE! 7 ]zU׵ѓx_4-&S>;0{ "tſD_x |Wܗ0m2W"o?FU" 9s `X0L> endobj 170 0 obj [ 352 0 459 0 0 1076 0 0 454 454 0 0 364 454 364 0 636 636 636 636 0 636 0 0 636 0 454 0 0 0 0 545 0 683 0 0 766 0 575 0 751 421 0 0 0 843 748 787 0 0 0 684 616 0 0 990 685 0 0 0 0 0 0 0 0 601 623 521 623 596 352 622 633 274 0 587 274 973 633 607 623 0 427 521 394 633 591 818 592 591 ] endobj 31 0 obj << /Type /Font /Subtype /TrueType /BaseFont /LHOQDK+Verdana-Italic /FontDescriptor 169 0 R /Widths 170 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 171 0 obj << /Length 172 0 R /Length1 11184 /Filter /FlateDecode >> stream xz xs9n6$͵ 0#$s@*hLCDEu#*ۧh=j[[V V>%l|7ɼ^3ف V"F RWGaj++nDl7B=E|+B\󪵛{c3ܗH.اDt ]7pktl/>o9-n~?zƞ֭kzƁq,\7ޏF@\!JfZȰ+݀ԋ8DT!/9>ˬ#?kA;?>|lQ1JZ)QIӋ%CZ'm3j&Ho~rW/s8_~[p9Q;Vvء?{8S9t8}0> ۭ+} ڏ鋖7EB1g1lj4FOa?A/=__2Cc| ]z'mJdH7p! B_4$t^CWC6 /^ xq8'nr)wUzqơΡ!Fz#SxTXƫ3lkfВaMM&+wb`v8XULfI2M 3!LLuJT~'*3+D b(]5/_)$EZ&*LQi{jh`6WE E 6DƎ1n i;Oث;ZOx|ti<|޽`R5ҟɣo& 6nH;_wIMUcޮG?Ǿ<}πC<:7-WM|,28+®@>:J_T? #߉a܂o&xnvc ؇mX@q'"/K.CZh7̼~ΣHAԊZq2Nå: <#h Þ=ѧXf<3Ca W]d>o!vy_x }A1A-8f>i5ՑN'{"uA3}+ Yh`z zՖ$"v0Zz;a%_+`u\&AguD튠ݞ3{NhygZac  gg'{ 3^(Nh}5pôTݺ{F7X;j#`d9gy73ZZZ]=mmm,ϨnjjT],J|4ݝk(,k(ky-cA.%|L4FUi s#U3XoDd'n0Y hip@N.Qo*ȇ(RQ~[*^6A|wvl?.>WOIECG^363yLM?5s}?Z,W7H%OXDߞ՛k @a?9t^t(mO.ۭckeaQbnNyI6 }܅nuTp M>j1YFByl¼Y@c/L$2'׍dcopC7h[ͱn-5lrǀÀj/F Gp'LGl"M0\P"w ;ӹGe  C4? 0^Un+1vHU:\7r7ܜ0f"?PXKȟa`{o;6/ܳ3;vC8w_4r]o/=}q2/ovAh8)R!_6DQ6<ў4ΐSfʌeւy3uy36nUr3b(qϚN+99Y)R`6SG*Uf&B&l m!{\P(*RhJ:AXRid6U9㢷91{:yIk_6-늲@VEnhyffeIU&oojܑ<^2?S0/?z`S93Xfޙ{nGn v hu~y u6żV1o6Fs̘y^%l>cYhXf A2 [>^'Y>P'/"I*!6̞0zmkˇ[ md_88D&?xd  ~uQgls>S.mzqmn\؜Z, GSS o0X=)h+VbwyC,n6\x`q"d źfQ^"YrO. 2;^<LEg&e^y8] q^be0EE|2-~6D "w„d`ح%B_#t-:~p^ sC op0,A :={n9/4jȤ0Ga}!\@shcm8C$&d4̬_b01!BCT5' r * HS`F0q0 (mԴT#把)ӏh#Z~kʎ^ݪzHЩI_6ߏׂ{pc3bV/8>sxd刪)bDE3 BOnFdL:h*+)F*ϵɟkx~7NMx =5 k0Uu6 LQ 1bCPn\(GQA^Qcl0D8@hs&]h#JgYnp4kD,#H`8Y0V)3@0 )jt08 D%f0兄V% -/0Ln&;&܀ $xQke~wvg[Z?aӃڲIO* *J~gKJ &C=Go{X&~ H@l`KM *W^/ IOyKjK:w_51mv:X̲(K4$1 $rmnݘ5h!mX q)iFUP1UMB' 'JP'(Fܻy?p1ă}g ahUjL=n:s..+U'qm7r7&ؐџmS3M5[|ǃә3y8E6Gq'x(ZшPF|@՗(vu. wV8m?l_V=d6'SKɷ_=$Mb1oVT}9LTVZv8O_nP:=TxXPY"9`BVArd,qJ?SODEO9eC~ 6VD-Ujei!c6l,|vodx[峿y;kS ǓwTkg9qΤS?rhgC!J v;d-&O|Ra&j<0,vo:c;fi2h?n( qȉ"{$z.9٤hv V"^:6A(hPNLLrҷMv/`&b#̚"Ȟ,ǜ78l+ !?Frf5ԕ`MP6ӈu ܀ *"FK0h>p- {T}f5?kMvj_hyw[8`N4黤Fv,jag8sMŴɷ%zTk!d9F33"i򀀈!&I!Ͽj73[/ٮR1Đ׈IE|sYU/4tz0̩zie=38Vw߽;Yʼn8>!Ht9 gSvP 71'և?4B v}'h;b~exOlAf hr\."GqQ9* ,Pm+twpv;6we9Eoڧϒ7qt߼F$zo#^=͡w?2&Q!lM zKI=mήxۮO6- @9)J\B*A eMx4ȃƗxBHĹrlqNc|jRg F7VCx1$2A`c 12P""3Gs&IYen! gdp={& 5-k8|4פ/xm-n>vbTv_%v#ӄ:~rҬ6G]HG7Y'HLww~}[L'A)HV%yD9G"|z endstream endobj 172 0 obj 8305 endobj 173 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 742 /Descent -210 /Flags 32 /FontBBox [-544 -303 1707 1014] /FontName /QXHJLY+Verdana-Bold /ItalicAngle 0 /StemV 0 /MaxWidth 1777 /XHeight 666 /FontFile2 171 0 R >> endobj 174 0 obj [ 342 0 0 0 0 0 0 0 0 0 0 0 0 0 361 0 0 711 711 711 711 711 0 0 0 0 0 0 0 0 0 0 0 776 762 0 830 0 650 811 837 0 0 0 0 948 0 850 733 0 0 710 682 0 0 1128 0 737 0 0 0 0 0 0 0 668 699 588 0 664 422 699 712 342 0 671 342 1058 712 687 699 0 497 593 456 712 650 0 0 651 ] endobj 13 0 obj << /Type /Font /Subtype /TrueType /BaseFont /QXHJLY+Verdana-Bold /FontDescriptor 173 0 R /Widths 174 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 175 0 obj << /Length 176 0 R /Length1 9688 /Filter /FlateDecode >> stream xz |U{uuUU}ӝ:IHAK9DPLC5tD%(jt曝cqVgDB:Yw}λ_*7nEF4hXݏX OWܴo3=Ῥ_.b[Wݶ26n=W /탎x}6o=k7H u7'GBۻ{]o|~F 6's؛<x'ClA,0:-,c=+%~Z(T|wߡN>-?}R'NF? C #|!M>7o@ՀWI2_|'_ģ?c Ծޠw $rɻ!jC,a#zK/`;\sA(ow@j Т';ɮ\}͚+[rsv%3Ȱ^%M6=&WrL2YmvEF( FNi5"LEˠRARA* ƂPUS7@ehleQ9/7pڄڪ6 eku44%Z4EQt@oi2{((5]c8 &8.ZGijmvDH{HgM6w=ٽzS__;٧~ʼnW]E Aܤlr^qH $O׊ I{wZT=3%ou݌桷p1Vt.-SoP'R+JKCEiyJnNvVfFiwJ+۬h18)p|S>#?Nv;JgE[ߞ4vߴӮD=Zﯩ% O("`|)q5䚞HިhQ5^}~jV*G)ěVPu$"P0bfk`VQ&Q;7>LD#ӽ=JwRGQ-Re`_-sC; m2-~jw5.*)xa97=\Z%Ëگ9<ﰦjT]<<r5ukzΦMtf z{6zMTm Iv$`F"krw>I@GԠ1F(ji$-G+ 28?l8pD!~`>2<\G&xi.6G1?#}pO8xy5& jkykhq{NmPqˁ `a#ROT}>T\o{rH *@q,&#S#W_8h.#g^N[]_e;xVN)P4$0WDq( k7-l _xORᄈEATE*~ZDȻi S5ꎎ|`Qg=NQg4 =iW\kh[^N؏ c7H`YCls!ɨmB{yLg(̜eoc8NW|T( /77ld`W ~DRGg' 0A]&% )X"ݪD FBx!^7` ^(,ʏ oas}pQ8#g'F0RO @t0|HP!C,_Oep44\ٜb7fh#y 9i&ϔ!iܱ١GbϦ<xQ)ey(~;eQQp((~VJX;P]u[(Kܮ 溺. $S \RJ3/B^atfs/o؅Myׯ6`>po2:5E=U Ӎ!i6ϖ&󭹫mr<3LNz}\7}2پ+  M&( ȋ5OqZ Y@rBO6֥ r쫺GI3J<1+ORߵu?5ke鸱tNj7% = P֨MBH_P 5͞f@OM&FϦ2k*|trVӘ#TU75 B@9=3+*)$| <-dxt96o;whaWsr\^S)[uъ= 9#7#8/MxM]ش/l>0<1";ư[<+L.kӀ;tO-%z·C;X+uM\kӭnnԁ)~`01vP4)A/zIJjՋe2d1bd%*Jp:)4^' S; wnqb||\q~J/P(ܑi>ť6xoUlWN7=jcv=hu)C'A :46X0gAƧRt&`Au0;SAMnWZ0t!NpӂͅyqPO>*Y7 </%@%*@zWp6c R7ISئU_>d=/n7 WuY]lv]7v%{i>9}A4\7Wbp]]z-9 R&eܓxu~m^eGÛ-Rv3J4QJT̕Nirԫ"mV":%I4GylG>;k:(b+b yX}ӱ 7nY{ym/9WO`yuNgeyY;Z^?]]{4% 6=º %n23kzUB0< XB2x$~.:8RzaB'FcEI(T67Lɏ0 AOո 4冉qjUb;L9T,.6/6z: j 26eYqf&KYVqE4=tȸ`(|Q[l*;[7BQ' A&B%NQ#Ik3KA 5|tKH^iѕ֖nM]Y쇎Z!bqg,.a,+g(n 7TIby H܁rJ\V:f?O\nQ,MK yl:DT bQL:j8@t !a z9E:HNɽMf/)pf rB)"=ĥ ̄S_Egw]j[1]Y>{:T.^ ->V;__c'v] BILm۳=cV"ʯ7,3njNAp3i4CR0WiX{$"qrg6;+{{;cOŎ8[=v?o4%Ma.Ks'xen%u03A/V8/j~q{>1Rx~Q#@Q2mb8bȈ[B1YM͸~ǘ[s:ReKE-UԳ'{f$ZPJo&;lZwߛ9c)JFQ2 ﵦJfѕI3RL1f]XiCH$ӐyQ"On-mev.%x@,m!`%bSM:d.ŎVkcuIO678&cӲpi hz<Ḧr\ Ʀ$͌~/:3Xz;eYGEaUJ\_ʶVIfYtwNVGr$,{T*TbiZzltDnaxڧ#8?% _hLe{7I Y<UO7imS9'#Nnn2v{ԉq16)%AkEuCiφVM(m5LHMZ>Zrѹ+mykBdVXYC6-TPŢ`!o3lso L3lZ)%"fa㩢M8eLvRtZd""Ӯ~'($U@*ˏ팏`98~.)0D kצ0c?ȥ>w֬і{rm-)P=OSm)Iജ IpX_Rc sE} yzRC2&NX*DT̛!=AG peP"sZ Aef/ iIS8e!;6\1e17ziz4)%/6Nos\zon˶6VHY'|4  7  uy bz~_6nZ1uwߠ>xk>=[xTD.?%Cգ4&ݤ-B-ki @Q}kMsuʒލ=7% endstream endobj 176 0 obj 7154 endobj 177 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 738 /Descent -210 /Flags 32 /FontBBox [-544 -303 1707 1014] /FontName /FSCPDW+Verdana-Bold /ItalicAngle 0 /StemV 0 /MaxWidth 1777 /XHeight 666 /FontFile2 175 0 R >> endobj 178 0 obj [ 342 0 0 0 0 0 0 0 0 0 0 0 0 0 361 0 0 711 711 711 711 711 711 0 0 0 0 0 0 0 0 0 0 776 0 724 0 0 650 0 837 0 0 0 0 0 0 0 733 0 0 710 682 0 0 0 0 737 0 0 0 0 0 0 0 668 0 588 699 664 0 699 712 342 0 671 342 1058 712 687 699 0 497 593 456 712 ] endobj 12 0 obj << /Type /Font /Subtype /TrueType /BaseFont /FSCPDW+Verdana-Bold /FontDescriptor 177 0 R /Widths 178 0 R /FirstChar 32 /LastChar 117 /Encoding /MacRomanEncoding >> endobj 179 0 obj << /Length 180 0 R /Length1 11500 /Filter /FlateDecode >> stream xz |Uキ^tNw:K'taI* t @؛%,`EQq|6A1㌂OquFg:wn'URUw{9˗vB1H5b.8~:{'BМu~%B\x΂UBjm+p.n:.}rn?ph♃ k|?E gZlyr -5x=nB)C\Je_AЯ!Uh|!d4#D8X?GiltoU{Ǐ/߽߮<ڷ[0->sURtBG6)nX牶'zO(_$/nۥ(O=yѶ$'Tr(bH;:9wr۽*iПbMullal;mߖiVi mQ{$ٶnbڒmfuKm3ʖaËo26mggS6*δJx}Z#+چkkn -oemx-1!2ɘmg{tYzwΕOs}MgMN&$&i-ZɬFӈjI * rFo=*G5HqG^,Fal><$*rN!^r $ 2Awc{ 'lg"w$BaxEʰ2iIqQ ?;$7ǓNw9v[jJ5)1g6 ^HjQ%rp$?QXGs`=zI YoH)?^O sYYE|U_ S#n7 $6Il *lTJlG$ur:7QKP׆8V Ձ#9#Az"ʶ U :oi.BpY#|eD>7F6{d4#Ѵ9Z5EV#IA {aάZP謂e;4M]1 D (sV;0N]~477'ػc`TW3͡SNM[p˼V:<{Yn-vi; +#J]`ꪚ/6j7z*AjZ-iQL{Mjrͥ0u,v 9je[AKt[Z[t[D;j;ӿa.; ᭵M lF7G`;.P=0ګU&& ,59Tll:(!ᖂ,*,m= zl4P'>՞zڳjϵۃNPS1QxS,/ݳ#&JCXZR{`Xţ^{E[x;ލy{Q5_NM^A5¹} 5Q'RR'Q9= R~+0b W nv4n fl<0}pm<_}\##CfIբ QGQBG2JAJ4D.>x;vA 𷯢p!~ 7,gƽWgIsDjzd^ҔjnjuHZ~"@LT'Q?|!?ap6pGz1=|,+) }np3^gfxY*KHB^brz[Pyy~nN7)*4K|q<xg6ZHޙ)˧5_OK1sVxh.\w> N۬FxG` Q(glliZ%/1MH`:qfnY4X IF/$Zmҥi`:/W7@^ڻxZ0/Go'"NL{;D] "r yyEg2{<"vb"F'U8o dEo;2! ;Jl"O}A_p5W"ðjIf(ij6mf+YV-y\Ph89 CߣkCzJ.Ō#ǜ(븜dGwr*QpʏE0̒84 Æe]ּKd]]r1BR)JZ͔}EPkRtY-"UZ ّ VEpC^BǃЕuA]|}kUzGeeiP|ǪGs_Yq:־:oß1wv޼qتR.d#&t !4ٸ8+9DH qu }ŲQPA_zl UnX'R˄Sw.!6yX8 n||ŝK>sq~CnkMGPn bXQ'%168,)_KU"Rӥ\bfoWÒuzY2Q"0b\)Y:7*A3]Q*<刚w$2S8-p+ `S,DmQ9nkwxѷ_'UBY+/2é'o\=(UWjO^l^%pvdx V.IQHqu)!v8DX BVZk ZYնְY²*i'mcfPdOb JAmAe? {P3f MRc*iEmRg>i Mڵpi.pDpῨ9b$gCϓ1;?eӻM075SOՍ~LhSΌ}wa??xwudλ#oME[c81w(%UamQ'pAPT~[q#_@+DUbUX fw޼}vZ08/%@b:[0]hdReONÞΞ~4] mW͉K c⪼uٳWdKH-J-JM/4 +˲)7+Ēx?;ٗ\$'jpVV\Pc3IXz. 1tx8.ݰaK/raA' .p@5 w f̙$%Ϸ~Җ;-Unl:ѬSDgMXR7zD!yhvpݖe~7hԖXݛvX[0_0_@cpRݦẲkb1Z*}ȴ"nMAtF,tvj$ [*R!q+U&siP,9sU~b, |fˠUƱ94Jmi>8<1ÏG(-m_:ɛv+A?w*oF o;3rɾOe¾i`ō  hwꌀrz}VMp Tj` tŢ7RH&̘҈]3Ȓòڔ}|}N~Il]bAqs򜶎7yq)ўj-ejq2eLҘylX2F鈹Nb7lrM*i ydމsȝ'4$.ľ秪.&z˒3=:yj<nɠb}V>8cm _lj;2tW1ˊsW=17qk?m s NG[c'7PĮ.f*Q֙5! W,bQeH٧"p%bq[LژVR/~_Ke\7L*gqM,fNpl?[qjI<{}Y#eԎ$LL2rg߈o=!4a oSz bK|*dw6+ +8̫$MI5h'aEC"=-zޞK#AH'$铰>opk--MLJ,<qXRZJ/3{|Ժ2"|i)Rcl, jyYtYcdW7g{φ]aUWggqƵ{WF6/[ۧ,">3-h-g a'k=:;.ɘf,UEƀ d#FFٸ6n0iƢXdY g 3dRi(ij~ Wg*Ukq=Qc}ղKY6gw4<1ƣ.œ]:p_n +)] _p_Mb[آ'?8$?;{q`FUOĆys8^w7׌=ݾbcuXDiLf;Zb65Q[eΊk[[J%@;1kƘfsI6rh6 04: !ɚTf8c3Pkw >8׃+EAu>Q5 m|8u9aCdו]øtaa,U =: 08U,V(|̄&a>,ouS&lWXLsT4qn]W`6Y _oWi0SiIHO5²dŒl{&bjP=# {VkO ls('ԄVV+3@@ z/_Pu)A_o 47d-.e4J]M>Y]R-mZbV;KP㎏c[eJ3*Yθj<4#S^0}D2SUc1BX6@je YExHp~$%uNƬj$Q ˪H=YD  f ecڎzw5"QN?BE9@ 7T  ̀Ę?6E#wrܱO> endobj 182 0 obj [ 352 0 0 0 0 0 0 0 454 454 0 0 364 454 0 0 0 636 636 636 636 0 0 0 0 0 454 0 0 0 0 0 0 0 0 698 766 0 575 0 751 0 0 0 0 843 0 0 0 0 0 684 616 0 0 990 0 0 0 0 0 0 0 0 0 601 623 521 623 596 352 622 633 274 0 587 274 973 633 607 623 0 427 521 394 633 0 0 0 591 ] endobj 42 0 obj << /Type /Font /Subtype /TrueType /BaseFont /XPVTNF+Verdana-Italic /FontDescriptor 181 0 R /Widths 182 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 183 0 obj << /Length 184 0 R /Length1 12636 /Filter /FlateDecode >> stream x{ |SUZNi6IwZRڦВM_ h@ JP3Q:x3C(EXAƹΈ:9O(2 CR0wnZ{흵[iڛ!-ڂX$/]ً!F}nE?wj͟FbJ[F(ֽKip-Kٽos:j};7$m )'WvudEowx=Ju(B =L G 2"?#ԏjq쥧ݫW$o -QfT)q^2#r`^qq=(n|t0:Gs }&^ņyyLKxqY3?2w\f֜dn7gkj7s34*`1W=\M0GO0Ptq%R.P:+ s~Tz={PVCGp=+ICnmaZ#.ɣ̲$wUcm)el2d&;˶mMrn7l542v߹e떁]޺{cXfXZ7J2j>ݯo3ɿc0r磝a!.KTp$.b\tܖJ:9RYa\Llqp&Zl^Sf绐u/\c!z$\!{$b =rt,5Byyްױ^ֽ0nj.XsIn3a?C~!h^:?+0:Fh?Vt_]xhz;u؍HIt=^[%+BGћ8-c DZ$^w"*@`Q֡m0x&UA_+E=NLxY&z xvósQ>mBw'Q&=c/p0ԇ>'_?aÊ@[ R#ğ$r-xK/{~͔eIY.K٤ӂLlVٽ]-,uz<nuGq.Z۾ }Q&|z@xk=Irl]nWF(}`d]CFçvu^e; L7H<\ȧ䄞ɽ8{kᩫCTӶ3⌚Z53M36}dwWIsǎ裳&1Pرѱshtq [ᎢVPNNgO:gL!sHFK2Mi (Aݱɝ-cwRkX'/f-hsH-s >x`΂#m fj: LܶOD߁c^%6lmy>9o@~/Z=N,:N@6,i$pDݜ.U˨UKhވ0h?7^Q tqڇn`s4?mpH@Mok@Xq42HK:T$Ȅ( YP2("beA;Cǻ~e|1k`TwO^y,V'mj)]ڐ6ۣkL1մ70c 29 ճ X4\&g\l0hZ uZֻ eYVk42aB>5kX$y9M*< ::g?s"%g|b_AXqO *eee%&Wy]\5;kR{=ZR_:+9cyV`VSi*.+\!AWoIkIot-f#\_(3-NY䌤.N[v LKk{>S??= V!2iBPd` 34MI j¢=6-Ŧ%8mhBțl6 C+ /D9c)vdrpL AV @{{.Wpdw,|kzƙ5aΗ2tKYڟ{6 [=mC 8V!yF?Oϫ,3JM:KMFn5afrf/pKtJf ¼&41\:F35IjR9G\ (OyIS bTd` ɣACd?f<1L3~?Hr?4W?VQEͦ` l%Tl7=-YyjqiM5?l|>u}pg’-M xfRoɴYL0]7mf^x5S'i+պ2ݕMeKީE 7;A^W#Hp:.SW\kvjk<,@h0ϳ*5z20*-"ɄN=œ[-Tj2ڗ܁8+X!Dd-y8O tZBBo#D"A%T+"~^`W+6WTL.ۍ1nć#k.SDŽʙCė^#SḷbŎ nlrZt>J l!ִ@#niiFC+Kb k xUk!¡M%/d*)ˉq!SϢf՛JeV/X X-ʔ U"%,ƺ7|p˷;n|fF]shKI΅qֱ!չ|J+56>'3f,Yk<~KA>@ V Um0,FߒĹ.AS[aQ A&."+]MDfhU# ra*5E9b\:8'?e.8jxPq?f`6g=뢱~* 1u (2ȫU,XtpVt;܁8ѹC+9.2F$2gAgɺV+Б7諀P`"|)me@(xP~v 8&X1 V+ Y0 f1SRg>?μOƆc׽)%֪kXfP"QŨTTJ0&!B;Q 7΍" L@c=L"Q"Dр ,@(3} * 3cZ0SsJxa┹uӚxq|߶‘?ݲ'6s8'57̟,,xj{L3kdjAvA~"-BL"fptlg[䬑X:E+O̵g2b񚤀,I36&չrjۘ3 ^̵ܹun3{%Yo,I`ɑ˥ OViqG`{Z0H,Y|Z'`. @,c\RĢ&c.jt /+F3 @Rȏ)}1ߧD(c`˩ xca&K=Q23HS03%_W \U@%cUnW )b+eB(xA7U,U"#Eݯ`i*̍/*JEπ"/€PA<d~1儕F'8}Wa%Xg` 6 `̝?=|?~plm-gHŠnҸ (rVySV/+ 蹐ү+XH[Sxz75#Vdc2ŖTjE5$r2\yRJ'L-@i$~#37D Jx:{2nlVI @0QH#:AOɺ&95rjhȫwhhd (z@0 " 筥WLRYMStTa83ib_ $܂He`_5CaMt)0v4%47V/[/j:ܩ.}r/kguݼMUd׉.,ti\{1'CfҞU4\[; +G?gn3Lp>ߖi)k-v֯:}h j9d%^I]M&;%`DM$G\]7UW^ÅtV[#ynSW\*+)k4Aj=x w&@n*TwAuA CH ٱLa4ST>63o6o$% "D}4X(=W+8qJw[d_O`O߻ZƹEE ^-Å 2Z]}tJf!0{E^᠒ٝhijVOMND,1A' ]a<`BzYg,ۈD=CtDBUB3Q]h`N];RHb"V@*Ģ4&Y"V,U1~&5kV7s .IIߕt}YY+s5 G^raUҴ)ER(if~uAh! l=xcMc͕9Ȃ|,JȬnt `YLA694J0!+@9sFKNn0i>5n1X].XzbuX'^^Άܢ9 $f,G6؂`fIFDl#dd<hq]K hv\ F!o"Q(QYq3@@KMG_ѐ'(UnCuRbv6)yNԔZj+xlOYjܼ=;?o˿,g!@J<&'Z)gX~ K{rŪ $rԒWEOczc9h+a G)'qȧ+>"Q~$0X lp[aҥ,L9zh?ȑ]ksߓX Cq1.]!4ff% k*J TDW*(Uje˹T6 5Fd:X~~(bX?Qj_iVM_]IlR1 `P1B)v cUؑM۹R%=^qy0:/~``ˀQf@E!0s{]`"2JhG?D'f*@$IЎR,%i0 9fyIIygUp+-ULxlLB*,* [ { ?BbⓉ9(Si4sh@M4+"So죋a4fiR аW0R,@ %1fFAEzJO*@V.<k-1(V;PO|I2Ёte#kg e rD(j%'@"Dl bF7*bT:kY-ZXN!"lҵ~h?a[**=`67mQ"gw;\«$p޿z0?y ^xc̅ĩ_B8 2х\gBp)Wu&T*5("[יPDK(JHL1w# KcXjj kM4%dZ"> - UH3*(q:ca05ԱCCT_`Y: rUDC+%&3 Tarx)'`4h;-q90PșSj`R\ \2W.țD۸d_|Ǟ'z`̤7q%6Koywxm@H |4C*f*Zg^a9UjeAh-cqzT:7cA9I% Ѡj^TDT 0%4YT  7X# y&b49G nP;0!_M+hjqVk|nܰLt}]nyc;vz<Ժ(S9Ms?n ~D}El{-Şk!0aقtF _p5j/)m9,hUKEKh7PP"R7&:)HDM7PR<H"cLbLDEceת[ާ'RsϹ/xطvXFrZgY,UfVK33<5*[˿ز77vVOq jӔ|L!HæK2<9 @c˵u^MkW76~}[AZ;`/Ut5t&C%?ѣD6 FBZTd&bUЅ1 VVw@J&ȫR'7?;X?&6]^0L~z,m-lc3{a_m[r0:m>:D"Lpo֐6$@|O-}buWED0;m*/Fs_7Z~sF_A̩l5l)C3W;2_R?XFy?PQ% ԀQ Zf9( 7/`.oԴ[ endstream endobj 184 0 obj 8534 endobj 185 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 738 /Descent -210 /Flags 32 /FontBBox [-495 -303 1446 1001] /FontName /FSCPDW+Verdana /ItalicAngle 0 /StemV 0 /MaxWidth 1521 /XHeight 663 /FontFile2 183 0 R >> endobj 186 0 obj [ 352 0 0 0 0 0 0 0 0 0 0 0 0 0 364 0 0 636 636 636 636 636 0 0 0 0 0 0 0 0 0 0 0 684 0 698 0 0 575 0 751 0 0 0 0 0 0 0 603 0 0 684 616 0 0 0 0 615 0 0 0 0 0 0 0 601 0 521 623 596 352 623 633 274 0 592 274 973 633 607 623 0 427 521 394 633 ] endobj 9 0 obj << /Type /Font /Subtype /TrueType /BaseFont /FSCPDW+Verdana /FontDescriptor 185 0 R /Widths 186 0 R /FirstChar 32 /LastChar 117 /Encoding /MacRomanEncoding >> endobj 187 0 obj << /Length 188 0 R /Length1 6020 /Filter /FlateDecode >> stream xX{xEi3I21Ld`^aH4$$IH`̃! Y^dWCQYīª-CcDX"W]W5ȧ=˟:wYHz%+[|)[Zn]V[O+[{Wl'!cik{BGסw@GB^h:V]Еk*􌕭ǟ֕K5k,hKFu8(-G h9R ȅL5~΋qՇ~I3_o}P.N~뚱'4O(J*X!q]'hW0H}n'u}wO=w גSB d^Cs'ٺVv~c+ YUnJ/lIٲ`:[cgB}nig=>/ֳ^__Ȯ/^t*?`d?ۺ/ϸ*UY~s%c{۽{= ~iMKi~d%ޚ$[.~Sٳg=޶{;/BeDZ.g;CoKoԆQHZ 盍l9udsk9e\Vfibfv5mJKe~^?Y@֝ SaA=TP'fX`9`X@ӧ& #'' oJ NaQx}PN[oV;| CZÉD&`ppAt*ժBV# 0`DjxqFhv~1וn}p]c'iH s8w6E"rk5kd(S;Z#*z!a0Ӿ`RRDHo x!|H +B<#P@y gl 4 qzx&'#w߱"Yn%D^5qG=yLa|ZZSqlAc~#,j(0j]-F;]\Mƫ-2x3q& ) JE*FjI/"oĜG&7,fkq]b׫X#55˱MY,qCݛ7ؖ~ s̝;͟[7pೊ m| 2z+y`$ "z0zV5$t1 h ICXAQJd2 NڠqP׍:+DPp7s BQd |x~sꜙWOQ\L_jk(he,,cbΧ3BXQ+KQ%436XZ`lN;-rWszsF'-5Y2Zۖddik)H%|)s$Ax^SDPQV-5UKbeA4dfB&C>-~KJ6Ϩ) dzdpL6aA1C. /{[4czhחuN,F(~~͆'JgZv=a3ر I;5˦r59b<5֔2\ pI,^YZTlNM'E8ߘOsT*C,TRPr V)Ș c!s&|P33 _E _9ax\)@X &`5a GfDG&KZDpƣXVV?eFuY ZܙW^X\gیOMW.>)_{+"iՓs:kkeɇllЌIyS/Z:[䞂OKCeVQ5%"JMy;Hnr]~Yhw<&'HURˉ,_y-r/xiu$2쇦>b.}k?a}r~tlv;p]ϽGWOo}'_ t!W%oYO\ҝckwMdNU>ڪr^HPl.[]Ξ,+hd#)uixS6oLwWs\U@6MN @M Vmr*hcim%8dnQjhlI-2co9S!\!٘nRfմpQwq:skȋp*oX4͵"__Q:PfӱSݫ7k@(fڔ,oɉ/ጲk/>{›?qe$K.# @)^DOl/Q*6hA QO IETJ?ɑF@N 5٢^ Vv^G?Iɠ'~S]kxJHm|NE7%/ǀP,;.bB~ē:cR 9V[y#tnUGs^ɜdV%T 6@-HkRt}2 צrRAIWA*Уݩ|LJeM,}I68SgKs& \bR*]~@ p5]ۚr˜Ï&A  Rtٔǫb_y4 N3N9SO}wblw;G,*_ϝ.m2# SP U!.Lԑ/Ҩѹ`Z endstream endobj 188 0 obj 4491 endobj 189 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 750 /Descent -210 /Flags 32 /FontBBox [-495 -303 1446 1001] /FontName /HCEQPX+Verdana /ItalicAngle 0 /StemV 0 /MaxWidth 1521 /XHeight 663 /FontFile2 187 0 R >> endobj 190 0 obj [ 352 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 636 636 636 636 636 636 636 636 636 636 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 352 0 0 0 0 0 0 0 0 607 ] endobj 15 0 obj << /Type /Font /Subtype /TrueType /BaseFont /HCEQPX+Verdana /FontDescriptor 189 0 R /Widths 190 0 R /FirstChar 32 /LastChar 111 /Encoding /MacRomanEncoding >> endobj 191 0 obj << /Length 192 0 R /Length1 8428 /Filter /FlateDecode >> stream x9 tTյd$3IHI2@r!`I$08!  )>)_wֻ3={ܵ׵"D RW4#1yxֵmAcq+m!'lԶ&ӟAȋڠ# X{[mw(._<2n:+nY [V&ཿ2}嚵#6(nǀ#%Ʈ@ih!PA2R<^s.;7Y'_DQ_ʋxCSV7$xhjL|tg~DȠ^R (Ȧ>io)g! H/C  =z(C^凇C{==NXOrg'Su)}{ʽ{} ڋB "it4zS)b=UWD%q0 /=?ޞ/{P5k׬YC+Iti})Oh=_G^xB<(^Z@x2x )WkUmF~~_߻RZ/C:k$_~H|7ކ;q^Wux Vq3n|+VYG'؋Sc6,8$"m! :.yCHn_/zգzG|=oO؃`λ#q#wL'ex'I.$ĎofN@OW;L|c|#'mhz*s(5r!ub݄…y19٣2 WIOKJq'$MZ&AcQ.AS5䍴G}g2- ϷRNN;j{V9r>TQ%ű#*8i&4Ie?$RrW|AEGh(rQU#WLzTD&$rv0]1ˁtIf]!Bp/ %q)vyrtuRFbASiA}i!&3V-XRga]=@76A/YRYv`mmt9}9q/fwvokG}Py^nd4;KY%ⲴYժziiߠ#-HKS ]^W5Rvx#򆑮aXy"V]S_S9 ӫ=\R<+j,mQM&OY<1VfV˔(cozFzL"Xww[n:9ܹ}:>]x] q9ֆ'Tԗz|6#ќs@@@+G TWѼ0렞( N=aQ+%GsI-}wέOh8RCA؏9se9t^:=9bտUv%E&Ʊ &IeP0fO'm?.\l @w_=*JںGT,B`Zۧd;LbaDNvH؅hk5rOz(9iBA~¼#Bף^;t^k<9 'Ѓ\ o~͍q  |(ėi~ A`p<:Y=+|L0@}ɡ˴DP#j~S(DHPer%k ,\D{ߡ|'|{'=L߉Lh? A gd"ًp+e,o]"N-c+WU*inڴt 'njjnYOӛ-jmY[>PLO)@ꪸ pڥ[n7̙qqlkDVzP,b"ta.E$ K@$ FQh?*W=Vbt+{=^-sw$ `_Ǐ ~[Q e"+a nZʍع ?9u[r$\L[uAL0īFTfH}a/APVR.'P>I@D դ\OdAeNF%JiuJuzdDm@MM'ЦSM}wժm?]G[ FW}}Κ;ޙV!%mUޥbhgJI)3ҌrO2_YdyMr'@-':Cʐ/cYN>`K8@M@Q@t@(rb9xVld+ & Q<,ȇmRǂ)16X `v`Ca78l`}_46,Zp5/օ9s聽+\y+*+ dWSzDq:rPء$S*CըU2T2^E;r8}?9Hz:óU|$$EϟAlz 'ҳj/rܦdY}G-f\'cͮ /gѲ}'ݩAvTtZ ACL6LCe7,I1G,y- u8穩cvX+6kDNK\]tz(.3i(K*Mߋl2A&/~)ު=yءdmwURU §Cqbh9f p1:JEDh3uYo243HMIIHN%`JEտ a|zjf=3wi5vi-IX! ˬP~[#ul Y(ff G]fqic |r``S%?vq`0M@Dq Rn/}&g[8): gor8w6ws-}J7FO{u8(={6/jo_78ՁSF33-S`3v\]1+U88Pg/.P~LrN;Y,}I1wD6vO%'5PWl 8clENή3#@.b}˟lZһdEl.K/"2DdL?fΘ1WBBDwn ;@߀=d9s%Av@/ƷdSz7_' v[UY L9RP&݃+kc9;I jWC?\H=PRoH_z@IzjSIA8`h 28S>s\7~W41٥Bg?Y8 O"~m7nno4 640/RgLS3C7,kޖ:flQZ)%K`9){k5I֖ bG&x3,tʧ{G~-cʬL)"?VA7B?|nL&2U͚r yU;˼b%vyΥ¦vYz%7ӎ.T҈΁.- R n!7yq[)NUIv$6]\X&"6U. U u~>KUYb $XQl3LJ}4|2E5 `9Ƹ|[GٶF $ PQ1 sC5" Q<~\e:!5 8F%U>]xr] ?"^9E-7&d줼Qɾ؜Lf?zCoӴső1NS|{\n$F,3O2jQYӰh J=CRL-S[ J_fne?Xùψ2_?|/M8y7xё432}n}7_#>oUffFvn8'`£j ABs ?~;p60-xY7Ῠ>Z qXc@ Ő8[$I'/rfē>'aΩڴ͗̓ \a1f&t\]%M!.6d%䳓é o9~.^ȵ*5Fp o%Nf ( @x-%f>A)uUg(cJQamˇkᴴgܳVrq~4Q%ڭp%S4p:8z>v~XxR :!FFL&&0KMd[r/(%!D I%-tPi4z^E)-3"tr/ Q-\=tV7ͯ1~V[!I>,t*GTQ%Bi|~T _o@7WX31WVxxx*~cUC-M4M[o[ endstream endobj 192 0 obj 6127 endobj 193 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 750 /Descent -210 /Flags 32 /FontBBox [-544 -303 1707 1014] /FontName /CTGWJY+Verdana-Bold /ItalicAngle 0 /StemV 0 /MaxWidth 1777 /XHeight 666 /FontFile2 191 0 R >> endobj 194 0 obj [ 342 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 711 0 711 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 546 0 0 0 0 847 0 0 0 0 0 0 0 0 0 0 0 692 0 0 0 0 0 0 668 699 588 699 664 422 699 712 342 0 671 342 1058 712 687 699 0 497 593 456 712 650 979 0 651 ] endobj 22 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CTGWJY+Verdana-Bold /FontDescriptor 193 0 R /Widths 194 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 195 0 obj << /Length 196 0 R /Length1 15524 /Filter /FlateDecode >> stream x{ |T9YL;>&Bd !`$ fD@LmՊ ~m@il_mkK_iRhk+j%ys' fr{>YsN6ԇLh1H]'i岛7zcl/B#+Ǝvy+lY;6 +z}J8;Er[bckM^7k{n|?{oY_y+fE7lWFM@#Ů][dhb$CHE"^u?yg fO?`~ZL&/?aUjҔ?}dSNOo6l簽`{g),~. ʡ9Vw|oOA1}ѢFzF9:Ä^hD!=~~ |i˧$t1|"F r,6%t"|;F~}x!M?M6evىx M|O{&{){BʞBeP C ʝC6厡<أǢ>;ƪaywc ^}Qak 0է]9e|Þs9KV5#ӒnM[>kb$%.wpd2[Lhİ abVS] ߌLfNk2\aӐ7;^/cpzD'E1BEXe29BΓSJK BSř4ϫ$'y.nhDX`x!|ljze/Ark eʚՔ=}:w]W`zo{=5ڨڦNo=cdW:הZZzzL8QUe(jmetWQ=`SwEtEqEJgz&^=<<>=szbp+75 G-Q _N#*wST=>#vrJb p 0@m>omo#i ڱ_He IQ‹h{Q{ZEKAc/Zyȣ^z5^z~tH把QrjbףvCCx2+qhgA,r ʵz*; <<vo5-)PuIWPs܏w=:Gdڟ#vttBÈxva{\@~-t6."\w`k ؖ%(Gg [:o,mp.v~5ph-eI@5E'>0:>ᷓkAL (S>*Xo7cnc -a='c\!JD\'JQ *j±-s_(:gࠏ y3t>V}NF6dGD.Fq(.&DAI(oTh8]=Z(el(r@y(BTG *EeMEU4⯈T,Kvw/OR8*^\!>&! IOôm5_,{,vZ''=[mnbGGc?-ǜ ]u׸uAE"L@S[:0 _ zϖWEq N %s!#! 4, FȆheAQP0PUbj嚴ZVյ’`KUWM?jifu`6UG537T)dZł#ո9?{ ɮeQigOP"t?@}ՑjU\UI.2U\uVW^9f43eJsW 8!KK]PWd+ Bh](6յKFGwlh~]li~oZqQIi5.3X]N^`|% O']Nw\5X+-movjW 3OəI>ߖӪy2q2okɶ@=6YT4T9V?=AX\1}[~a8/~ME~s\3MEU,6KinMS7}9Wk{˜Bj7&YXAE@#ZZGe`nW! pel/ņƚƋO<ƆmmVٲe ֒eKbeK.?-~}}' ,{{bIp My[, GFLg&u@T._@09c@w &X :s(XT&\Y͕Ry%D0ys#)ģjV\JlNϜn+2fؖ6 XIzw$IԵu %qϠw)|U\@4 Զ+1+"]ڊKҀEǂVVe'kҿnY~ǶE?;Bjq3#_Ӽ{ϪMJ_޺[v7ȢjDmhd `ڵk])=?uނѾ˦++ZϹ%'\w+[q⾻Sm 9U'kEބfXe vG*TUZ_U~v]o"ŵMqKc$^-`6FaCh3 FS13fx 4}q3͆%b$׀UC`! ;tVAޏwɿbGqW)ž[smx]?Uk7hGBt$<:PDc/z\1\TB4AfkkrJJ⑌ԇ2x7, Խj*=^ N.h<8p *yjMd qK rnjN_ C%;VYteIڶ/\'3f5TP239CQk|.>0)Z6n69`OFL30*Z6a[.o+o l}e nltmLZϓPq^P .)^\(MA>*f%( RО B#eÊ%" fSrh=/utQT40,PYf^H]tӝOAb拹:WM`dgbF־sY w~3S_Y͙پ.r`zwqiM%=~WEe.ce5e5G'7eF{5jlhwy4Ҭ j!9C' ̸N~m'~ΗLj؉~&CR(  i5;Hgbyݹ\677cr8rO%Ōw;%Y.8 R `q6RxneJKJJ mG̒'?ʱŇڵ% sWW44WVlgj~'lyY`Ҟz8Xesڡ7XXQ~f]gJJC9i5 A[-@K,@*՜|OYml1"_n7(Ң0q): _i8BfG jN.>gS]z> j ^"> cqPtdD s%t'!?`wIk a5n@b(,7kqxTVWlJ'!PCIIB~`剪-FA1*sv fd .&zq0p <683mRpH|mB?YJ10h|0Ic c6)< yD:W#`˗ȼEcI=8߮Vbq6ג>q )dD4c0`3rpL$hffثӣ|D @ECAG!0]l\*1vI7f%NB yQ+D(yk6bAD DI*}}1!I PںtGUeJ# AlS4i[% Ǜc~_uA}E :"8zٕ_2<ǝ|UBo3LĀ@(aU=mFI&(KIŘِ!d0TV4l_:d8bt: P.X$4AGw10R leY!NF2F nASBn0.&XTo~L ( av@+P%2o!<7Kk# 'nB/^~noxZv<DLXg?p70huND'FO@ӡ S¤&&HPA&0 #KL:.Q1F1wuPkz_l0t^߭=Nhcҳ|08rHz />`\ R#11.&Qz8{  p1EXO짧rmvX{P[x9~HcJ p{IA`gcNga BǴ%޺;L,),{eǝ/VTSDK^ jŧH0 =/O+` Cс7B:wwWmrϏ:hr+/i@ \N *?px=jӼ@(ޢ"y~BKyylɷ[kRl2K<5l3IJjyD5!*/(VdE_|5)e+޼֜trVvږ=x+ɂo*Mc%$uorzr˹BόԉA ŽK,~0{KTO=n-n69nۜo!$ [bMf}Y'DFҽ퉶D]< bC?IM'kЍ 8SmŁF[}6?p/Ͷ1(#@t;ӱ+v"^q@*>ȟk{-9qn`[*S;oI0s{K pߒ&8T?:33{vkUfE8M*{zl&#D/nJ,Ҁq(օih5T嚴6Tf3<`o3mLM i1Sl/ ͡:8{o( holYם@I1}1M-8ޱc}w^̩%Gy ^Y^p2(%(jي6X ?@ŢZ-L`C/4ȃ(GqG&(n4FK.e,r2mgK5%mIm~îWK}-1lKؽҐa="op^3!Bd6Dl5g*Pb4AL{OR JvcG=4J\{Srȁ`vLD* <_8KŹ\!j,nz'SX" `NBZ9`_/1}b;lgympFKR+ B2DXJXA`@ aVVd-H@_@DP}xj%'KKڠU]I&W=M^؍@g&35p$WFǽ=k" &=<\a \CRבt#zc#f7E 3UOdSnwB/ 5K"YYP‹Au G& z)E 08Jt (/ôFkñ`I)>N+I^QѷoY>|kA_9ƷCݦ.mZ?t:j{|ܫm{Rsa5YOj!-Sq} n wfܢtFCd+ʈCu:}eӃ:W{T^9H{k3{빬29NMvNǕ_X ti;Hgfw<&,U${T%Βf%yʍʭ^KpL4,Ԍ\pB@+OƲw$p LKK>2JҘP6NƉw/fQBkRtE@ =r{NLU*,|~Ύ/tpÏ ];ukR܅GR74G.4ͨ)ɧyi sY!P !j5ИNf90J hG,2N9ȹmN2^H!!肂PSM]G:v羜7G=}acm{Y[Mfĕt|WRIl9ҁN*1v'ՒM40JC-6ZfɝB|*Fl6Z6:oII2eqL r6%=ΤRpC |\Liر#?Xfuַоq683:r:tWkHc~D7ul @ƻOꨪ: ES6bD%h3 Y@aAk'qCM8}.j*B0x*f'~vpuvk_jz?(L}Z>_jN!|l{N.wW*V&B+->p'gX!>I`Q<ϋPDm8$Di%iڷz.N93j^[@wiδ{ٲdz4ɉ.tN©{_k>'Q06|0Ɩc`nP~r*meC 3aw8dIm0BpPW (jJ(]];h9gU^>9[ d.OuSo~MKoR>=+fAC#˘[ up>]KgKNcІG :A'a,N-]^B2CL-Cm(/W !RR(Sg<)b2x>9ĕ Uxy r=xY&Vƈ~:K#%J8$q KspԅH7PI.4>C321 HL(ҟJ 5A<Ÿ}Yw$% zoH HSߓ hflm036*--I0a;6]حO̘Vv+۲=x?om[uݸ{o,Gnb/4%;&Y[څ`Vӿ | L|=+1ՠpjQ6 O V'jQ'J&c,~b,Ŭ4 N؝AA-h (R-dnc?xù2.i=`%1_em}Eߟu$7`lr,tq [a87,Mi@驐2`$v / 8D[g5y;SS} ) \@ ֨iQ`[s,|]Ёcw27x,ed-e2BJh@u!Y$?$m@N'zO KsiPl11#첱1ڝ Ug2zN]'M n6d- lTkXH泋y5]#]ZoH"ƝY) 睐ŋ>[~W+!V"L})ūBX갧 |FZ? mLJk!w:_x|1nFǜPaFtIB/. "KT39SbLKsi F_O 1"9fkk0E5CNO_!Rꢦ(PO-0`dANf *X%lLBt]rlEzAk&<vaN}֋_f'.^hME|RčoQN@N n5,"v[ppF>GC N Dx(2f5 <7„U?h3ZJ[:hX!RHj }^*5,ROju]Jc+?(Fx}n?1~]Útv.abX/bxxPxB|E|CPݱOEjդOJ6 P9ă#Ye=@ pehkvsaeiل|`rzj3X~ɵSaU{ Ch:fGh L̓]nJBu1D\'s ԓ[ӿ.7N endstream endobj 196 0 obj 11682 endobj 197 0 obj << /Type /FontDescriptor /Ascent 1005 /CapHeight 742 /Descent -210 /Flags 32 /FontBBox [-544 -303 1707 1014] /FontName /DXOHQI+Verdana-Bold /ItalicAngle 0 /StemV 0 /MaxWidth 1777 /XHeight 565 /FontFile2 195 0 R >> endobj 198 0 obj [ 342 0 0 0 0 0 862 0 543 543 0 0 361 480 361 689 711 711 711 711 711 711 0 0 711 0 0 0 0 0 0 0 0 776 762 724 830 683 650 811 837 546 0 771 637 948 847 850 733 0 782 710 682 812 0 1128 0 0 692 0 0 0 0 711 0 668 699 588 699 664 422 699 712 342 403 671 342 1058 712 687 699 0 497 593 456 712 650 979 669 651 597 ] endobj 43 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DXOHQI+Verdana-Bold /FontDescriptor 197 0 R /Widths 198 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding >> endobj 199 0 obj (yao::manual) endobj 200 0 obj (Mac OS X 10.6.1 Quartz PDFContext) endobj 201 0 obj (Francois Rigaut) endobj 202 0 obj (firefox-bin) endobj 203 0 obj (D:20091111025659Z00'00') endobj 1 0 obj << /Title 199 0 R /Author 201 0 R /Producer 200 0 R /Creator 202 0 R /CreationDate 203 0 R /ModDate 203 0 R >> endobj xref 0 204 0000000000 65535 f 0000427456 00000 n 0000004912 00000 n 0000288426 00000 n 0000000022 00000 n 0000004892 00000 n 0000005016 00000 n 0000007943 00000 n 0000324294 00000 n 0000402428 00000 n 0000342722 00000 n 0000355187 00000 n 0000383731 00000 n 0000375792 00000 n 0000319748 00000 n 0000407640 00000 n 0000005204 00000 n 0000007922 00000 n 0000014442 00000 n 0000007979 00000 n 0000014421 00000 n 0000014549 00000 n 0000414545 00000 n 0000017893 00000 n 0000014688 00000 n 0000017872 00000 n 0000018000 00000 n 0000023580 00000 n 0000018126 00000 n 0000023559 00000 n 0000023687 00000 n 0000366676 00000 n 0000026266 00000 n 0000023840 00000 n 0000026245 00000 n 0000026373 00000 n 0000033748 00000 n 0000026499 00000 n 0000033727 00000 n 0000033855 00000 n 0000034099 00000 n 0000095754 00000 n 0000393112 00000 n 0000427083 00000 n 0000098515 00000 n 0000095776 00000 n 0000098494 00000 n 0000105937 00000 n 0000098552 00000 n 0000105916 00000 n 0000106044 00000 n 0000299667 00000 n 0000113053 00000 n 0000106210 00000 n 0000113032 00000 n 0000113160 00000 n 0000121839 00000 n 0000288550 00000 n 0000113327 00000 n 0000121818 00000 n 0000121947 00000 n 0000128799 00000 n 0000169766 00000 n 0000169788 00000 n 0000176139 00000 n 0000122231 00000 n 0000128778 00000 n 0000000000 00000 n 0000345738 00000 n 0000176160 00000 n 0000176577 00000 n 0000176597 00000 n 0000177030 00000 n 0000183780 00000 n 0000177050 00000 n 0000183759 00000 n 0000183888 00000 n 0000191766 00000 n 0000184055 00000 n 0000191745 00000 n 0000191874 00000 n 0000195492 00000 n 0000192069 00000 n 0000195471 00000 n 0000195600 00000 n 0000211351 00000 n 0000226758 00000 n 0000195817 00000 n 0000211329 00000 n 0000226780 00000 n 0000227727 00000 n 0000227747 00000 n 0000228694 00000 n 0000235987 00000 n 0000228714 00000 n 0000235966 00000 n 0000236095 00000 n 0000243009 00000 n 0000236249 00000 n 0000242988 00000 n 0000243118 00000 n 0000351105 00000 n 0000249062 00000 n 0000243327 00000 n 0000249040 00000 n 0000249173 00000 n 0000254546 00000 n 0000249316 00000 n 0000254524 00000 n 0000254657 00000 n 0000260422 00000 n 0000288678 00000 n 0000254798 00000 n 0000260400 00000 n 0000260534 00000 n 0000265469 00000 n 0000260677 00000 n 0000265447 00000 n 0000265581 00000 n 0000270943 00000 n 0000265724 00000 n 0000270921 00000 n 0000271055 00000 n 0000276512 00000 n 0000271198 00000 n 0000276490 00000 n 0000276624 00000 n 0000282283 00000 n 0000276806 00000 n 0000282261 00000 n 0000282395 00000 n 0000288174 00000 n 0000282535 00000 n 0000288152 00000 n 0000288286 00000 n 0000288797 00000 n 0000288898 00000 n 0000288965 00000 n 0000299102 00000 n 0000299125 00000 n 0000299356 00000 n 0000299847 00000 n 0000319097 00000 n 0000319120 00000 n 0000319355 00000 n 0000319922 00000 n 0000323826 00000 n 0000323848 00000 n 0000324079 00000 n 0000324473 00000 n 0000342092 00000 n 0000342115 00000 n 0000342341 00000 n 0000342897 00000 n 0000345134 00000 n 0000345156 00000 n 0000345381 00000 n 0000345415 00000 n 0000345717 00000 n 0000345903 00000 n 0000350620 00000 n 0000350642 00000 n 0000350873 00000 n 0000351286 00000 n 0000354774 00000 n 0000354796 00000 n 0000355022 00000 n 0000355362 00000 n 0000366115 00000 n 0000366138 00000 n 0000366372 00000 n 0000366858 00000 n 0000375256 00000 n 0000375278 00000 n 0000375509 00000 n 0000375972 00000 n 0000383218 00000 n 0000383240 00000 n 0000383471 00000 n 0000383911 00000 n 0000392579 00000 n 0000392601 00000 n 0000392835 00000 n 0000393294 00000 n 0000401921 00000 n 0000401943 00000 n 0000402169 00000 n 0000402602 00000 n 0000407185 00000 n 0000407207 00000 n 0000407433 00000 n 0000407815 00000 n 0000414034 00000 n 0000414056 00000 n 0000414287 00000 n 0000414725 00000 n 0000426500 00000 n 0000426523 00000 n 0000426754 00000 n 0000427263 00000 n 0000427294 00000 n 0000427347 00000 n 0000427382 00000 n 0000427413 00000 n trailer << /Size 204 /Root 136 0 R /Info 1 0 R /ID [ <33daf6b4c3947e141fdcbf3628327a0e> <33daf6b4c3947e141fdcbf3628327a0e> ] >> startxref 427582 %%EOF yao-5.4.0/examples/000077500000000000000000000000001234404334100141245ustar00rootroot00000000000000yao-5.4.0/examples/6x6LGS.par000066400000000000000000000053211234404334100156220ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simili Altair LGS, full diffraction WFS, spot elongation"; sim.pupildiam = 240; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 30.; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 14000.; wfs(n).laserpower = 10.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 1.2; wfs(n).npixels = 2; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).kernel = 1.0 wfs(n).dispzoom = 2.; wfs(n).optthroughput = 0.5; n = 2; wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).dispzoom = 0.15; wfs(n).optthroughput = 0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 40; dm(n).alt = 0.; dm(n).coupling = 0.17; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; n = 2; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 10; //------------------------------- mat.condition = &([15.,15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 20.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 100; loop.skipby = 10000; loop.jumps2swapscreen = 3; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/altairLGS.par000066400000000000000000000055601234404334100164600ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simili Altair LGS, full diffraction WFS, spot elongation"; sim.pupildiam = 240; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 30.; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 14000.; wfs(n).laserpower = 10.; wfs(n).shmethod = 2; wfs(n).shnxsub = 12; wfs(n).pixsize = 0.1; wfs(n).npixels = 20; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).kernel = 1.0 wfs(n).dispzoom = 2.; wfs(n).optthroughput = 0.5; n = 2; wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).dispzoom = 0.15; wfs(n).optthroughput = 0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 13; dm(n).pitch = 20; dm(n).alt = 0.; dm(n).coupling = 0.17; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; n = 2; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 10; dm(2).gain = 0.5; //------------------------------- mat.condition = &([15.,15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 20.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 100; loop.skipby = 10000; loop.jumps2swapscreen= 3; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/altairLGS_ir.par000066400000000000000000000054661234404334100171570ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simili Altair LGS, full diffraction WFS, spot elongation"; sim.pupildiam = 240; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 14000.; wfs(n).laserpower = 10.; wfs(n).shmethod = 2; wfs(n).shnxsub = 12; wfs(n).pixsize = 0.1; wfs(n).npixels = 20; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).kernel = 1.0 wfs(n).dispzoom = 2.; wfs(n).optthroughput = 0.5; n = 2; wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).lambda = 1.95; // H + K wfs(n).gspos = [22.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 12.; wfs(n).skymag = 14.5; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.12; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).noise = 1; wfs(n).ron = 12.; wfs(n).nintegcycles = 4; wfs(n).dispzoom = 0.15; wfs(n).optthroughput = 0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 13; dm(n).pitch = 20; dm(n).alt = 0.; dm(n).coupling = 0.17; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; n = 2; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 10; //------------------------------- mat.condition = &([15.,15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2.5e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 20.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 100; loop.skipby = 10000; loop.jumps2swapscreen = 3; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/ashfast-bench.par000066400000000000000000000041601234404334100173370ustar00rootroot00000000000000// Aosimul par file, V2.4.0 //------------------------------- sim.name = "Simple SH6x6 w/ TT mirror, full diffraction WFS"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1"]+".fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([11.]); atm.layeralt = &([0.]); atm.winddir = &([0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 1; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput =0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 2; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 2; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 2000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.stats_every = 200; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/c188-bench.par000066400000000000000000000034651234404334100164000ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple Curvature 36 actuators with noise"; sim.pupildiam = 128; sim.debug = 1; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "curvature"; wfs(n).nsubperring = &([6,12,20,26,32,40,52]); wfs(n).l = 0.4; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).noise = 0; wfs(n).ron = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).nelperring = &([6,12,20,26,32,40,52]); dm(n).unitpervolt = 0.01; dm(n).push4imat = 1000; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0.]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 300; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/curvature.par000066400000000000000000000036021234404334100166510ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple Curvature 36 actuators with noise"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "curvature"; wfs(n).nsubperring = &([6,12,18]); wfs(n).l = 0.2; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).skymag = 18.; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).darkcurrent = 400; wfs(n).nintegcycles= 1; wfs(n).fieldstopdiam = 4.; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).nelperring = &([6,12,18]); dm(n).unitpervolt = 1.0; dm(n).push4imat = 10; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([2.20]); target.xposition = &([0.]); target.yposition = &([0.]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100000; loop.ittime = 2e-3; loop.startskip = 1; loop.skipevery = 100000; loop.stats_every = 1; loop.skipby = 1000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/extreme1.par000066400000000000000000000041471234404334100163700ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "ExtremeAO, SVIPC, full diffraction WFS"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 32; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 0; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 33; dm(n).pitch = 4; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.condition = &([15.]); mat.method = "mmse-sparse"; mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/extreme2.par000066400000000000000000000036351234404334100163720ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "ExtremeAO, SVIPC, full diffraction WFS"; sim.pupildiam = 256; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen4096_"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 64; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 0; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "zernike"; dm(n).nzer = 21; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; //------------------------------- mat.condition = &([15.]); mat.method = "mmse-sparse"; mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/extreme3.par000066400000000000000000000041471234404334100163720ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "ExtremeAO, SVIPC, full diffraction WFS"; sim.pupildiam = 256; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 64; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 0; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 65; dm(n).pitch = 4; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.condition = &([15.]); mat.method = "mmse-sparse"; mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/glao.par000066400000000000000000000055571234404334100155660ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "GLAO example, 3 8x8 SHWFS, w/ disk harmonics"; sim.pupildiam = 128; sim.debug = 1; sim.verbose = 1; sim.svipc_wfs_nfork= 3; //------------------------------- tel.diam = 8.0; //VLT tel.cobs = 0.14; //VLT //------------------------------- seeing = 1.00; // in arcsec at 550nm (V band) r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^1.2; //atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.dr0at05mic = tel.diam/r0at500; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4","5","6"]+".fits"); atm.layerfrac = &([0.64,0.2,0.05,0.05,0.05,0.01]); atm.layerspeed = &([11.,20,29,35,30,40]); atm.layeralt = &([0.,400,2000,6000,8500,13000]); atm.winddir = &([0,0,0,0,0,0]); //------------------------------- nwfs = 3; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [50.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,-52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 3; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "diskharmonic"; dm(n).ndh = 9; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 1; //------------------------------- mat.condition = &([50.]); mat.file = ""; //------------------------------- target.lambda = &([2.23]); xy = (indices(3)-2.)*60.; target.xposition = &(xy(,,1)(*)); target.yposition = &(xy(,,2)(*)); target.dispzoom = &(array(1.,numberof(xy(,,1)))); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 2; loop.niter = 500; loop.ittime = 2.5e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/mad_glao_star.par000066400000000000000000000055511234404334100174320ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "MAD GLAO"; sim.pupildiam = 128; sim.debug = 1; sim.verbose = 1; //------------------------------- tel.diam = 8.0; //VLT tel.cobs = 0.14; //VLT //------------------------------- seeing = 1.50; // in arcsec at 550nm (V band) r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^1.2; //atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.dr0at05mic = tel.diam/r0at500; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4","5","6"]+".fits"); atm.layerfrac = &([0.64,0.2,0.05,0.05,0.05,0.01]); atm.layerspeed = &([11.,20,29,35,30,40]); atm.layeralt = &([0.,400,2000,6000,8500,13000]); atm.winddir = &([0,0,0,0,0,0]); //------------------------------- nwfs = 3; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [50.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,-52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 3; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).rint = &([0.000,0.290,0.464,0.641,1.066]); dm(n).rout = &([0.290,0.464,0.641,0.820,1.825]); dm(n).nelperring = &([4,8,12,16,20]); dm(n).unitpervolt = 0.01; dm(n).push4imat = 500; //------------------------------- mat.condition = &([50.]); mat.file = ""; //------------------------------- target.lambda = &([2.23]); xy = (indices(9)-5.)/4.*60.; target.xposition = &(xy(,,1)(*)); target.yposition = &(xy(,,2)(*)); target.dispzoom = &(array(1.,numberof(xy(,,1)))); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 2; loop.niter = 3000; loop.ittime = 2.5e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/mad_mcao_star.par000066400000000000000000000063271234404334100174310ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "MAD MCAO"; sim.pupildiam = 128; sim.debug = 1; sim.verbose = 1; //------------------------------- tel.diam = 8.0; //VLT tel.cobs = 0.14; //VLT //------------------------------- seeing = 0.60; // in arcsec at 550nm (V band) r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^1.2; //atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.dr0at05mic = tel.diam/r0at500; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4","5","6"]+".fits"); atm.layerfrac = &([0.4,0.2,0.1,0.1,0.1,0.1]); atm.layerspeed = &([11.,20,29,35,30,40]); atm.layeralt = &([0.,400,2000,6000,8500,13000]); atm.winddir = &([0,0,0,0,0,0]); //------------------------------- nwfs = 3; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [50.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,-52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; n = 3; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).rint = &([0.000,0.290,0.464,0.641,1.066]); dm(n).rout = &([0.290,0.464,0.641,0.820,1.825]); dm(n).nelperring = &([4,8,12,16,20]); dm(n).unitpervolt = 0.01; dm(n).push4imat = 500; n =2; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 8500.; scal = (60*4.848e-6*8500.*2+8)/8.; // 60 arcsec both side at 8500m dm(n).rint = &([0.000,0.290,0.464,0.641,1.066]*scal); dm(n).rout = &([0.290,0.464,0.641,0.820,1.825]*scal); dm(n).nelperring = &([4,8,12,16,20]); dm(n).unitpervolt = 0.01; dm(n).push4imat = 500; //------------------------------- mat.condition = &([50.]); mat.file = ""; //------------------------------- target.lambda = &([2.23]); xy = (indices(9)-5.)/4.*60.; target.xposition = &(xy(,,1)(*)); target.yposition = &(xy(,,2)(*)); target.dispzoom = &(array(1.,numberof(xy(,,1)))); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 2; loop.niter = 3000; loop.ittime = 2.5e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/mcao-8x8.par000066400000000000000000000110551234404334100161760ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Gemini MCAO system"; sim.pupildiam = 64; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 35.0; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.5,0.2,0.2,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 9; wfs = array(wfss,nwfs); for (n=1;n<=5;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.2; wfs(n).npixels = 6; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.589; wfs(n).noise = 1; wfs(n).ron = 4.5; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).kernel = 0.8; wfs(n).laserpower = 8.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).dispzoom = 1.1; wfs(n).biasrmserror = 2.; wfs(n).flatrmserror = 0.01; wfs(n).nintegcycles = 1; wfs(n).centGainOpt = 1; wfs(n).optthroughput = 0.5; wfs(n).rayleighflag = 1; } wfs(1).gspos = [-30,-30]; wfs(2).gspos = [30,-30]; wfs(3).gspos = [0,0]; wfs(4).gspos = [-30,30]; wfs(5).gspos = [30,30]; for (n=6;n<=9;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.65; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).dispzoom = 0.6; wfs(n).biasrmserror = 0.; wfs(n).flatrmserror = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput = 0.5; } wfs(6).gspos = [40,0]; wfs(7).gspos = [0,-40]; wfs(8).gspos = [-40,0]; wfs(9).gspos = [0,40]; //------------------------------- ndm = 5; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 9; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; dm(n).noextrap = 1; n = 2; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 12; dm(n).pitch = 8; dm(n).alt = 4500.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 1.2; dm(n).noextrap = 1; n = 3; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 8; dm(n).pitch = 16; dm(n).alt = 9000.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; dm(n).noextrap = 1; n = 4; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; n = 5; dm(n).type = "aniso"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 9000.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; //------------------------------- mat.condition = &([15.,15]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); //target.xposition = &([0, 0, 0, 0, 0,10,10,10,10,10,20,20,20,20,20,30,30,30,30,30,40,40,40,40,40,-30,30.,-30]); // //target.yposition = &([0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,-30.,-30,30]); // //target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.3); target.xposition = &([ 0, 0, 0, 0,15,15,15,15,30,30,30,30,45,45,45,45,-30,30.,-30]); target.yposition = &([ 0,15,30,45, 0,15,30,45, 0,15,30,45, 0,15,30,45,-30.,-30,30]); target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 30.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/mcao.par000066400000000000000000000105421234404334100155510ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Gemini MCAO system"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([1.0,0.,0.,0.]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 9; wfs = array(wfss,nwfs); for (n=1;n<=5;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 1.0; wfs(n).npixels = 2; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.589; wfs(n).noise = 1; wfs(n).ron = 4.5; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).kernel = 0.8; wfs(n).laserpower = 8.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).dispzoom = 1.1; wfs(n).biasrmserror = 2.; wfs(n).flatrmserror = 0.01; wfs(n).nintegcycles = 1; wfs(n).centGainOpt = 1; wfs(n).optthroughput = 0.5; wfs(n).rayleighflag = 1; } wfs(1).gspos = [-30,-30]; wfs(2).gspos = [30,-30]; wfs(3).gspos = [0,0]; wfs(4).gspos = [-30,30]; wfs(5).gspos = [30,30]; for (n=6;n<=9;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.65; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).dispzoom = 0.6; wfs(n).biasrmserror = 0.; wfs(n).flatrmserror = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput = 0.5; } wfs(6).gspos = [40,0]; wfs(7).gspos = [0,-40]; wfs(8).gspos = [-40,0]; wfs(9).gspos = [0,40]; //------------------------------- ndm = 5; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 19; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; n = 2; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 22; dm(n).pitch = 8; dm(n).alt = 4500.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 1.2; n = 3; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 16; dm(n).pitch = 16; dm(n).alt = 9000.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; n = 4; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; dm(n).gain = 0.3; n = 5; dm(n).type = "aniso"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 9000.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; dm(n).gain = 0.3; //------------------------------- mat.condition = &([15.,15]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([0.85,1.25,1.65,2.2]); target.xposition = &([0, 0, 0, 0, 0,10,10,10,10,10,20,20,20,20,20,30,30,30,30,30,40,40,40,40,40,-30,30.,-30]); // target.yposition = &([0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,-30.,-30,30]); // target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.3); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 30.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/mcao2-bench.par000066400000000000000000000103711234404334100167100ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Gemini MCAO system"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 9; wfs = array(wfss,nwfs); for (n=1;n<=5;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 1.0; wfs(n).npixels = 2; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.589; wfs(n).noise = 1; wfs(n).ron = 4.5; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).kernel = 0.8; wfs(n).laserpower = 8.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).dispzoom = 1.1; wfs(n).biasrmserror = 2.; wfs(n).flatrmserror = 0.01; wfs(n).nintegcycles = 1; wfs(n).centGainOpt = 1; wfs(n).optthroughput = 0.5; wfs(n).rayleighflag = 1; } wfs(1).gspos = [-30,-30]; wfs(2).gspos = [30,-30]; wfs(3).gspos = [0,0]; wfs(4).gspos = [-30,30]; wfs(5).gspos = [30,30]; for (n=6;n<=9;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.65; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).dispzoom = 0.6; wfs(n).biasrmserror = 0.; wfs(n).flatrmserror = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput = 0.5; } wfs(6).gspos = [40,0]; wfs(7).gspos = [0,-40]; wfs(8).gspos = [-40,0]; wfs(9).gspos = [0,40]; //------------------------------- ndm = 5; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 19; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 15; dm(n).pitchMargin = 0.5; n = 2; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 22; dm(n).pitch = 8; dm(n).alt = 4500.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 10; dm(n).pitchMargin = 1.2; n = 3; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 16; dm(n).pitch = 16; dm(n).alt = 9000.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 10; dm(n).pitchMargin = 0.5; n = 4; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; n = 5; dm(n).type = "aniso"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 9000.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; //------------------------------- mat.condition = &([15.,15]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([0.85,1.25,1.65,2.2]); target.xposition = &([0, 0, 0, 0, 0,10,10,10,10,10,20,20,20,20,20,30,30,30,30,30,40,40,40,40,40,-30,30.,-30]); // target.yposition = &([0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,-30.,-30,30]); // target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.3); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 30.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/mcao2.par000066400000000000000000000103041234404334100156270ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Gemini MCAO system"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1"]+".fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([11.]); atm.layeralt = &([0.]); atm.winddir = &([0]); //------------------------------- nwfs = 9; wfs = array(wfss,nwfs); for (n=1;n<=5;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 1.0; wfs(n).npixels = 2; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.589; wfs(n).noise = 1; wfs(n).ron = 4.5; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).kernel = 0.8; wfs(n).laserpower = 8.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).dispzoom = 1.1; wfs(n).biasrmserror = 2.; wfs(n).flatrmserror = 0.01; wfs(n).nintegcycles = 1; wfs(n).centGainOpt = 1; wfs(n).optthroughput = 0.5; wfs(n).rayleighflag = 1; } wfs(1).gspos = [-30,-30]; wfs(2).gspos = [30,-30]; wfs(3).gspos = [0,0]; wfs(4).gspos = [-30,30]; wfs(5).gspos = [30,30]; for (n=6;n<=9;n++) { wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).lambda = 0.65; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).dispzoom = 0.6; wfs(n).biasrmserror = 0.; wfs(n).flatrmserror = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput = 0.5; } wfs(6).gspos = [40,0]; wfs(7).gspos = [0,-40]; wfs(8).gspos = [-40,0]; wfs(9).gspos = [0,40]; //------------------------------- ndm = 5; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 19; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; n = 2; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 22; dm(n).pitch = 8; dm(n).alt = 4500.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 1.2; n = 3; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 16; dm(n).pitch = 16; dm(n).alt = 9000.; dm(n).hyst = 0.03; dm(n).thresholdresp = 0.4; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20; dm(n).pitchMargin = 0.5; n = 4; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; n = 5; dm(n).type = "aniso"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 9000.; dm(n).hyst = 0.0; dm(n).thresholdresp = 0.01; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 5; //------------------------------- mat.condition = &([15.,15]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([0.85,1.25,1.65,2.2]); target.xposition = &([0, 0, 0, 0, 0,10,10,10,10,10,20,20,20,20,20,30,30,30,30,30,40,40,40,40,40,-30,30.,-30]); // target.yposition = &([0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,0,10,20,30,40,-30.,-30,30]); // target.dispzoom = &([1.,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]*1.3); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 30.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/poliahu_wfs_svipc_timing.png000066400000000000000000000156241234404334100217350ustar00rootroot00000000000000PNG  IHDRgh pHYsttfxtEXtSoftwareGPL Ghostscript 8.71?h4IDATxz0_9 k]ͤ*$11)gͶg)s15-OxNxI@+eЦQ;}vc[ͳ>8 P- mHFS ?gi> I )/4W nfp8KxNj_N+EL %^PzUD,8H{{6 5j}nԾPR)5{56꓂˸DFЄ2g-bެw37*ip;u{]씩kLV5qmRw(0kUښ3^gnQ2}Fşgܘ1 վ6cJm4@Tr)QW{3I_&} ͡ I_&}3i>Pv1}%+|䑾M@4{3/DW)8K@4 Ѥ 48E@4 Ѥ=4H'} h6$z}o Sف";Pt @ Ѥ/D7|hIi>O@4 Ѥ#4!} h)lM@7;rz+ فNp@yhYF>$} hqH_&} hI |I_&}(M@7=fw]6v[d3Dь|@@4 Ѥo/'} hW~5`S6fgD^nV6VCC@ʯu5HvMY~%き|xԯSd0 -vq5ީ1ϫw,;Kqkr5+ BOwgs0۔.0=ګ}uҷ!} hҷ"/!} hoc- Њ@)d) [dsuhIi>M@k,#`ڷRM@͋kmR}odI.} h|tj}ޮި@rvk7C.E+(oʯkfh.O>\k)DjR8e;ڬL ӴwV|x3 ^ղ7!1hJ~U۝JM]n9:Ҵ( MU-Xug֜s(:?7wA#uV S9ƈ__.atb3C9E^Uirb`׾O':sװg^XT=tabRvK} 6- EG=MٔLYC'VHWٞ:Y9}얽s{ثq)Gі._}g*UgBoёΈw_kb#*pzoh^<:XrE:ϐ]{gIه۶Qm{ԾTs{|n,)[ }E.t{wz:Rr6b{Ӿ|_)t*eLyU]P;R3+=w@.t;QPzGZʾ6zY-O6fѳd}Vc myu;ܥ.tC ťdzYۇΘmuﲒ¼* ΃ygjnGM@51g9U҅vD.~M.3iWJ7p)[pD g'zEvP[lBB1c} zܟ+˜>i壶3lmSjS%/Ԧ|yzFHû>?qrE*3jk&\;Otf~b (@"~p­aZw-@t.oP?}.Єw[\vC>s@Аc?Z2;28? Ň"S|>@=w+ӯ Z=M?Jc,U,}'2 tZUxsrD" l\ʹcVϢ C-}gfk8֕.ˆ^΍zRʛ #%SVϢ+;RVcnH\ؗ}ubny@M Qxu߭l3uOD/d%%VE/ / clk^l"VY}MMy ]XvuDS۫}'z8}ҷ,zX}_(ellND/@A+Nn'!Tvdفb/DtOhI_wp},/DM@4} I_&} gl g7}3d1ֺG 6~(mv{'<@ͻ aNY:m%}5Qj_f/D3<@j_ 0N.~/%SVu '> ?W2Șgx1M@4k]@ Q5 _:X-wJA 8_ bb%}gj$R;rHoM#1R2e5Pqtd C]D/(iլp=\l־W .g[ ?=w|.Ζǟ o(=`VoF}"0/-O8.TА&k 2 @N\4A&tFm*f;xE%v>Z|zp/ Ѥ/DM@4 Y I_VM>0L}Ow;8ߞqyz͟]9|}{E0,kZݑnn]Cǰ{3j= _Ӻ,6F7nUkځyFb7սڬ3.ukW3jߗF}^ֽ WH]6w_o8=6I.Ϛ̧B U{˽rRg̷=YZsۣG$}N=v_W|Q93=}ˡ468})%5jg}ntӽtb:w\}|3c5?A\ǞvW[wӏ:<~rD7엧oK )tRyg 'c?ޮ#U34cv72Nmuw ? H mxtN¥\MܪW%},n\OEl?j_ Za"d  ^##|} ;c%`"YSڥ ei8NSz2UH_`oZѣmghkڗ<??O-2"/4(mީ̢nH_2n[L_:PFGF IENDB`yao-5.4.0/examples/pyr.par000066400000000000000000000041641234404334100154470ustar00rootroot00000000000000// YAO parameter file //------------------------------- tel.diam = 8; tel.cobs = 0.; sim.name = "8 metre telescope w/ Pyramid WFS" sim.pupildiam = 128; sim.debug = 0; sim.verbose = 1; //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "pyramid"; wfs(n).fstop = "round"; wfs(n).fssize = 1.6; wfs(n).lambda = 0.65; wfs(n).shnxsub = 32; wfs(n).npixpersub = sim.pupildiam/wfs(n).shnxsub; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = -5; wfs(n).skymag = 15.; wfs(n).noise = 1; wfs(n).ron = 3.; wfs(n).darkcurrent = 0.; wfs(n).pyr_mod_npts= 16; wfs(n).pyr_mod_ampl= 0.45; wfs(n).pyr_padding = 2; wfs(n).pyr_mod_loc = "after"; //------------------------------- ndm = 1; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = wfs(n).shnxsub+1; dm(n).pitch = wfs(n).npixpersub; dm(n).alt = 0.; dm(n).unitpervolt = 1.; dm(n).push4imat = 0.10; dm(n).elt = 1; dm(n).gain = 1.; dm(n).regtype = "laplacian"; if (wfs(1).type == "hartmann"){ dm(1).regparam = 1e-2; } else {dm(1).regparam = 1e-2;} //dm(1).regparam = 3e-2; //------------------------------- mat.method = "mmse"; // mat.method = "svd"; // mat.condition = &([10.]); // mat.file = ""; //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); r0 = 0.10; //------------------------------- atm.dr0at05mic = tel.diam/r0; // this is r0=0.2 at 500 nm atm.screen = &(Y_USER+"data/screen1.fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([12.]); atm.layeralt = &([0.]); atm.winddir = &([0.]); //------------------------------- gs.zeropoint = 1.2e11; //------------------------------- loop.gain = 0.3; loop.framedelay = 2; loop.niter = 100000; loop.startskip = 30; loop.ittime = 0.001; loop.modalgainfile = "simulModeGains.fits"; // loop.leak = 0.05; yao-5.4.0/examples/sbfmcao01_wfs_svipc_timing.png000066400000000000000000000202321234404334100220360ustar00rootroot00000000000000PNG  IHDRgh pHYsttfxtEXtSoftwareGPL Ghostscript 8.71?h4 IDATxۚ:P_+/vBXj Ey~Иif8w?#ѻ{mp|N_`mkJ iэ=Ezٳc}W>`Ajo%"w~ RQ݇ɏ4M])ډ:jF}?Z!;3]Gv+j;6ӝ:G_ݩaVAbL<ه3];mOv!}lmn+[}|n-nyY۪P3~XsHyoԾ"cFx?{ZY;tGčY{6o?Pۓ7Gԡ͸qk}Dws!ҷENK?F͆O(g"[z!f6ڲM6Eܣc`wöJ?#g3ύu^n!Uh6t{c7Jd$-gV9:ֆAۏGۊOp =1؂g_j-v~;Tl]'%*NN)Exf6f"o5mNW$8-wYiޏOe52$IS1=7Hth||(J3H߶$vf%EF7ryš^") eۛqeeqpF91 6Wٓ-CIۇ-|@~6PF=\QԾ=i.L̞^IlD1kJ#x#6kxҷ҂]uKkA{]E5lpnE ]R$"S3+ %s$v?~yWHiE)q_-~_} x}sugqzSԔ!1\ww7e \-{n=hf]#/lOO7po>F]ʛ|0*Q;u>9Sޣ]'yېyjmݦmH~ك̻ȁ#RĻyjw2./TOЦ ߇`mMyhj_&} hI_&} hI_ze(^ #}JƤ/DM@4 Ѥ/DZw3ڵ\q4MjzQn ㊹;MZ >w pcy)3sd4!eL}K1 }_Jp7{FZosƫZO @ju]~^2Zq ~uW}WЋVۘ;hE/izߎ} Cif8H@4 Ѥ/DM0m$M@/t PN׳?*}QкaJ}#{բR` ՍWy+F:@OP>;M+q?\: 3v>jߔpë@$˩gp:/ wN|:H7xMɔ?m>vC-J~_o{HI~'[xܯjс6nJ %Vjj8Ƌ@!ԙg/>>,j^ &[Qq;4==hP}?j)\lj8-Dmhr 6GHfÏ;>Kɛn}ѯx I! o,+Gfso&<Ǿ^Do߷h `씩|ZIm 9d ;s5<.)yK٩}wk3xI[PSWzr^#"ѸZWW;l mp:6tbN/޽1MS_ ܏9Kmվ;k+MvnlZ_ir1j_/:=)yl"/P/ֺmg^yNqJ~}MPiuՐy_ic0܌y~^`ڷ%>V}jH>LGK;վu.wBJ, HI_7WJPY>{rMMyŸn陻wu𗫏ff} izh`uC[PAs pfi!}g;͋~`ug޷3_ܽ絒K)L #Qy>/ƀlF m{bMl5Ȣi^-Wu?گ5f);Pw} {(1> V^x X|Z` <Rz[{ɶF"gy9s|TbH[H_Cگ fت}U]PB V0 ~׳Quh .}(y3pʱ+q53ϣ0 ^yl3a|ge!k5\ ܊x_85ETq󾉱aR2eq.}Ӟ_0 xJ٣+X};F+"zi=37 +x<J^\F嶔4kuyi~o#wV&s#8}٨r~03E3&EØfTf` sY%.[1y:)iXgSЌ`GM<i ^:Uz&?bKf 0}6\ފNk]آ^ i)p؍lx~3O#xhp8>,2Af95 =Q{`e kpߋtB2ׁ.0 f犣VȳvzR`Y 0M i犣>W*|g01U;U6f@УY nV3^/A.VIrҗuplk:Un9`gtq+j_n/i~D'zW۠!o;\rC9nC63,8r&10eaH `2-8\A\q9D"腗?;Ù݉o#"cޝ}N1*`^fr0_+zéGN2%/ɿ8 |{}`k79>riz<Q6{!vvAB~;3( )/dD/$uEy7D/Pǟz C0m.srޗ9d0pĚ^/ ~=Qrg)l6jg$ z!:)xEpD/dYH)B?dpD/gIdNh"|epcD/b')b. z8:GEϋRS40?YJXdp% _(ŽDV?ؽ&] J)/9׳wCAf_~\g?5D/OTreRb _qr#*:p6E>hp?`'vWagX~,]@Mea}+bxw9HX /p);N!zjwRoy [ nv{}.jckO{_`>va a~RJQNߟZNDYfi~,'0;C.|?>Y ď~XBc|Wçu<6XBCB$~FD/Tq/c= KUtP~d2E,zYK_AN0 mڎ>Rp/oIZ->;Cy'Шԙg1Ա7zk;/F< 1P 0,\]=$mvO = X\OS785WC@N~aP"C9?H,n YH3pڧyuRvcM0s3enZW@Ô jş@+2Bm3]XGW"Ib'YX.-Nw\puQ}ѵ>o\5Fa͗ʎޏD@́e}I|޷J8D=<7oqETwk5}ۋJj,kjQ_ NgRg%.́Fov2@IJ~hSXvTgynIZOgj*YV]T-k] eԾ/mV}+o/7ƣv}/,zk+cq# ZH_RI_&} hI_ #i!k(wL_ @فbI_&} hI_6} j)w<\-׾ dXH_ r|˂ӺPV+z f B*yR[}i\ @))(g/.RpM@4 Ʃ} JUm镸4$ȶ* ϩ2,w: ԾY3|/Ds/DO_UPցD4Zի3w|N:(V I_#P]{%ZPmW^6'e|=/eg:VSi;@;<@4 Ѥ/D|ղ`Wv !:MʸK<'Dk'z1 Ѥ/Dk]{Ўʵ{:w}GZ<6ЬڂZP\AqIa<'Dwy'ΓM@4 ר3˄Daf0L I_&} hI_A[6 F Ѥ/D g_9r+۫}cclkÅQu۷kݽj_:} OXR]=9TpyPg PM Ծб@#/tC0&14=zox݇}GxOk-S>t}hc$c;v*Zn3toi[ ޘ%ޞ@^| 8,#/ҖK9)UyUeHv1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 100; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 101; dm(n).pitch = 4; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; dm(n).regtype = "laplacian"; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 100; //------------------------------- mat.method = "mmse-sparse"; //mat.condition = &([25.]); mat.file = ""; mat.sparse_MR = 25000; mat.sparse_MN = 500000; //------------------------------- tel.diam = 30; tel.cobs = 0.15; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh16x16.par000066400000000000000000000040271234404334100157530ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH16x16 svipc tests"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh16x16_svipc.par000066400000000000000000000041311234404334100171530ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH16x16 svipc tests"; sim.pupildiam = 128; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 8.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- //mat.method = "mmse-sparse"; mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh200x200_svipc.par000066400000000000000000000042341234404334100173050ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH200x200 svipc tests"; sim.pupildiam = 800; sim.debug = 1; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 300; atm.screen = &(Y_USER+"data/wide_screens_"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 200; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 201; dm(n).pitch = 4; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; dm(n).regtype = "laplacian"; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 100; //------------------------------- mat.method = "mmse-sparse"; //mat.condition = &([25.]); mat.file = ""; mat.sparse_MR = 100000; mat.sparse_MN = 2000000; //------------------------------- tel.diam = 42; tel.cobs = 0.15; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh64x64_svipc.par000066400000000000000000000041331234404334100171630ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH64x64 svipc tests"; sim.pupildiam = 256; sim.debug = 1; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 100; atm.screen = &(Y_USER+"data/screen4096_"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 64; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 65; dm(n).pitch = 4; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; dm(n).regtype = "laplacian"; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 100; //------------------------------- mat.method = "mmse-sparse"; //mat.condition = &([25.]); mat.file = ""; //------------------------------- tel.diam = 30; tel.cobs = 0.15; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh6m2-bench.par000066400000000000000000000040421234404334100166440ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple SH6x6 w/ TT mirror, full diffraction WFS"; sim.pupildiam = 60; sim.debug = 2; sim.verbose = 2; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; wfs(n).optthroughput=0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 2; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 2; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh6x6.par000066400000000000000000000037661234404334100156220ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH6x6 w/ TT mirror and WFS, full diffraction WFS"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 20; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 5000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh6x6_4cell.par000066400000000000000000000041041234404334100166700ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH6x6 w/ TT mirror and WFS, full diffraction WFS"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 1.0; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 20; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 50; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 100; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/sh6x6_svipc.par000066400000000000000000000040751234404334100170200ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH6x6 w/ TT mirror and WFS, full diffraction WFS"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).svipc = 2; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 20; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 100; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/shwfs-generic.par000066400000000000000000000050671234404334100174040ustar00rootroot00000000000000teldiam = 42.0; pupd = 84*10; nxsub = 84; seeing = 0.7; //------------------------------- sim.name = "generic SHWFS"; sim.pupildiam = pupd; sim.debug = 2; sim.verbose = 2; //------------------------------- r0 = (0.5e-6)/(seeing*4.848e-6); atm.dr0at05mic = teldiam/r0; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/wide_screens_"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).shnxsub = nxsub; wfs(n).npixpersub = sim.pupildiam/wfs(n).shnxsub; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 1; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; sim.pupildiam = wfs(n).npixpersub * wfs(n).shnxsub; write,format="Telescope diameter = %.1f m\n",teldiam; write,format="Pupil diameter = %d pixels\n",sim.pupildiam; write,format="Shack-Hartmann = %dx%d\n",nxsub,nxsub; write,format="Seeing = %.2f ''\n",seeing; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = wfs(1).shnxsub+1; dm(n).pitch = wfs(1).npixpersub; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 30; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 50; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = teldiam; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/shwfs-tests.par000066400000000000000000000043431234404334100171260ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH6x6 w/ TT mirror and WFS, full diffraction WFS"; sim.pupildiam = 120; sim.debug = 2; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 12.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; wfs(n).fstop = "square"; wfs(n).fssize = 10.; n = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [40.,40.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "zernike"; dm(n).iffile = ""; dm(n).nzer = 21; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 1; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 5000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/test-all.i000066400000000000000000000055711234404334100160330ustar00rootroot00000000000000require,"yao.i"; write,"CREATING PHASE SCREENS"; if (!open(Y_USER+"data/screen1.fits","r",1)) { mkdirp,Y_USER+"data/screen"; create_phase_screens,1024,256,prefix=Y_USER+"data/screen"; } f = findfiles("test*.par"); f = f(sort(f)); if (get_argv()(0)=="bench") f = findfiles("*-bench.par"); if (get_argv()(0)=="toy") f = findfiles("toy*.par"); struct perf_s{string parfile; string name; float itps; string display; float strehl; float lambda;}; //perf = array(perf_s,numberof(f)+1); perf = []; smdebug=0; write,"LOOPING ON TEST*.PAR"; for (i=1;i<=numberof(f);i++) { write,format="\n\nTesting %s\n\n",f(i); aoread,f(i); sim.verbose = 1; sim.debug=0; // SVIPC settings: sim.svipc = 0; wfs.svipc = 0; // wfs.svipc = 2; // sim.svipc = 1+2; // sim.svipc=1+2+4; disp = 10; if (!strmatch(f(i),"fast")) loop.niter = 500; else disp=0; // let's not display for the fast demo aoinit,disp=disp,clean=1; random_seed,0.5; ran1init; aoloop,disp=disp,no_reinit_wfs=1,controlscreen=10*(i==2)*(disp!=0); go,all=1; grow,perf,perf_s(); perf(0).parfile = f(i); perf(0).name=sim.name; perf(0).itps = iter_per_sec; perf(0).display = (disp?"ON":"OFF"); perf(0).strehl = strehl(1,0); // first position, last lambda perf(0).lambda = (*target.lambda)(0); // same without displays disp=0; random_seed,0.5; ran1init; aoloop,disp=disp,no_reinit_wfs=1; go,all=1; grow,perf,perf_s(); perf(0).parfile = f(i); perf(0).name=sim.name; perf(0).itps = iter_per_sec; perf(0).display = (disp?"ON":"OFF"); perf(0).strehl = strehl(1,0); // first position, last lambda perf(0).lambda = (*target.lambda)(0); if (sim.svipc||anyof(wfs.svipc)) status = quit_forks(); // hitReturn; } //~ write,format="\n\nTesting %s (no display)\n\n",f(0); //~ aoread,f(0); //~ sim.verbose = 1; //~ sim.debug=0; //~ loop.niter = 500; //~ aoinit,disp=0; //~ aoloop,disp=0; //~ go,all=1; //~ perf(0).parfile = f(0); //~ perf(0).name=sim.name; //~ perf(0).itps = iter_per_sec; //~ perf(0).display = "OFF"; //~ perf(0).strehl = strehl(1,0); // first position, last lambda //~ perf(0).lambda = (*target.lambda)(0); write,"\nSUCCESS: ALL TESTS OK.\n\nPerformance Summary:"; f = open(swrite(format="test-all_v%s.dat",yaoVersion),"a"); write,f,format="%s\n","----------------------------------------------------------"; write,f,format="%s\n",timestamp(); write,format="%-12s %-34s %-8s%-10s%-10s\n","Parfile","Name","iter/s","Display?","Strehl"; write,f,format="%-12s %-34s %-8s%-10s%-10s\n","Parfile","Name","iter/s","Display?","Strehl"; for (i=1;i<=numberof(perf);i++) { if (strlen(perf(i).name)>34) name = strpart(perf(i).name,1:31)+"..."; else name = perf(i).name; str = swrite(format="%-12s %-34s %-8.1f%-10s%.2f@%.2fmic",\ strpart(strtok(perf(i).parfile,".")(1),1:12), \ name,perf(i).itps,perf(i).display,perf(i).strehl,perf(i).lambda); write,format="%s\n",str; write,f,format="%s\n",str; } close,f; yao-5.4.0/examples/test-all_v4.10.4.dat000066400000000000000000000027651234404334100173470ustar00rootroot00000000000000 Sun Oct 14 01:02:23 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 118.7 ON 0.34@1.65mic test Simple SH6x6 w/ TT mirror, full... 129.6 OFF 0.34@1.65mic test1 Simili Altair LGS, full diffrac... 69.9 ON 0.58@1.65mic test1 Simili Altair LGS, full diffrac... 82.2 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 368.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 524.9 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 49.4 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.9 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 590.8 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 903.4 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.2 OFF 0.84@2.20mic test6 DH WFS & DM 547.9 ON 0.49@1.65mic test6 DH WFS & DM 1035.9 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.2 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 28.2 OFF 0.50@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 986.1 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1955.7 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v4.10.99.dat000066400000000000000000000141101234404334100174300ustar00rootroot00000000000000 Mon Oct 15 12:49:36 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 118.4 ON 0.34@1.65mic test Simple SH6x6 w/ TT mirror, full... 129.2 OFF 0.34@1.65mic test1 Simili Altair LGS, full diffrac... 69.8 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 81.2 OFF 0.57@1.65mic test2 SH 12x12, quick method, with se... 350.4 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 520.8 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.8 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 61.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 526.7 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 904.5 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.1 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.5 OFF 0.84@2.20mic test6 DH WFS & DM 383.2 ON 0.49@1.65mic test6 DH WFS & DM 763.2 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.9 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.8 OFF 0.50@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 841.0 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2028.7 OFF 0.47@1.65mic Mon Oct 15 13:28:14 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 116.8 ON 0.34@1.65mic test Simple SH6x6 w/ TT mirror, full... 128.3 OFF 0.34@1.65mic test1 Simili Altair LGS, full diffrac... 69.1 ON 0.59@1.65mic test1 Simili Altair LGS, full diffrac... 80.8 OFF 0.59@1.65mic test2 SH 12x12, quick method, with se... 348.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 506.9 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 47.9 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 61.9 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 553.3 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 871.9 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 60.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.7 OFF 0.84@2.20mic test6 DH WFS & DM 490.2 ON 0.49@1.65mic test6 DH WFS & DM 985.8 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.0 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.8 OFF 0.50@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 897.9 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1912.8 OFF 0.47@1.65mic ---------------------------------------------------------- Mon Oct 15 15:04:00 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 117.1 ON 0.34@1.65mic test Simple SH6x6 w/ TT mirror, full... 128.1 OFF 0.34@1.65mic test1 Simili Altair LGS, full diffrac... 69.1 ON 0.59@1.65mic test1 Simili Altair LGS, full diffrac... 79.8 OFF 0.59@1.65mic test2 SH 12x12, quick method, with se... 347.3 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 487.9 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.5 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 595.7 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 904.4 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.8 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.2 OFF 0.84@2.20mic test6 DH WFS & DM 560.7 ON 0.49@1.65mic test6 DH WFS & DM 1015.2 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.3 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 28.0 OFF 0.50@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1040.4 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2006.3 OFF 0.47@1.65mic ---------------------------------------------------------- Tue Oct 16 12:15:55 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 117.0 ON 0.35@1.65mic test Simple SH6x6 w/ TT mirror, full... 126.6 OFF 0.35@1.65mic test1 Simili Altair LGS, full diffrac... 69.6 ON 0.59@1.65mic test1 Simili Altair LGS, full diffrac... 81.6 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 391.4 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 513.4 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.9 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.0 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 583.8 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 874.0 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.5 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.2 OFF 0.84@2.20mic test6 DH WFS & DM 585.9 ON 0.49@1.65mic test6 DH WFS & DM 997.6 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.1 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.8 OFF 0.51@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1018.9 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2002.0 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v5.0.0.dat000066400000000000000000000030571234404334100172560ustar00rootroot00000000000000---------------------------------------------------------- Tue Oct 16 15:32:29 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 146.2 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 173.0 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 69.8 ON 0.59@1.65mic test1 Simili Altair LGS, full diffrac... 82.0 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 396.8 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 519.0 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.0 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 60.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 575.3 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 871.3 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.1 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.1 OFF 0.84@2.20mic test6 DH WFS & DM 568.3 ON 0.49@1.65mic test6 DH WFS & DM 1002.8 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.8 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.5 OFF 0.51@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1010.3 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1946.5 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v5.0.2.dat000066400000000000000000000112151234404334100172530ustar00rootroot00000000000000---------------------------------------------------------- Wed Oct 17 21:52:50 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 146.3 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 173.6 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 69.4 ON 0.59@1.65mic test1 Simili Altair LGS, full diffrac... 82.0 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 344.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 518.7 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 49.1 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.7 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 496.0 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 899.4 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.8 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.6 OFF 0.84@2.20mic test6 DH WFS & DM 438.9 ON 0.49@1.65mic test6 DH WFS & DM 1011.2 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.4 ON 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 28.2 OFF 0.51@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 752.1 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1991.3 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Oct 18 09:51:34 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 131.9 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 153.7 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 57.6 ON 0.61@1.65mic test1 Simili Altair LGS, full diffrac... 65.4 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 276.1 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 371.7 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 38.4 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 46.4 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 533.1 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 888.1 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.2 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 66.1 OFF 0.84@2.20mic test6 DH WFS & DM 427.4 ON 0.49@1.65mic test6 DH WFS & DM 1019.4 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 13.2 ON 0.18@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 13.3 OFF 0.15@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 807.7 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1985.3 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Oct 18 10:58:11 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 145.0 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 172.3 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 69.8 ON 0.58@1.65mic test1 Simili Altair LGS, full diffrac... 81.5 OFF 0.59@1.65mic test2 SH 12x12, quick method, with se... 353.3 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 520.3 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.8 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 63.3 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 505.2 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 904.2 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.3 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.5 OFF 0.84@2.20mic test6 DH WFS & DM 456.0 ON 0.50@1.65mic test6 DH WFS & DM 1042.5 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.2 ON 0.51@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 28.2 OFF 0.51@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 767.0 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2010.0 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v5.0.4.dat000066400000000000000000000061361234404334100172630ustar00rootroot00000000000000---------------------------------------------------------- Fri Oct 19 15:11:35 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 128.1 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 149.2 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 55.8 ON 0.61@1.65mic test1 Simili Altair LGS, full diffrac... 64.3 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 272.4 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 353.0 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 36.3 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 44.4 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 415.4 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 555.9 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 60.4 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.8 OFF 0.84@2.20mic test6 DH WFS & DM 538.8 ON 0.50@1.65mic test6 DH WFS & DM 996.1 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 12.7 ON 0.18@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 12.9 OFF 0.14@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 964.3 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1951.2 OFF 0.47@1.65mic ---------------------------------------------------------- Tue Oct 23 23:45:11 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 129.1 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 151.9 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 56.2 ON 0.61@1.65mic test1 Simili Altair LGS, full diffrac... 65.0 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 271.9 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 365.1 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 37.8 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 45.7 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 388.4 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 563.8 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.6 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 65.4 OFF 0.84@2.20mic test6 DH WFS & DM 462.0 ON 0.50@1.65mic test6 DH WFS & DM 1023.8 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 15.7 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 16.0 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 813.5 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2012.4 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v5.1.1.dat000066400000000000000000000112151234404334100172530ustar00rootroot00000000000000---------------------------------------------------------- Wed Oct 24 16:11:16 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 128.3 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 149.4 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 55.3 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 63.8 OFF 0.59@1.65mic test2 SH 12x12, quick method, with se... 290.8 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 347.3 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 36.6 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 45.3 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 428.2 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 548.3 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 58.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.9 OFF 0.84@2.20mic test6 DH WFS & DM 571.6 ON 0.50@1.65mic test6 DH WFS & DM 994.1 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 15.3 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 15.7 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1029.6 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1947.6 OFF 0.47@1.65mic ---------------------------------------------------------- Wed Oct 24 16:16:55 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 145.1 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 169.8 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 67.1 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 80.2 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 391.6 ON 0.80@1.65mic test2 SH 12x12, quick method, with se... 507.1 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.0 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 61.2 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 588.9 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 881.6 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.0 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 64.2 OFF 0.84@2.20mic test6 DH WFS & DM 576.4 ON 0.50@1.65mic test6 DH WFS & DM 1007.0 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.6 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.5 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1000.9 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1920.8 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Oct 25 14:04:24 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 143.3 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 170.8 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 67.5 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 81.4 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 398.6 ON 0.80@1.65mic test2 SH 12x12, quick method, with se... 518.3 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.6 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.4 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 589.2 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 887.1 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 65.0 OFF 0.84@2.20mic test6 DH WFS & DM 582.8 ON 0.50@1.65mic test6 DH WFS & DM 1039.0 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.0 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.8 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1033.7 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2005.0 OFF 0.47@1.65mic yao-5.4.0/examples/test-all_v5.1.9.dat000066400000000000000000000115441234404334100172700ustar00rootroot00000000000000---------------------------------------------------------- Fri Oct 26 13:49:04 2012, has_lapack=0 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 172.9 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 83.1 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 521.5 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 63.0 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 842.5 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 65.9 OFF 0.84@2.20mic test6 DH WFS & DM 1042.9 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.0 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1999.1 OFF 0.47@1.65mic has_lapack=1 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 165.5 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 65.8 OFF 0.59@1.65mic test2 SH 12x12, quick method, with se... 459.7 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 59.5 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 767.7 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 75.0 OFF 0.84@2.20mic test6 DH WFS & DM 1137.6 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 31.7 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1567.1 OFF 0.47@1.65mic ---------------------------------------------------------- Fri Oct 26 13:57:34 2012, _has_lapack=0, sim.svipc=7 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 115.3 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 82.8 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 210.1 OFF 0.76@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 57.4 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 255.3 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 61.3 OFF 0.84@2.20mic test6 DH WFS & DM 250.0 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.4 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 434.1 OFF 0.46@1.65mic ---------------------------------------------------------- Fri Oct 26 14:02:06 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 149.2 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 173.0 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 71.0 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 81.9 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 368.6 ON 0.80@1.65mic test2 SH 12x12, quick method, with se... 522.7 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 49.9 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 63.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 548.3 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 897.3 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.2 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 66.1 OFF 0.84@2.20mic test6 DH WFS & DM 465.6 ON 0.50@1.65mic test6 DH WFS & DM 1020.5 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.6 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 27.3 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 778.3 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1950.6 OFF 0.47@1.65mic ---------------------------------------------------------- Thu May 23 06:26:39 2013 Parfile Name iter/s Display? Strehl ashfast-benc Simple SH6x6 w/ TT mirror, full... 1847.6 OFF 0.50@1.65mic ashfast-benc Simple SH6x6 w/ TT mirror, full... 1838.0 OFF 0.50@1.65mic c188-bench Simple Curvature 36 actuators w... 101.1 ON 0.64@1.65mic c188-bench Simple Curvature 36 actuators w... 117.3 OFF 0.64@1.65mic mcao2-bench Gemini MCAO system 7.1 ON 0.74@2.20mic mcao2-bench Gemini MCAO system 7.3 OFF 0.74@2.20mic sh6m2-bench Simple SH6x6 w/ TT mirror, full... 317.5 ON 0.45@1.65mic sh6m2-bench Simple SH6x6 w/ TT mirror, full... 391.1 OFF 0.45@1.65mic yao-5.4.0/examples/test-all_v5.2.0.dat000066400000000000000000000112151234404334100172530ustar00rootroot00000000000000---------------------------------------------------------- Thu Dec 20 11:26:20 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 100.0 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 100.0 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 100.0 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 100.0 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 100.0 ON 0.80@1.65mic test2 SH 12x12, quick method, with se... 100.0 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 100.0 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 100.0 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 100.0 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 100.0 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 100.0 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 100.0 OFF 0.84@2.20mic test6 DH WFS & DM 100.0 ON 0.50@1.65mic test6 DH WFS & DM 100.0 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 100.0 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 100.0 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 100.0 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 100.0 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Dec 20 11:30:49 2012 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 145.7 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 169.9 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 68.0 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 80.7 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 372.8 ON 0.80@1.65mic test2 SH 12x12, quick method, with se... 524.1 OFF 0.80@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.0 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 63.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 594.0 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 893.2 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 59.8 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.8 OFF 0.84@2.20mic test6 DH WFS & DM 518.5 ON 0.50@1.65mic test6 DH WFS & DM 1002.6 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.6 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.8 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 999.9 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 2055.2 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Aug 8 16:32:48 2013 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 151.8 ON 0.45@1.65mic test Simple SH6x6 w/ TT mirror, full... 168.0 OFF 0.45@1.65mic test1 Simili Altair LGS, full diffrac... 69.8 ON 0.60@1.65mic test1 Simili Altair LGS, full diffrac... 81.4 OFF 0.60@1.65mic test2 SH 12x12, quick method, with se... 378.5 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 496.6 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 48.5 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 62.8 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 546.5 ON 0.58@2.20mic test4 Simple Curvature 36 actuators w... 824.1 OFF 0.58@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 62.1 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.1 OFF 0.84@2.20mic test6 DH WFS & DM 492.8 ON 0.50@1.65mic test6 DH WFS & DM 973.0 OFF 0.50@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.8 ON 0.62@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.3 OFF 0.62@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1075.7 ON 0.36@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1888.2 OFF 0.36@1.65mic yao-5.4.0/examples/test-all_v5.3.0.dat000066400000000000000000000114531234404334100172600ustar00rootroot00000000000000---------------------------------------------------------- Wed Oct 30 15:57:54 2013 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 87.0 ON 0.44@1.65mic test Simple SH6x6 w/ TT mirror, full... 95.3 OFF 0.44@1.65mic test1 Simili Altair LGS, full diffrac... 37.1 ON 0.62@1.65mic test1 Simili Altair LGS, full diffrac... 43.3 OFF 0.62@1.65mic test2 SH 12x12, quick method, with se... 199.7 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 250.2 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 25.8 ON 0.06@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 32.9 OFF 0.06@2.23mic test4 Simple Curvature 36 actuators w... 280.2 ON 0.59@2.20mic test4 Simple Curvature 36 actuators w... 411.0 OFF 0.59@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 38.5 ON 0.87@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 39.9 OFF 0.87@2.20mic test6 DH WFS & DM 170.1 ON 0.49@1.65mic test6 DH WFS & DM 334.6 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 13.8 ON 0.63@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 14.2 OFF 0.63@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 540.2 ON 0.47@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 944.4 OFF 0.47@1.65mic ---------------------------------------------------------- Thu Jun 5 20:01:42 2014 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 151.8 ON 0.44@1.65mic test Simple SH6x6 w/ TT mirror, full... 236.0 OFF 0.44@1.65mic test1 Simili Altair LGS, full diffrac... 60.5 ON 0.57@1.65mic test1 Simili Altair LGS, full diffrac... 78.1 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 221.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 350.0 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 45.1 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 61.7 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 392.9 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 654.0 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 57.9 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 65.3 OFF 0.84@2.20mic test6 DH WFS & DM 186.6 ON 0.49@1.65mic test6 DH WFS & DM 393.2 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 24.4 ON 0.10@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.5 OFF 0.10@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 616.7 ON 0.44@1.65mic test8 Simple SH6x6 w/ TT mirror, full... 1392.4 OFF 0.44@1.65mic ---------------------------------------------------------- Thu Jun 5 20:08:43 2014 Parfile Name iter/s Display? Strehl test Simple SH6x6 w/ TT mirror, full... 167.0 ON 0.44@1.65mic test Simple SH6x6 w/ TT mirror, full... 241.1 OFF 0.44@1.65mic test0 Simple SH6x6 w/ TT mirror, full... 56.9 ON 0.44@1.65mic test0 Simple SH6x6 w/ TT mirror, full... 60.1 OFF 0.44@1.65mic test1 Simili Altair LGS, full diffrac... 65.1 ON 0.57@1.65mic test1 Simili Altair LGS, full diffrac... 72.9 OFF 0.58@1.65mic test2 SH 12x12, quick method, with se... 252.0 ON 0.79@1.65mic test2 SH 12x12, quick method, with se... 375.8 OFF 0.79@1.65mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 45.4 ON 0.05@2.23mic test3 GLAO example, 3 8x8 SHWFS, w/ d... 64.3 OFF 0.05@2.23mic test4 Simple Curvature 36 actuators w... 434.5 ON 0.56@2.20mic test4 Simple Curvature 36 actuators w... 720.8 OFF 0.56@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 63.4 ON 0.84@2.20mic test5 2.5 metre telescope w/ Pyramid WFS 67.0 OFF 0.84@2.20mic test6 DH WFS & DM 212.8 ON 0.49@1.65mic test6 DH WFS & DM 443.3 OFF 0.49@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 25.4 ON 0.10@1.65mic test7 LGS SH12x12, Extended WFS (11 n... 26.2 OFF 0.10@1.65mic test8 Simple SH6x6 (geometrical) 708.1 ON 0.44@1.65mic test8 Simple SH6x6 (geometrical) 1416.7 OFF 0.44@1.65mic yao-5.4.0/examples/test-extfield.i000066400000000000000000000036361234404334100170670ustar00rootroot00000000000000require,"yao.i"; parfile = "sh6x6.par"; nois = 0; skymag = 8; gsmag = 10.5; niter = 200; disp = 10; wfs_disp_crop_edges = 1; alls = []; aoread,parfile; loop.niter=niter; wfs(1).fssize=1.6; wfs(1).noise = nois; wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; aoinit,disp=1,clean=1; fits_write,"imat1.fits",iMat,overwrite=1; aoloop,disp=disp; ran1init; go,all=1; grow,alls,avg(strehl); // aoread,parfile; loop.niter=niter; // wfs(1).fssize=1.6; // wfs(1).spotpitch=8; // wfs(1).noise = nois; // wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; // aoinit,disp=1,clean=1; // fits_write,"imat2.fits",iMat,overwrite=1; // aoloop,disp=disp; // ran1init; // go,all=1; // grow,alls,avg(strehl); aoread,parfile; loop.niter=niter; wfs(1).extfield=4.; wfs(1).spotpitch=20; wfs(1).fssize=1.6; wfs(1).noise = nois; wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; aoinit,disp=1,clean=1; fits_write,"imat3.fits",iMat,overwrite=1; aoloop,disp=disp; ran1init; go,all=1; grow,alls,avg(strehl); aoread,parfile; loop.niter=niter; wfs(1).extfield=8.; wfs(1).spotpitch=10; wfs(1).fssize=1.6; wfs(1).noise = nois; wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; aoinit,disp=1,clean=1; fits_write,"imat4.fits",iMat,overwrite=1; aoloop,disp=disp; ran1init; go,all=1; grow,alls,avg(strehl); aoread,parfile; loop.niter=niter; wfs(1).extfield=10.; wfs(1).spotpitch=24; wfs(1).fssize=1.6; wfs(1).noise = nois; wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; aoinit,disp=1,clean=1; fits_write,"imat5.fits",iMat,overwrite=1; aoloop,disp=disp; ran1init; go,all=1; grow,alls,avg(strehl); // with sky aoread,parfile; loop.niter=niter; wfs(1).extfield=10.; wfs(1).spotpitch=24; wfs(1).fssize=3.2; wfs(1).noise = 1; wfs(1).gsmag = gsmag; wfs(1).skymag = skymag; aoinit,disp=1,clean=1; aoloop,disp=disp; ran1init; go,all=1; alls; dev = (alls-avg(alls))/avg(alls); dev; if (anyof(dev>0.001)) write,"There seems to be an issue with extfield."; \ else write,"All great with extfield!"; yao-5.4.0/examples/test-shwfs.i000066400000000000000000000000361234404334100164040ustar00rootroot00000000000000require,"yao.i"; shwfs_tests; yao-5.4.0/examples/test.par000066400000000000000000000043521234404334100156130ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple SH6x6 w/ TT mirror, full diffraction WFS"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; if (yao_major_version&&(yao_major_version>=4)&&(yao_minor_version>=10)) { wfs(n).extfield = 2.; } //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 50; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 50; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/test0.par000066400000000000000000000043661234404334100157000ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple SH6x6 w/ TT mirror, full diffraction WFS"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(1).extfield = 8.; wfs(1).spotpitch = 24; wfs(1).fstop = "square"; wfs(1).fssize = 1.6; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 50; dm(n).elt = 1; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 50; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/test1.par000066400000000000000000000056021234404334100156730ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simili Altair LGS, full diffraction WFS, spot elongation"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 40.; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 95000.; wfs(n).gsdepth = 10000.; wfs(n).laserpower = 25.; wfs(n).skymag = 20.; wfs(n).shmethod = 2; wfs(n).shnxsub = 12; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.1; wfs(n).kernel = 1.0 wfs(n).dispzoom = 2.; wfs(n).noise = 1; wfs(n).ron = 5; n = 2; wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 15.; wfs(n).skymag = 18.5; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).pixsize = 0.5; wfs(n).npixels = 4; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).dispzoom = 0.15; wfs(n).noise = 1; wfs(n).ron = 5; wfs(n).darkcurrent = 200; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 13; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 50; dm(n).elt = 1; dm(n).coupling = 0.15; n =2; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 10; dm(n).gain = 0.3; //------------------------------- mat.condition = &([15.,15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.,10,10]); target.yposition = &([0,0,10]); target.dispzoom = &([1.,1.,1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/test2.par000066400000000000000000000047051234404334100156770ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH 12x12, quick method, with separate Quadcell and TT mirror"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 40.; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).subsystem = 1; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 1; wfs(n).shnxsub = 12; wfs(n).filtertilt = 1; // using a dedicated TT guide star, so I filter this one. wfs(n).skymag = 18.; n = 2; wfs(n).type = "hartmann"; wfs(n).subsystem = 2; wfs(n).lambda = 0.65; wfs(n).gspos = [5.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 16.; wfs(n).skymag = 20.5; wfs(n).shmethod = 2; wfs(n).shnxsub = 1; wfs(n).npixels = 2; wfs(n).pixsize = 0.5; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).darkcurrent = 500.; wfs(n).dispzoom = 0.1; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).nxact = 13; dm(n).pitch = 5; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 2; n =2; dm(n).type = "tiptilt"; dm(n).subsystem = 2; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 2; dm(n).gain = 0.5; //------------------------------- mat.condition = &([15.,100.]); //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0.]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 0; loop.niter = 500; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/test3.par000066400000000000000000000056201234404334100156750ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "GLAO example, 3 8x8 SHWFS, w/ disk harmonics"; sim.pupildiam = 128; sim.debug = 1; sim.verbose = 1; sim.svipc_wfs_nfork = 3; //------------------------------- tel.diam = 8.0; //VLT tel.cobs = 0.14; //VLT //------------------------------- seeing = 1.00; // in arcsec at 550nm (V band) r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^1.2; //atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.dr0at05mic = tel.diam/r0at500; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4","5","6"]+".fits"); atm.layerfrac = &([0.64,0.2,0.05,0.05,0.05,0.01]); atm.layerspeed = &([11.,20,29,35,30,40]); atm.layeralt = &([0.,400,2000,6000,8500,13000]); atm.winddir = &([0,0,0,0,0,0]); //------------------------------- nwfs = 3; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [50.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; n = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,-52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; n = 3; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [-40.,52.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 11.; wfs(n).shmethod = 2; wfs(n).shnxsub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 8; wfs(n).noise = 1; wfs(n).ron = 6.0; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; //------------------------------- ndm = 1; dm = array(dms,ndm); n = 1; dm(n).type = "dh"; dm(n).ndh = 45; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 1; //------------------------------- mat.condition = &([50.]); mat.file = ""; //------------------------------- target.lambda = &([2.23]); xy = (indices(3)-2.)*60.; target.xposition = &(xy(,,1)(*)); target.yposition = &(xy(,,2)(*)); target.dispzoom = &(array(1.,numberof(xy(,,1)))); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 2; loop.niter = 500; loop.ittime = 2.5e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; //------------------------------- yao-5.4.0/examples/test4.par000066400000000000000000000036161234404334100157010ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "Simple Curvature 36 actuators with noise"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "curvature"; wfs(n).nsubperring = &([6,12,18]); wfs(n).l = 0.2; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).skymag = 18.; wfs(n).noise = 1; wfs(n).ron = 0.; wfs(n).darkcurrent = 400; wfs(n).nintegcycles = 1; wfs(n).fieldstopdiam = 4.; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "bimorph"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).nelperring = &([6,12,18]); dm(n).unitpervolt = 0.01; dm(n).push4imat = 10; //------------------------------- mat.condition = &([15.]); //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65,2.2]); target.xposition = &([0.]); target.yposition = &([0.]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 1000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; yao-5.4.0/examples/test5.par000066400000000000000000000040461234404334100157000ustar00rootroot00000000000000// YAO parameter file //------------------------------- tel.diam = 2.5; tel.cobs = 0.; sim.name = "2.5 metre telescope w/ Pyramid WFS" sim.pupildiam = 64; sim.debug = 0; sim.verbose = 1; //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "pyramid"; wfs(n).fstop = "round"; wfs(n).fssize = 2.0; wfs(n).lambda = 0.65; wfs(n).shnxsub = 8; wfs(n).npixpersub = sim.pupildiam/wfs(n).shnxsub; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 8; wfs(n).skymag = 15.; wfs(n).noise = 1; wfs(n).ron = 3.; wfs(n).darkcurrent = 0.; wfs(n).pyr_mod_npts = 16; wfs(n).pyr_mod_ampl = 0.25; wfs(n).pyr_padding = 1; wfs(n).pyr_mod_loc = "after"; //------------------------------- ndm = 1; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = wfs(n).shnxsub+1; dm(n).pitch = wfs(n).npixpersub; dm(n).alt = 0.; dm(n).unitpervolt = 1.; dm(n).push4imat = 0.05; dm(n).elt = 1; dm(n).gain = 1.; dm(n).regtype = "laplacian"; if (wfs(1).type == "hartmann"){ dm(1).regparam = 1e-2; } else {dm(1).regparam = 1e-2;} //------------------------------- mat.method = "mmse"; //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- r0 = 0.10; atm.dr0at05mic = tel.diam/r0; // this is r0=0.2 at 500 nm atm.screen = &(Y_USER+"data/screen1.fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([12.]); atm.layeralt = &([0.]); atm.winddir = &([0.]); //------------------------------- gs.zeropoint = 1.2e11; //------------------------------- loop.gain = 0.3; loop.framedelay = 2; loop.niter = 100000; loop.startskip = 30; loop.ittime = 0.001; yao-5.4.0/examples/test6.par000066400000000000000000000033001234404334100156710ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "DH WFS & DM"; sim.pupildiam = 64; sim.debug = 1; sim.verbose = 1; //------------------------------- tel.diam = 3.6; //------------------------------- seeing = 1.00; // in arcsec at 550nm (V band) r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^1.2; //atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.dr0at05mic = tel.diam/r0at500; atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.6,0.1,0.1,0.1]); atm.layerspeed = &([11.,20,35,30]); atm.layeralt = &([0.,400,6000,13000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "dh"; wfs(n).ndh = 45; wfs(n).lambda = 0.65; wfs(n).gspos = [00.,0.]; wfs(n).gsalt = 0.; //------------------------------- ndm = 1; dm = array(dms,ndm); n = 1; dm(n).type = "dh"; dm(n).ndh = 45; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).push4imat = 0.01; //------------------------------- mat.condition = &([50.]); //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0.]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 3e11; //------------------------------- loop.gain = 0.4; loop.framedelay = 2; loop.niter = 500; loop.ittime = 2.5e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; //------------------------------- yao-5.4.0/examples/test7.par000066400000000000000000000116471234404334100157070ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "LGS SH12x12, Extended WFS (11 npt profile)"; sim.pupildiam = 120; sim.debug = 0; sim.verbose = 1; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- tel.diam = 12.; tel.cobs = 0.1125; //------------------------------- nwfs = 2; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); no_pad_simage = 1; n = 1; wfs(n).subsystem = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 90000.; wfs(n).gsdepth = 10000.; wfs(n).gsdepth = 2000.; wfs(n).laserpower = 30.; wfs(n).kernel = 1.1; wfs(n).LLTxy = [0.,0.]; wfs(n).gsmag = 7.; wfs(n).shmethod = 2; wfs(n).shnxsub = 12; wfs(n).pixsize = 0.25; wfs(n).npixels = 8; wfs(n).extfield = 5.; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; wfs(n).lgs_prof_amp= &float([0.6,1.2,0.9,0.9,0.5,0.2]); wfs(n).lgs_prof_alt= &float([92 ,94 ,96 ,98 ,100,102]*1e3); wfs(n).fssize = 4.; wfs(n).filtertilt = 1; wfs(n).correctUpTT = 1; wfs(n).uplinkgain = 0.2; wfs(1).lgs_prof_amp = &float([1.0,1.0]); wfs(1).lgs_prof_alt = &float([90000,100000]); wfs(1).lgs_prof_alt = &float([90000,95000]); wfs(1).lgs_focus_alt=0; shwfs_comp_lgs_defocuses,1; func one_layer(void) { extern wfs; wfs(1).lgs_prof_amp = &float([1.0]); wfs(1).lgs_prof_alt = &float([94000]); wfs(1).lgs_focus_alt=94000; shwfs_comp_lgs_defocuses,1; } func all_layers(void) { wfs(1).lgs_prof_amp= &float([0.6,1.2,0.9,0.9,0.5,0.2]); wfs(1).lgs_prof_alt= &float([92 ,94 ,96 ,98 ,100,102]*1e3); wfs(1).lgs_prof_amp= &float(makegaussian(21,10)(11,)); (*wfs(1).lgs_prof_amp)(3) *=2 ; // this will put two points separated by 10km, for calibrations of the method: //~ *wfs(1).lgs_prof_amp *=0; //~ (*wfs(1).lgs_prof_amp)(3) = 2; //~ (*wfs(1).lgs_prof_amp)(8) = 3; wfs(1).lgs_prof_alt= &float((89+indgen(21)*1)*1e3); // that should be fwhm=10km wfs(1).lgs_focus_alt = 0.; // will be set by shwfs_comp_lgs_defocuses() shwfs_comp_lgs_defocuses,1; } func all_layers2(ns,npt,fwhm) { extern wfs; wfs(ns).lgs_prof_amp= &float(makegaussian(npt,npt/2*fwhm/10.)(npt/2+1,)); (*wfs(ns).lgs_prof_amp)(3) *=2 ; wfs(ns).lgs_prof_alt= &float(span(90,110,npt)*1e3); // that should be fwhm=10km wfs(ns).lgs_focus_alt = 0.; // will be set by shwfs_comp_lgs_defocuses() shwfs_comp_lgs_defocuses,ns; } func ubc_profile(bin2) { extern wfs; amp = [0.00125154,0.00143618,0.00161906,0.0481773,0.043927,0.0533849,0.0932741, 0.0816419,0.0849489,0.155098,0.146013,0.130336,0.096709,0.022861,0.0130669, 0.00831713,0.00523775,0.0045743,0.0048842,0.00324208]; alt = [90,91.3158,92.6316,93.9474,95.2632,96.5789,97.8947,99.2105,100.526,101.842, 103.158,104.474,105.789,107.105,108.421,109.737,111.053,112.368,113.684,115]*1e3; if (bin2) { amp = (amp+roll(amp,1))(indgen(10)*2); alt = (alt+roll(alt,1))(indgen(10)*2)/2.; } for (i=1;i<=6;i++) { wfs(i).lgs_prof_amp= &float(amp); wfs(i).lgs_prof_alt= &float(alt); wfs(i).lgs_focus_alt = 0.; // will be set by shwfs_comp_lgs_defocuses() shwfs_comp_lgs_defocuses,i; } } all_layers2,1,11,10.; n = 2; wfs(n).subsystem = 2; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsmag = 7.; wfs(n).shmethod = 1; wfs(n).shnxsub = 1; wfs(n).noise = 0; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).dispzoom = 0.0; //------------------------------- ndm = 2; dm = array(dms,ndm); mergedms4disp = 1; n =1; dm(n).subsystem = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = wfs(n).shnxsub+1; dm(n).pitch = sim.pupildiam/wfs(n).shnxsub; dm(n).ndh = 40; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 20.; dm(n).elt = 0; n =2; dm(n).subsystem = 2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 400; //------------------------------- mat.method = "mmse"; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 20000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; //------------------------------- yao-5.4.0/examples/test8.par000066400000000000000000000040631234404334100157020ustar00rootroot00000000000000// Aosimul par file, V2.4.0 //------------------------------- sim.name = "Simple SH6x6 (geometrical)"; sim.pupildiam = 60; sim.debug = 0; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1"]+".fits"); atm.layerfrac = &([1.0]); atm.layerspeed = &([11.]); atm.layeralt = &([0.]); atm.winddir = &([0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 1; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.1; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 0.05; wfs(n).shthreshold = 0.; wfs(n).nintegcycles = 1; wfs(n).optthroughput= 0.5; //------------------------------- ndm = 2; dm = array(dms,ndm); n =1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 7; dm(n).pitch = 10; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 2; n =2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0005; dm(n).push4imat = 2; //------------------------------- mat.condition = &([15.]); //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2e11; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.15; loop.framedelay = 1; loop.niter = 2000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 1000; loop.skipby = 10000; loop.stats_every = 200; //------------------------------- yao-5.4.0/examples/testclean000077500000000000000000000000741234404334100160350ustar00rootroot00000000000000#!/bin/sh \rm *.fits *.ps *.res *.ruo *.rco *~ 2> /dev/null yao-5.4.0/examples/todel-svipc.par000066400000000000000000000042731234404334100170670ustar00rootroot00000000000000// YAO parameter file //------------------------------- //------------------------------- tel.diam = 8; tel.cobs = 0.; sim.name = "Toy simulation using svd reconstructor" sim.pupildiam = 128; sim.debug = 0; sim.verbose = 2; sim.svipc = 1+4; YAO_SAVEPATH="~/.yorick/yao/"; // where to save the output to the simulations //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).npixpersub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 6; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 0; dm(n).gain = 1.; dm(n).regparam = 1e-4; n = 2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0001; dm(n).push4imat = 100; dm(n).gain = 0.8; dm(n).regparam = 0.; //------------------------------- mat.method = "svd"; mat.condition = &([15.]); //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); r0 = 0.13 //------------------------------- atm.dr0at05mic = tel.diam/r0; atm.screen = &(Y_USER+"data/screen"+["1","2"]+".fits"); atm.layerfrac = &([0.6,0.4]); atm.layerspeed = &([12.,15.]); atm.layeralt = &([0.,5000]); atm.winddir = &([0.,0.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.5; loop.framedelay = 2; loop.niter = 1000; loop.ittime = 0.001; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.stats_every = 10; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/todel.par000066400000000000000000000036151234404334100157440ustar00rootroot00000000000000// YAO parameter file //------------------------------- sim.name = "SH6x6 w/ TT mirror and WFS, full diffraction WFS"; sim.pupildiam = 120; sim.debug = 2; sim.verbose = 0; //------------------------------- atm.dr0at05mic = 42.44; // this is r0=0.166 at 550 nm atm.screen = &(Y_USER+"data/screen"+["1","2","3","4"]+".fits"); atm.layerfrac = &([0.4,0.2,0.3,0.1]); atm.layerspeed = &([11.,20,29,35]); atm.layeralt = &([0.,400,6000,9000]); atm.winddir = &([0,0,0,0]); //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 12.; wfs(n).shmethod = 2; wfs(n).shnxsub = 6; wfs(n).pixsize = 0.2; wfs(n).npixels = 10; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; wfs(n).fstop = "square"; wfs(n).fssize = 10.; //------------------------------- ndm = 1; dm = array(dms,ndm); n =1; dm(n).type = "zernike"; dm(n).iffile = ""; dm(n).nzer = 21; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 1; //------------------------------- mat.condition = &([15.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.1125; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.6; loop.framedelay = 1; loop.niter = 5000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.modalgainfile = "simulModeGains.fits"; //------------------------------- yao-5.4.0/examples/toy-8m-mmse.par000066400000000000000000000042551234404334100167320ustar00rootroot00000000000000// YAO parameter file //------------------------------- //------------------------------- tel.diam = 8; tel.cobs = 0.; sim.name = "Toy simulation using mmse matrix reconstructor" sim.pupildiam = 128; sim.debug = 0; sim.verbose = 2; YAO_SAVEPATH="~/.yorick/yao/"; // where to save the output to the simulations //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).npixpersub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 6; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 1; dm(n).gain = 1.; dm(n).regparam = 1e-4; dm(n).regtype = "laplacian"; n = 2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0001; dm(n).push4imat = 100; dm(n).gain = 0.8; dm(n).regparam = 0.; //------------------------------- mat.method = "mmse"; //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); r0 = 0.13 //------------------------------- atm.dr0at05mic = tel.diam/r0; atm.screen = &(Y_USER+"data/screen"+["1","2"]+".fits"); atm.layerfrac = &([0.6,0.4]); atm.layerspeed = &([12.,15.]); atm.layeralt = &([0.,5000]); atm.winddir = &([0.,0.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.5; loop.framedelay = 2; loop.niter = 1000; loop.ittime = 0.001; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.stats_every = 10; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/toy-8m-sparse.par000066400000000000000000000042731234404334100172660ustar00rootroot00000000000000// YAO parameter file //------------------------------- //------------------------------- tel.diam = 8; tel.cobs = 0.; sim.name = "Toy simulation using mmse-sparse matrix reconstructor" sim.pupildiam = 128; sim.debug = 0; sim.verbose = 2; YAO_SAVEPATH="~/.yorick/yao/"; // where to save the output to the simulations //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).npixpersub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 6; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 1; dm(n).gain = 1.; dm(n).regparam = 1e-4; dm(n).regtype = "laplacian"; n = 2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0001; dm(n).push4imat = 100; dm(n).gain = 0.8; dm(n).regparam = 0.; //------------------------------- mat.method = "mmse-sparse"; //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); r0 = 0.13 //------------------------------- atm.dr0at05mic = tel.diam/r0; atm.screen = &(Y_USER+"data/screen"+["1","2"]+".fits"); atm.layerfrac = &([0.6,0.4]); atm.layerspeed = &([12.,15.]); atm.layeralt = &([0.,5000]); atm.winddir = &([0.,0.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.5; loop.framedelay = 2; loop.niter = 1000; loop.ittime = 0.001; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.stats_every = 10; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/toy-8m-svd.par000066400000000000000000000042411234404334100165600ustar00rootroot00000000000000// YAO parameter file //------------------------------- //------------------------------- tel.diam = 8; tel.cobs = 0.; sim.name = "Toy simulation using svd reconstructor" sim.pupildiam = 128; sim.debug = 0; sim.verbose = 2; YAO_SAVEPATH="~/.yorick/yao/"; // where to save the output to the simulations //------------------------------- nwfs = 1; // number of WFSs (>1 if e.g. mcao) wfs = array(wfss,nwfs); n = 1; wfs(n).type = "hartmann"; wfs(n).lambda = 0.65; wfs(n).gspos = [0.,0.]; wfs(n).gsalt = 0.; wfs(n).gsmag = 5.; wfs(n).shmethod = 2; wfs(n).shnxsub = 16; wfs(n).npixpersub = 8; wfs(n).pixsize = 0.3; wfs(n).npixels = 6; wfs(n).noise = 1; wfs(n).ron = 3.5; wfs(n).shthreshold = 0.; wfs(n).nintegcycles= 1; //------------------------------- ndm = 2; dm = array(dms,ndm); n = 1; dm(n).type = "stackarray"; dm(n).iffile = ""; dm(n).nxact = 17; dm(n).pitch = 8; dm(n).alt = 0.; dm(n).unitpervolt = 0.01; dm(n).push4imat = 100; dm(n).elt = 1; dm(n).gain = 1.; dm(n).regparam = 1e-4; n = 2; dm(n).type = "tiptilt"; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 0.0001; dm(n).push4imat = 100; dm(n).gain = 0.8; dm(n).regparam = 0.; //------------------------------- mat.method = "svd"; mat.condition = &([15.]); //------------------------------- target.lambda = &([2.2]); target.xposition = &([0.]); target.yposition = &([0]); target.dispzoom = &([1.]); r0 = 0.13 //------------------------------- atm.dr0at05mic = tel.diam/r0; atm.screen = &(Y_USER+"data/screen"+["1","2"]+".fits"); atm.layerfrac = &([0.6,0.4]); atm.layerspeed = &([12.,15.]); atm.layeralt = &([0.,5000]); atm.winddir = &([0.,0.]); //------------------------------- gs.zeropoint = 1e11; //------------------------------- loop.gain = 0.5; loop.framedelay = 2; loop.niter = 1000; loop.ittime = 0.001; loop.startskip = 10; loop.skipevery = 10000; loop.skipby = 10000; loop.stats_every = 10; loop.modalgainfile = "simulModeGains.fits"; yao-5.4.0/examples/toy-dh.par000066400000000000000000000031021234404334100160300ustar00rootroot00000000000000// Aosimul par file, V2.4.0 //------------------------------- sim.name = "Toy system with DH"; sim.pupildiam = 64; sim.debug = 1; sim.verbose = 2; //------------------------------- atm.dr0at05mic = 44.; atm.screen = &(["~/.yorick/data/screen1.fits"]); atm.layerfrac = &([1.0]); atm.layerspeed = &([10.]); atm.layeralt = &([0.]); atm.winddir = &([0]); //------------------------------- nwfs = 1; wfs = array(wfss,nwfs); n = 1; wfs(n).type = "dh"; wfs(n).ndh = 45; wfs(n).subsystem = 1; wfs(n).lambda = 0.650; wfs(n).gspos = [0,0]; //------------------------------- ndm = 1; dm = array(dms,ndm); n = 1; dm(n).type = "dh"; dm(n).ndh = 45; dm(n).subsystem = 1; dm(n).iffile = ""; dm(n).alt = 0.; dm(n).unitpervolt = 1; dm(n).push4imat = 0.02; //------------------------------- mat.condition = &([50.]); mat.file = ""; //------------------------------- tel.diam = 7.9; tel.cobs = 0.; //------------------------------- target.lambda = &([1.65]); target.xposition = &([0]); target.yposition = &([0]); target.dispzoom = &([1.]); //------------------------------- gs.zeropoint = 2e11; gs.lgsreturnperwatt = 22.; gs.zenithangle = 0.; //------------------------------- loop.gain = 0.4; loop.framedelay = 1; loop.niter = 10000; loop.ittime = 2e-3; loop.startskip = 10; loop.skipevery = 500; loop.skipby = 5000; loop.modalgainfile = "null.fits"; yao-5.4.0/examples/user1.glade000066400000000000000000000021261234404334100161620ustar00rootroot00000000000000 False True False hello world ! True True True True True 0 yao-5.4.0/examples/user1.py000066400000000000000000000015151234404334100155370ustar00rootroot00000000000000#!/usr/bin/env python # template user1.py # To add some user widgets in yao interfaces # 1) modify user*.glade: # - implement button/widgets in user*.glade & edit for callbacks. # 2) in user*.py: # - change label # - add callback functions to your buttons, etc. # first panel is user1 # second panel is user2 import gobject import gtk import gtk.glade import os import string import sys class user1: def __init__(self, path='.', parent=None, py2yo=None): self.py2yo=py2yo self.gladefile = 'user1.glade' self.glade = gtk.glade.XML(os.path.join(path,self.gladefile), root='top') self.top = self.glade.get_widget('top') self.glade.signal_autoconnect(self) if parent: parent.foreach(parent.remove) parent.add(self.top) parent.show() def label(self): return 'my button' yao-5.4.0/examples/yao_loop_example.i000066400000000000000000000031061234404334100176320ustar00rootroot00000000000000require,"yao.i"; write,"CREATING PHASE SCREENS"; if (!open(Y_USER+"data/screen1.fits","r",1)) { create_phase_screens,1024,256,prefix=YUSER+"data/screen"; } window,33,wait=1; // read out parfile aoread,"test.par"; atm.dr0at05mic = 35; // be more gentle // define vector on which we want to loop and final strehl array // we want to estimate performance for 3 values of the guide star // magnitude and 4 values of the loop gain (for instance) gsmagv = [6,9,12]; gainv = [0.01,0.1,0.5,1.0]; strehlarray = array(0.,[2,numberof(gsmagv),numberof(gainv)]); // loop on gsmag and gain for (ii=1;ii<=numberof(gsmagv);ii++) { for (jj=1;jj<=numberof(gainv);jj++) { wfs(1).gsmag=gsmagv(ii); loop.gain=gainv(jj); // it's safer, but not always necessary, to call again // aoinit (here for gsmag). some parameters do not need it. aoinit,disp=1; aoloop,disp=1; go, all=1; // after_loop is now called automatically at last it of go() //after_loop; // to wrap up the analysis and print out results strehlarray(ii,jj) = strehllp(0); // fill in result array // and display results as we go: window,33; fma; for (ll=1;ll<=ii;ll++) { plg,strehlarray(ll,),gainv,color=-ll-4; plp,strehlarray(ll,),gainv,color=-ll-4,symbol=4,size=0.6; ylims=limits()(3:4); ymax=ylims(2); yspace=(ylims(2)-ylims(1))/15.; plt,swrite(format="gsmag=%d",gsmagv(ll)),0.011,ymax-yspace*(ll-1), \ justify="LT",tosys=1,color=-ll-4; } logxy,1,0; xytitles,"Loop Gain",swrite(format="Strehl @ %.2fmicrons",(*target.lambda)(0)); window,0; } } yao-5.4.0/flags.txt000066400000000000000000000004061234404334100141430ustar00rootroot00000000000000wfs_disp_crop_edges: if set to one, will crop the edges of SH WFS spot image in WFS display (wfs._dispimage) to 50% of spot pitch. Otherwise, will display the whole SHWFS image, that may include larger edges due for instance to a wfs.extfield > wfs.spotpitch. yao-5.4.0/letter.gs000066400000000000000000000067731234404334100141550ustar00rootroot00000000000000# Gist work.gs drawing style # $Id: letter.gs,v 1.1.1.1 2007/12/12 23:29:11 frigaut Exp $ # A single coordinate system on a portrait page # Legends: two columns below viewport, contours in single column to right # See the header file gist.h for a more complete description of the # meanings of the various keywords set in this file; they coincide with the # values of the corresponding C data structure members defined in gist.h. # Here is a brief description: # Units and coordinate systems: # viewport, tickOff, labelOff, tickLen, xOver, yOver, height (of text) # legends.(x,y,dx,dy) # Coordinates are in Gist's "NDC" coordinate system. In this system, # 0.0013 unit is 1.000 point, and there are 72.27 points per inch. # The lower left hand corner of the sheet of paper is at (0,0). # For landscape=0, the 8.5 inch edge of the paper is horizontal; # for landscape=1, the 11 inch edge of the paper is horizontal. # width # Line width is measured in relative units, with 1.0 being 1/2 point. # Ticks flags (add together the ones you want): # 0x001 Draw ticks on bottom or left edge of viewport # 0x002 Draw ticks on top or right edge of viewport # 0x004 Draw ticks centered on origin in middle of viewport # 0x008 Ticks project inward into viewport # 0x010 Ticks project outward away from viewport (0x18 for both) # 0x020 Draw tick label numbers on bottom or left edge of viewport # 0x040 Draw tick label numbers on top or right edge of viewport # 0x080 Draw all grid lines down to gridLevel # 0x100 Draw single grid line at origin # Line types: # solid 1 # dash 2 # dot 3 # dash-dot 4 # dash-dot-dot 5 # Font numbers: # Courier 0x00 # Times 0x04 # Helvetica 0x08 # Symbol 0x0c # Schoolbook 0x10 # Add 0x01 for bold, 0x02 for italic # This actually repeats the default values in gread.c landscape= 0 default = { legend= 0, viewport= { 0., 1.0, 0., 1.0 }, ticks= { horiz= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 3, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.395, yOver= 0.370 }, vert= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 4, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.150, yOver= 0.370 }, frame= 0, frameStyle= { color= -2, type= 1, width= 1.0 }}} # The one coordinate system matches the default template exactly system= { legend= "System 0" } legends= { x= 0.04698, y= 0.360, dx= 0.3758, dy= 0.0, textStyle= { color= -2, font= 0x00, height= 0.0156, orient= 0, alignH= 1, alignV= 1, opaque= 0 }, nchars= 36, nlines= 20, nwrap= 2 } clegends= { x= 0.6182, y= 0.8643, dx= 0.0, dy= 0.0, textStyle= { color= -2, font= 0x00, height= 0.0156, orient= 0, alignH= 1, alignV= 1, opaque= 0 }, nchars= 14, nlines= 28, nwrap= 1 } yao-5.4.0/shwfs_yao_geometry.png000066400000000000000000000627561234404334100167510ustar00rootroot00000000000000PNG  IHDRJj>ysBIT|d pHYs̢tEXtSoftwarewww.inkscape.org< IDATxwx驪B -  PE:At""H5H !ukVb I6!ysfow˾;g1f3"""""" pw""""":(㒤ωvBVKW"[Iҏ $""Lk˕+)R4@}ɚ͋(sTYx99s$GD]yI!!ܱ&O]wA| ''$6ͷ'W.$GDdpy(Z58K>ΗP!"i-$seh+tADD$ -?(!W.ѼYMo" yS,^<7y﷌F瀀̛;KRdykJc=k |DΜyx }?NϘѓ}Ƒ;wGDcN<șG̒%Qn[!3fjv9w.8ƾ}FF+4g횅^l}5sQ~3+H&''g|Us[xxZJ~an Em,mZۗCc\]hq{>#ݺ}ɓ4#,LI=tôH 1'?s~-Șd2Y0:y\w?+30;܉W&O]u=s&^z5,)41vm;\LHʣ ""BQO04C3u.]:mƟоݻ|aƏɓY3GbO3y*rcЧ߄XnܸK0a|?BBy͆LGADD$0p 4l6[0?-bԹ?ZщcGdԡ|Ш ϑm۶Wƌds(Ub7o^rc3мYMuk.QhfIɓT\ """)Ht>b dfƌ]hǏ37P~31wx2;w?&**];jx2k,ŀh~Eۆg6򕇩RgxD$%SxI2dlӲUwf3 O݃W^y#U̟7p?wަC~@Mة .3/cOcy"L&7;EDk """)4s]'v#Nq#"}^H2x:;Phi>AիϸXSN6ss4IDDDR:Ijܽ{;O [6/f8eΜ>@YptLx6:pJn6k3ǹB7ƾZDR7⯀>^k͛Ն9?joϞ=Η_~ĕ+rُ)SXڽf}i,˖=S`KRn&LƍKnO0y L&}>%"I!>}c^{՛| [i}ᅢk᷍8uoYqYf3<#zᑁû۶X|X M#*2 ~[pvvPܾe~'jͺHʢ+""" k6/L&ٳ匷M"p*T#**K@MXxulrhnت,Oֿ7eݻ'** ;bm>Vy2db1j"**3pvnn4|%KC!"l6ۻ]`˟s炉Lso%Kv{! dɒ q woRP =mwv7nB"nZvYrN?@hȝ;?yw{hc.?M:NN S}6XWAÖDDx qsۻᶹr#W| ˖-'l\ː'9::SZlquuDr,'W-[uE/qqqw97 [p;oa醦} uk`+]MAD ;vl{enؗ<|x刈]v;5U78w,c۷{mjstKEݳ1dpg\Uڥ "iÇ9'-ŶڻlbɼFa.LddKJsD$MbҙfafDDRc4=\UڢٖD$9xp'þSa2Cn\? ODDGsNҪzT3 "i3k^cIDDl}%۷ekZ*hؒ a|;K ""Ϗ0fɌGػƒ .LISVZ/kGY+Y_t=4lIDҔZSFmǔCxa+_'Cu"" wdl6+7=E&cuiƒ9.|+4h{|OQ6g˖3+Ӷ״ٻ4CÖD$ʚ͋odT L"")d^l,:SpHf ",U wx (D$џeVf݌5/bK~ދO*.'MSxy;;gƳ'.GD$2LҮ}o6v p "92j.E]HS4ݾJt]M-P˔/IsE=S"]yCtADҌ{UHRʑ^g*_ "f\#ڻ IJo>w/ [CDDDDD [4~]ȓUȳ1]Eڠ "iV\Pg(<$ [CDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD QxCDDDDD1DADDDDD Qxѭiݼǎl[ Ǐmmܸ~n5$S'wѦEF$Y73Z7/#$k"iƒ<.iln\׵Vǹ˯kڭaݏ\-rT_m,n\`oƒ^|2YIK]HR{&+__J~uEͿA&g.RjQ6\\1|qsOO~~2U_ϋ}ؿs:_(E=ɘ1S7a!̛ӟ!2"ekЮ82{z%[*lΧ>F~ 7A:$xܵ'sz^DxcVȩS9aa)\EWȐ!K#"1c|w S&vCTZ/޾7y)ŊW ~՛ݻV`rlhq{`֏_Q f/ekc=߷..]>SoJADD%#8|wܻ&'o޵W?O;‰;ضe1]òGc6GY_piljٜ&)~OE otcG2ng|͂XFFF0tpcNڃkܹ΄?gu1?}jO׵޼߸;ޛ8޶-|was_sTwX0oYvݶܾu!xA 4@:3ubg~Fu3 *Uc9ڹ[70bnjBߘ8=QQ?Fs䉝v7s''Kმ8yb'+ [ f'`6uk'}|V$""vz,KWo fÁ}ywqu.#M>؉l&O?JcI.#7"""f&ᑉ,d!LԙcG5knzk}ѣe[g|G:/+1|W3WNKүp1o$|cS&vAh#O` Wx?&c>O7?CB;p9s^aқ n+C` ˮb`b>3|7C"J9yb'2eg̸]"E_~Lqn9[ K\t1ӺߣG޵j^. L&C̐! #;B>ab*^%KUΝe>(Ç6y˕˧1c(>iڟW_kcӖ]|I DD$U(#Ο?bLLW App5_AW#n\?ϐ \t9 ЧRB>7L>EΜ Ů+,_:puMǀ!eCI{}ptt򥓱n8w|g1>x5Y!Sdϑlߺn+aݏO߿~} Y:7.8^^/<IDDD3!0{״oS=V2m)UotquU̚wNO3cOu,C~$u.:c΂L wlbڔ/qq"":7.PHEz|5_WLNN΄<䧙ٵ77ZYIDD$U8FވL܅Ƕ%K. L[9S/пIVEe""¨fs~Gw͈]Q[DDǚ֖處׻S'u53_pP W}ļA_eJ|_oOHu6f̀8HE hӲ?/n=?t6ηHj ""Ϳ.6ۜმpppP vdJ.n:30/Y'vr70%jNr#n˦/pk Axxh}[]{6fsȝ0c'}b/g}OZpEU6t蛺V8JYܹ}[g`v8CEG׮{Vφu?kf+^C$RxTc.\^[39QQ|7L n=fRxe*Vz6Fǘ)Z>G?17LppM8$!5/LΕ ycݫțX`т! 0d52dY!\aK'6kg,_:{V1S6>}bzDEEݷq9 *G^sqrrw]:lnu_jV׈bwqZL&=Eh}e9ٽ?heboƒ &ֹ2sg>BBr1V.G6?C"iw@dd};LN ۵?#,4s5붶ƒ+?n^K l43q6fLIux>5_:cSUppp,y-9sc ܘǶq9fLɉ;pvv+ |=v,c܁888ҫ"󕰾o=G>\z_t\ݻVp?AA8x`#zft6К ?Nმŀ!+xg̘W.]Fv= IDATls>'ٲ= ڄӧ4'tc`+> QQ|Ҵ?_k[tX|6ךP+Z=*1"""v;!c< xXm^);Ow=' ԘRZ6N]pYNa0mK1w3vT+1#[yw#ϕ} |ˬb 3׻6l}L&mڍۻrW76Ӧ(^\;v77 Y*qfB mk1ہڞӋngPʻ kϮZ1ggW \A1_^}1{,?2>Suɠ~سk%{vwppc60 zU`A6ףhHhY!|ݚ6qS|vdD' ""lJK'^\vggWZAժ<irx`rTވ }\fȘrӳ׼8gqrrπe SOO۲f͐6il G}*^9_tԮۖB:fCȕ0+㯀?yPDOς9rx3a)"M>C25l&2eNh8dϑ~W0Oɐ1KmSXe&N=9uj7"4,}(\">ILc'oQfC'^+Yᳶ(QjU\'d0>^gܤ},;cGbLb .]O/WO|Wvvqo=PDҬ]`eVr炉O7|q(|@BGYz2S&vzeIS4,^zٻx[3֓T/OLvh7$o ADDDDD QxCDDDDD1D-HVp2en-]V6<< {7!~'LxzAJP&dȒe$wy?` = d &Gp&6}ߎ17.ZkH9P *^ngf70fKx eyAN.VJkH3;8+a ! BnO*n_;@vVt,YBƍɑ#GɊ+ț7/UTFϞ=*T%"okm#8f&c<;nyDED܇Ч94 Y["-<Ͱr2t-%0m4]{NX-!u | GYh9it֍ $gt ę3g(ZhqYZnM5ضm[[DR`JCu1ߏ<݂o&0X9C}fT]ؾ^| <.!1Ll2S:\|p&&ggy /w ]&@&[ |ajl6uD3_lwoXL\Gc{S0Ac|x(]_B/&~m"${x c!SqXry6 ].w"%߹#0C6 H:ر#^^^ΝҥKۻIcO^ :LjS6 " d6p﵈GkaxKo`ULd( [qC|A&[ۦc<5suuO>w";up)ik\K6 kJ㖡LU[O-c; n ېC4#d*ykwÄ/&"" \s{1币 V WІ$/KD$Y~I_­ PKyX:@%=KA"pOl%k֭>|ŋSzuҧ]ѣG"gΜeLѣG9|02dB ,YGDŽEGEEs˗|dzر;v0p@G֭cǏ_,'>}Cq=kqhǎOO\Ǔ>|ȑ#G8|0T\"E`2'cDD6mȑʕ+Ǻy[DwƄۙ5e1=pkg cV(V5yj,awpOmL&KhP(9*2Lp{aL/}PXX7f͚5 .Ν;cLAzj֬I%غu+ `ԨQDFF8^ٙ6m~}nܸ6mpj̤_|apsg+WҼy̹nwakѧ~|2]vܼy3FGGGzquu-/_͛7jժ,q|7ӧOvڱz*%KܹoߞQF >"<~HGWp}Lٓ AտnȐ rkEjJ-?lqtU-{RW8\ncҜc;`hI}k֬!SL4lؐuGX|ݽ{w~~~TTcǎDj(_<<`:uFѢE f͚CTԭ[7Ə@"Ex饗Ț5+G?dر_kR%%V^QF?^:jݝZjz].]"""͛[+Vʕ+Çٻw/#Gdݺu˗ϺPPwҥK^y啧ߟurqZ*˗'$$[G:uر#'O͛7y&J7ݻ,_iӦq V\g[DR˪̏U1#y ) \-Sx3\ S-#",IÙ0ohCΚLH$猐ukeO0TolY]3gҨQ#0`uϿݺu[nQT)̙CŊcl7o]veΜ9)S=zX͝;ȑ#СC!;4k֌ӴiSv܉#YfgϞ 6} ͛7!C{ڴic۱chѢGYflٲ%Vya6iժǏLJ9scӧ .dرļy̜9'' ͪUXl5J=ː%[K'19e\%y|xDd^m 钵<I"I6&8&u}9^N}!iܸ<5%KG9(gΜl߾=Vph֬+Vd2ѧON:ڵ+` ;v5ֿXblݺB w^(mű@ٲeپ};c;6Q6m46oތ7۶m2lErĉXՕɓ'[@߿?6nCQSgprs-áS$$ k~ ̬Ep&stUmK%_MѢڷlْΝ;zjݳݸqȒ%Kk֬IV eٲeѠA6Kt:ղҤIԩ 2X -\{Rt'N$SC OmR얫'un]JrD$%Ixs6%]-S cSY!km~Gh}^z2ydׯO|8qb w :x`mY&={WY6_ZpttɓDD\)QQQ=z|t_q|-"W69Z?MZKbvA͉Hʗ$aD˯.IGdΜ9FO'ٳgcΖ{W&wp#Zp\Hʗ~8=. sps-n,òs"l_u8p6mpƍχeIwq~ܭ[7}̞֭=WWWTu%SL\+VĻGСM6=zxu/fݺun:us#.]oX@D_wB$"{lm-Qê{{կ3kZwx)SB޼y( 5jXo~Ҽyhذ!fCRdIr̈́ ˕)S`6Ǽ+ח5kryT_e˖, $$fk&M0cƌX;v5jpjԨ_~q1RGU=󧴨(/^L%(SLݬ-")ûfutf%z9kCHjhr{sA?/3@|o]7};2~xC>>xz]Μ9?> H~ ??xpuue̘1ۗGr12gLŊ)^x+,Ŋc֬Y֡Q/_>6oެ+"L#8%qĹlRB"%7P8+']åSY2{ҧOOjըVSLٲewww4h`#Kt҆O Q~}Cf͚ԬY3Z^2ԧ7,_dqjք8czgT)Qn>BCnk登ecI|6,l[@?l7/&_-"8%<6Tr!$Nǵu[@DDR-_㓔7J? kgdrG7E߈gVBI9<߇)F~CTTM`"?0яx׶k)3zfYRfKINm:ck=AN$]G֕[L|o39XfZJΟ~[N%Y[\aw+ɺ6,z ڻC&NȩSRM"|{6dM毀l`\\Rjt6~މHᮍF\Q:0ЏMz:Yst?*!\Sw3[˹ckMX~SLd}uFDDRmlLBX=ƵY@l ۊ=[<>lFxytTUR ((B0H L6"j{ULKAQtW4bl{Fd δC_i bA0ds8$I@YV {9='Km0l p-5 g%yBe] .,,gwK@l9 qW$݉jР+ֆc lsRrs%&qަrw:E`+Nw)#_o]@>_so3^D*;Z}[r}c-H^$&J];GP9V$i-ވ督Ǥ-L:6c=) "* Ki3O[ ]Qհކ?98$p[qᐘ@Q{Ӵ};5>uum z-ǶKsoy4Š me l=a4~]R-@g_wiRFي[}[tG6jJ^vhOHSK['Ed+G"<朇-5;?׸q'BwܱZMdH\#:u_Ç_ٍqԩ}qNu<9b9DS9<8[n_f?a-a{9<$Փ ~ :wjo|r_dUǠFiNwK%Tr%܉I4xZ5j;4'߱m Ĝ Ϻ6p8C݉!_)Ň u] O0$'`*, ĜރJ8KJ%v]uu^9D;x-A 2TM|bCdUvK@p;%[#)85`/%(lj |{KbGeGq_WYvp )p^ANCʏT-IWK(/؁ @ ZxvF/GV!Ce^0@$EƩPv@ZAԩJuTU|!Ԯ4<DN #uǤo=R y/\Wj_w Nz1*Pgtfm_ϳbyO]$H?~l/?$Rg7uW+j^]w\*i3,{rtM+G%JF !_i92f:ҡҡ #e8]^91_&@rIä͜J❒?&Q[^duHCQRSbOXi|ه(bUH!tBbxߍ˷J{WؾKRI^sh{¶cνkW/H* }MQV(D:K͕k n4cI!AVD=$gvlUa nR5@}jh$In54u>ORfGo؎ͽp=4QsiJGjXH:~{I %wK?-!Q{Ԥ}5"xڨIRKJjoc;;I~$5v5tr(/KɞpJHJ@lX%9R{I'UrIs,+y$1nEIi,]6 }KMH\}+(%yR|ɝ,y$}/T-e(?.h/w67H}FHJ|Z K8..UouyNݝ8U~ϾsC8ğk3"mK.^?җ~TW`_핔R!Yp~|Tcx {'TW"-< Rvo/=z3қ~Z~C0ϐnno~@04 5k/n?`pWSJc Q*&\,|*9Wa{+Ʌ_> ]v* \qERnH;I(4e')*6绨 z^e m?n>D4FN+)Bϓ u>v-#WT@Tɾs(MJ>6b<g✞%]#RaT/-](5l*5jjm^j}j#!Ija?^`txTrB*=.?bU'QJ/%_R f LLk~Tx$chTj7 JyfُRɩ IIIꖘNR78{SrHW:<#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`d))1U|w8уZtQOo.y`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#FD-ۤHW8W>_+8| - [`Ö72H tP 6FbԪe v1l #F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#F!<0Bx`#FD!t#]ϔI[t 1l <PHWj#s,˲ZaK!<0Bx`֯_sF ꄙ3gj߾}.|}۷֮]r|M'PIIIqDxP2͙3G;v+"SN<~X]tH+V[n1c?r٣[oUƍ#]uV 2D#GΝ;%I) @hU׮YF{ĉUPP~BxPÇ5ydS~h"uQsUyyyK"<y^=sر{95%4}tuM+Wh-.qyԩSe\.'ņyk׮a?788qBwy-[R@-x<M:Ugϖ yׯӧO>_>9R'N {7wȲ,-YDog4t)==]ÇS]/VQQc={jkT <PTTYfi޼y5pm/K*j߾v]m[Ehhܸf͚ &vŸ0l @T͞=[[n 7r8Ν;5iҤ;voիW+##C!!C(''G>5jl 2D6mҳ>4IB=CZ|yxтr4._B+92TO\pz~z 80Pgiرڱc|A%$$DXm Yٶmt2y|MDv>F(/k͵zޮ]xbKɩk|qq.]o&(5 T @[n믿^+W4zΜ9sC{~^uIҴi4o^9XQw}wN)--Uyyι&t x,X Iz裏Jۧ~r'|RYYY̌]kuH܈cV~UVjժU4hLJ4uÖCJKK%;ǏkÆ ڰaҔ=zrUWPP+WjJJJ x|\R~f}ڽ{$izǔ)ST9V^^^|EYbIٳѣGWoq'\[Nڵ&Ms%%%Ѻu,u=wp +))f̘anKRG>}O>J$o~3TRSSEYG<ĝ ޽[/e%$$+PffL.KSVV˵~z_^&LoQ""XXL+''>--I֯YƊ$YK.SZMZgs͚5$ꫯ6QF$^ڒd 2׮]ky<v[3gδJJJ[Ç$Y͛-˪Cvv%Сf͚3WXa5k֬щ 5k֨]vZfzqFL]|Œ7|W_}yIw߭?\+h޼yJLLԲeԮ]0ꕕ);;[^WիJ?˲4~xeggkUj̒dtMն_2$p\֐!C-[J={vvg=䓕Gjjh"Yճ7nv岬d#֦M$uE\BAA~mvmJII xQ+WԘ1c*?X6mRue}g裏tȑjzxb_ڹs6nܨݻwM6ׯ."{ھ}nj)''G6mRBBԽ{y999u]<"!<0Bx`#F!<0Bx`#F!<0nIENDB`yao-5.4.0/shwfs_yao_geometry.svg000066400000000000000000000345051234404334100167530ustar00rootroot00000000000000 image/svg+xml extfield spotpitch fssize npixels x pixsize yao-5.4.0/turbulence.i000066400000000000000000000221361234404334100146340ustar00rootroot00000000000000/* * turbulence.i * * A collection of routines about turbulence. * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ // define function names. Will be redefined by GUI routine if needed: func null (arg,..) { return 0; } pyk_error=pyk_info=pyk_warning=gui_message=gui_progressbar_frac=gui_progressbar_text=null; //+++++++++++++++++++++++++++ func phase_struct_func(phase,npt,step,plot=) /* DOCUMENT phase_struct_func(phase,npt,step,plot=) Compute (and plot) structure function along the first dimension of array. Transpose if you need to plot structure function along another dimension. The structure function is defined as: SF(j) = avg( ( phase - shift_along_dim1_by_j (phase) )^2. ) F.Rigaut, 2001/11/10. SEE ALSO: - */ { if (is_void(step)) {step=1;} xm = min([npt,((dimsof(phase))(2))/step-1]); psfx = array(float,xm); for (i=step;i<=xm*step;i=i+step) { psfx(i/step) = avg((phase(1:-i,..)-phase(1+i:,..))^2.); } psfx = grow(0.,psfx); if (is_set(plot)) { fma; plg,psfx,step*(indgen(xm+1)-1.); } return psfx; } phaseStructFunc = phase_struct_func; //+++++++++++++++++++++++++++ func create_phase_screens(dimx,dimy,l0=,prefix=,nalias=,no_ipart=,silent=) /* DOCUMENT create_phase_screens(dimx,dimy,prefix=) Create phase screens and save them in fits files. The saved phase screens have a dimension dimx*dimy. Number of phase screens = dimx/dimy. The phase screens are normalized so that 1 pixel = 1 r0, i.e. the variance of the squared difference of the screen with itself at one pixel interval is 6.88 (rd^2). dimx = long dimension of result screens dimy = short dimension of result screens prefix = Prefix to filename. if prefix is not set, the screens are returned by not saved. no_ipart = set to loose the imaginary part. Gain some RAM to reach larger dimension. Example: create_phase_screens,2048,256,prefix="screen256" F.Rigaut, 2001/11/10. modify 2003 Feb 24 to add dimy (before dimy=256) and prefix SEE ALSO: generate_phase, phase_struct_func. */ { if (is_void(l0)) l0 = 0.; if (yaopy) gui_progressbar_text,"Generating the screen power spectrum"; nps = (no_ipart?1:2); nscreen = dimx/dimy*nps; pscreen = generate_phase_with_L0(dimx,l0,nalias=nalias,no_ipart=no_ipart,silent=silent); if (yaopy) gui_progressbar_frac,0.25; if (!silent) write,"Normalizing phase screens"; if (yaopy) gui_progressbar_text,"Normalizing phase screens"; off = [1,5]; // spatial offset for structure function normalization psfunc = array(float,off(2)); for (i=off(1);i<=off(2);i++ ) { // need to split over phase screens to reduce load on RAM fsx = fsy = 0.; for (n=1;n<=nps;n++) { fsx += avg((pscreen(1:-i,,n)-pscreen(i+1:,,n))^2.); fsy += avg((pscreen(,1:-i,n)-pscreen(,i+1:,n))^2.); } fsx /= nps; fsy /= nps; psfunc(i) = sqrt((fsx+fsy)/2.); if (yaopy) gui_progressbar_frac,0.25+0.6*(i-off(1))/(off(2)-off(1)); } c = (24./5.*gamma(6/5.))^(5/6.); r = float(indgen(off(2))); if (l0 == 0){ theo = sqrt(2*c*r^(5./3.)); } else { f0 = 1./l0; c = (24./5.*gamma(6/5.))^(5/6.); r = float(indgen(off(2))); include, "gsl.i", 3; // loads the Bessel functions, but does not crash if function does not exist if (gsl_sf_bessel_Knu == []){ // function does not exist, use an approximation write, "*** WARNING: gsl_sf_bessel_Knu is not defined ***"; write, "Normalization might be wrong with finite outer scale"; write, "Please install ygsl (https://github.com/emmt/ygsl)"; write, "*************************************************"; theo = psfunc; // do not renormalize } else { // bessel function is defined theo = sqrt(2*c*gamma(11./6.)/(2^(5./6)*pi^(8./3))*(f0)^(-5./3)*(gamma(5./6.)/2^(1./6.) - (2*pi*r*f0)^(5./6.)*gsl_sf_bessel_Knu(5./6., 2*pi*r*f0))); } } nfact = avg(psfunc(off(1):off(2))/theo(off(1):off(2))); if (!silent) write,format="normalization factor (actual/theo)= %f\n", avg(psfunc(off(1):off(2))/theo(off(1):off(2))); if (!silent) write,psfunc(off(1):off(2))/theo(off(1):off(2)); pscreen(*) = pscreen(*)/float(nfact); if (!silent) write,"Sectioning and saving phase screens"; if (yaopy) gui_progressbar_text,"Sectioning and saving phase screens"; pscreen = reform(pscreen,[3,dimx,dimy,nscreen]); if (!is_void(prefix)) { for (i=1;i<=nscreen;i++) { fname = prefix+((nscreen==1) ? "":swrite(i,format="%i"))+".fits"; fits_write,fname,pscreen(,,i),overwrite=1; if (yaopy) gui_progressbar_text,swrite(format="Saving %s",fname); if (yaopy) gui_progressbar_frac,0.85+0.15*i/nscreen; } } if (yaopy) after,4,clean_progressbar; return pscreen; } createPhaseScreens = create_phase_screens; func clean_progressbar(void) { gui_progressbar_text,""; gui_progressbar_frac,0.; } //+++++++++++++++++++++++++++ func generate_phase(dim,silent=) /* DOCUMENT generate_phase(size) Generate by Fourier an un-normalized 2D phase screen from the -11/3 amplitude and a randomn phase component. Only returns the real part. Beware that these screens have a effective outer scale of about half the length of the screen. F.Rigaut, 2001/11/10. SEE ALSO: create_phase_screens, phase_struct_func. */ { randomize; if (!silent) write,"Creating arrays"; if (!silent) write,"Creating amplitude"; tmp = clip(dist(dim),1e-8,); amp = eclat(tmp^(-11.f/6.f)); p = array(complex,dim,dim); p.re = amp; p.im = amp; amp = []; if (!silent) write,"Creating phase"; pha = float(random(dim,dim)*2.*pi); p.re = p.re*cos(pha); p.im = p.im*sin(pha); pha = []; p.re(1,1)= 0.; p.im(1,1)= 0.; if (!silent) write,"Doing FFT..."; phaout = float(fft(p,1)); p = []; return phaout; } //+++++++++++++++++++++++++++ func generate_von_karman_spectrum(dim,k0,nalias=,silent=) /* DOCUMENT func generate_von_karman_spectrum(sdim,bdim,k0) generate correct von Karman spectrum including aliasing. SEE ALSO: */ { if (is_void(nalias)) nalias = 0; if (!silent) for (i=1;i<=2*nalias+1;i++) write,format="%s","#"; res = array(float,[2,dim,dim]); for (i=-nalias;i<=nalias;i++) { for (j=-nalias;j<=nalias;j++) { if ((i==0) && (j==0)) { // bug ((1,1) pixel shift fixed 2009oct13) tmp = sqrt(dist(dim)^2.f+k0^2.); } else { tmp = sqrt(dist(dim,xc=i*dim+dim/2,yc=j*dim+dim/2)^2.f+k0^2.); } if ((i==0) && (j==0)) tmp = clip(tmp,1.,); amp = (6.88*0.00969)*tmp^(-11.f/6.f); res += amp; } if (!silent) write,format="%s","#"; } if (!silent) write,format="%s\n"," > Done"; roll,res; res = float(res); return res; } //+++++++++++++++++++++++++++ func generate_phase_with_L0(dim,l0,nalias=,silent=,no_ipart=) /* DOCUMENT generate_phase(size,l0) Generate by Fourier an un-normalized 2D phase screen from the -11/3 amplitude and a randomn phase component. Returns the real and complex parts. Uses fftVE and cosf/sinf to keep floats for RAM use consideration (the previous version of this routine was using the yorick fft, thus double complex, which limits things on my machine to 4096 screens). dim: desired dimension of the result phase screens l0: outer scale IN PIXELS no_ipart = loose the im part to gain RAM F.Rigaut, 2001/11/10. SEE ALSO: create_phase_screens, phase_struct_func. */ { if (l0 == 0.) { k0=0.0f; } else { k0 = float(dim)/l0; } randomize; gui_progressbar_frac,0.01; if (!silent) { write,"Creating arrays"; write,"Creating amplitude"; } // tmp = clip(float(sqrt(dist(dim)^2.f+k0^2.)),1e-8,); // amp = 6.88*0.00969*dim*eclat(tmp^(-11.f/6.f)); // amp = eclat(generate_von_karman_spectrum(dim,clip(2*dim,,2048),k0)); // amp = dim*eclat(generate_von_karman_spectrum(dim,1024,k0)); amp = dim*generate_von_karman_spectrum(dim,k0,nalias=nalias,silent=silent); gui_progressbar_frac,0.10; amp = float(amp); // normalized so that the structure function is correct for r0 = 1 pixel tmp = []; if (!silent) write,"Creating phase"; pha = reform(float(2*pi*random(dim*dim)),dimsof(amp)); re = amp*cosf(pha); im = amp*sinf(pha); amp = pha = []; re(1,1) = 0.0f; im(1,1) = 0.0f; if (!silent) write,"Doing FFT..."; phaout = fftVE(re,im,1); if (no_ipart) phaout = phaout(,,1); gui_progressbar_frac,0.20; re = im = []; return phaout; } yao-5.4.0/utils.c000066400000000000000000000035571234404334100136240ustar00rootroot00000000000000/* * utils.c * * C utility functions for yao * * This file contains a number of utility functions, coded in C to gain * execution time. It addresses functionalities that are missing in * yorick, mostly concerning 2D image processing. * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ #include #include #include #include #include "ydata.h" #include "yapi.h" #include "pstdlib.h" /************************************************************************ * noop. For testing and timing. with parameter passing * ************************************************************************/ int _mynoop2(float *in, int nx, int ny, float *out, int fx, int fy, int binfact) { return(0); } void Y_usleep(int nArgs) { long milliseconds = YGetInteger(sp-nArgs+1); // useconds_t us; // us = (useconds_t)(milliseconds*1000l); usleep(milliseconds*1000l); } int _cosf(float *x, long n) { long i = 0; for (i=0;i False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 normal V5.3.0 Francois Rigaut, 2001-2013 YAO is an Adaptive Optics simulation package written in yorick, an open source interpreted language. It features Shack-Hartmann and curvature wavefront sensors, Stack array (piezostack) or curvature deformable mirrors, or modal (Zernike) correctors. An arbitrary number of WFS or DM can be used, with possible conjugation at altitude. Systems such as GLAO, MCAO, NGS AO and LGS AO can easily be simulated. System configuration is done through a parameter file. The current GUI only provides a convenient way to interface with the main YAO functions and to change/play with some of the main system parameters, and see the changes at once. This tool can be viewed as very practical for AO education purposes. http://www.maumae.net/yao Copyright (c) 2002-2013, Francois Rigaut 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 (to receive a copy of the GNU General Public License, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA). Written by Francois Rigaut (francois.rigaut@anu.edu.au), Marcos van Dam (marcos@flatwavefronts.com), Ralf Flicker & Damien Gratadour (damien.gratadour@obspm.fr) Debian packaging by Thibaut Paumard. translator-credits True False 2 True False end False True end 0 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Disp True True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Clean True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Forcemat True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK SVD True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Keep DM config True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK savecb True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK disp True True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK no reinit wfs True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False True False True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False _File True False gtk-open False True True Edit Configuration True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False True False gtk-edit gtk-save False True True gtk-save-as False True True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-quit True False True True True False Subsystems True False True False Show WFSs & DMs True True False Create Phase Screens Phase Screens True False True False Create phase screens for use by yao. Those are 2048x256 (default) fits files storing value of phase delays for von-karmann turbulence. These screens are saved in the path given in the atm.screen variable. If no parfile has been read out yet, they will be saved in Y_USER/data Create phase screens True True False _Help True False True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Toggle debug statements python <> yorick debug True gtk-about True False True True False True 0 True False True False 3 True False True False 2 0 out True False 12 True False 3 True False True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True True True 0 Browse... True True False True False False 1 Edit 70 True False True False True False False 2 False False 2 0 True False 11 True aoread 80 True True False True True True 0 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK aoinit 80 True False True False True True True 0 18 True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False 1 True True 1 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK aoloop 80 True False True False True True True 0 18 True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False 1 True True 2 False False 2 1 True False True go True False True False True True True 0 pause True False True False True True True 1 step True False True False True True True 2 restart True False True False True True True 3 False False 2 2 True False <b>Main</b> True label_item True True 2 0 True False False 2 0 out True False 12 True False 3 3 2 10 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 1 0 10000 1 10 0 0.10000000149 True 1 2 2 3 Pause 70 True True False True Resume 70 True True False True 1 2 True False 1 2 True False 0 Display rate 2 3 True False 0 Image Display 1 2 True False True inst. True True False True True False False 0 avg. True True False True True image_disp_inst False False 1 1 2 1 2 True False <b>Displays</b> True label_item False False 3 1 True True 0 True False False 3 True False 1 5 Seeing (550nm) True True 0 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 4 0.10000000000000001 0.5 0 0.0001 3 True True True 1 True False 1 5 Loop Gain True True 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 3 0.01 10 0 0.0099999997764800008 3 True True True 3 True False 1 5 Image lambda True True 4 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0.40000000000000002 0.40000000000000002 10 0.01 10 0 0.0099999997764800008 2 True True True 5 False False 2 1 550 540 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False 3 2 False False 0 True True False True False False 3 0 out True False 12 True False True False 3 Subtract background True True False True True True True 0 Noise True True False True True True True 1 Correct Up TT True True False True True True True 2 True False 10 2 2 True False 0 5 #integ. cycles 1 2 7 8 True False 0 5 SH Kernel 1 2 6 7 True False 0 5 SH Threshold 1 2 5 6 True False 0 5 RON 1 2 4 5 True False 0 5 GS depth 1 2 3 4 True False 0 5 GS Alt 1 2 2 3 True False 0 5 GS mag 1 2 1 2 True False 0 5 EFD 1 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 20 1 10 0 0.0099999997764800008 7 8 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 10 0.10000000000000001 10 0 0.0099999997764825821 6 7 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 -100 100 0.10000000000000001 10 0 0.0099999997764800008 2 5 6 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 100 0.10000000000000001 10 0 0.0099999997764800008 2 4 5 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 50000 100 10 0 1 3 4 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 500000 100 10 0 1 2 3 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 25 0.10000000000000001 10 0 0.0099999997764800008 2 1 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0.050000000000000003 0.050000000000000003 10 0.02 10 0 0.0099999997764800008 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False False True True 0.20000000000000001 0 3 0.050000000000000003 0.10000000000000001 0 0.01 2 8 9 True False 0 5 Pyr. modul ["] 1 2 8 9 True True 3 True True 0 True False 1 True True False True True False False 0 2 True False True True False False 1 3 True False True True False False 2 4 True False True True False False 3 5 True False True True False False 4 6 True False True True False False 5 7 True False True True False False 6 8 True False True True False False 7 9 True False True True False False 8 10 True False True True False False 9 11 True False True True False False 10 12 True False True True False False 11 False False 1 True False <b>WFSs</b> True label_item False False 0 True False False 3 0 out True False 12 True False True False 3 Reset True True True True False False 0 Flatten True True True True False False 1 Extrapolated actuators True True False True True False False 2 True False 4 2 2 True False 0 5 Saturation Voltage 1 2 3 4 True False 0 5 Y misregistration 1 2 2 3 True False 0 5 X misregistration 1 2 1 2 True False 0 5 DM gain 1 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 10000 1 10 0 1 3 4 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True misregistration DM/WFS in pupil diameter unit False False True True 0 -1 1 0.01 0.10000000000000001 0 0.0099999997764800008 3 2 3 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True misregistration DM/WFS in pupil diameter unit False False True True 0 -1 1 0.01 0.10000000000000001 0 0.0099999997764800008 3 1 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True 0 0 3 0.050000000000000003 10 0 0.0099999997764800008 3 True True 3 True True 0 True False 1 True True False True True False False 0 2 True False True True False False 1 3 True False True True False False 2 4 True False True True False False 3 5 True False True True False False 4 6 True False True True False False 5 7 True False True True False False 6 8 True False True True False False 7 9 True False True True False False 8 10 True False True True False False 9 False False 1 True False <b>DMs</b> True label_item False False 1 True False WFS & DM False tab False 1 True False User 1 1 False tab False 2 True False User 2 2 False tab True True 1 True True 1 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 2 False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 False False True 3 True False False True 4 550 700 False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False _File True False gtk-save True False True True gtk-save-as True False True True True False gtk-close True False True True True False _Help True False gtk-about True False True True False True 0 True True automatic automatic True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 4 4 True True 1 500 300 False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False _File True False gtk-save True False True True True False gtk-close True False True True True False _Help True False gtk-about True False True True False True 0 True True automatic automatic True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 4 4 True True 1 yao-5.4.0/yao.gs000066400000000000000000000120061234404334100134300ustar00rootroot00000000000000# Gist style sheet made by Yorick write_style function # Created: Mon Jan 12 16:05:50 2004 # (5 coordinate systems) landscape= 0 default= { legend= 0, viewport= { 0.06, 0.40, 0.66, 1.00 }, ticks= { horiz= { nMajor= 5.000000, nMinor= 25.000000, logAdjMajor= 1.200000, logAdjMinor= 1.200000, nDigits= 3, gridLevel= 1, flags= 0x02b, tickOff= 0.000700, labelOff= 0.010000, tickLen= { 0.008512, 0.005674, 0.003783, 0.002553, 0.001702 }, tickStyle= { color= 254, type= 1, width= 1.000000 }, gridStyle= { color= 254, type= 3, width= 1.000000 }, textStyle= { color= 254, font= 0x08, height= 0.016278, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.395000, yOver= 0.370000 }, vert= { nMajor= 5.000000, nMinor= 25.000000, logAdjMajor= 1.200000, logAdjMinor= 1.200000, nDigits= 4, gridLevel= 1, flags= 0x02b, tickOff= 0.000700, labelOff= 0.006000, tickLen= { 0.008512, 0.005674, 0.003783, 0.002553, 0.001702 }, tickStyle= { color= 254, type= 1, width= 1.000000 }, gridStyle= { color= 254, type= 3, width= 1.000000 }, textStyle= { color= 254, font= 0x08, height= 0.016278, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.150000, yOver= 0.370000 }, frame= 1, frameStyle= { color= 254, type= 1, width= 1.000000 }}} system= { legend= "System 0ght (4)" } system= { legend= "System 0ght (4)", viewport= { 0.45, 0.79, 0.66, 1.00 }, ticks= { horiz= { tickLen= { 0.008535, 0.005690, 0.003794, 0.002561, 0.001707 }, textStyle= { color= 254, font= 0x08, height= 0.016370, orient= 0, alignH= 0, alignV= 0, opaque= 0 }}, vert= { tickLen= { 0.008535, 0.005690, 0.003794, 0.002561, 0.001707 }, textStyle= { color= 254, font= 0x08, height= 0.016370, orient= 0, alignH= 0, alignV= 0, opaque= 0 }}}} system= { legend= "System 0ght (4)", viewport= { 0.06, 0.40, 0.25, 0.42 }, ticks= { horiz= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 3, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.395, yOver= 0.350 }, vert= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 4, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.100, yOver= 0.350 }, frame= 1, frameStyle= { color= -2, type= 1, width= 1.0 }}} system= { legend= "System 0ght (4)", viewport= { 0.06, 0.40, 0.455, 0.615 }, ticks= { horiz= { tickLen= { 0.006077, 0.004052, 0.002701, 0.001823, 0.001215 }, textStyle= { color= 254, font= 0x08, height= 0.008299, orient= 0, alignH= 0, alignV= 0, opaque= 0 }}, vert= { tickLen= { 0.006077, 0.004052, 0.002701, 0.001823, 0.001215 }, textStyle= { color= 254, font= 0x08, height= 0.008299, orient= 0, alignH= 0, alignV= 0, opaque= 0 }}}} system= { legend= "System 0ght (4)", viewport= { 0.44, 0.79, 0.25, 0.60 }, ticks= { horiz= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 3, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.395, yOver= 0.350 }, vert= { nMajor= 7.5, nMinor= 50.0, logAdjMajor= 1.2, logAdjMinor= 1.2, nDigits= 4, gridLevel= 1, flags= 0x000, tickOff= 0.0007, labelOff= 0.0182, tickLen= { 0.0143, 0.0091, 0.0052, 0.0026, 0.0013 }, tickStyle= { color= -2, type= 1, width= 1.0 }, gridStyle= { color= -2, type= 3, width= 1.0 }, textStyle= { color= -2, font= 0x08, height= 0.0182, orient= 0, alignH= 0, alignV= 0, opaque= 0 }, xOver= 0.100, yOver= 0.350 }, frame= 1, frameStyle= { color= -2, type= 1, width= 1.0 }}} legends= { x= 0.046980, y= 0.360000, dx= 0.375800, dy= 0.000000, textStyle= { color= 254, font= 0x00, height= 0.015600, orient= 0, alignH= 1, alignV= 1, opaque= 0 }, nchars= 36, nlines= 20, nwrap= 2 } clegends= { x= 0.618200, y= 0.864300, dx= 0.000000, dy= 0.000000, textStyle= { color= 254, font= 0x00, height= 0.015600, orient= 0, alignH= 1, alignV= 1, opaque= 0 }, nchars= 14, nlines= 28, nwrap= 1 } yao-5.4.0/yao.i000066400000000000000000004653531234404334100132700ustar00rootroot00000000000000/* * yao.i * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ extern aoSimulVersion, aoSimulVersionDate; aoSimulVersion = yaoVersion = aoYaoVersion = yao_version = "5.4.0"; aoSimulVersionDate = yaoVersionDate = aoYaoVersionDate = "2014jun05"; write,format=" Yao version %s, Last modified %s\n",yaoVersion,yaoVersionDate; // find and include yao.conf now if any: Y_CONF = get_env("Y_CONF"); y_user = streplace(Y_USER,strfind("~",Y_USER),get_env("HOME")) if (noneof(Y_CONF)) \ Y_CONF = "./:"+y_user+":"+pathform(_(y_user,Y_SITES,Y_SITE)+"conf/"); path2conf = find_in_path("yao.conf",takefirst=1,path=Y_CONF); if (!is_void(path2conf)) { path2conf = dirname(path2conf)+"/"; write,format=" Found and included yao.conf in %s\n",path2conf; require,path2conf+"yao.conf"; } // before we do anything else (to avoid forking a large process), // let's try to determine what OS we are in: //f = popen("uname",0); //rep = ""; read,f,format="%s",rep; //close,f; //rep = strcase(0,rep); //if ( (rep=="darwin") || (rep=="linux") ) os_env = rep; else os_env="unknown"; os_env="unknown"; plug_in,"yao"; require,"yao_utils.i"; require,"yao_fast.i"; require,"yao_wfs.i"; require,"yao_dm.i"; require,"aoutil.i"; require,"yao_gui.i"; require,"utils.i"; require,"yao_newfits.i"; require,"yao_util.i"; require,"yao_lgs.i"; require,"turbulence.i"; require,"plot.i"; // in yorick-yutils require,"yao_structures.i"; require,"yaodh.i"; include, "lapack.i",3; // optional if (lpk_gesv != []){ write, "Using ylapack to do matrix inversions: LUSolve = lpk_gesv"; LUsolve = lpk_gesv; // that simple } // can't call use_sincos_approx directly in yao.conf, as not defined, work around: if (use_sincos_approx_default!=[]) use_sincos_approx,use_sincos_approx_default; // compatibility with GUI (yaopy.i) func null (arg,..) { return 0; } // set up for notify. Disabled by default. Set "use_notify" to enable // we have to do that as soon as possible to avoid forking large a process // this spawned bash session can actually be used for other purposes if // needed. func on_bash_out(msg) { write,msg; } func notify(msg) { if (!use_notify) return; // allows to turn off/on notify within the session bash,swrite(format="notify-send -i %s \"%s\"\n",icon,msg); } icon = "/home/frigaut/Pictures/logos/yao_64_inv.png"; if (use_notify) bash = spawn("/bin/bash",on_bash_out); else bash=null; func parse_yao_version(ver) { extern yao_major_version,yao_minor_version; tmp = strtok(ver,".",3); yao_major_version = tonum(tmp(1)); yao_minor_version = tonum(tmp(2)); } parse_yao_version,yao_version; // import fftw wisdom file: if (fftw_wisdom_file==[]) fftw_wisdom_file=Y_USER+"fftw_wisdom_file.dat"; if (_import_wisdom(expand_path(fftw_wisdom_file))){ write,format=" Warning: Can't read FFTW wisdom from %s\n",expand_path(fftw_wisdom_file); write, "Run init_fftw_wisdom to create a new file"; } // All below is designed to be overwritten by appropriate values // in yaopy.i when using yao through the GUI pyk_error = pyk_info = pyk_warning = null; gui_message = gui_message1 = gui_progressbar_frac = gui_progressbar_text = null; clean_progressbar = gui_show_statusbar1 = gui_hide_statusbar1 = pyk_flush = null; YAO_SAVEPATH = get_cwd(); //---------------------------------------------------- func comp_dm_shape_init(nm) { extern wpupil; if (numberof(wpupil)!=ndm) wpupil = array(pointer,ndm); wpupil(nm) = &long(where((abs(*dm(nm)._def))(,,sum))); } func comp_dm_shape(nm,command,extrap=) /* DOCUMENT comp_dm_shape(nm,command,extrap=) Fast compute of DM #nm shape from a command vector. Branch over _dmsum or _dmsumelt according to case. nm: DM yao # command: POINTER to a float vector containing the commands length of vector = numberof(*dm(nm)._command) = dm(nm)._nact extrap : Compute for extrapolated only (otherwise compute for valid only) so that to compute valid + extrap, you have to make 2 calls, one with and one without the extrap keyword set. SEE ALSO: */ { if (dmsum_use_new&&(wpupil==[])) for (i=1;i<=ndm;i++) comp_dm_shape_init,i; if (typeof(*command)!="float") error,"command is not float"; n1 = dm(nm)._n1; n2 = dm(nm)._n2; nxy = int(n2-n1+1); sphase = array(float,[2,nxy,nxy]); if (!is_set(extrap)) { // pegged valid actuators (right now, set to position 0): if (dm(nm).pegged) { com = *command; com(*dm(nm).pegged) = 0.0f; command = &com; // this way this does not go up in integrated commands } if (dm(nm)._flat_command) { com = *command; com -= float(*dm(nm)._flat_command); command = &com; } if (dm(nm).elt == 1) { //use fast dm shape computation _dmsumelt, dm(nm)._def, dm(nm)._eltdefsize, dm(nm)._eltdefsize, int(dm(nm)._nact), dm(nm)._i1, dm(nm)._j1, command, &sphase,nxy,nxy; } else { // use standard if (dmsum_use_new) _dmsum2, dm(nm)._def, wpupil(nm), \ numberof(*wpupil(nm)), dm(nm)._nact, command, &sphase, numberof(sphase); else _dmsum, dm(nm)._def, nxy, nxy, dm(nm)._nact, command, &sphase; // } } } else { // extrapolated actuators // pegged extrapolated actuators (right now, set to position 0): if (dm(nm).epegged) { com = *command; com(*dm(nm).epegged) = 0.0f; command = &com; // this way this does not go up in integrated commands } if (dm(nm).elt == 1) { //use fast dm shape computation _dmsumelt, dm(nm)._edef, dm(nm)._eltdefsize, dm(nm)._eltdefsize, int(dm(nm)._enact), dm(nm)._ei1, dm(nm)._ej1, command, &sphase,nxy,nxy; } else { // use standard if (dmsum_use_new) _dmsum2, dm(nm)._edef, wpupil(nm), \ numberof(*wpupil(nm)), dm(nm)._enact, command, &sphase, numberof(sphase); else _dmsum, dm(nm)._edef, nxy, nxy, dm(nm)._enact, command, &sphase; } } // temporary method for shifting DMs/influence functions // one can not anymore use the straight (*dm._def)(,,sum), // but instead should always use comp_dm_shape. if (dm(nm)._puppixoffset!=[]) { sphase = roll(sphase,dm(nm)._puppixoffset); } if (dm(nm).disjointpup) { // we have to filter by disjointpup(,,nm) sphase *= disjointpup(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2,nm); } return sphase; } //---------------------------------------------------- func control_screen(i,init=) /* DOCUMENT control_screen(i,init=) While the loop is running, brings up another graphic window in which some loop parameters are displayed. I rarely use this feature anymore. i is the loop counter. Not intended for use by the end user. SEE ALSO: */ { local x0,y0,x,y; y0 = 0.80; x0 = 0.150; ygstep = 0.03; mygstep = 0.022; sygstep = 0.017; csize = 12; if ( (xft!=[]) && (xft()==1) ) { csfont = "Courier:antialias=0"; } else csfont="courier"; /* y0 = 0.86; x0 = 0.05; ygstep = 0.037; mygstep = 0.030; sygstep = 0.025; csize = 18; */ if (is_set(init) || !window_exists(2)) { // dheight = (nwfs+target._nlambda+1)*sygstep + 10*ygstep; // dheight = long(dheight/0.77*570); if (window_exists(2)) winkill,2; // make sure window,2,width=410,height=320,style="letter.gs",wait=1,dpi=70; // window,2,width=570,height=dheight,style="letter.gs",wait=1,dpi=70; limits,0.,1.,0.,1.; progress_bar,0,pbid1,init=[x0,y0-ygstep,x0+0.25,y0-ygstep+0.015]; if (is_set(init)) { window_select,0; return; } } window,2; fma; y = y0; if (!remainingTimestring) remainingTimestring="N/A"; plt,sim.name+" / Time left: "+remainingTimestring,x0,y,tosys=1,\ height=csize,justify="LA"; y -= ygstep; it = swrite(format="%d/%d iterations",i,loop.niter); plt,it,x0+0.27,y,tosys=1,height=csize,justify="LA",font=csfont; y -= ygstep; progress_bar,i*100./loop.niter,pbid1; // s = "WFS rms Tip Tilt "; s = "WFS Tip Tilt "; if (anyof(wfs.correctUpTT)) { s = s+"UpTip UpTilt "; if (anyof(wfs.centGainOpt)) { s = s+"CentG "; } } plt,s,x0,y,tosys=1,height=csize,justify="LA",font=csfont; y -= mygstep; for (i=1;i<=nwfs;i++) { s = swrite(format="%3i % 6.3f % 6.3f ",i, wfs(i)._lastvalidtt(1),wfs(i)._lastvalidtt(2)); if (anyof(wfs.correctUpTT)) { if (wfs(i).correctUpTT) { s = s+swrite(format="% 6.3f % 6.3f ", wfs(i)._upttcommand(1),wfs(i)._upttcommand(2)); } else { s = s+" - - "; } if (anyof(wfs.centGainOpt)) { if (wfs(i).centGainOpt) { s = s+swrite(format="% 6.3f ",wfs(i)._centroidgain); } else { s = s+"- "; } } } plt,s,x0,y,tosys=1,height=csize,justify="LA",font=csfont; y -= sygstep; } // print out TTM command wtt = where(dm.type == "tiptilt"); if (numberof(wtt) != 0) { wtt = wtt(0); s = swrite(format="TT Mirror: % 6.3f % 6.3f",(*dm(wtt)._command)(1), (*dm(wtt)._command)(2)); y -= sygstep; plt,s,x0,y,tosys=1,height=csize,justify="LA",font=csfont; y -= ygstep; } // print out Strehls: plt,"Strehl Ratio Lambda Avg rms Min Max",x0,y,tosys=1,height=csize, justify="LA",font=csfont; y -= sygstep; for (jl=1;jl<=target._nlambda;jl++) { strehlle = imav(max,max,,jl)/sairy/(niterok+1e-5); s = swrite(format="Since Start %6.3f %6.3f %6.3f %6.3f %6.3f", (*target.lambda)(jl),strehlle(avg),strehlle(rms), min(strehlle),max(strehlle)); plt,s,x0,y,tosys=1,height=csize,justify="LA",font=csfont; y -= sygstep; if (jl == target._nlambda) { strehlse = im(max,max,)/sairy; s = swrite(format="Instantaneous %6.3f %6.3f %6.3f %6.3f %6.3f", (*target.lambda)(jl),strehlse(avg),strehlse(rms), min(strehlse),max(strehlse)); plt,s,x0,y,tosys=1,height=csize,justify="LA",font=csfont; y -= sygstep; } } window_select,0; } //---------------------------------------------------- func mcao_rayleigh(nwfs,xsubap,ysubap,zenith=,fov=,aspp=) /* DOCUMENT mcao_rayleigh(nwfs,xsubap,ysubap,zenith=,fov=,aspp=) Computes the rayleigh backscattering from other LGS beams (fratricide) Called from shwfs_init() SEE ALSO: shwfs_init */ { as2rd = dtor/3600.; cobs = 0; // position of GS/WFS in arcsec: w = where(wfs._gsalt > 0); // xwfs = [0,-30.0,30.0,30.0,-30.0]; // ywfs = [0,30.0,30.0,-30.0,-30.0]; xwfs = wfs(w).gspos(1,); ywfs = wfs(w).gspos(2,); nbeams = numberof(xwfs); if (!is_set(zenith)) {zenith = 0.;} zenith = zenith*dtor; if (!is_set(fov)) { fov = 2;} // FoV (arcsec) if (!is_set(aspp)) { aspp = 1;} // arcsec per pixel // I have not implemented the 4 following parameters in the parfile. // one has to fill it by hand in the code for now!!!!!!! beamdiameter = 0.3; // fwhm of gaussian laser beam in meter laserlambda = wfs(nwfs).lambda*1e-6; //589e-9; diamsubap = tel.diam/wfs(nwfs).shnxsub; // side of a subaperture [m] r0 = (tel.diam/atm.dr0at05mic)*cos(zenith)^0.6; seeing = laserlambda/r0/4.848e-6; spotsize = 1.0; // irrelevant for rayleigh in this code. d = 1e-2; // linear size of aperture for flux (/cm^2) some angle phin = sqrt(xwfs(nwfs)^2.+ywfs(nwfs)^2.)*as2rd; thetan = atan(xwfs(nwfs),ywfs(nwfs)); // range vector to sample h (for Rayleigh only) // rvec = spanl(2000,altsod,150); rvec = spanl(1000,altsod,50); // definitions for sodium GS: // range vector for sodium: rvecsod = span(altsod-fwhmsod,altsod+fwhmsod,20); // loop on beams for (beam=1;beam<=nbeams;beam++) { // define "beam" position angles phib = sqrt(xwfs(beam)^2.+ywfs(beam)^2.)*as2rd; thetab = atan(xwfs(beam),ywfs(beam)); // loop on altitude for RAYLEIGH for (i=1;i<=numberof(rvec)-1;i++) { // range r = (rvec(i+1)+rvec(i))/2.; // altitude z = r*cos(zenith); // delta range deltar = rvec(i+1)-rvec(i); // fit to the lidar equation: sbnr = 16.12*exp(-z*0.14177e-3)*1e-6; // total number of photons received per cm^2 and period (800Hz) rayleigh = wfs(beam).laserpower/(6.62e-34*3e8/589e-9)*sbnr*d^2/(4*pi*r^2.)* deltar*loop.ittime*wfs(nwfs).optthroughput; if (rayleigh_fudge) rayleigh *= rayleigh_fudge; // compute position angles of the beam center for this altitude alpha = sin(phib)*cos(thetab)-sin(phin)*cos(thetan) - xsubap/r + xsubap/altsod; beta = sin(phib)*sin(thetab)-sin(phin)*sin(thetan) - ysubap/r + ysubap/altsod; alpha /= 4.848e-6; // in arcsec beta /= 4.848e-6; if (sim.debug > 3) { write,format="range = %f, alpha = %f, beta = %f\n",r,alpha,beta; } // generate gaussian: fwhm = beamdiameter/r/as2rd; // in arcsec // blur due to finite range of this layer of rayleigh scatering blur = (altsod - r)/altsod*diamsubap/r/4.848e-6; fwhm = sqrt(fwhm^2. + seeing^2.+blur^2.); g = makegaussian(dim,fwhm/aspp,xc=0.5+dim/2+alpha/aspp,yc=0.5+dim/2+beta/aspp,norm=1); if (cobs) { fwhmobs = fwhm/2; fwhmobs = sqrt(fwhmobs^2. + seeing^2.); gobs = makegaussian(dim,fwhmobs/aspp,xc=0.5+dim/2+alpha/aspp,yc=0.5+dim/2+beta/aspp); gobs = gobs*max(g); g = g-gobs; } // add contribution from this slab. Correctly normalized // in photons/cm^2/exptime/laser_power/telescope+system_throughput imrayl += g*rayleigh; } // loop on altitude for SODIUM // Na return detected on WFSCCD in ph/cm^2/exptime/laser_power/telescope+system_throughput: nPhotonFromSodStar = wfs(beam).laserpower*gs.lgsreturnperwatt*loop.ittime* cos(zenith)*wfs(nwfs).optthroughput; sodprofile = exp(-((rvecsod-altsod)/(fwhmsod/2.))^4.); sodprofile = sodprofile/sum(sodprofile)*nPhotonFromSodStar; for (i=1;i<=numberof(rvecsod)-1;i++) { // range r = rvecsod(i); sodium = sodprofile(i); // compute position angles of the beam center for this altitude alpha = sin(phib)*cos(thetab)-sin(phin)*cos(thetan) - xsubap/r + xsubap/altsod; beta = sin(phib)*sin(thetab)-sin(phin)*sin(thetan) - ysubap/r + ysubap/altsod; alpha /= 4.848e-6; // in arcsec beta /= 4.848e-6; if (sim.debug > 3) { write,format="range = %f, alpha = %f, beta = %f\n",r,alpha,beta; } // generate gaussian: fwhm = beamdiameter/r/as2rd; // in arcsec // here I'll have to take the defocus of range r into account fwhm = sqrt(fwhm^2. + seeing^2.); g = makegaussian(dim,fwhm/aspp,xc=0.5+dim/2+alpha/aspp,yc=0.5+dim/2+beta/aspp,norm=1); // add contribution from this slab. Correctly normalized // in photons/cm^2/exptime/laser_power/telescope+system_throughput imstar += g*sodium; } if (sim.debug > 3) { fma; pli,imrayl+imstar,-dim/2*aspp,-dim/2*aspp,+dim/2*aspp,+dim/2*aspp; pause,20; } } return [imrayl,imstar]; } //---------------------------------------------------- func do_imat(disp=) /* DOCUMENT do_imat(disp=) Measure the interaction matrix. Each actuator are actuated in a row, a measurement vector is taken and placed into the iMat. The reference (for phase=0) is subtracted. disp = set to display stuff as it goes. This routine uses: - dm._nact, _n1, _n2, _def (extern) - mircube (extern) This routine calls: - mult_wfs_int_mat This routine sets: - iMat (extern) SEE ALSO: prep_svd, build_cmat */ { extern wfs; gui_progressbar_frac,0.; gui_progressbar_text,"Doing interaction matrix"; if (mat.method == "mmse-sparse"){ extern MR, MN; MR = mat.sparse_MR; MN = mat.sparse_MN; } indexDm = array(long,2,ndm); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } ntot = sum(dm._nact); ncur=1; if (disp) { plsys,1; animate,1; } // save state of noise/nintegcycle/etc: everything that is not desired // when doing the iMat: store_noise_etc_for_imat,noise_orig, cycle_orig, kconv_orig, \ skyfluxpersub_orig, bckgrdcalib_orig, bias_orig, \ flat_orig,darkcurrent_orig,use_sincos_approx_orig,\ rayleigh_orig; // sync forks if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); // for imat ETA: tic; ndone=0; // Loop on each mirror: for (nm=1;nm<=ndm;nm++) { n1 = dm(nm)._n1; n2 = dm(nm)._n2; // if (sim.verbose>1) {write,format="\rDoing DM# %d, actuator %s",nm," ";} if (sim.verbose) write,""; subsys = dm(nm).subsystem; // Loop on each actuator: command = array(float,dm(nm)._nact); for (i=1;i<=dm(nm)._nact;i++) { ncur++; gui_progressbar_frac,float(ncur)/ntot; gui_progressbar_text,\ swrite(format="Doing interaction matrix, DM#%d, actuator#%d",nm,i); if (sim.verbose) { eta = (ndone?(ntot-ndone)*tac()/ndone:0.0f); write,format="\rDoing DM# %d, actuator %d/%d, ETA %.1fs",\ nm,i,dm(nm)._nact,eta; } // if (sim.verbose>1) {write,format="%d ",i;} mircube *= 0.0f; command *= 0.0f; command(i) = float(dm(nm).push4imat); mircube(n1:n2,n1:n2,nm) = comp_dm_shape(nm,&command); if (mat.method != "mmse-sparse"){ if (!dm(nm).ncp){ // Fill iMat (reference vector subtracted in mult_wfs_int_mat): iMat(,i+indexDm(1,nm)-1) = mult_wfs_int_mat(disp=disp,subsys=subsys)/dm(nm).push4imat; } } else { if (!dm(nm).ncp){ rcobuild, iMatSP, float(mult_wfs_int_mat(disp=disp,subsys=subsys)/dm(nm).push4imat), mat.sparse_thresh; } else { rcobuild, iMatSP, float(mult_wfs_int_mat(disp=disp,subsys=subsys)/dm(nm).push4imat*0.), mat.sparse_thresh; } } // display, if requested: // WFS spots: if (is_set(disp)) { fma; plt,sim.name,0.01,0.227,tosys=0; if (!allof(wfs.shmethod ==1)) { if (wfs_display_mode=="spatial") { disp2d,wfs._dispimage,wfs.pupoffset(1,),wfs.pupoffset(2,),2; mypltitle,"WFSs spots (spatial mode)",[0.,-0.005],height=12; } else { disp2d,wfs._dispimage,wfs.gspos(1,),wfs.gspos(2,),2; mypltitle,"WFSs spots",[0.,-0.005],height=12; } } if ((nm==1) && (i==1)) { plsys,2; limits,square=1; limits; } // mirror surface plsys,3; limits,square=1; if (mergedms4disp) { //e.g. GMT case tmp = mircube(,,sum); pli,(tmp-min(tmp))*ipupil,1,0.,2,1.; range,0.25,0.75; } else { pli,(mircube(,,1)-min(mircube(,,1)))*ipupil,1,0.,2,1.; if (ndm==1) range,0.25,0.75; for (jj=2;jj<=ndm;jj++) { //pli,mircube(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2,nm),nm,0.,nm+1,1.; if (dm(jj).alt==0) { pli,(mircube(,,jj)-min(mircube(,,jj)))*ipupil,jj,0.,jj+1,1.; } else { pli,(mircube(,,jj)-min(mircube(,,jj))),jj,0.,jj+1,1.; } } } // mypltitle,"DM(s)",[0.,0.008],height=12; myxytitles,"","DM(s)",[0.010,0.],height=12; if ((dm(nm).type == "aniso") && (sim.debug >= 2)) hitReturn; } // end of display section if (sleep) usleep,sleep; if ((sim.debug>=3) && (i==(dm(nm)._nact/2))) hitReturn; ndone++; } if (sim.verbose) {write," ";} } // restore original values to WFS structure: restore_noise_etc_for_imat,noise_orig, cycle_orig, kconv_orig, \ skyfluxpersub_orig,bckgrdcalib_orig, bias_orig, \ flat_orig,darkcurrent_orig,use_sincos_approx_orig,\ rayleigh_orig; // sync forks if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); // Display if needed: if ((mat.method != "mmse-sparse") && ((sim.debug>=1) || (disp == 1))) { tv,-iMat,square=1; mypltitle,"Interaction Matrix",[0.,-0.005],height=12; if (sim.debug >= 1) typeReturn; } if (disp) {plsys,1; animate,0; } clean_progressbar; } func store_noise_etc_for_imat(&noise_orig, &cycle_orig, &kconv_orig, &skyfluxpersub_orig, &bckgrdcalib_orig, &bias_orig, &flat_orig, &darkcurrent_orig, &use_sincos_approx_orig,&rayleigh_orig) { extern wfs; noise_orig = cycle_orig = kconv_orig = array(0n,nwfs); darkcurrent_orig = rayleigh_orig = array(float,nwfs); skyfluxpersub_orig = bckgrdcalib_orig = bias_orig = flat_orig = array(pointer,nwfs); use_sincos_approx_orig = [use_sincos_approx()]; // & need a vector use_sincos_approx,0; for (ns=1;ns<=nwfs;ns++) { // Impose noise = rmsbias = rmsflat = 0 for interaction matrix measurements noise_orig(ns) = wfs(ns).noise; wfs(ns).noise = 0n; cycle_orig(ns) = wfs(ns).nintegcycles; wfs(ns).nintegcycles = 1n; darkcurrent_orig(ns) = wfs(ns).darkcurrent; wfs(ns).darkcurrent = float(0.); rayleigh_orig(ns) = wfs(ns).rayleighflag; wfs(ns).rayleighflag = 0n; if (*wfs(ns)._skyfluxpersub!=[]) { skyfluxpersub_orig(ns) = &(*wfs(ns)._skyfluxpersub); *wfs(ns)._skyfluxpersub *= 0; } if (*wfs(ns)._bckgrdcalib!=[]) { bckgrdcalib_orig(ns) = &(*wfs(ns)._bckgrdcalib); *wfs(ns)._bckgrdcalib *= 0; } if (wfs(ns).type == "hartmann" ) { kconv_orig(ns) = wfs(ns)._kernelconv; wfs(ns)._kernelconv = 1n; bias_orig(ns) = &(*wfs(ns)._bias); *wfs(ns)._bias = *wfs(ns)._bias*0.0f; flat_orig(ns) = &(*wfs(ns)._flat); *wfs(ns)._flat = *wfs(ns)._flat*0.0f+1.0f; } } } func restore_noise_etc_for_imat(noise_orig, cycle_orig, kconv_orig, skyfluxpersub_orig,bckgrdcalib_orig, bias_orig, flat_orig, darkcurrent_orig, use_sincos_approx_orig,rayleigh_orig) { extern wfs; use_sincos_approx,use_sincos_approx_orig(1); for (ns=1;ns<=nwfs;ns++) { wfs(ns).noise = noise_orig(ns); wfs(ns).darkcurrent = darkcurrent_orig(ns); wfs(ns).rayleighflag = rayleigh_orig(ns); wfs(ns).nintegcycles = cycle_orig(ns); if (*wfs(ns)._skyfluxpersub!=[]) \ wfs(ns)._skyfluxpersub = skyfluxpersub_orig(ns); if (*wfs(ns)._bckgrdcalib!=[]) \ wfs(ns)._bckgrdcalib = bckgrdcalib_orig(ns); if (wfs(ns).type == "hartmann" ) { wfs(ns)._kernelconv = kconv_orig(ns); wfs(ns)._bias = bias_orig(ns); wfs(ns)._flat = flat_orig(ns); } } } //---------------------------------------------------- func prep_svd(imat,subsystem,svd=,disp=) /* DOCUMENT prep_svd(imat,subsystem,svd=,disp=) Does the SVD decomposition and fill out the modToAct (V) and mesToMod (UT) matrices for further use by build_cmat() imat = the imat to inverse disp = set if display is required. This routine uses: - imat (input) This routine calls: - SVdec This routine sets: - eigenvalues (extern) - modToAct (extern) - mesToMod (extern) Note: The Mode-to-Actuator (modToAct) matrix has to be used as follow: modes-coef = actToMod(,+) * command-coef(+) SEE ALSO: do_imat, build_cmat */ { // Define some extern variables: extern modToAct,mesToMod,eigenvalues; // Decompose to prepare inversion: if (sim.verbose>1) {write,"Doing SVD\n";} eigenvalues = SVdec(imat,u,vt); // Some debug output if needed: if (sim.verbose) { write,format="Smallests 2 normalized eigenvalues = %f", eigenvalues(-1)/max(eigenvalues),eigenvalues(0)/max(eigenvalues); } if (sim.verbose>1) { write,"Normalized eigenvalues:"; write,eigenvalues/max(eigenvalues); th = 1.0f/(*mat.condition)(subsystem); do { plot,eigenvalues/max(eigenvalues); plg,array(1/(*mat.condition)(subsystem),numberof(eigenvalues)),color="red",type=2; limits,square=0; mypltitle,"Normalized eigenvalues",[0.,-0.005],height=12; if (yaopy) break; if (is_set(svd)) { th = kinput("New Threshold ? (return to continue)",th); change = ( (th==1/(*mat.condition)(subsystem))? 0:1); if (change) (*mat.condition)(subsystem) = 1/th; } } while (change == 1); if (!yaopy) typeReturn; } modToAct = transpose(vt); // actToMod = LUsolve(modToAct); mesToMod = transpose(u); // used to be called ut // Some debug display if needed: if (sim.debug>=2) { tv,modToAct; mypltitle,"modToAct Matrix",[0.,-0.005],height=12; if (!yaopy) typeReturn; if (sim.debug>=3) { tv,modToAct(,+)*modToAct(,+); mypltitle,"modToAct(,+)*modToAct(,+)",[0.,-0.005],height=12; if (!yaopy) typeReturn; } tv,mesToMod; mypltitle,"mesToMod Matrix",[0.,-0.005],height=12; if (!yaopy) typeReturn; if (sim.debug>=3) { tv,mesToMod(,+)*mesToMod(,+); mypltitle,"mesToMod(,+)*mesToMod(,+)",[0.,-0.005],height=12; if (!yaopy) typeReturn; } } } //---------------------------------------------------- // func svdmodes_variance(void) // { // prepzernike,sim._size,sim.pupildiam,sim._size/2.+0.5,sim._size/2.+0.5; // fma; pli,zernike(1)+ipupil // } //---------------------------------------------------- func build_cmat(condition,modalgain,subsystem=,all=,nomodalgain=,disp=) /* DOCUMENT build_cmat(condition,modalgain,subsystem=,all=,nomodalgain=,disp=) Build the command matrix from V,UT, the eigenvalues and the modal gains F.Rigaut, June 17,2002 condition = Filter eigenvalues ev (and modes) for max(ev)/ev > condition modalgain = vector of system mode gains to pre-multiply the control matrix with. rarely used as these modes are not generally natural w.r.t. the turbulence. all = if not set, one (1) mode is forced to be discarded (useful if regular AO system using a DM with a piston component and condition number too large). Normally, set all=1. nomodalgain = if set, the modal gain are not taken into account. disp = set to display stuff. This routine uses: - dm._def, _nact, _n1, _n2 (extern) - ipupil (extern) - mat.condition (extern) - modalgain (extern) - eigenvalues (extern) - modToAct (extern) - mesToMod (extern) This routine calls: - Nothing This routine sets: - NModesControlled (extern) This routine returns: - cMat SEE ALSO: do_imat, prep_svd */ { extern NModesControlled; neigen = numberof(eigenvalues); mev = array(float,neigen,neigen); mask = ((eigenvalues/max(eigenvalues)) > (1./condition)); if (numberof(ev_user_mask)==numberof(mask)) mask = (mask|ev_user_mask); if (is_set(nomodalgain)) { ev = eigenvalues; } else { ev = eigenvalues/modalgain; } // Including the mode gains and eigenvalues here: for (i=1;i<=neigen;i++) { if (mask(i) == 1) {mev(i,i)=1./ev(i);} } // the last eigenvalue is filtered except if all is set. if (!is_set(all)) {mev(0,0) = 0.;} NModesControlled = sum(mev != 0.); // Compute the Command matrix: cmat = (modToAct(,+)*mev(+,))(,+) * mesToMod(+,); if (sim.verbose) { write,long(clip(sum(mask == 0),1-long(is_set(all)),)), format="%i modes discarded in the inversion\n"; } //========================================= // DISPLAY OF THE FILTERED MODES: // BEGINNING OF DISPLAY, NOTHING IMPORTANT // UNTIL "END OF DISPLAY" //========================================= if ((sim.debug>=1) && (disp >= 1) ) { n1 = (sim._size-sim.pupildiam)/2-2; n2 = (sim._size+sim.pupildiam)/2+2; nxy = n2-n1+1; sswfs = where(wfs.subsystem == subsystem); cubphase = array(float,[3,nxy,nxy,numberof(sswfs)]); subpos = wfs(sswfs).gspos; disp2d,cubphase,subpos(1,),subpos(2,),1,zoom=0.9,init=1; // find out to where is DM N in this subsystem "modToAct" matrix: ssdm = where(dm.subsystem == subsystem); // indexDm = array(long,[2,2,numberof(ssdm)]); indexDm = array(long,[2,2,ndm]); index = 0; for (nm=1;nm<=ndm;nm++) { if (dm(nm).subsystem == subsystem) { indexDm(,nm) = [index+1,index+dm(nm)._nact]; index = index+dm(nm)._nact; } } write,"Displaying filtered modes, type 'q' to exit display"; // loop on modes mircube *= 0.0f; for (i=neigen;i>=NModesControlled+1;i--) { // loop over dm to build mircube for (nm=1; nm<=ndm; nm++) { if (dm(nm).subsystem == subsystem) { n1 = dm(nm)._n1; n2 = dm(nm)._n2; nxy = n2-n1+1; scommand = float(modToAct(indexDm(1,nm):indexDm(2,nm),i)); mircube(n1:n2,n1:n2,nm) = comp_dm_shape(nm,&scommand); } } // Loop over WFS to get integrated phase n1 = (sim._size-sim.pupildiam)/2-2; n2 = (sim._size+sim.pupildiam)/2+2; nxy = n2-n1+1; nnss = 1; for (ns=1;ns<=nwfs;ns++) { if (wfs(ns).subsystem == subsystem) { phase = get_phase2d_from_dms(ns,"wfs")*ipupil; // fill cubphase cubphase(,,nnss) = phase(n1:n2,n1:n2); nnss++; } } // display using disp2d of integrated phases fma; plt,sim.name,0.01,0.227,tosys=0; disp2d,cubphase,subpos(1,),subpos(2,),1; mypltitle,swrite(format="Mode %d, Normalized eigenvalue = %f", i,eigenvalues(i)/max(eigenvalues)),[0.,-0.005],height=12; // display of DM shapes plsys,3; limits,square=1; tmp = []; for (nm=1;nm<=ndm;nm++) { if (dm(nm).subsystem == subsystem) { if (dm(nm).alt == 0.) {mircube(,,nm) *= ipupil;} grow,tmp,transpose(mircube(,,nm)); } } if (tmp != []) {pli,transpose(tmp);} mypltitle,"DM(s)",[0.,0.008],height=12; rep = typeReturn(); if (rep == "q") break; } } //========================================= // END OF DISPLAY //========================================= return cmat; } //---------------------------------------------------- func swap_screens(void) /* DOCUMENT swap_screens Swap the phase screens. This is to get better statistics out of fewer phase screens and iterations. The 2nd phase screen becomes the 1rst one, 3->2, etc... This routine uses the phase screens and normalization factor stored in extern by get_turb_phase_init SEE ALSO: */ { extern pscreens; weight = currentScreenNorm; // avoid division per zero // it's legitimate to have one screen == 0 weight += (weight == 0); // get rid of layer strength normalization factor: pscreens = pscreens/weight(-,-,); // swap screens: pscreens = pscreens(,,((indgen(nscreens)) % nscreens)+1); // re-apply normalization: weight = currentScreenNorm; pscreens = pscreens*weight(-,-,); } //---------------------------------------------------- func get_turb_phase_init(skipReadPhaseScreens=) /* DOCUMENT get_turb_phase_init(skipReadPhaseScreens=) Initializes everything for get_turb_phase (see below), which returns the interpolated, integrated phase to the loop function for iteration number "iter". Returns the "ok" parameter which is set to 0 if this step is not to be used to compute statistics. AUTHOR: F.Rigaut, June 11, 2002. SEE ALSO: aoinit, aoloop, get_turb_phase. */ { extern pscreens,// contains screens, dim [dim Screen X,dim Screen Y, nscreens] nscreens, // number of screens noptics, // number of optics optphasemaps, // phase maps for each optics xposvec, // contains X position vs iteration# of center of beam in // phase screen N, in pixel coords. dim [N iteracurwtions,nscreens] yposvec, // same for Y. This should be cst in the current implementation // as the screens have been cut in Y, therefore are not periodic // and therefore we can not wrap. wfsxposcub, // contains the position of the ray at which a given X pixel // intersects the Nth phase screen, for each WFS GS. // dimension [dimX outphase, nscreens, #GS] wfsyposcub, // Same for Y gsxposcub, // contains the position of the ray at which a given X pixel // intersects the Nth phase screen, for each star at which the perf // is evaluated dimension [dimX outphase, nscreens, #Star] gsyposcub, // Same for Y dmwfsxposcub, // contains the position of the ray at which a given X pixel // intersects the Nth mirror, for each WFS GS. // dimension [dimX outphase, ndm, #GS] dmwfsyposcub, // Same for Y dmgsxposcub, // contains the position of the ray at which a given X pixel // intersects the Nth mirror, for each star at which the perf // is evaluated dimension [dimX outphase, ndm, #Star] dmgsyposcub, // Same for Y optwfsxposcub,// contains the position of the ray at which a given X pixel // intersects the Nth optics, for each WFS GS. // dimension [dimX outphase, noptics, #GS] optwfsyposcub,// Same for Y optgsxposcub, // contains the position of the ray at which a given X pixel // intersects the Nth optics, for each star at which the perf // is evaluated dimension [dimX outphase, noptics, #Star] optgsyposcub, // Same for Y xmargins, // value of xposvec so that no pixel indice < 1 or > dimx(screen) // in any off-axis beam and altitude (low margin, up margin) ymargins, // same for Y. We use that in get_turb_phase to determine when to // wrap. //~ statsokvec, // 1 if it is ok to collect stats at this iteration. //~ // 0 if not, e.g. we just did a jump. dim [iteration] inithistory, // 1 if init has been done. screendim; // [phase screen X dim, Y dim] before they are extended for safe wrapping extern currentScreenNorm; // current screen normalization. Used when swaping screen. // Define a few variables: nscreens = numberof(*atm.screen); if (opt!=[]) noptics = numberof(opt); else noptics=0; wfsxposcub = wfsyposcub = array(float,[3,_n,nscreens,nwfs]); gsxposcub = gsyposcub = array(float,[3,_n,nscreens,target._ntarget]); dmwfsxposcub = dmwfsyposcub = array(float,[3,_n,ndm,nwfs]); dmgsxposcub = dmgsyposcub = array(float,[3,_n,ndm,target._ntarget]); if (noptics) { optwfsxposcub = optwfsyposcub = array(float,[3,_n,noptics,nwfs]); optgsxposcub = optgsyposcub = array(float,[3,_n,noptics,target._ntarget]); } //======================================================= // READS AND NORMALIZE THE PHASE SCREENS // the phase screens now (v2.4) are normalized in microns //======================================================= if (!is_set(skipReadPhaseScreens)) { // Compute normalization factor: (*atm.layerfrac) = (*atm.layerfrac)/sum(*atm.layerfrac); weight = float(sqrt(*atm.layerfrac)*(atm.dr0at05mic/ cos(gs.zenithangle*dtor)^0.6/sim.pupildiam)^(5./6.)); // above: in radian at 0.5 microns weight = weight * float(0.5/(2*pi)); // ... and now in microns. /*===================================================== How to relate r0(layer) and atm.layerfrac ? r0(i) = r0 of layer i r0tot = total r0 f(i) = "fraction" in layer i ( = (*atm.layerfrac)(i) ) we have: weight(i) = sqrt(f(i)) * (D/r0tot)^(5/6.) = (D/r0(i))^(5/6.) thus f(i) = (r0tot/r0(i))^(5./3) inversely, we have: r0(i) = r0tot / f(i)^(3./5) =====================================================*/ if (sim.verbose) { write,format="Reading phase screen \"%s\"\n",(*atm.screen)(1); } // read the first one, determine dimensions, stuff it: tmp = yao_fitsread((*atm.screen)(1)); dimx = dimsof(tmp)(2); dimy = dimsof(tmp)(3); screendim = [dimx,dimy]; if (dimx == dimy){ // can wrap both x and y // Extend dimension in X and Y for wrapping issues // Made larger to accommodate GLAO, Marcos van Dam, May 2012 pscreens = array(float,[3,dimx+4*sim._size,dimy+4*sim._size,nscreens]); // Stuff it pscreens(1:dimx,1:dimy,1) = tmp; // free RAM tmp = []; // Now read all the other screens and put in pscreens for (i=2;i<=nscreens;i++) { if (sim.verbose) { write,format="Reading phase screen \"%s\"\n",(*atm.screen)(i); } pscreens(1:dimx,1:dimy,i) = yao_fitsread((*atm.screen)(i)); } // Extend the phase screen length for safe wrapping: pscreens(dimx+1:,,) = pscreens(1:4*sim._size,,); pscreens(,dimy+1:,) = pscreens(,1:4*sim._size,); } else { // Extend dimension in X for wrapping issues pscreens = array(float,[3,dimx+2*sim._size,dimy,nscreens]); // Stuff it pscreens(1:dimx,,1) = tmp; // free RAM tmp = []; // Now read all the other screens and put in pscreens for (i=2;i<=nscreens;i++) { if (sim.verbose) { write,format="Reading phase screen \"%s\"\n",(*atm.screen)(i); } pscreens(1:dimx,,i) = yao_fitsread((*atm.screen)(i)); } // Extend the phase screen length for safe wrapping: pscreens(dimx+1:,,) = pscreens(1:2*sim._size,,); // Can't do in Y as the phase screens are not periodic (they have been cutted) // pscreens(,dimy+1:,) = pscreens(,1:sim._size,); } // apply weights to each phase screens (normalize): // the screens are expressed in microns pscreens = pscreens*weight(-,-,); currentScreenNorm = weight; //============================================= // READ THE OPTICS PHASE MAPS // the dimension of all the optical phase maps // should be the same. These phase maps should // be big enough so that the interpolation will // not go outside of the provided map. That is, // the indices in opt**xposcub (and y), with ** // being wfs and gs, should not define points // outside of the provided phase maps. // THIS IS LEFT TO THE RESPONSIBILITY OF THE // USER. I do however a simple check below. // Normaly, this should not be a problem: // if some indices are outside the maps, it means // either that the maps are not big enough, in // which case we should not use it, or that // there was an error in the definition of the // altitude. //============================================= if (noptics) { psize = tel.diam/sim.pupildiam; if (sim.verbose) { write,"Reading optics. I am expecting phase maps with a pixel"; write,format=" size of %fm/pixel, as projected in the entrance\n",psize; write,"pupil plane. It is also your responsibility to provide phase"; write,"maps of adequate dimension, i.e. large enough"; write,format="Reading phase map for optics \"%s\"\n",opt(1).phasemaps; } tmp = yao_fitsread(YAO_SAVEPATH+opt(1).phasemaps); optdims = dimsof(tmp); optdimx = optdims(2); optdimy = optdims(3); if (optdimx != optdimy) error,"Optics phase maps should be square arrays"; optphasemaps = array(float,[3,optdimx,optdimy,noptics]); // Stuff it optphasemaps(,,1) = float(tmp); for (i=2;i<=noptics;i++) { if (sim.verbose) { write,format="Reading phase map for optics \"%s\"\n",opt(i).phasemaps; } tmp = yao_fitsread(YAO_SAVEPATH+opt(i).phasemaps); if (anyof(dimsof(tmp) != optdims)) error,"All optics phase maps should have the same dimensions"; optphasemaps(,,i) = float(tmp); } opt._cent = optdimx/2.+(sim._cent-sim._size/2.); // (sim._cent-sim._size/2.) = 0. or 0.5 } } //==================================== // PREPARE GEOMETRY FOR INTERPOLATION //==================================== // Build a vector of position (integer position in equivalent // iterations: iposvec = indgen(loop.niter); iposvec = iposvec+((iposvec-1)/loop.skipevery)*loop.skipby; // build a vector of the iterations at which statistics // should be accumulated. 1 if ok to accumulate statistics, 0 if not. // 2012oct16: moved to aoloop() //~ statsokvec = (indgen(loop.niter)-1) % loop.skipevery; //~ statsokvec = (statsokvec >= loop.startskip); // Build the position vector vs iteration by phase screen deltax = sim.pupildiam/tel.diam*(*atm.layerspeed)*cos(dtor*gs.zenithangle)*loop.ittime; // has to start away from edge as this is the coordinate of the beam center // will modified later on when we know the beams geometry. see few lines below. xposvec = (1.+iposvec*deltax(-,)*cos(dtor*(*atm.winddir)(-,))); yposvec = (1.+iposvec*deltax(-,)*sin(dtor*(*atm.winddir)(-,))); psize = tel.diam/sim.pupildiam; // pixel in meter //=========================================================== // PRE-COMPUTATION OF THE INTERSECT POSITIONS FOR EACH WFS GS //=========================================================== // zero-centered vector of position (our reference) xref = indgen(_n)-(_n+1)/2.; yref = indgen(_n)-(_n+1)/2.; // loop on WFS for (n=1;n<=nwfs;n++) { // loop on screen for (ns=1;ns<=nscreens;ns++) { // offsets of the center of beam on screen NS xoff = (wfs(n).gspos)(1)*4.848e-6*(*atm._layeralt)(ns)/psize; yoff = (wfs(n).gspos)(2)*4.848e-6*(*atm._layeralt)(ns)/psize; // if we are dealing with LGS, there is a geometric // factor on the beam size if (wfs(n)._gsalt != 0) { fact = (wfs(n)._gsalt-(*atm._layeralt)(ns))/wfs(n)._gsalt; } else { fact = 1.; } // Compute and stuff the array wfsxposcub(,ns,n) = xref*fact + xoff; wfsyposcub(,ns,n) = yref*fact + yoff; } // loop on DMs for (ns=1;ns<=ndm;ns++) { // offsets of the center of beam on DM NS xoff = (wfs(n).gspos)(1)*4.848e-6*(dm.alt)(ns)/psize; yoff = (wfs(n).gspos)(2)*4.848e-6*(dm.alt)(ns)/psize; // if we are dealing with LGS, there is a geometric // factor on the beam size if (wfs(n)._gsalt != 0) { fact = (wfs(n)._gsalt-(dm.alt)(ns))/wfs(n)._gsalt; } else { fact = 1.; } // Compute and stuff the array dmwfsxposcub(,ns,n) = xref*fact + xoff; dmwfsyposcub(,ns,n) = yref*fact + yoff; } // loop on optics for (ns=1;ns<=noptics;ns++) { // offsets of the center of beam on optics #NS xoff = (wfs(n).gspos)(1)*4.848e-6*opt(ns).alt/psize; yoff = (wfs(n).gspos)(2)*4.848e-6*opt(ns).alt/psize; // if we are dealing with LGS, there is a geometric // factor on the beam size if (wfs(n)._gsalt != 0) { fact = (wfs(n)._gsalt-opt(ns).alt)/wfs(n)._gsalt; } else { fact = 1.; } // Compute and stuff the array optwfsxposcub(,ns,n) = xref*fact + xoff; optwfsyposcub(,ns,n) = yref*fact + yoff; } } // type conversion: wfsxposcub = float(wfsxposcub); wfsyposcub = float(wfsyposcub); dmwfsxposcub = float(dmwfsxposcub); dmwfsyposcub = float(dmwfsyposcub); optwfsxposcub = float(optwfsxposcub); optwfsyposcub = float(optwfsyposcub); //============================================================= // PRE-COMPUTATION OF THE INTERSECT POSITION FOR EACH PERF STAR //============================================================= // loop on target for (n=1;n<=target._ntarget;n++) { // loop on screen for (ns=1;ns<=nscreens;ns++) { // offsets of the center of beam on screen NS xoff = (*target.xposition)(n)*4.848e-6*(*atm._layeralt)(ns)/psize; yoff = (*target.yposition)(n)*4.848e-6*(*atm._layeralt)(ns)/psize; // note: that's target. we can't be dealing with LGS here (no fact) // Compute and stuff the array gsxposcub(,ns,n) = xref + xoff; gsyposcub(,ns,n) = yref + yoff; } // loop on DMs for (ns=1;ns<=ndm;ns++) { // offsets of the center of beam on DM NS xoff = (*target.xposition)(n)*4.848e-6*(dm.alt)(ns)/psize; yoff = (*target.yposition)(n)*4.848e-6*(dm.alt)(ns)/psize; // note: that's target. we can't be dealing with LGS here (no fact) // Compute and stuff the array dmgsxposcub(,ns,n) = xref + xoff; dmgsyposcub(,ns,n) = yref + yoff; } // loop on optics for (ns=1;ns<=noptics;ns++) { // offsets of the center of beam on DM NS xoff = (*target.xposition)(n)*4.848e-6*opt(ns).alt/psize; yoff = (*target.yposition)(n)*4.848e-6*opt(ns).alt/psize; // note: that's target. we can't be dealing with LGS here (no fact) // Compute and stuff the array optgsxposcub(,ns,n) = xref + xoff; optgsyposcub(,ns,n) = yref + yoff; } } // type conversion: gsxposcub = float(gsxposcub); gsyposcub = float(gsyposcub); dmgsxposcub = float(dmgsxposcub); dmgsyposcub = float(dmgsyposcub); optgsxposcub = float(optgsxposcub); optgsyposcub = float(optgsyposcub); //====================================== // SOME CHECKS TO AVOID INDICES OVERFLOW //====================================== // Now we can modify xposvec and yposvec to make sure we are not going // out of the phase screen arrays xmargins = abs([min(_(wfsxposcub(*),gsxposcub(*))),max(_(wfsxposcub(*),gsxposcub(*)))]); ymargins = abs([min(_(wfsyposcub(*),gsyposcub(*))),max(_(wfsyposcub(*),gsyposcub(*)))]); xposvec = xposvec - min(xposvec) + xmargins(1) +1; yposvec = yposvec - min(yposvec) + ymargins(1) +1; // wrap so that it never goes out of bound (including off axis stuff) // have to do that for each screens as they are moving at different speeds for (ns=1;ns<=nscreens;ns++) { // we know that xposvec is now purely positive (lines above), // so that it is enough to insure that it will never go above upper limit: // If pixel position of beam center (xposvec) is larger than the // initial dimension of the screen + the xmargin necessary so that // off-axis beams don't hit negative indices, then it is // time to wrap by subtracting the original screen Xdim to // xposvec. xposvec(,ns) = xmargins(1)+ ( (xposvec(,ns)-xmargins(1)) % screendim(1)); if (dimx == dimy){yposvec(,ns) = ymargins(1)+ ( (yposvec(,ns)-ymargins(1)) % screendim(2));} // don't do for Y as we're not allowed to move along Y // (screen not periodic) } // type conversion: xposvec = float(xposvec); yposvec = float(yposvec); // so now we have everything initiliazed, and we will just have to // interpolate the phase screen at points // xposvec(iteration,screen#) + wfsxposcub(,screen#,wfs#) // and corresponding for Y, and integrate on screen# // to get the phase for a given WFS // this integration is done by the C routine _get2dPhase // which take, in addition to the screens and output phase parameters, // only a set of X and Y positions as input [the one we just talked // about, xposvec(iteration) + wfsxposcub(,,wfs#) ]. // check that y index does not overflow: if (dimx != dimy){get_turb_phase_initCheckOverflow;} inithistory = 1; return 1; } //---------------------------------------------------- func get_turb_phase(iter,nn,type) /* DOCUMENT get_turb_phase(iter,n,type) Returns the interpolated, integrated phase along the turbulent phase screen data cube to the loop function for iteration number "iter". You have to call get_turb_phase_init to initialize prior using. SEE ALSO: aoinit, aoloop, get_turb_phase_init. */ { if (!inithistory) {error,"get_turb_phase has not been initialized !";} sphase = array(float,_n,_n); bphase = array(float,sim._size,sim._size); // Now we can call the C interpolation routine and get the integrated // phase for this star // there are a few things to do to get ready psnx = dimsof(pscreens)(2); psny = dimsof(pscreens)(3); nscreens = dimsof(pscreens)(4); // here we have a branch to be able to process wfs and targets with the same // subroutine, this one. if (type == "wfs") { // mod 2011jan19 w/ DG to get rid of screens above LGS if (wfs(nn).gsalt>0) nscreens = long(sum(*atm.layeralt < wfs(nn).gsalt)); // stuff xshifts with fractionnal offsets, add xposvec for each screen xshifts = wfsxposcub(,,nn)+xposvec(iter,)(-,); yshifts = wfsyposcub(,,nn)+yposvec(iter,)(-,); } else if ( type == "target") { // stuff xshifts with fractionnal offsets, add xposvec for each screen xshifts = gsxposcub(,,nn)+xposvec(iter,)(-,); yshifts = gsyposcub(,,nn)+yposvec(iter,)(-,); } ishifts = int(xshifts); xshifts = xshifts - ishifts; jshifts = int(yshifts); yshifts = yshifts - jshifts; err = _get2dPhase(&pscreens,psnx,psny,nscreens, &sphase,_n,_n, &ishifts,&xshifts, &jshifts,&yshifts); if (err != 0) {error,"Error in get_turb_phase";} bphase(_n1:_n2,_n1:_n2) = sphase; return bphase; } //---------------------------------------------------- func get_phase2d_from_dms(nn,type) /* DOCUMENT get_phase2d_from_dms(nn, type) Similar than get_turb_phase excepts it works on the mirror shape data cube. Returns the integrated phase along one given direction. nn = yao object # of type as below type = "wfs" or "target". so get_phase2d_from_dms(2,"wfs") will return the phase integrated along the third dimension of the cube (different altitude) in the direction of wfs #2. uses mircube (extern) = cube or image of phase screen (mirrors) first plan = first mirror shape second plan = second mirror shape etc... should be of size sim._size * sim._size SEE ALSO: */ { sphase = array(float,_n,_n); bphase = array(float,sim._size,sim._size); if (anyof(dm.ncp)||(target.ncpdm)||((type=="wfs")&&(wfs(nn).ncpdm))) { mirrorcube = mircube; // create a copy dmidx = where(dm.ncp == 0); if (type == "target"){ if (*target.ncpdm != []){ ncpdm = (*target.ncpdm)(nn); if (ncpdm != 0 && noneof(dmidx == ncpdm)){ grow, dmidx, ncpdm; } } } else { // type == "wfs" if (wfs(nn).ncpdm != 0 && noneof(dmidx == wfs(nn).ncpdm)){ grow, dmidx, wfs(nn).ncpdm; } } mirrorcube = mirrorcube(,,dmidx); } else eq_nocopy,mirrorcube,mircube; // Now we can call the C interpolation routine and get the integrated // phase for this star // there are a few things to do to get ready psnx = dimsof(mirrorcube)(2); psny = dimsof(mirrorcube)(3); nmirrors = dimsof(mirrorcube)(4); // here we have a branch to be able to process wfs and targets with the same // subroutine, this one. if (type == "wfs") { // stuff xshifts with fractional offsets, add xposvec for each screen xshifts = dmwfsxposcub(,,nn)+(sim._cent+dm.misreg(1,)-1)(-,); yshifts = dmwfsyposcub(,,nn)+(sim._cent+dm.misreg(2,)-1)(-,); } else if ( type == "target") { // stuff xshifts with fractional offsets, add xposvec for each screen xshifts = dmgsxposcub(,,nn)+(sim._cent+dm.misreg(1,)-1)(-,); yshifts = dmgsyposcub(,,nn)+(sim._cent+dm.misreg(2,)-1)(-,); } ishifts = int(xshifts); xshifts = xshifts - ishifts; jshifts = int(yshifts); yshifts = yshifts - jshifts; err = _get2dPhase(&mirrorcube,psnx,psny,nmirrors, &sphase,_n,_n, &ishifts,&xshifts, &jshifts,&yshifts); if (err != 0) {error,"Error in get_phase2d_from_dms";} bphase(_n1:_n2,_n1:_n2) = sphase; return bphase; } //---------------------------------------------------- func get_phase2d_from_optics(nn,type) /* DOCUMENT get_phase2d_from_optics(nn,type) Same as get_phase2d_from_dms, but for static optical elements defined in the opt structure. See get_phase2d_from_dms. nn = wfs or GS # type = "wfs" or "target" SEE ALSO: */ { if (opt==[]) return 0.0f; // select optics in path that apply to type: // there are noptics = numberof(opt) if (type=="wfs") { w = where(opt.path_type!="target"); // no common or wfs optics, return: if (numberof(w)==0) return 0.0f; // now for each ok optics, check this wfs has not been excluded for (no=1;no<=numberof(w);no++) { if (opt(w(no)).path_type=="common") continue; else { // necessarily, this is a "wfs" optics if (noneof(*opt(w(no)).path_which==nn)) w(no)=-1; } if (opt(w(no)).scale==0) w(no)=-1; } w = w(where(w>=0)); if (numberof(w)==0) return 0.0f; } if (type=="target") { w = where(opt.path_type!="wfs"); // no common or science optics, return: if (numberof(w)==0) return 0.0f; // now for each ok optics, check this target has not been excluded for (no=1;no<=numberof(w);no++) { if (opt(w(no)).path_type=="common") continue; else { // necessarily, this is a "target" optics if (noneof(*opt(w(no)).path_which==nn)) w(no)=-1; } if (opt(w(no)).scale==0) w(no)=-1; } w = w(where(w>=0)); if (numberof(w)==0) return 0.0f; } sphase = array(float,_n,_n); bphase = array(float,sim._size,sim._size); thisphasemaps = optphasemaps(,,w)*opt(w).scale(-,-,); // Now we can call the C interpolation routine and get the integrated // phase for this star // there are a few things to do to get ready psnx = dimsof(thisphasemaps)(2); psny = dimsof(thisphasemaps)(3); nopts = dimsof(thisphasemaps)(4); // here we have a branch to be able to process wfs and targets with the same // subroutine, this one. if (type == "wfs") { // stuff xshifts with fractional offsets, add xposvec for each screen xshifts = optwfsxposcub(,,nn)+(opt._cent+opt.misreg(1,)-1)(-,w); yshifts = optwfsyposcub(,,nn)+(opt._cent+opt.misreg(2,)-1)(-,w); } else if ( type == "target") { // stuff xshifts with fractional offsets, add xposvec for each screen xshifts = optgsxposcub(,,nn)+(opt._cent+opt.misreg(1,)-1)(-,w); yshifts = optgsyposcub(,,nn)+(opt._cent+opt.misreg(2,)-1)(-,w); } ishifts = int(xshifts); xshifts = float(xshifts - ishifts); jshifts = int(yshifts); yshifts = float(yshifts - jshifts); err = _get2dPhase(&thisphasemaps,psnx,psny,nopts, &sphase,_n,_n, &ishifts,&xshifts, &jshifts,&yshifts); // if (err != 0) {error,"Error in get_phase2d_from_optics";} bphase(_n1:_n2,_n1:_n2) = sphase; return bphase; } //---------------------------------------------------- func correct_uplink_tt(phase, ns) /* DOCUMENT correct_uplink_tt(phase, ns) Apply tiptilt phase correction to a phase term, given wfs._upttcommand determined previously. SEE ALSO: */ { wfs(ns)._upttcommand += wfs(ns).uplinkgain * wfs(ns)._tt; phase -= wfs(ns)._upttcommand(1) * tip1arcsec; phase -= wfs(ns)._upttcommand(2) * tilt1arcsec; return phase; } //---------------------------------------------------- func split_wfs_vector(v) /* DOCUMENT split_wfs_vector(v) Splits a single vector (out of mult_wfs or mult_wfs_int_mat) into as many individual wfs vectors as there are sensors. Return a pointer vector to the individual wfs vectors. SEE ALSO: split_dm_vector(v) */ { vp = []; vs = v(1:wfs(1)._nmes); grow,vp,&vs; iend = wfs(1)._nmes; for (ns=2;ns<=nwfs;ns++) { istart = iend+1; iend = istart+wfs(ns)._nmes-1; vs = v(istart:iend); grow,vp,&vs; } return vp; } //---------------------------------------------------- func split_dm_vector(v) /* DOCUMENT split_dm_vector(v) Splits the single vector (out of cMat matrix multiply in aoloop) into as many individual command vector as there are DMs. Return a pointer vector to the individual command vectors. SEE ALSO: split_wfs_vector */ { vp = []; vs = v(1:dm(1)._nact); grow,vp,&vs; iend = dm(1)._nact; for (ns=2;ns<=ndm;ns++) { istart = iend+1; iend = istart+dm(ns)._nact-1; vs = v(istart:iend); grow,vp,&vs; } return vp; } //---------------------------------------------------- func check_control_parameters(void){ /* DOCUMENT check_control_parameters(void) Check the control parameters and update them SEE ALSO: */ // first, convert the controllers into what is implemented gainho = *loop.gainho; leakho = *loop.leakho; for (nm=1;nm<=ndm;nm++){ ctrlnum = *dm(nm).ctrlnum; ctrlden = *dm(nm).ctrlden; if (numberof(ctrlnum) > 10){ write, format = "dm(%d).ctrlnum must have 10 or fewer values \n",nm; exit; } if (numberof(ctrlden) > 10){ write, format = "dm(%d).ctrlden must have 10 or fewer values \n",nm; exit; } if ((ctrlnum != []) && (ctrlden != [])){ // ctrlnum and ctrlden are defined if (sim.verbose){write, format = "Using dm.ctrlden and dm.ctrlnum for DM %d \n",nm;} } else { ctrlnum = [loop.gain*dm(nm).gain]; if (gainho != []){ grow, ctrlnum, dm(nm).gain*gainho; } ctrlden = [1,-1+loop.leak]; if (leakho != []){ grow, ctrlden, -1+leakho; } } dm(nm)._ctrlnum = &(ctrlnum); dm(nm)._ctrlden = &(ctrlden); } } //---------------------------------------------------- func aoall(parfile,disp=,dpi=,clean=,controlscreen=) /* DOCUMENT aoall(parfile,disp=,dpi=,clean=,controlscreen=) Shorthand for aoread, aoinit, aoloop and go SEE ALSO: aoread, aoinit, aoloop, go */ { aoread,parfile; aoinit,disp=disp,dpi=dpi,clean=clean; aoloop,disp=disp,dpi=dpi,controlscreen=controlscreen; after,0.1,go; } //---------------------------------------------------- func aoread(parfile) /* DOCUMENT aoread(parfile) Define the relevant structure/variable, and reads out the AO simulation parameter file (e.g. "sh6.par"), Does a check of the WFS pixel/subaperture sizes. This is the first function to call in the ao serie (normally, aoinit and aoloop follow). This routine was kept separate from aoinit to keep the possibility to change variables inbetween the aoread and the aoinit calls. example: > aoread,"sh6.par" > loop.niter = 1000 > aoinit SEE ALSO: aoinit, aoloop, go */ { extern atm,opt,sim,wfs,dm,mat,tel,target,gs,loop,parprefix,oparfile; write,format="Yao, Version %s, %s\n",aoSimulVersion, aoSimulVersionDate; if (Y_VERSION == "1.5.12") { error,"SVD is broken in yorick 1.5.12 ! Get a later version."; } // if we are re-reading and had forks, get rid of them: if ((wfs!=[])&&(anyof(wfs.svipc>1))) status=quit_wfs_forks(); if (strmatch(parfile,".par")) { tmp = strpart(parfile,strword(parfile,"/",50)); tmp = tmp(where(tmp)); tmp = tmp(0); tmp = strpart(tmp,strword(tmp,".",5)); tmp = tmp(where(tmp)); parprefix = tmp(:-1)(sum); } else { parprefix = parfile; } oparfile = parfile; // flush any prior assignments to ao members atm=opt=sim=wfs=dm=mat=tel=target=gs=loop=cwfs=[]; // INIT STRUCTURES: atm = atm_struct(); opts = opt_struct(path_type="common",scale=1.0); sim = sim_struct(); wfss = wfs_struct(dispzoom=1,_bckgrdsub=1,shcalibseeing=0.667,subsystem=1); dms = dm_struct(gain=1.,coupling=0.2); mat = mat_struct(file="",fit_type="target",fit_which=1); tel = tel_struct(); target = target_struct(); gs = gs_struct(); loop = loop_struct(modalgainfile="",stats_every=4,startskip=10); if (!fileExist(parfile)) { exit,swrite(format="Can not find parameter file %s !",parfile);} // read out the parfile. This stuffs values into the structures: include,parfile,1; //===================================== // PARAMETER CHECKS. SETS SOME DEFAULTS //===================================== check_parameters; wfs._origpixsize = wfs.pixsize; gui_message,"Next step: click on aoinit"; } //---------------------------------------------------- func aoinit(disp=,clean=,forcemat=,svd=,dpi=,keepdmconfig=) /* DOCUMENT aoinit(disp=,clean=,forcemat=,svd=,dpi=,keepdmconfig=) Second function of the ao serie. Initialize everything in preparation for the loop (aoloop). Follows a call to aoread, parfile. disp = set to display stuff clean = if set, aoinit will start fresh. *Nothing* is kept from previous runs. forcemat = set to force measuring new iMat and computing new cMat. svd = set to enter SVD threshold condition by hand dpi = dpi of graphic window keepdmconfig = when forcemat=1, the default behavior is to agregate the previously determined active and extrapolated actuators and do the new interacton matrix with all of them. The selection of valid/extrapolated is then reset (and re-executed when the interaction matrix is done). Setting keepdmconfig=1 impose that the valid/extrapolated setting remains as it was. SEE ALSO: aoread, aoloop */ { extern pupil,ipupil; extern iMat,cMat,fMat,dMat; extern iMatSP,AtAregSP,fMatSP,GxSP, polcMatSP; extern modalgain; extern _n,_n1,_n2,_p1,_p2,_p; extern def,mircube; extern tip1arcsec,tilt1arcsec; extern aoinit_disp,aoinit_clean,aoinit_forcemat; extern aoinit_svd,aoinit_keepdmconfig; extern tipvib, tiltvib; extern segmenttiptiltvib,segmentpistonvib; extern default_dpi; disp = ( (disp==[])? (aoinit_disp==[]? 0:aoinit_disp):disp ); clean = ( (clean==[])? (aoinit_clean==[]? 0:aoinit_clean):clean ); forcemat = ( (forcemat==[])? (aoinit_forcemat==[]? 0:aoinit_forcemat):forcemat ); svd = ( (svd==[])? (aoinit_svd==[]? 0:aoinit_svd):svd ); keepdmconfig = ( (keepdmconfig==[])? (aoinit_keepdmconfig==[]? 0:aoinit_keepdmconfig):keepdmconfig ); // initialize DM hysteresis parameters for (nm=1;nm<=ndm;nm++){ dm(nm)._alpha = [0.01,0.2,4]; dm(nm)._beta = [0.4,0.63,0.89]; dm(nm)._w = [0.2,0.35,0.45]; } if (mat.method == "mmse-sparse"){ require,"soy.i"; extern MR,MN; MR = mat.sparse_MR; MN = mat.sparse_MN; mat.file = parprefix+"-iMat.rco"; } else { mat.file = parprefix+"-mat.fits"; } if (sim.verbose>1) write,format="Starting aoinit with flags disp=%d,clean=%d,"+ \ "forcemat=%d,svd=%d,keepdmconfig=%d\n", \ disp,clean,forcemat,svd,keepdmconfig; sphase = bphase = mircube = []; hcp_file,YAO_SAVEPATH+parprefix+"init.ps",ps=1; //===================================== // PARAMETER CHECKS. SETS SOME DEFAULTS //===================================== check_parameters; if (!is_set(disp)) {disp = 0;} if (!is_set(dpi)) {dpi = 70;} if (is_set(clean)) {forcemat=1;} default_dpi=dpi; if (anyof(wfs.nintegcycles != 1) && (loop.method == "open-loop")) { exit, ">> nintegcycles > 1 not implemented for open-loop, exiting"; } // Sets other parameters: sim._size = int(2^ceil(log(sim.pupildiam)/log(2)+1)); size = sim._size; // mircube will receive the shape of each DM (one plan per DM): mircube = array(float,sim._size,sim._size,ndm); // INITIALIZE OUTPUT RESULT FILE YAO_SAVEPATH+parprefix.RES if (!fileExist(YAO_SAVEPATH+parprefix+".res")) { if (sim.verbose) { write,">> File "+parprefix+".res not found, creating one...\n"; } f = open(YAO_SAVEPATH+parprefix+".res","w"); close,f; } f = open(YAO_SAVEPATH+parprefix+".res","a+"); write,f,format="=============================\n%s\n",sim.name; close,f; //=================================================================== // INIT SVIPC IF NEEDED: //=================================================================== if ( anyof(wfs.svipc>1) || (sim.svipc) ) { require,"yao_svipc.i"; status = svipc_init(); } //=================================================================== // INITIALIZE SOME STUFF FOR OFF ZENITH CONFIGURATIONS: wfs._gsalt = wfs.gsalt / cos(gs.zenithangle*dtor); wfs._gsdepth = wfs.gsdepth / cos(gs.zenithangle*dtor); // dm.alt is not modified by the zenith angle in the system I simulate. atm._layeralt= &(*atm.layeralt / cos(gs.zenithangle*dtor)); //=================================================================== // INITIALIZE PUPIL // set pupil center: If SH wfs, should be between four central pixels // except if nbsub is odd and npixpersub is odd. // 02/20/03: FIX ME: Should rework this part to allow for mixture // of curvature and SH. //=================================================================== cent = []; for (i=1;i<=nwfs;i++) { wfs(i)._cyclecounter = 1; if ( (wfs(i).type == "hartmann") || (wfs(i).type == "pyramid") ) { if (wfs(i).npixpersub) { npixpersub = wfs(i).npixpersub; } else { npixpersub = float(sim.pupildiam)/wfs(i).shnxsub; if (npixpersub != int(npixpersub)) { write,"sim.pupildiam should be a multiple of wfs.shnxsub !"; return -1; } } if (odd(wfs(i).shnxsub) && odd(npixpersub)) { grow,cent,sim._size/2+1; } else { grow,cent,sim._size/2+0.5; } } else if (wfs(i).type == "curvature") { grow,cent,sim._size/2+1; } else if (wfs(i).type == "zernike") { grow,cent,sim._size/2+1; } else if (wfs(i).type == "dh") { // for dh we dont mind, as they can be produced for // any cent. } else { if (cent == []){ grow,cent,sim._size/2+0.5; write,format ="FIXME: user wfs function: assuming cent is at %.1f\n", float(sim._size/2+1); } else { grow,cent,cent(1); write,format = "FIXME: user wfs function: assuming cent is at %.1f\n",float(cent(1)); } } } if (nallof(wfs.type=="dh") && anyof(cent != cent(1))) { write,"Wrong mix of hartmann/curvature or subaperture odd/even !"; write,"I can't handle that as some of your selected sensor require"; write,"the pupil to be centered on a pixel and others in between 2 pixels"; write,"Sorry :-("; exit; } if (allof(wfs.type=="dh")) cent=sim._size/2+0.5; sim._cent = cent(1); // Initialize pupil array: pupil = float(make_pupil(sim._size,sim.pupildiam,xc=sim._cent,yc=sim._cent,\ real=sim.pupilapod,cobs=tel.cobs)); // changed from real=1 by Marcos. ipupil = float(make_pupil(sim._size,sim.pupildiam,xc=sim._cent,yc=sim._cent,\ cobs=tel.cobs)); if (user_pupil) user_pupil; pupil = float(pupil); ipupil = float(ipupil); //================================== // DEFINE INDICES FOR SUBARRAY WORK: //================================== _p = sim.pupildiam; _p1 = long(ceil(sim._cent-_p/2.)); _p2 = long(floor(sim._cent+_p/2.)); _p = _p2-_p1+1; _n = _p+4; _n1 = _p1-2; _n2 = _p2+2; //================================== // INITIALIZE DISPLAYS //================================== if (is_set(disp) || (sim.debug>0)) { if (!yaopy) { // set if using pygtk GUI, which prevents remapping a new window status = create_yao_window(); } if (wfs_display_mode=="spatial") { disp2d,wfs._dispimage,wfs.pupoffset(1,),wfs.pupoffset(2,),2,\ zoom=wfs.dispzoom,init=1; } else { disp2d,wfs._dispimage,wfs.gspos(1,),wfs.gspos(2,),2,zoom=wfs.dispzoom,init=1; } } //================================== // INITIALIZE PHASE SCREENS //================================== if (sim.verbose) {write,"\n> INITIALIZING PHASE SCREENS";} gui_message,"Initializing phase screens"; get_turb_phase_init; //================================== // INITIALIZE SENSOR //================================== if (sim.verbose) {write,"\n> INITIALIZING SENSOR GEOMETRY";} gui_message,"Initializing sensor geometry"; for (n=1;n<=nwfs;n++) { if (wfs(n).type == "curvature") { // build subaperture geometry: make_curv_wfs_subs,n,size,sim.pupildiam; // init WFS curv_wfs,pupil,pupil*0.0f,n,init=1; wfs(n)._nsub = int(sum(*(wfs(n).nsubperring))); wfs(n)._nmes = wfs(n)._nsub; } else if (wfs(n).type == "hartmann") { // init WFS: if (wfs(n).disjointpup) { shwfs_init,disjointpup(,,n),n,imat=1,clean=clean; } else shwfs_init,ipupil,n,imat=1,clean=clean; wfs(n)._nmes = 2*wfs(n)._nsub; } else if (wfs(n).type == "pyramid") { // init WFS v = pyramid_wfs(pupil,pupil*0.,n,disp=disp,init=1); wfs(n)._nsub = numberof(v)/2; wfs(n)._nmes = 2*wfs(n)._nsub; } else if (wfs(n).type == "zernike") { zernike_wfs,ipupil,ipupil*0.,n,init=1; } else if (wfs(n).type == "dh") { dh_wfs,ipupil,ipupil*0.,n,init=1; } else { // assign user_wfs to requested function/type: cmd = swrite(format="user_wfs = %s",wfs(n).type); include,[cmd],1; user_wfs,ipupil,ipupil*0.,n,init=1; } if ( (wfs(n).disjointpup) && (disjointpup==[]) ) \ error,swrite(format="wfs(%d).disjointpup set but disjointpup does not exist\n",n); } // set up array for uplink TT compensation: xy = indices(sim._size); fact = 4.848 * (tel.diam/sim.pupildiam); tip1arcsec = float(xy(,,1)*fact); tilt1arcsec = float(xy(,,2)*fact); //=============================== // GET WFS REFERENCE MEASUREMENTS //=============================== mircube *= 0.0f; // disable filtertilt is any mem = wfs.filtertilt; wfs.filtertilt *= 0n; for (ns=1;ns<=nwfs;ns++) { wfs(ns)._refmes = &(array(0.0f,wfs(ns)._nmes)); } // save state of noise/nintegcycle/etc: everything that is not desired // when doing the iMat: store_noise_etc_for_imat,noise_orig, cycle_orig, kconv_orig, \ skyfluxpersub_orig, bckgrdcalib_orig, bias_orig, \ flat_orig, darkcurrent_orig, use_sincos_approx_orig,\ rayleigh_orig; // sync forks if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); refmes = mult_wfs_int_mat(disp=disp); wfs._refmes = split_wfs_vector(refmes); wfs.filtertilt = mem; //============================================ // GET WFS TIP AND TILT REFERENCE MEASUREMENTS //============================================ // disable filtertilt is any mem = wfs.filtertilt; wfs.filtertilt *= 0n; // step per pixel to have a x" tilt: if (!push4ttref) push4ttref=0.1; // in arcsec // tip: mircube *= 0.0f; mircube(,,1) = float(tip1arcsec*push4ttref); // we've changed some wfs value. sync svipc if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); mes = mult_wfs_int_mat(disp=disp)/push4ttref; // mes in arcsec wfs._tiprefv = split_wfs_vector(mes); for (ns=1;ns<=nwfs;ns++) { wfs(ns)._tiprefvn = &(*wfs(ns)._tiprefv/sum(*wfs(ns)._tiprefv^2.)); } // now the tip ref vector are normalized, so to compute the tip content // one has just to do sum(vector * tiprefv) // tilt: mircube(,,1) = float(tilt1arcsec*push4ttref); // we've changed some wfs value. sync svipc if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); mes = mult_wfs_int_mat(disp=disp)/push4ttref; // mes in arcsec wfs._tiltrefv = split_wfs_vector(mes); for (ns=1;ns<=nwfs;ns++) { wfs(ns)._tiltrefvn = &(*wfs(ns)._tiltrefv/sum(*wfs(ns)._tiltrefv^2.)); } // restore pre-operation filtertilt: wfs.filtertilt = mem; // restore original values to WFS structure: restore_noise_etc_for_imat,noise_orig, cycle_orig, kconv_orig, \ skyfluxpersub_orig,bckgrdcalib_orig, bias_orig, \ flat_orig, darkcurrent_orig, use_sincos_approx_orig,\ rayleigh_orig; // sync forks if needed: if ( (anyof(wfs.type=="hartmann"))&&(anyof(wfs.svipc>1))) s = sync_wfs_forks(); //================================== // INITIALIZE DM INFLUENCE FUNCTIONS //================================== if (sim.verbose) {write,"\n> Initializing DM influence functions";} gui_message,"Initializing DMs"; // loop over DMs: for (n=1;n<=ndm;n++) { if ( (dm(n).disjointpup) && (disjointpup==[]) ) \ error,swrite(format="dm(%d).disjointpup set but disjointpup does not exist\n",n); if (dm(n).pupoffset!=[]) \ dm(n)._puppixoffset = long(dm(n).pupoffset/tel.diam*sim.pupildiam); if (clean) dm(n)._def = dm(n)._edef = &([]); // Set _n1 and _n2, the limit indices if (dm(n).type == "stackarray") { // find out the support dimension for the given mirror. extent = dm(n).pitch*(dm(n).nxact+2.); // + 1.5 pitch each side dm(n)._n1 = long(clip(floor(sim._cent-extent/2.),1,)); dm(n)._n2 = long(clip(ceil(sim._cent+extent/2.),,sim._size)); } else { // we are dealing with a curvature mirror, TT, zernike,dh or aniso: dm(n)._n1 = 1; dm(n)._n2 = sim._size; } // special case = (only) 6 pixels margin each side: // note: "upgraded" from 2 to 8 to allow more margin when misregistering if (dm(n).alt == 0) { extent=sim.pupildiam+16; dm(n)._n1 = long(clip(floor(sim._cent-extent/2.),1,)); dm(n)._n2 = long(clip(ceil(sim._cent+extent/2.),,sim._size)); } // compute influence functions: // If file exist, read it out: if ( (fileExist(YAO_SAVEPATH+dm(n).iffile)) && (!is_set(clean)) ) { if (sim.verbose) { write,format=">> Reading file %s\n",dm(n).iffile; } if (dm(n).use_def_of) { write,format="Replicating influence functions of DM%d\n",dm(n).use_def_of; dm(n)._def = dm(dm(n).use_def_of)._def; } else { dm(n)._def = &(float(yao_fitsread(YAO_SAVEPATH+dm(n).iffile))); } dm(n)._nact = dimsof(*(dm(n)._def))(4); if ( dm(n).type == "stackarray" ) { dm(n)._x = &(yao_fitsread(YAO_SAVEPATH+dm(n).iffile,hdu=1)); dm(n)._y = &(yao_fitsread(YAO_SAVEPATH+dm(n).iffile,hdu=2)); if (dm(n).elt == 1) { dm(n)._eltdefsize = dimsof(*(dm(n)._def))(2); dm(n)._i1 = &(int(yao_fitsread(YAO_SAVEPATH+dm(n).iffile,hdu=3))); dm(n)._j1 = &(int(yao_fitsread(YAO_SAVEPATH+dm(n).iffile,hdu=4))); } } if ( (fileExist(YAO_SAVEPATH+dm(n)._eiffile)) && (!is_set(clean)) ) { if (sim.verbose) { write,format=">> Reading extrapolated actuators file %s\n",dm(n)._eiffile; } dm(n)._edef = &(float(yao_fitsread(YAO_SAVEPATH+dm(n)._eiffile))); dm(n)._enact = dimsof(*(dm(n)._edef))(4); if ( dm(n).type == "stackarray" ) { dm(n)._ex = &(yao_fitsread(YAO_SAVEPATH+dm(n)._eiffile,hdu=1)); dm(n)._ey = &(yao_fitsread(YAO_SAVEPATH+dm(n)._eiffile,hdu=2)); if (dm(n).elt == 1) { dm(n)._ei1 = &(int(yao_fitsread(YAO_SAVEPATH+dm(n)._eiffile,hdu=3))); dm(n)._ej1 = &(int(yao_fitsread(YAO_SAVEPATH+dm(n)._eiffile,hdu=4))); } } } } else { // else compute the influence functions: if (sim.verbose) { write,format=">> Computing Influence functions for mirror # %d\n",n; } if (fileExist(YAO_SAVEPATH+dm(n)._eiffile)) {// delete the extrapolated influence functions remove, YAO_SAVEPATH+dm(n)._eiffile; } if (disp) { plsys,1; animate,1; } if (dm(n).use_def_of) { write,format="Replicating influence functions of DM%d\n",dm(n).use_def_of; dm(n)._def = dm(dm(n).use_def_of)._def; dm(n)._nact = dm(dm(n).use_def_of)._nact; } else { if (dm(n).type == "bimorph") { make_curvature_dm, n, disp=disp,cobs=tel.cobs; } else if (dm(n).type == "stackarray") { if (dm(n).elt == 1) { make_pzt_dm_elt, n, disp=disp; } else { make_pzt_dm, n, disp=disp; } } else if (dm(n).type == "zernike") { make_zernike_dm, n, disp=disp; } else if (dm(n).type == "dh") { make_dh_dm, n, disp=disp; } else if (dm(n).type == "kl") { make_kl_dm, n, disp=disp; } else if (dm(n).type == "tiptilt") { make_tiptilt_dm, n, disp=disp; } else if (dm(n).type == "segmented") { make_segmented_dm, n, disp=disp; } else if (dm(n).type == "aniso") { make_aniso_dm, n, disp=disp; } else { // we're dealing with a user defined DM function: // assign user_wfs to requested function/type: cmd = swrite(format="user_dm = %s",dm(n).type); include,[cmd],1; user_dm, n; } } if (dm(n).ifunrot) { hxy = dimsof(*dm(n)._def)(2)/2.+0.5; for (i=1;i<=dm(n)._nact;i++) { (*dm(n)._def)(,,i) = rotate2((*dm(n)._def)(,,i),dm(n).ifunrot,xc=hxy,yc=hxy); } xy = (*dm(n)._x)(,-); grow,xy,(*dm(n)._y)(,-); xy -= sim._cent; xy = transpose(xy); xy = mrot(dm(n).ifunrot)(+,) * xy(+,); xy += sim._cent; (*dm(n)._x) = xy(1,); (*dm(n)._y) = xy(2,); } if (dm(n).xscale) { dd = dimsof(*dm(n)._def)(2); xx = yy = indgen(dd); xx = (xx-dd/2.)*(1.+dm(n).xscale)+dd/2.; for (i=1;i<=dm(n)._nact;i++) (*dm(n)._def)(,,i) = bilinear((*dm(n)._def)(,,i),xx,yy,grid=1); } if (disp) { plsys,1; animate,0; } // the IF are in microns/volt if (sim.verbose) { write,format="\n>> Storing influence functions in %s...",dm(n).iffile; } if (dm(n).use_def_of) yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,[0.]; else yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,*(dm(n)._def); if (sim.verbose) write,"Done"; if ( dm(n).type == "stackarray" ) { yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,*(dm(n)._x),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,*(dm(n)._y),exttype="IMAGE",append=1; if (dm(n).elt == 1) { yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,long(*(dm(n)._i1)),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(n).iffile,long(*(dm(n)._j1)),exttype="IMAGE",append=1; } } } } //============================== // INITIALIZE VIBRATION SPECTRUM //============================== if ((tel.tipvib_white_rms) || (tel.tipvib_1overf_rms) || ((*tel.tipvib_peaks)!=[])) { // user has defined at least one of the vibration param. tipvib = generate_vib_time_serie(loop.ittime,loop.niter,tel.tipvib_white_rms,\ tel.tipvib_1overf_rms, *tel.tipvib_peaks, *tel.tipvib_peaks_rms, \ peak_width = *tel.tipvib_peaks_width); } else { tipvib = []; } if ((tel.tiltvib_white_rms) || (tel.tiltvib_1overf_rms) || ((*tel.tiltvib_peaks)!=[])) { // user has defined at least one of the vibration param. tiltvib = generate_vib_time_serie(loop.ittime,loop.niter,tel.tiltvib_white_rms,\ tel.tiltvib_1overf_rms, *tel.tiltvib_peaks, *tel.tiltvib_peaks_rms, \ peak_width = *tel.tiltvib_peaks_width); } else { tiltvib = []; } //========================================= // DO INTERACTION MATRIX WITH ALL ACTUATORS //========================================= // determine whether a new interaction matrix is needed need_new_iMat = (forcemat || anyof(!fileExist(YAO_SAVEPATH+dm.iffile))); if (need_new_iMat == 0){ if (!fileExist(YAO_SAVEPATH+mat.file)){ if (mat.method == "mmse-sparse" && fileExist(YAO_SAVEPATH + parprefix+"-mat.fits")){ // convert the full matrix into a sparse matrix write, "Saving " + parprefix + "-mat.fits" + " as a sparse matrix"; tmp = yao_fitsread(YAO_SAVEPATH+ parprefix + "-mat.fits"); iMat = tmp(,,1); iMatSP = sprco(float(iMat)); save_rco,iMatSP,YAO_SAVEPATH+mat.file; svd = 1; // need to generate a new reconstructor } else if (mat.method != "mmse-sparse" && fileExist(YAO_SAVEPATH + parprefix+"-iMat.rco")){ write, "Saving " + parprefix + "-iMat.rco" + " as a full matrix"; iMatSP = restore_rco(YAO_SAVEPATH + parprefix+"-iMat.rco"); iMat = rcoinf(iMatSP); yao_fitswrite, YAO_SAVEPATH + mat.file, [iMat,iMat]; svd = 1; // need to generate a new reconstructor } else { need_new_iMat = 1; } } } if (need_new_iMat == 1){ if (!is_set(keepdmconfig)) { // concatenate dm._def and dm._edef for (nm=1;nm<=ndm;nm++) { // loop on DMs if ((*dm(nm)._edef) != []) { // if _edef == [], there is no extrap. act. defined dm(nm)._def = &(_(*dm(nm)._def,*dm(nm)._edef)); dm(nm)._x = &(_(*dm(nm)._x,*dm(nm)._ex)); dm(nm)._y = &(_(*dm(nm)._y,*dm(nm)._ey)); if (dm(nm).elt == 1) { dm(nm)._i1 = &(int(_(*dm(nm)._i1,*dm(nm)._ei1))); dm(nm)._j1 = &(int(_(*dm(nm)._j1,*dm(nm)._ej1))); } dm(nm)._nact = dimsof(*(dm(nm)._def))(4); dm(nm)._edef = dm(nm)._ex = dm(nm)._ey = &([]); dm(nm)._enact = 0; if (dm(nm).elt == 1) { dm(nm)._ei1 = dm(nm)._ej1 = &([]); } } } } if (sim.verbose) {write,"\n> DOING INTERACTION MATRIX";} gui_message,"Doing interaction matrix"; if (mat.method != "mmse-sparse"){ iMat = array(double,sum(wfs._nmes),sum(dm._nact)); cMat = array(double,sum(dm._nact),sum(wfs._nmes)); if (sim.verbose>1) write,format="sizeof(iMat) = %dMB\n",long(sizeof(iMat)/1.e6); pause,100; } else { iMatSP = rco(); } // measure interaction matrix: estDMs = where(!dm.dmfit_which); // DMs used to estimate wavefront if ( sum(dm(estDMs)._nact) > sum(wfs._nmes) ) { write,format="\n\nWarning: Underconstrained problem: nact (%d) > nmes (%d)\n",sum(dm._nact),sum(wfs._nmes); if (mat.method == "svd"){ write,format="%s\n\n","I will not be able to invert the iMat using"+\ " the simple yao SVD"; typeReturn; } } if (use_user_imat) iMat = user_imat; else do_imat,disp=disp; // select valid actuators by their response, only if // 1. at least one of the DM is a stackarray (otherwise it does not make sense) // 2. user has not selected "keepdmconfig" // otherwise we proceed without filtering any actuators if (anyof(dm.type == "stackarray") && !is_set(keepdmconfig)) { indexDm = array(long,[2,2,ndm]); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } // response from actuators: if (mat.method == "mmse-sparse"){ AtA = rcoata(iMatSP); resp = sqrt((*AtA.xd)(1:AtA.r)); // take the diagonal actuators_to_remove = []; } else { resp = sqrt((iMat^2.)(sum,)); //resp = (abs(iMat))(max,); // marcos commented this. problem? } if (sim.debug >= 2) {fma; plh,resp; limits,square=0; typeReturn;} for (nm=1;nm<=ndm;nm++) { // filter actuators only in stackarray mirrors: if (dm(nm).type == "stackarray") { dmx = *dm(nm)._x; dmy = *dm(nm)._y; if (dm(nm).elt == 1) { dmi1 = *dm(nm)._i1; dmj1 = *dm(nm)._j1; } tmp = resp(indexDm(1,nm):indexDm(2,nm)); if (dm(nm).thresholdresp < 0.) { do { // criteria for an actuator to be retained as valid: ok = where(tmp > dm(nm).thresholdresp*max(tmp)); nok= where(tmp <= dm(nm).thresholdresp*max(tmp)); dm(nm)._x = &(dmx(ok)); dm(nm)._y = &(dmy(ok)); if (numberof(nok) != 0) { dm(nm)._ex = &(dmx(nok)); dm(nm)._ey = &(dmy(nok)); } graphic_config,dm(nm).subsystem,nm; write,format="DM #%d: # of valid actuators: %d ",nm,numberof(ok); again = "y"; read,prompt="Again ? ",again; if (again != "n") { read,prompt=swrite(format="Threshold (old = %f) : ",\ dm(nm).thresholdresp),dm(nm).thresholdresp; } } while (again != "n"); } if (dm(nm).ncp){// if DM used for WFS ok = indgen(numberof(tmp)); nok = []; } else { ok = where(tmp > dm(nm).thresholdresp*max(tmp)); nok= where(tmp <= dm(nm).thresholdresp*max(tmp)); if (numberof(nok)==0) nok=[]; } dm(nm)._indval = &ok; dm(nm)._indext = &nok; dm(nm)._x = &(dmx(ok)); dm(nm)._y = &(dmy(ok)); if (dm(nm).elt == 1) { dm(nm)._i1 = &(int(dmi1(ok))); dm(nm)._j1 = &(int(dmj1(ok))); } if (numberof(nok) == 0) continue; //yes, it should be here. dm(nm)._ex = &(dmx(nok)); dm(nm)._ey = &(dmy(nok)); if (dm(nm).elt == 1) { dm(nm)._ei1 = &(int(dmi1(nok))); dm(nm)._ej1 = &(int(dmj1(nok))); } dm(nm)._edef = &((*(dm(nm)._def))(,,nok)); dm(nm)._def = &((*(dm(nm)._def))(,,ok)); if (sim.verbose) { write,format="DM #%d: # of valid actuators: %d. "+ "(I got rid of %d actuators after iMat)\n", nm,numberof(ok),numberof(nok); write,format=">> valid I.F. stored in %s\n",dm(nm).iffile; } // rewrite influence function file: yao_fitswrite,YAO_SAVEPATH+dm(nm).iffile,*(dm(nm)._def); yao_fitswrite,YAO_SAVEPATH+dm(nm).iffile,*(dm(nm)._x),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(nm).iffile,*(dm(nm)._y),exttype="IMAGE",append=1; if (dm(nm).elt == 1) { yao_fitswrite,YAO_SAVEPATH+dm(nm).iffile,long(*(dm(nm)._i1)),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(nm).iffile,long(*(dm(nm)._j1)),exttype="IMAGE",append=1; } dm(nm)._nact = (dimsof(*(dm(nm)._def)))(4); // write extrapolated actuator influence functions file: yao_fitswrite,YAO_SAVEPATH+dm(nm)._eiffile,*(dm(nm)._edef); yao_fitswrite,YAO_SAVEPATH+dm(nm)._eiffile,*(dm(nm)._ex),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(nm)._eiffile,*(dm(nm)._ey),exttype="IMAGE",append=1; if (dm(nm).elt == 1) { yao_fitswrite,YAO_SAVEPATH+dm(nm)._eiffile,long(*(dm(nm)._ei1)),exttype="IMAGE",append=1; yao_fitswrite,YAO_SAVEPATH+dm(nm)._eiffile,long(*(dm(nm)._ej1)),exttype="IMAGE",append=1; } dm(nm)._enact = (dimsof(*(dm(nm)._edef)))(4); if (sim.debug >= 1) { tv,comp_dm_shape(nm,&(array(1.0f,dm(nm)._nact))); mypltitle,swrite(format="Pushing on all actuator of DM#%d",nm),[0.,-0.005],height=12; typeReturn; } if (mat.method == "mmse-sparse"){ grow, actuators_to_remove, indexDm(1,nm)-1+nok; } else { iMat(,indexDm(1,nm)-1+nok) *=0.; } } } if (mat.method == "mmse-sparse"){ // remove all the rows with a response that is too low // need to remove them from the end so as not to disturb numbering if (numberof(actuators_to_remove) > 0){ for (act_ii = numberof(actuators_to_remove); act_ii >=1; act_ii--){ rcodr,iMatSP,actuators_to_remove(act_ii); } } } else { iMat = iMat(,where(iMat(rms,) != 0.)); cMat = transpose(iMat)*0.; } } } //========================================= // LOAD OR COMPUTE THE EXTRAPOLATION MATRIX //========================================= // Normally, I don't load the valid to extrapolation actuator file. // It is NOT saved anyway. // it's fast enough to compute it here from the existing data (position // and number of extrapolation actuators). // However, if the user want to use its own extrapolation method (the one // here, although it works fine, is pretty dumb), I provide a way to do it // by providing a file name (dm(nm).ecmatfile). If this file exist, I will // use it. for (nm=1;nm<=ndm;nm++) { if (dm(nm).type != "stackarray") continue; // possible but not implemented. if (dm(nm).noextrap == 1) { // we have to get rid of any extrapolated actuator now dm(nm)._edef = dm(nm)._ex = dm(nm)._ey = &([]); if (dm(nm).elt == 1) { dm(nm)._ei1 = dm(nm)._ej1 = &([]); } dm(nm)._enact = 0; continue; } if (dm(nm)._enact == 0) continue; // no extrapolated actuator if (fileExist(YAO_SAVEPATH+dm(nm).ecmatfile)) { // if defined and exist, we read it and proceed if (sim.verbose) { write,format="Reading valid to extrap. matrix %s\n",dm(nm).ecmatfile; } dm(nm)._extrapcmat = yao_fitsread(YAO_SAVEPATH+dm(nm).ecmatfile); } else { // we compute the valid to extrap matrix: if (sim.verbose) { write,format="Computing valid to extrap. matrix for DM#%d\n",nm; } tx = *dm(nm)._x; ty = *dm(nm)._y; tex = *dm(nm)._ex; tey = *dm(nm)._ey; disact = sqrt( (tx-tex(-,))^2. + (ty-tey(-,))^2. ); // distance from extrap to valid disact = disact/dm(nm).pitch; // now in pitch unit (1,2,..) disact = exp(-(disact/0.7)^2.); // "influence function" for extrap. command disact = disact / disact(sum,)(-,); dm(nm)._extrapcmat = &(transpose(disact)); } } /* STILL TO BE IMPLEMENTED IN V1.2 I'll keep it for later. // INITIALIZE NON-COMMON PATH REFERENCE MEASUREMENTS: if (wfs.type == "hartmann") { if (abs(ao.refZernikes)(sum) != 0) { prepzernike,ao._size,ao.PupilDiam,ao._cent,ao._cent; phase = ipupil*0.; for (i=1;i<=numberof(ao.refZernikes);i++) { phase += ao.refZernikes(i)*zernike_ext(i+1);} noise = ao.WfsNoise; ao.WfsNoise = 0.; WfsRefMes = sh_wfs(ipupil,phase); ao.WfsNoise = noise; if (ao.verbose>=1) {write,format="WfsRefMes rms = %f, Min = %f and Max = %f\n", WfsRefMes(rms),min(WfsRefMes),max(WfsRefMes);} } else { WfsRefMes = array(float,ao._WfsNMes); if (ao.verbose>=1) {write,"No WFS reference used\n";} } } */ // INITIALIZE MODAL GAINS: if (mat.method == "svd"){ if (sim.verbose) {write,"\n> INITIALIZING MODAL GAINS";} gui_message,"Initializing modal gains"; modalgain = []; if (strlen(loop.modalgainfile)&&(fileExist(YAO_SAVEPATH+loop.modalgainfile))) { if (sim.verbose) {write,format=">> Reading file %s\n\n",loop.modalgainfile;} modalgain = yao_fitsread(YAO_SAVEPATH+loop.modalgainfile); } if (numberof(modalgain) != sum(dm._nact)) { if (sim.verbose) { write,format="I did not find %s or it did not have the right\n ", loop.modalgainfile; write,format=" number of elements (should be %i), so I have generated\n", sum(dm._nact); write," a modal gain vector with ones in it.\n"; } modalgain = array(1.,sum(dm._nact)); } } // INITIALIZE COMMAND MATRIX: if (sim.verbose) {write,"\n> INTERACTION AND COMMAND MATRICES";} gui_message,"Initializing control matrix"; if ((fileExist(YAO_SAVEPATH+mat.file)) && (forcemat != 1)) { if (sim.verbose) {write,format=">> Reading file %s\n",mat.file;} if (mat.method != "mmse-sparse") { // read out mat file and stuff iMat and cMat: tmp = yao_fitsread(YAO_SAVEPATH+mat.file); iMat = tmp(,,1); cMat = transpose(tmp(,,2)); tmp = []; if (anyof(dm.dmfit_which)){ if (fileExist(YAO_SAVEPATH+parprefix+"-dMat.fits")){ dMat = yao_fitsread(YAO_SAVEPATH + parprefix + "-dMat.fits"); } else { svd = 1; } if (fileExist(YAO_SAVEPATH+parprefix+"-cMat.fits")){ cMat = yao_fitsread(YAO_SAVEPATH + parprefix + "-cMat.fits"); } else { svd = 1; } for (nm=1;nm<=numberof(dm);nm++){ if (dm(nm).dmfit_which){ filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".fits"); if (fileExist(filename)){ dm(nm)._fMat = &yao_fitsread(filename); } else { svd = 1; } } } } } else { dMat = []; iMatSP = restore_rco(YAO_SAVEPATH+mat.file); if (fileExist(YAO_SAVEPATH+parprefix+"-AtAreg.ruo")){ AtAregSP = restore_ruo(YAO_SAVEPATH+parprefix+"-AtAreg.ruo"); } else { svd = 1; } if (fileExist(YAO_SAVEPATH+parprefix+"-GxSP.rco")){ GxSP = restore_rco(YAO_SAVEPATH+parprefix+"-GxSP.rco"); } else { svd = 1; // need to recreate reconstructors } if (anyof(dm.dmfit_which)) { if (fileExist(YAO_SAVEPATH+parprefix+"-polcMat.rco")){ polcMatSP = restore_rco(YAO_SAVEPATH+parprefix+"-polcMat.rco"); } else { svd = 1; // need to recreate reconstructors } for (nm=1;nm<=numberof(dm);nm++){ if (dm(nm).dmfit_which){ filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".rco"); if (fileExist(filename)){ dm(nm)._fMat = &restore_rco(filename); } else { svd = 1; // need to recreate reconstructors } } } } } } if (svd || forcemat || need_new_iMat){ // create the regularization matrices nDMs = numberof(dm); for (nm=1;nm<=nDMs;nm++){ if (*dm(nm).regmatrix != []){ dm(nm)._regmatrix = dm(nm).regmatrix; } else if (mat.method == "mmse"){ if ((dm(nm).type == "stackarray") && (dm(nm).regtype == "laplacian")){ xpos = *dm(nm)._x; ypos = *dm(nm)._y; pitch2 = dm(nm).pitch^2; L = array(float,dm(nm)._nact, dm(nm)._nact); for (ii=1;ii<=dm(nm)._nact;ii++){ xii = xpos(ii); yii = ypos(ii); dx = xpos - xii; dy = ypos - yii; dist2= dx^2+dy^2; L(ii,ii) = -1.; L(ii,where(dist2 == pitch2)) = 0.25; } dm(nm)._regmatrix = &(L(+,)*L(+,)); } else { // identity matrix dm(nm)._regmatrix = &unit(dm(nm)._nact); } } else if (mat.method == "mmse-sparse") { if ((dm(nm).type == "stackarray") && (dm(nm).regtype == "laplacian")){ xpos = *dm(nm)._x; ypos = *dm(nm)._y; pitch2 = dm(nm).pitch^2; laplacian_mat = rco(); for (ii=1;ii<=dm(nm)._nact;ii++) { xii = xpos(ii); yii = ypos(ii); dx = xpos - xii; dy = ypos - yii; dist2= dx^2+dy^2; lvec = array(float,dm(nm)._nact); lvec(ii) = -1.; ww = where(dist2 == pitch2); if (numberof(ww)) lvec(ww) = 0.25; rcobuild,laplacian_mat,lvec,mat.sparse_thresh; } dm(nm)._regmatrix = &rcoata(laplacian_mat); } else { // identity matrix dm(nm)._regmatrix = &spunit(dm(nm)._nact); } } } // create the fitting matrices for tomography if (mat.fit_simple == 1){ for (nm=1;nm<=numberof(dm);nm++){ if (dm(nm).dmfit_which){ virtualDMs = int(*dm(nm).dmfit_which); nVirtualDMs = numberof(virtualDMs); if (dm(nm).type == "stackarray"){ xloct = *dm(nm)._x; // location of the tomography actuators yloct = *dm(nm)._y; xlocv = ylocv = []; // location of the virtual actuators for (c1=1;c1<=nVirtualDMs;c1++){ grow, xlocv, *dm(virtualDMs(c1))._x; grow, ylocv, *dm(virtualDMs(c1))._y; } } else if (dm(nm).type == "zernike"){ xloct = indgen(dm(nm).minzer:dm(nm).nzer); yloct = indgen(dm(nm).minzer:dm(nm).nzer); xlocv = ylocv = []; // location of the virtual actuators for (c1=1;c1<=nVirtualDMs;c1++){ grow, xlocv, indgen(dm(virtualDMs(c1)).minzer:dm(virtualDMs(c1)).nzer); grow, ylocv, indgen(dm(virtualDMs(c1)).minzer:dm(virtualDMs(c1)).nzer); } } if (mat.method == "mmse"){ dm(nm)._fMat = &array(float,[2,dm(nm)._nact,sum(dm(virtualDMs)._nact)]); for (c1=1;c1<=numberof(xlocv);c1++){ v1 = ((xloct == xlocv(c1)) + (yloct == ylocv(c1)) == 2); (*dm(nm)._fMat)(,c1) = float(v1); } filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".fits"); yao_fitswrite,filename,*dm(nm)._fMat; } else { temp = rco_d(); for (c1=1;c1<=numberof(xlocv);c1++){ v1 = ((xloct == xlocv(c1)) + (yloct == ylocv(c1)) == 2); rcobuild, temp, float(v1), mat.sparse_thresh; } dm(nm)._fMat = &rcotr(temp); filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".rco"); save_rco, *dm(nm)._fMat, filename; } } } } else { // mat.fit_simple = 0 // define a grid on which to sample the phase dims = (dimsof(pupil))(2); idx = indgen(int(ceil(mat.fit_subsamp/2.)):dims:mat.fit_subsamp); pupil_sub = pupil(idx,idx); wpupil_sub = where(pupil_sub); npix = numberof(wpupil_sub); for (nm=1;nm<=numberof(dm);nm++){ if (dm(nm).dmfit_which){ virtualDMs = int(*dm(nm).dmfit_which); nVirtualDMs = numberof(virtualDMs); // calculate the matrix that shows how the tomographic DM affects the phase n1 = dm(nm)._n1; n2 = dm(nm)._n2; if (mat.method == "mmse"){ tomoMat = array(float,[2,npix,dm(nm)._nact]); } else { tomoMatSP = rco(); } command = array(float,dm(nm)._nact); for (i=1;i<=dm(nm)._nact;i++) { if (sim.verbose) { write,format="\rFitting DM# %d, actuator %d/%d",nm,i,dm(nm)._nact; } mircube *= 0.0f; command *= 0.0f; command(i) = float(1.); mircube(n1:n2,n1:n2,nm) = comp_dm_shape(nm,&command); if (dm(nm).ncp){ // DM on WFS path only phase = get_phase2d_from_dms(dm(nm).ncpfit_which,dm(nm).ncpfit_type)-get_phase2d_from_dms(mat.fit_which,mat.fit_type); } else { phase = get_phase2d_from_dms(mat.fit_which,mat.fit_type); } phase = phase(idx,idx); active_phase = phase(wpupil_sub); if (mat.method == "mmse"){ tomoMat(:,i) = active_phase; } else { rcobuild, tomoMatSP, float(active_phase), mat.sparse_thresh; } } // calculate the matrix that shows how the virtual DMs affect the phase if (mat.method == "mmse"){ virtMat = array(float,[2,npix,sum(dm(virtualDMs)._nact)]); } else { regmatrix = *dm(nm)._regmatrix; ruox, regmatrix, dm(nm).regparam; tomoFit = ruoadd(rcoata(tomoMatSP),regmatrix); regmatrix = []; dm_fMatSP = rco(); } row = 0; zeros_act = array(float,dm(nm)._nact); for (k=1;k<=nVirtualDMs;k++) { nv = virtualDMs(k); n1 = dm(nv)._n1; n2 = dm(nv)._n2; command = array(float,dm(nv)._nact); for (i=1;i<=dm(nv)._nact;i++) { if (sim.verbose) { write,format="\rFitting DM# %d, actuator %d/%d",nv,i,dm(nv)._nact; } row += 1; mircube *= 0.0f; command *= 0.0f; command(i) = 1.; mircube(n1:n2,n1:n2,nv) = comp_dm_shape(nv,&command); if (dm(nm).ncp){ // DM on WFS path only phase = get_phase2d_from_dms(dm(nm).ncpfit_which,dm(nm).ncpfit_type)-get_phase2d_from_dms(mat.fit_which,mat.fit_type); } else { phase = get_phase2d_from_dms(mat.fit_which,mat.fit_type); } phase = phase(idx,idx); active_phase = phase(wpupil_sub); if (mat.method == "mmse"){ virtMat(:,row) = active_phase; } else { temp = rcoxv(tomoMatSP,active_phase); if (sum(temp != 0) == 0){ // sparse CG method does not work if all zeros temp = zeros_act; } else { temp = ruopcg(tomoFit,temp,zeros_act,tol=mat.sparse_pcgtol); } rcobuild, dm_fMatSP, temp, mat.fit_minval; } } } if (mat.method == "mmse"){ dm(nm)._fMat = &(LUsolve(tomoMat(+,)*tomoMat(+,) + dm(nm).regparam* (*dm(nm)._regmatrix),tomoMat(+,)*virtMat(+,))); filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".fits"); yao_fitswrite,filename,*dm(nm)._fMat; } else { tomoMatSP = tomoFit = virtMatSP = []; dm(nm)._fMat = &rcotr(dm_fMatSP); filename = YAO_SAVEPATH+parprefix+"-fMat"+swrite(nm, format="%i"+".rco"); save_rco, *dm(nm)._fMat, filename; dm_fMatSP = []; } } } } } // in the opposite case, plus if svd=1 (request re-do SVD): if ((!fileExist(YAO_SAVEPATH+mat.file)) || (forcemat == 1) || (svd == 1)) { if (mat.method == "svd") { if (sim.verbose) { write,">> Preparing SVD and computing command matrices"; } // do the SVD and build the command matrix: sswfs = ssdm = []; for (ns=1;ns<=nwfs;ns++) {grow,sswfs,array(wfs(ns).subsystem,wfs(ns)._nmes);} for (nm=1;nm<=ndm;nm++) {grow,ssdm,array(dm(nm).subsystem,dm(nm)._nact);} for (ss=1;ss<=max(dm.subsystem);ss++) { wsswfs = where(sswfs == ss); wssdm = where(ssdm == ss); imat = iMat(wsswfs,wssdm); mg = modalgain(wssdm); prep_svd,imat,ss,svd=svd,disp=disp; tmpdisp = noneof(dm(where(dm.subsystem == ss)).type == "aniso"); cmat = build_cmat( (*mat.condition)(ss), mg, subsystem=ss, all=1,disp=tmpdisp); cMat(wssdm,wsswfs) = cmat; } } else if (mat.method == "mmse") { if (anyof(dm.dmfit_which)){ estAct = []; // actuators used to estimate wavefront realAct = []; // real (non virtual) actuators used to compensate the wavefront actno = 0; for (nm=1;nm<=ndm;nm++){ if (!dm(nm).dmfit_which){ grow, estAct, indgen(1+actno:actno+dm(nm)._nact); } if (!dm(nm).virtual & !dm(nm).ncp){ grow, realAct, indgen(1+actno:actno+dm(nm)._nact); } actno += dm(nm)._nact; } Ga = iMat(:,realAct); Gx = iMat(:,estAct); AtA = Gx(+,)*Gx(+,); nEstAct = numberof(estAct); nRealAct = numberof(realAct); Cphi = array(float,[2,nEstAct,nEstAct]); mc = 0; for (nm=1;nm<=nDMs;nm++){ if (!dm(nm).dmfit_which){ Cphi(mc+1:mc+dm(nm)._nact,mc+1:mc+dm(nm)._nact) = \ dm(nm).regparam*(*dm(nm)._regmatrix); mc += dm(nm)._nact; } } cMat = LUsolve(AtA+Cphi,transpose(Gx)); yao_fitswrite, YAO_SAVEPATH + parprefix + "-cMat.fits", cMat; realDMs = where(!dm.virtual & !dm.ncp); // DMs used to compensate wavefront estDMs = where(!dm.dmfit_which); // DMs used to estimate wavefront nRealAct = sum(dm(realDMs)._nact); nEstAct = sum(dm(estDMs)._nact); fMat = array(float,[2,nRealAct, nEstAct]); indexDm = array(long,2,ndm); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } startIdx = 1; for (nm=1;nm<=nDMs;nm++){ if (!dm(nm).virtual & !dm(nm).ncp){ idx = indgen(startIdx:startIdx + dm(nm)._nact - 1); startIdx += dm(nm)._nact; if (!dm(nm).dmfit_which) { // real (ordinary) DM vidx = indgen(indexDm(1,nm):indexDm(2,nm)); fMat(idx,vidx) = float(unit(dm(nm)._nact)); } else { // tomographic DM vidx = []; virtualDMs = int(*dm(nm).dmfit_which); for (c1=1;c1<= numberof(virtualDMs);c1++){ grow, vidx, indgen(indexDm(1,virtualDMs(c1)):indexDm(2,virtualDMs(c1))); } fMat(idx,vidx) = *dm(nm)._fMat; } } } Dterm = Ga(,+)*fMat(+,)-Gx; polcMat = Gx(+,)*Dterm(+,)-Cphi; dMat = LUsolve(AtA+Cphi,polcMat); yao_fitswrite, YAO_SAVEPATH + parprefix + "-dMat.fits", dMat; } else { nAct = (dimsof(iMat))(3); Cphi = array(float,[2,nAct,nAct]); mc = 0; // matrix counter nDMs = numberof(dm); for (nm=1;nm<=nDMs;nm++){ if (!dm(nm).dmfit_which){ Cphi((mc+1):(mc+dm(nm)._nact),(mc+1):(mc+dm(nm)._nact)) = \ (*dm(nm)._regmatrix)*dm(nm).regparam; mc += dm(nm)._nact; } } cMat = LUsolve(iMat(+,)*iMat(+,)+Cphi,transpose(iMat)); } } else if (mat.method == "mmse-sparse") { // create the regularization matrices for each DM nAct = iMatSP.r; nDMs = numberof(dm); CphiSP = []; for (nm=1;nm<=nDMs;nm++) { regmatrix = *dm(nm)._regmatrix; ruox, regmatrix, dm(nm).regparam; // multiply the matrix by a constant if (!dm(nm).dmfit_which){ if (CphiSP == []) { CphiSP = regmatrix; } else { spcon, CphiSP,regmatrix, diag=1, ruo=1; } } } if (anyof(dm.dmfit_which)) { estAct = []; // actuators used to estimate wavefront realAct = []; // real (non virtual) actuators used to compensate // the wavefront actno = 0; for (nm=1;nm<=ndm;nm++){ if (!dm(nm).dmfit_which){ grow, estAct, indgen(1+actno:actno+dm(nm)._nact); } if (!dm(nm).virtual & !dm(nm).ncp){ grow, realAct, indgen(1+actno:actno+dm(nm)._nact); } actno += dm(nm)._nact; } // create copies of iMatSP and remove the rows corresponding to // virtual actuators or tomographic actuators. Need to copy the // data in the pointers to avoid modifying the data in iMatSP. GaSP = iMatSP; GaSP.ix = &(*iMatSP.ix); GaSP.jx = &(*iMatSP.jx); GaSP.xn = &(*iMatSP.xn); GxSP = iMatSP; GxSP.ix = &(*iMatSP.ix); GxSP.jx = &(*iMatSP.jx); GxSP.xn = &(*iMatSP.xn); for (a1=iMatSP.r;a1>=1;a1--){ if (noneof(estAct == a1)){ rcodr, GxSP, a1; } if (noneof(realAct == a1)){ rcodr, GaSP, a1; } } save_rco,GxSP,YAO_SAVEPATH+parprefix+"-GxSP.rco"; // create a global fitting matrix fMatSP = []; indexDm = array(long,2,ndm); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } nEstAct =sum(dm(where(!dm.dmfit_which))._nact); nEstDMs = numberof(where(!dm.dmfit_which)); nRealAct = sum(dm(where(!dm.virtual & !dm.ncp))._nact); for (nm=1;nm<=numberof(dm);nm++) { if (dm(nm).virtual){ continue; } // no virtual DMs in the rows if (dm(nm).ncp){ continue; } // no non-common path DMs in the rows if (dm(nm).dmfit_which) { dmfMat = rcotr(*dm(nm)._fMat); vdmidx = []; for (mm=1;mm<=nEstDMs;mm++){ if (anyof(mm == *dm(nm).dmfit_which)){ grow, vdmidx, indgen(indexDm(1,mm):indexDm(2,mm)); } } for (c1=1;c1<=dm(nm)._nact;c1++){ row = array(float,[2,nEstAct,1]); vec = array(float,nRealAct); vec(c1) = 1.; row(vdmidx) = rcoxv(dmfMat, vec); // extract row c1 if (fMatSP == []){ fMatSP = sprco(row); } else { rcobuild, fMatSP, row, mat.sparse_thresh; } } } else { // an ordinary DM for (c1=1;c1<=dm(nm)._nact;c1++){ row = array(float,[2,nEstAct,1]); row(indexDm(1,nm)+c1-1)=1; if (fMatSP == []){ fMatSP = sprco(row); } else { rcobuild, fMatSP, row, mat.sparse_thresh; } } } } t1 = rcoatb(rcotr(fMatSP),rcotr(GaSP)); fMatSP = GaSP = []; AtA = rcoata(GxSP); AtAregSP = ruoadd(AtA,CphiSP); AtA = []; (*GxSP.xn) *= -1; DtermSP = rcoadd(t1,GxSP); t1 = []; (*GxSP.xn) *= -1; t2 = rcoatb(DtermSP,GxSP); DtermSP = []; CphiSPrco = ruo2rco(CphiSP); CphiSP = []; *CphiSPrco.xn *= -1; polcMatSP = rcotr(rcoadd(t2,CphiSPrco)); t2 = CphiSPrco = []; save_rco,polcMatSP,YAO_SAVEPATH+parprefix+"-polcMat.rco"; } else { GxSP = iMatSP; AtA = rcoata(iMatSP); AtAregSP = ruoadd(AtA,CphiSP); AtA = CphiSP = []; save_rco,GxSP,YAO_SAVEPATH+parprefix+"-GxSP.rco"; } save_rco,iMatSP,YAO_SAVEPATH+mat.file; iMatSP = []; save_ruo,AtAregSP,YAO_SAVEPATH+parprefix+"-AtAreg.ruo"; } if (mat.method != "mmse-sparse") { // More debug display if (sim.debug>=3){ tv,cMat(,+)*iMat(+,); mypltitle,"cMat(,+)*iMat(+,)",[0.,-0.005],height=12; typeReturn; tv,iMat(,+)*cMat(+,); mypltitle,"iMat(,+)*cMat(+,)",[0.,-0.005],height=12; typeReturn; } // save the results: if (noneof(dm.dmfit_which)){ yao_fitswrite,YAO_SAVEPATH+mat.file,[iMat,transpose(cMat)]; } else { // just save the iMat and force the recreation of cMat on reload yao_fitswrite,YAO_SAVEPATH+mat.file,[iMat,iMat]; } } } //=================================================================== // COMPUTE THE COMMAND VECTOR FOR OFFLOADING THE ANISOPLANATISM MODES //=================================================================== if (anyof(dm.type == "aniso")) { // find which DM is the aniso DM: nmaniso = where(dm.type == "aniso"); if (numberof(nmaniso) != 1) { pyk_error,"there can be only one aniso DM !"; error,"there can be only one aniso DM !"; } // finds which DM is at altitude 0 w0 = where((dm.alt == 0)*(dm.virtual == 0)); nmlow = where( (dm(w0).type == "stackarray") | (dm(w0).type == "bimorph") | (dm(w0).type == "zernike") | (dm(w0).type == "dh") ); nmlow = w0(nmlow); if (numberof(nmlow) == 0) { pyk_error,"I can not find a DM at altitude 0 to produce the lower "+ "part of the anisoplanatism modes !"; error,"I can not find a DM at altitude 0 to produce the lower "+ "part of the anisoplanatism modes !"; } if (numberof(nmlow) > 1) { pyk_warning,swrite(format=\ "Weird. There are %d high-order DMs at altitude=0 (look at console)",\ numberof(nmlow)); write,format="Weird. There are %d high-order DMs at altitude=0:", \ numberof(nmlow); for (i=1;i<=numberof(nmlow);i++) { write,format="DM #%d:",nmlow(i); print,dm(i); } rep = ""; question = "Which one ? ["+strcompress(strjoin(swrite(nmlow),","),all=1)+"] "; read,prompt=question,rep; tmp=0; sread,rep,tmp; if (noneof(nmlow == tmp)) { error,"Invalid selection"; } nmlow = tmp; } // finds which DM is at altitude specified by dm(nmaniso).alt wn0 = where(dm.alt == dm(nmaniso).alt); nmhigh = where( (dm(wn0).type == "stackarray") | (dm(wn0).type == "bimorph") | (dm(wn0).type == "zernike") | (dm(wn0).type == "dh") ); nmhigh = wn0(nmhigh); if (numberof(nmhigh) == 0) { pyk_error,"I can not find a DM at the requested altitude to produce "+ \ "the higher part of the anisoplanatism modes !"; error,"I can not find a DM at the requested altitude to produce "+ \ "the higher part of the anisoplanatism modes !"; } if (numberof(nmhigh) > 1) { pyk_warning,swrite(format=\ "Weird. There are %d high-order DMs at altitude %.0f (look at console)", numberof(nmhigh),dm(nmaniso).alt); write,format="Weird. There are %d high-order DMs at altitude %.0f:", numberof(nmhigh),dm(nmaniso).alt; for (i=1;i<=numberof(nmhigh);i++) { write,format="DM #%d:",nmhigh(i); print,dm(i); } rep = ""; question = "Which one ? ["+strcompress(strjoin(swrite(nmhigh),","),all=1)+"] "; read,prompt=question,rep; tmp=0; sread,rep,tmp; if (noneof(nmhigh == tmp)) { error,"Invalid selection"; } nmhigh = tmp; } project_aniso_dm,nmaniso(1),nmlow(1),nmhigh(1),disp=0; } //========================== // OUTPUT GRAPHIC FOR CONFIG //========================== if ((disp == 1)&&(!yaopy)) graphic_config; hcp_finish; //=================================== // PRINT OUT SUMMARY FOR WFSs AND DMs //=================================== if ( sim.verbose > 0) { write,""; write,format="%s:\n","Summary"; for (nm=1;nm<=ndm;nm++) { write,format="Mirror #%1d, %s, %d actuators, conjugated @ %.0f m\n", nm,dm(nm).type,dm(nm)._nact,dm(nm).alt; } for (ns=1;ns<=nwfs;ns++) { write,format="WFS #%2d, %s (meth. %d), %2d subap., offaxis "+ "(%+4.1f\",%+4.1f\"), noise %s\n", ns,wfs(ns).type,wfs(ns).shmethod,wfs(ns)._nsub,wfs(ns).gspos(1), wfs(ns).gspos(2), ( (wfs(ns).noise && (wfs(ns).shmethod == 2)) ? "enabled" : "disabled" ); } write,format="D/r0 (500nm) = %.1f; %d iterations\n",atm.dr0at05mic/ cos(gs.zenithangle*dtor)^0.6,loop.niter; } // same in result file: f = open(YAO_SAVEPATH+parprefix+".res","a+"); write,f,""; write,f,format="%s:\n","Summary"; for (nm=1;nm<=ndm;nm++) { write,f,format="Mirror #%1d, %s, %d actuators, conjugated @ %.0f m\n", nm,dm(nm).type,dm(nm)._nact,dm(nm).alt; } for (ns=1;ns<=nwfs;ns++) { write,f,format="WFS #%2d, %s (meth. %d), %2d subap., offaxis "+ "(%+4.1f\",%+4.1f\"), noise %s\n", ns,wfs(ns).type,wfs(ns).shmethod,wfs(ns)._nsub,wfs(ns).gspos(1), wfs(ns).gspos(2), ( (wfs(ns).noise && (wfs(ns).shmethod == 2)) ? "enabled" : "disabled" ); } write,f,format="D/r0 (500nm) = %.1f; %d iterations\n",atm.dr0at05mic/ cos(gs.zenithangle*dtor)^0.6,loop.niter; close,f; // make sure kernelconv is good after the imat: for (ns=1;ns<=nwfs;ns++) { wfs(ns)._kernelconv = 1n; if ((wfs(ns).kernel==0)&&(wfs(ns)._gsdepth==0)) wfs(ns)._kernelconv = 0n; if (wfs(ns).shmethod==1) wfs(ns)._kernelconv = 0n; } // basic initialization in case of svipc use: if (sim.svipc) require,"yao_svipc.i"; if (aoinit_user_func!=[]) status = aoinit_user_func(); gui_message,"aoinit done: click on aoloop"; notify,swrite(format="%s: aoinit done",parprefix); } //--------------------------------------------------------------- func aoloop(disp=,savecb=,dpi=,controlscreen=,nographinit=,anim=,savephase=,no_reinit_wfs=) /* DOCUMENT aoloop(disp=,savecb=,dpi=,controlscreen=,nographinit=,anim=,savephase=) Prepare all arrays for the execution of the loop (function go()). disp = set to display stuff as the loop goes savecb = set to save "circular buffers" dpi = dpi of graphic window controlscreen = set to display an additional graphic window with main loop parameters updating as the loop goes. nographinit = not sure. this must be for the GUI anim = set to 1 to use double buffering. Avoids flicker but might confuse the user if not turned off in normal operation see animate() yorick function. ON by default. savephase = set to save residual wavefront on first target as fits file no_reinit_wfs = don't re-init wfs SEE ALSO: aoread, aoinit, go, restart */ { extern looptime, mircube, command, wfsMesHistory, cubphase; extern im, imav, imtmp, airy, sairy, fwhm, e50; extern niterok; extern pp, sphase, bphase, imphase, dimpow2, cMat, pupil, ipupil; extern time, strehllp, strehlsp, itv, ok, njumpsinceswap; extern remainingTimestring ; extern cbmes, cbcom, cberr; extern indexDm, aniso, waniso, wdmaniso; extern ditherPeriod, ditherAmp, ditherGain, cggain, ditherMes; extern ditherCosLast, ditherSinLast, ditherMesCos, ditherMesSin; extern dispImImav; extern loopCounter, nshots, statsokvec; extern savecbFlag, dpiFlag, controlscreenFlag; extern dispFlag, nographinitFlag, animFlag; extern aoloop_disp,aoloop_savecb,aoloop_no_reinit_wfs; extern commb,errmb; // minibuffers extern default_dpi; extern savephaseFlag; if ((disp==[])&&(aoloop_disp!=[])) disp=aoloop_disp; if ((savecb==[])&&(aoloop_savecb!=[])) savecb=aoloop_savecb; if ((no_reinit_wfs==[])&&(aoloop_no_reinit_wfs!=[])) no_reinit_wfs=aoloop_no_reinit_wfs; if (anim==[]) anim=1; // let's make it the default dispFlag = disp; savecbFlag = savecb; dpiFlag = dpi; controlscreenFlag = controlscreen; nographinitFlag = nographinit; animFlag = anim; savephaseFlag = savephase; gui_message,"Initializing loop"; check_control_parameters; // update the control laws // Initialize hysteresis parameters for (nm=1;nm<=ndm;nm++){ dm(nm)._x0 = &array(float,dm(nm)._nact); dm(nm)._y0 = &array(float,[2,dm(nm)._nact,3]); dm(nm)._xlast = &array(float,dm(nm)._nact); dm(nm)._ylast = &array(float,[2,dm(nm)._nact,3]); dm(nm)._signus = &array(long,dm(nm)._nact); } if (aoloop_user_func!=[]) status = aoloop_user_func(); // Initialize displays: if (!is_set(disp)) {disp = 0;} if (!is_set(controlscreen)) {controlscreen = 0;} if (is_set(disp) && !is_set(nographinit)) { if (!yaopy) status = create_yao_window(); } if (is_set(controlscreen) && !is_set(nographinit)) { control_screen,0,init=1; } size = sim._size; // Some arrays initialization: looptime = 0.; mircube = array(float,[3,size,size,ndm]); command = array(float,sum(dm._nact)); wfsMesHistory = array(float,[2,sum(wfs._nmes),loop.framedelay+1]); cubphase = array(float,[3,size,size,target._ntarget]); im = array(float,[3,size,size,target._ntarget]); imav = array(float,[4,size,size,target._ntarget,target._nlambda]); imtmp = array(float,[2,size,size]); airy = calc_psf_fast(pupil,pupil*0.); sairy = max(airy); fwhm = e50 = array(float,[2,target._ntarget,target._nlambda]); pp = array(complex,[2,size,size]); sphase = array(float,[2,_n,_n]); bphase = array(float,[2,size,size]); imphase = array(float,[2,size,size]); dimpow2 = int(log(size)/log(2)); cMat = float(cMat); pupil = float(pupil); ipupil = float(ipupil); time = array(float,10); strehllp = strehlsp = itv = []; ok = 0; niterok = 0; remainingTimestring = ""; njumpsinceswap = 0; // number of jumps since last screen swap // minibuffers for up to 10th order filters (control laws): // determine number of actuators and commands nComm = 0; nAct = 0; for (nm=1;nm<=ndm;nm++){ if (dm(nm).virtual == 0) nComm += dm(nm)._nact; if (*dm(nm).dmfit_which == []) nAct += dm(nm)._nact; } commb = array(float,[2,nComm,10]); errmb = array(float,[2,nAct,10]); if (is_set(savecb)) { cbmes = array(float,[2,sum(wfs._nmes),loop.niter]); cbcom = array(float,[2,sum(nComm),loop.niter]); cberr = array(float,[2,sum(nAct),loop.niter]); } // Special: re-init the WFS, since it includes the computation of // the # of photons/WFS and the WFS bias anf flats, in case something // has changed since the aoinit. The # of photons in particular is one // parameter we often want to vary without having to go through the // whole aoinit again. For a curvature wfs, it re-inits the # of // photons and the extra-focal distance, so it is possible to loop // on "aoloop" with various l without the need for a aoinit (although // you would still be using the cMat determined for the original l, // but that might be on purpose). // Sometimes, a re-init might take a long time (e.g. for ELT systems), // and might be unnecessary, so the user might want to skip it. Use // no_reinit_wfs=1 to do so. for (ns=1;ns<=nwfs;ns++) { // zero fsm! got burn by this one! wfs(ns)._tt *= 0; wfs(ns)._upttcommand *= 0; // define _dispimage if (wfs(ns).type=="zernike") continue; if (wfs(ns).type=="dh") continue; wfs(ns)._dispimage = &(*wfs(ns)._fimage*0.0f); if (!no_reinit_wfs) { if (wfs(ns).type == "hartmann") { if (wfs(ns).disjointpup) { shwfs_init,disjointpup(,,ns),ns,silent=1; } else shwfs_init,ipupil,ns,silent=1; } else if (wfs(ns).type == "curvature") { curv_wfs,pupil,pupil*0.0f,ns,init=1,silent=1; } } else { // even if no_reinit asked, we need to do at least // the following as it may have been left in an imat state. if (wfs(ns).type == "hartmann") \ shwfs_init_common_kernel,ns,imat=0; } } statsokvec = (indgen(loop.niter)-1) % loop.skipevery; statsokvec = (statsokvec >= loop.startskip); // special: re-init phase screens, as often we want to change the // number of iterations without re-doing the full aoinit // note: ok, but have to quit_forks() explicitely if using svipc. if (loop.niter > dimsof(xposvec)(2)) get_turb_phase_init; // reset cyclecounters wfs._cyclecounter = wfs._cyclecounter*0 +1; indexDm = array(long,2,ndm); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } for (nm=1;nm<=ndm;nm++) { dm(nm)._command = &(array(float,dm(nm)._nact)); } // Set up for anisoplatism modes aniso = anyof(dm.type == "aniso"); if (aniso) { waniso = indexDm(1,where(dm.type == "aniso"))+[0,1,2]; wdmaniso = where(dm.type == "aniso")(0); if (sim.verbose>1) { print,"index of anisoplatism modes in command vector:",waniso; } } // dithering set up for upTT compensation (LGS only) wfs._centroidgain = array(1.f,nwfs); // if (anyof(wfs.centGainOpt)) { // we dither if there is an uplink, filtertilt is set and // centGainOpt is requested ditherPeriod = 8; ditherAmp = 0.05; // supposed to be in arcsec ditherGain = 0.1; cggain = 0.1; // 0.01; ditherCosLast = ditherSinLast = 0.0; ditherMesCos = ditherMesSin = ditherMes = array(0.,nwfs); //} // verbose if (sim.verbose) { write,format="\n> Starting loop with %i iterations\n",loop.niter; } // display if (is_set(disp)) { if (target._ntarget == 1) { // if only one target, display correct plate scale for image display *target.dispzoom = [(*target.lambda)(0)*1e-6/4.848e-6/ tel.diam*sim.pupildiam/sim._size/2*sim._size]; // last 2 terms to accomodate internal dispzoom scaling } disp2d,im,*target.xposition,*target.yposition,1, zoom=*target.dispzoom,init=1; if (wfs_display_mode=="spatial") { disp2d,wfs._dispimage,wfs.pupoffset(1,),wfs.pupoffset(2,),2,\ zoom=wfs.dispzoom,init=1; } else { disp2d,wfs._dispimage,wfs.gspos(1,),wfs.gspos(2,),2,zoom=wfs.dispzoom,\ init=1; } } dispImImav = 0; // 0 is to display im, 1 to display imav olddisp = disp; oldcontrolscreen = controlscreen; // Main loop: loopCounter=0; nshots = -1; if (sim.svipc) { status = svipc_init(); status = svipc_start_forks(); status = init_sync(); status = reset_strehl(); } if (animFlag && dispFlag) { plsys,1; animate,1; } gui_message,"Initializing loop...done. \"go\" to start, \"pause\" to pause"; } func go(nshot,all=) /* DOCUMENT go will start or resume the AO loop go will go once through this function, and then call itself, until loop.niter has been reached or nshot has been done since last user- entered go. Because go() comes back to the main yorick prompt after each iteration, the user can enter commands, or ask to pause the loop, at any time. example: ... aoloop,disp=1 go ... the loop goes, one iteration after another and prints out thing on screen dispFlag=0 // turns off display. the loop keeps going loop.gain = 0.2 // change the loop integrator gain reset // flatten the DMs stop // pause the loop cont // continues the loop nshot = # of iterations to go through. if not set, will go until loop.niter (total # of iterations) has been done all = do all remaining iteration without returning to the yorick prompt. This is useful in scripts to avoid messy side effects of set_idler. SEE ALSO: aoloop, stop, cont, reset, restart, whereat, after_loop */ { extern niterok, starttime, endtime, endtime_str, tottime, now2, nshots; extern dispFlag, savecbFlag, dpiFlag, controlscreenFlag; extern nographinitFlag,savephaseFlag; extern cbmes, cbcom, cberr; extern iMatSP, AtAregSP extern commb,errmb; // minibuffers (last 10 iterations) extern im,imav; extern iter_per_sec; gui_show_statusbar1; if (go_user_func!=[]) status = go_user_func(); if (nshot!=[]) { if (animFlag&&dispFlag) { plsys,1; animate,1; } nshots = nshot; } disp = dispFlag; savecb = savecbFlag; dpi = dpiFlag; controlscreen = controlscreenFlag; nographinit = nographinitFlag; savephase = savephaseFlag; if (loopCounter==0) { // initialize timers tic,2; starttime = _nowtime(2); tottime = 0.; } go_start: now = tac(2); loopCounter++; nshots--; // update gui progress bar, but don't do it too often. if (max_progressbar_update_freq==[]) max_progressbar_update_freq=5.; // in Hz if (tac(3)>(1./max_progressbar_update_freq)) { gui_progressbar_frac,float(loopCounter)/loop.niter; gui_progressbar_text,swrite(format="%d out of %d iterations",loopCounter, \ loop.niter); tic,3; } comvec=[]; if (loopCounter>loop.niter) { exit,"Can't continue: loopCounter > loop.niter !"; } i = loopCounter; tic; time(1) = tac(); prevOK = ok; check_control_parameters; // update the control laws //========================== // DITHERING // act on wfs._upttcommand // sense on wfs._tt if (anyof(wfs.centGainOpt)) { wdither = where((wfs.correctUpTT == 1) & (wfs.centGainOpt ==1) & (wfs.filtertilt == 1)); if (numberof(wdither) != 0) { nditherarray = array(1.,numberof(wdither)); } ditherCosCurr = ditherAmp*cos(2*pi*i/ditherPeriod); ditherSinCurr = ditherAmp*sin(2*pi*i/ditherPeriod); // subtract last command and add new. the circular motion is // known. radius=ditherAmp. wfs(wdither)._upttcommand -= [ditherCosLast,ditherSinLast]*nditherarray(-,); wfs(wdither)._upttcommand += [ditherCosCurr,ditherSinCurr]*nditherarray(-,); ditherCosLast = ditherCosCurr; ditherSinLast = ditherSinCurr; // do the temporal filtering on cos and sin measurements // (see requirements documents I wrote for tOSC regarding the process) ditherMesCos = (1-ditherGain)*ditherMesCos + ditherGain*wfs._tt(1,)* cos(2*pi*i/ditherPeriod); ditherMesSin = (1-ditherGain)*ditherMesSin + ditherGain*wfs._tt(2,)* sin(2*pi*i/ditherPeriod); ditherMes = 2.*sqrt(ditherMesCos^2.+ditherMesSin^2.); // clip,ditherMes,ditherAmp/4,ditherAmp*4; // ditherMes(wdither); // wfs._tt; if (i > 30) { wfs(wdither)._centroidgain += cggain*(ditherAmp-ditherMes(wdither)); } } // END OF DITHERING PART //=========================== // get the turbulent phase: // Do the wavefront sensing: if (anyof([sim.svipc>>0,sim.svipc>>2]&1)) { // parallel computing. svipc_wfsmes = topwfs_svipc(); } else WfsMes = mult_wfs(i,disp=disp); time(2) += tac(); ok = statsokvec(i); if ((prevOK-ok)==1) { // After a jump njumpsinceswap++; if (njumpsinceswap==loop.jumps2swapscreen) { if (sim.verbose) write,"Reset and screens swap"; swap_screens; // swap screens njumpsinceswap = 0; // reset "jumps since last swap" counter } else { write,"Reset"; } status = reset(); } // Handling frame delay (0 -> no frame delay at all, 1 -> regular // one frame delay of integrator, 2 -> integrator + one frame // computation, etc... wfsMesHistory = roll(wfsMesHistory,[0,-1]); if (anyof([sim.svipc>>0,sim.svipc>>2]&1)) { // parallel computing. wfsMesHistory(,loop.framedelay) = svipc_wfsmes; } else { wfsMesHistory(,loop.framedelay+1) = WfsMes; } usedMes = float(wfsMesHistory(,1)); time(3) += tac(); // RECONSTRUCTION: // computes the actuator error vector from the measurements: if (mat.method == "mmse-sparse") { if (i == 1){ MR = mat.sparse_MR; MN = mat.sparse_MN; } if (sum(usedMes != 0) == 0){ // sparse CG method does not work if all zeros err = array(float,AtAregSP.r); } else { Ats=rcoxv(GxSP,usedMes) if ((loop.method == "pseudo open-loop") && (i > 1) && (polcMatSP != [])){ // apply polc correction polccorr = rcoxv(polcMatSP,estdmcommand); if (anyof(wfs.nintegcycles > 1)){ // if some DMs are not updating because the WFSs have not finished // integrating, then the POLC correction should not be applied to // those DMs // Check to see which DMs have updated; only non tomographic DMs mc = 0; // counter for (nm=1;nm<=numberof(dm);nm++){ if (!dm(nm).dmfit_which){ comms = Ats(mc+1:mc+dm(nm)._nact); if (comms(rms) == 0){ // has not updated polccorr(mc+1:mc+dm(nm)._nact) = 0; } mc += dm(nm)._nact; } } } Ats -= polccorr; } err = float(ruopcg(AtAregSP,Ats, array(float,AtAregSP.r), tol=mat.sparse_pcgtol)); } } else { err = cMat(,+) * usedMes(+); if ((loop.method == "pseudo open-loop") && (i > 1) && (dMat != [])){ polccorr = dMat(,+)*estdmcommand(+); //pseudo open loop correction if (anyof(wfs.nintegcycles > 1)){ // if some DMs are not updating because the WFSs have not finished // integrating, then the POLC correction should not be applied to // those DMs. // Check to see which DMs have updated; only non tomographic DMs mc = 0; // counter for (nm=1;nm<=numberof(dm);nm++){ if (!dm(nm).dmfit_which){ comms = err(mc+1:mc+dm(nm)._nact); if (comms(rms) == 0){ // has not updated polccorr(mc+1:mc+dm(nm)._nact) = 0; } mc += dm(nm)._nact; } } } err -= polccorr; } } if (user_loop_err!=[]) user_loop_err; // get the anisoplanatism mode coefficients and project it // in the actuator space if (aniso) { err += dm(wdmaniso).gain*(comaniso(,+) * err(waniso)(+)); err(waniso) = 0.; // dm(wdmaniso)._command = invcomaniso(+,)* } time(4) += tac(); // Computes the mirror shape using influence functions: for (nm=1; nm<=ndm; nm++) { if (dm(nm).type == "aniso") { grow,comvec,*dm(nm)._command; continue; } n1 = dm(nm)._n1; n2 = dm(nm)._n2; nxy = n2-n1+1; if (*dm(nm).dmfit_which == []){ // not a tomographic DM // update the command vector for this DM: // this DM error: ctrlden = *dm(nm)._ctrlden; ctrlnum = *dm(nm)._ctrlnum; command = *dm(nm)._command*(-ctrlden(2)); for (order=3;order<=numberof(ctrlden);order++){ imb = (i-order+1)%10; command -= commb(indexDm(1,nm):indexDm(2,nm),imb)*ctrlden(order); } dmerr = err(indexDm(1,nm):indexDm(2,nm)); command -= dmerr*ctrlnum(1); for (order=2;order<=numberof(ctrlnum);order++){ imb = (i-order+1)%10; command -=errmb(indexDm(1,nm):indexDm(2,nm),imb)*ctrlnum(order); } *dm(nm)._command = command; } else { // tomographic DM; DM commands from virtual DMs virtualDMs = int(*dm(nm).dmfit_which); virtualdmcommand = []; for (idx=1;idx<= numberof(virtualDMs);idx++){ grow, virtualdmcommand, *dm(virtualDMs(idx))._command; } if (mat.method == "mmse-sparse"){ *dm(nm)._command = rcoxv(*dm(nm)._fMat,virtualdmcommand); } else { *dm(nm)._command = (*dm(nm)._fMat)(,+)*virtualdmcommand(+); } } if (dm(nm).filtertilt){ // filter piston, tip and tilt if (dm(nm).type == "stackarray"){ // todo: have a variable to store xv and yv to avoid recomputing xv = *dm(nm)._x - avg(*dm(nm)._x); xv = xv / sqrt(sum(xv*xv)); yv = *dm(nm)._y - avg(*dm(nm)._y); yv = yv / sqrt(sum(yv*yv)); *dm(nm)._command -= avg(*dm(nm)._command); *dm(nm)._command -= (xv(+)*(*dm(nm)._command)(+))*xv; *dm(nm)._command -= (yv(+)*(*dm(nm)._command)(+))*yv; } if (dm(nm).type == "zernike"){ if (dm(nm).minzer <= 3){ (*dm(nm)._command)(1:4-dm(nm).minzer) = 0; } } } estdmcommand = []; for (idx=1;idx<=ndm;idx++){ if (!dm(idx).dmfit_which){ grow, estdmcommand, *dm(idx)._command; } } if (dm(nm).maxvolt != 0) { dm(nm)._command=&(float(clip(*dm(nm)._command,-dm(nm).maxvolt,dm(nm).maxvolt))); } if (user_loop_command!=[]) user_loop_command,nm; if (dm(nm).virtual == 0){ grow,comvec,*dm(nm)._command; if (dm(nm).hyst > 0){ mircube(n1:n2,n1:n2,nm) = comp_dm_shape(nm,&(hysteresis(*dm(nm)._command,nm))); } else { mircube(n1:n2,n1:n2,nm) = comp_dm_shape(nm,dm(nm)._command); } if ( (nm==1) && (add_dm0_shape!=[]) ) mircube(,,1) += add_dm0_shape; // extrapolated actuators: if ((dm(nm)._enact != 0) && (dm(nm).noextrap == 0)) { ecom = float(((*dm(nm)._extrapcmat)(,+))*(*dm(nm)._command)(+)); mircube(n1:n2,n1:n2,nm) += comp_dm_shape(nm,&ecom,extrap=1); } } else { mircube(n1:n2,n1:n2,nm) = 0.; //virtual DM, does not produce a shape } } // fill minibuffers errmb(,(i%10)) = err; // 10 will go in 0, which is 10. commb(,(i%10)) = comvec; // 10 will go in 0, which is 10. if (tipvib!=[]) { // add tip vibrations // if there is a TTM, add it there if (anyof(dm.type=="tiptilt")) nmvib=where(dm.type=="tiptilt")(1); else nmvib=1; // otherwise put it to 1. mircube(,,nmvib) += tipvib(i)*tip1arcsec; } if (tiltvib!=[]) { // add tilt vibrations // if there is a TTM, add it there if (anyof(dm.type=="tiptilt")) nmvib=where(dm.type=="tiptilt")(1); else nmvib=1; // otherwise put it to 1. mircube(,,nmvib) += tiltvib(i)*tilt1arcsec; } if (segmenttiptiltvib!=[]) { // add tiptilt vibrations on a segment by segment basis, designed primarily for GMT but could be used for any telescope // if there is a TTM, add it there if (anyof(dm.type=="tiptilt")) nmvib=where(dm.type=="tiptilt")(1); else nmvib=1; // otherwise put it to 1. mircube(,,nmvib) += make_segment_tiptilt(segmenttiptiltvib(,i)); } if (segmentpistonvib!=[]) { // add piston vibrations on a segment by segment basis, designed primarily for GMT but could be used for any telescope nmvib=1; mircube(,,nmvib) += make_segment_piston(segmentpistonvib(,i)); } time(5) += tac(); ok = ok*((i % loop.stats_every) == 0); // accumulate stats only every 4 iter. if (user_go_ok) ok = user_go_ok(); okdisp = ( is_set(disp) && (((i-1) % disp) == 0) ); if (nshots>0) okdisp=is_set(disp); okcscreen = ( is_set(controlscreen) && (((i-1) % controlscreen) == 0) ); if (is_set(controlscreen) && (i == loop.niter)) okcscreen=1; // display at last iteration if (savephase||okdisp) { // get the residual phase; initially for the first target // display and save the residual wavefront if (residual_phase_what==[]) residual_phase_what="target"; if (residual_phase_which==[]) residual_phase_which=1; residual_phase=get_phase2d_from_dms(residual_phase_which,residual_phase_what) + get_phase2d_from_optics(residual_phase_which,residual_phase_what) + get_turb_phase(i,residual_phase_which,residual_phase_what); residual_phase1d = residual_phase(where(pupil > 0)); residual_phase1d -= min(residual_phase1d); residual_phase(where(pupil > 0)) = residual_phase1d; if (savephase){ fname = swrite(format="%s/%s_rwf%d.fits",YAO_SAVEPATH,parprefix,loopCounter); yao_fitswrite,fname,float(residual_phase*pupil); } if (residual_phase_zcontent) { // project residual phase on zernike // init zernikes: extern rp_zerns,rp_nzerns,rp_w,rp_rms,rp_z; if (rp_zerns==[]) { if (!rp_nzerns) rp_nzerns = 45; rp_zerns = array(float,[3,_n,_n,rp_nzerns]); // I've done the zernike thingy in a very stupid way. // it might have been used/initialized elsewhere and I can // mess up this initialisation here. To avoid this, temporarily: if (zrmod!=[]) error,"zernike have already been initialized, can't do!"; prepzernike,_n,sim.pupildiam; for (nz=1;nz<=rp_nzerns;nz++) rp_zerns(,,nz) = zernike(nz); rp_zerns = rp_zerns(*,)(where(pupil(_n1:_n2,_n1:_n2)),); rp_zerns = QRsolve(transpose(rp_zerns),unit(rp_nzerns)); rp_w = where(pupil); } rp1d = residual_phase(rp_w); rp_rms = rp1d(rms)*1000.; // in nm rp_z = rp1d(+)*rp_zerns(+,)*1000.; // in nm } } // Computes the instantaneous PSF: if (ok) { if ((sim.svipc>>1)&1) { // use child if (psf_child_started) { // read previous results: if (smdebug) write,"main: waiting for ready from PSF fork"; sem_take,semkey,4; if (smdebug) write,"main: received ready from PSF fork"; // results are ready. im = shm_read(shmkey,"imsp"); imav = shm_read(shmkey,"imlp"); niterok += 1; grow,itv,i; if (disp_strehl_indice) sind=disp_strehl_indice; else sind=1; grow,strehlsp,im(max,max,sind)/sairy; grow,strehllp,imav(max,max,sind,0)/sairy/(niterok+1e-5); } extern psf_child_started; // give the go for next batch: shm_write,shmkey,"loop_counter",&([loopCounter]); shm_write,shmkey,"mircube",&mircube; if (smdebug) write,"main: giving trigger to PSF child"; sem_give,semkey,3; psf_child_started = 1; } else { // compute integrated phases and fill phase cube for (jl=1;jl<=target._nlambda;jl++) { for (jt=1;jt<=target._ntarget;jt++) { cubphase(,,jt) = get_phase2d_from_dms(jt,"target") + \ get_phase2d_from_optics(jt,"target") + \ get_turb_phase(i,jt,"target"); // vibration already added to dm1 } // compute image cube from phase cube status = _calc_psf_fast(&pupil,&cubphase,&im,2^dimpow2, target._ntarget,float(2*pi/(*target.lambda)(jl)),1n); // Accumulate statistics: imav(,,,jl) = imav(,,,jl) + im; } niterok += 1; grow,itv,i; if (disp_strehl_indice) sind=disp_strehl_indice; else sind=1; grow,strehlsp,im(max,max,sind)/sairy; grow,strehllp,imav(max,max,sind,0)/sairy/(niterok+1e-5); } } time(6) += tac(); // Displays if (disp) { for (ns=1;ns<=nwfs;ns++ ) { // if cyclecounter = 1, a final image just got computed if (wfs(ns).type=="zernike") continue; if (wfs(ns)._cyclecounter == wfs(ns).nintegcycles) { if (wfs(ns).type!="hartmann") *wfs(ns)._dispimage = *wfs(ns)._fimage; // for hartmann, done within shwfs() } } } // testing display by external yorick process. Proof of concept. if ((display_offline)&&(shm_init_done)) { // nothing to do right now as we use variables shm_var'ed from // sh_wfs + loopCounter already in shm } if (okdisp) { if (!animFlag) fma; // PSF Images plt,sim.name,0.01,0.227,tosys=0; if (dispImImav) { disp2d,imav,*target.xposition,*target.yposition,1,power=0.5; } else { disp2d,im,*target.xposition,*target.yposition,1,power=0.5; } for (j=1;j<=nwfs;j++) { plg,wfs(j).gspos(2),wfs(j).gspos(1),marker='\2', type="none",marks=1,color="red"; } mypltitle,"Instantaneous PSFs",[0.,-0.00],height=12; myxytitles,"","arcsec",[0.005,0.01],height=12; // WFS spots if (!allof(wfs.shmethod ==1)) { if (wfs_display_mode=="spatial") { disp2d,wfs._dispimage,wfs.pupoffset(1,),wfs.pupoffset(2,),2; mypltitle,"WFSs (spatial mode)",[0.,-0.005],height=12; } else { disp2d,wfs._dispimage,wfs.gspos(1,),wfs.gspos(2,),2; mypltitle,"WFSs",[0.,-0.00],height=12; } } // mirror surface plsys,3; limits,square=1; if (mergedms4disp) { //e.g. GMT case tmp = mircube(,,sum); pli,(tmp-min(tmp))*ipupil,1,0.,2,1.; range,0.25,0.75; } else { pli,(mircube(,,1)-min(mircube(,,1)))*ipupil,1,0.,2,1.; for (nm=2;nm<=ndm;nm++) { if (dm(nm).alt==0) { pli,(mircube(,,nm)-min(mircube(,,nm)))*ipupil,nm,0.,nm+1,1.; } else { pli,(mircube(,,nm)-min(mircube(,,nm))),nm,0.,nm+1,1.; } } } myxytitles,"","DM(s)",[0.005,0.],height=12; // Strehl plots if (anyof(itv)) { plsys,4; if (plot_rps) { extern plot_rps_limit_done; if (rp_z!=[]) { plh,rp_z(2:),indgen(2:rp_nzerns); myxytitles,"Z#","Z value [nm]",[0.005,0.008],height=12; if (!plot_rps_limit_done) { range,-600,600; plot_rps_limit_done=1; } } } else { if (rolling_strehl_disp_length) { ii = clip(numberof(itv)-rolling_strehl_disp_length/clip(loop.stats_every,1,),1,); } else ii=1; plg,strehlsp(ii:),itv(ii:),marks=0; plg,strehllp(ii:),itv(ii:),marks=0,color="red"; myxytitles,"",swrite(format="Strehl @ %.2f mic", \ (*target.lambda)(0)),[0.005,-0.005],height=12; range,0.,1.; } } // Display residual wavefront plsys,5; pli, (pupil*residual_phase)(n1:n2,n1:n2); if (rp_rms!=[]) \ plt,swrite(format="rms=%dnm",long(rp_rms)),0.450,0.579,\ tosys=0,height=10,justify="LA"; mypltitle,swrite(format="Residual wavefront on %s #%d",residual_phase_what,\ residual_phase_which),[0.,-0.0],height=12; if (user_plot != []) user_plot,i,init=(i==1); // execute user's plot routine if it exists. if (animFlag && (nshots!=0) && (loopCounter 2) && ((i % 20) == 1)) || (nshots>=0)) { if (numberof(*target.xposition)==1) { write,"Iter# Inst.Strehl Long expo.Strehl Time Left it/s"; } else { write," Short expo. image Long expos. image "; write,"Iter# Max.S/Min.S/Avg.S Max.S/Min.S/Avg.S Time Left it/s"; } } if ((looptime > 2) || ((i % 50) == 1) || (nshots>=0)) { if (numberof(*target.xposition)==1) { msg = swrite(format="%5i %5.3f %5.3f %s", i,im(max,max,max)/sairy, imav(max,max,max,0)/sairy/(niterok+1e-5), remainingTimestring); msg1 = swrite(format=" %.1f",iter_per_sec); write,msg+msg1; header = "Iter# Inst.Strehl Long expo.Strehl Time Left"; msg = swrite(format="%5i %5.3f %5.3f %s", i,im(max,max,max)/sairy, imav(max,max,max,0)/sairy/(niterok+1e-5), remainingTimestring); gui_message1,header; gui_message,msg; } else { msg = swrite(format="%5i %5.3f %5.3f %5.3f %5.3f %5.3f %5.3f %s", i,im(max,max,max)/sairy,min(im(max,max,))/sairy, avg(im(max,max,))/sairy,imav(max,max,max,0)/sairy/(niterok+1e-5), min(imav(max,max,,0))/sairy/(niterok+1e-5), avg(imav(max,max,,0))/sairy/(niterok+1e-5),remainingTimestring); msg1 = swrite(format=" %.1f",iter_per_sec); write,msg+msg1; header = "Iter# Inst:Max.S/Min.S/Avg.S Avg:Max.S/Min.S/Avg.S Time Left"; msg = swrite(format="%5i %5.3f %5.3f %5.3f %5.3f %5.3f %5.3f %s", i,im(max,max,max)/sairy,min(im(max,max,))/sairy, avg(im(max,max,))/sairy,imav(max,max,max,0)/sairy/(niterok+1e-5), min(imav(max,max,,0))/sairy/(niterok+1e-5), avg(imav(max,max,,0))/sairy/(niterok+1e-5),remainingTimestring); gui_message1,header; gui_message,msg; } } } time(8) += tac(); if (nshots==0) { if (animFlag && dispFlag) { plsys,1; animate,0; } return; } if (user_end_go != []) status = user_end_go(); // execute user's routine if it exists. tic,2; endtime=_nowtime(2); endtime_str = gettime(); // if (loopCounter>0)&1) sem_take,semkey,1; after_loop; notify,swrite(format="%s: %d iterations completed",parprefix,loopCounter) } maybe_prompt; } func reset(void,nmv=) /* DOCUMENT reset(void,nmv=) Flattens/reset all the DMs (or a subset if nmv not void) SEE ALSO: */ { extern command,mircube,wfsMesHistory,dm,ndm; if (nmv==[]) nmv=indgen(ndm); if (command!=[]) command *=0.0f; for (i=1;i<=numberof(nmv);i++) { nm = nmv(i); *dm(nm)._command *=0.0f; } mircube *=0.0f; wfsMesHistory *=0.0f; } func stop(void) /* DOCUMENT stop(void) Pause the loop SEE ALSO: cont, go, restart */ { write,format="Stopping @ iter=%d\n",loopCounter; gui_hide_statusbar1; if (animFlag&&dispFlag) { plsys,1; animate,0; } set_idler; } func cont(void) /* DOCUMENT cont(void) Resume the loop SEE ALSO: stop, restart, go */ { write,"Proceeding..."; if (animFlag&&dispFlag) { plsys,1; animate,1; } set_idler,go; } func restart(void) /* DOCUMENT restart(void) Re-initialize all variable and reset loop counter to zero. SEE ALSO: go */ { extern imav, ditherMesCos, ditherMesSin; extern niterok, loopCounter; extern command, mircube, wfsMesHistory; extern strehllp,strehsp, itv; extern startime; loopCounter = 0; imav *= 0.0f; wfs._upttcommand *= 0.0f; wfs._centroidgain *= 0.0f+1.0f; ditherMesCos = ditherMesSin = 0.; command *=0.0f; mircube *=0.0f; wfsMesHistory *=0.0f; for (nm=1;nm<=ndm;nm++) {*dm(nm)._command *= 0.0f;} strehllp = strehlsp = itv = []; tic,2; starttime = _nowtime(2); niterok = 0; // set_idler,go; } func disptoggle(void) { dispFlag=1-dispFlag; } func whereat(void) { write,format="@ iter=%d\n",loopCounter; } func do_prompt(void) { write,format="%s ",">"; } func after_loop(void) /* DOCUMENT after_loop(void) Wraps up when all iterations have been done. Compute various performance criteria (Strehl, FWHM, various performance timers, ...) SEE ALSO: aoloop, go */ { extern strehllp,strehsp, itv; extern cbmes, cbcom, cberr; extern strehl,e50,fwhm; extern iter_per_sec; savecb = savecbFlag; gui_message,swrite(format="Saving results in %s.res (ps,imav.fits)...",YAO_SAVEPATH+parprefix); if (sim.verbose>0) \ write,format="Saving results in %s.res (ps,imav.fits)...\n",\ YAO_SAVEPATH+parprefix; time2 = (time - roll(time,1))/loopCounter; timeComments = ["WF sensing","Reset and measurement history handling","cMat multiplication",\ "DM shape computation","Target PSFs estimation","Displays",\ "Circular buffers, end-of-loop printouts"]; for (i=2;i<=8;i++) { write,format="time(%d-%d) = %5.2f ms (%s)\n",i-1,i,time2(i)*1e3,timeComments(i-1);} write,format="Finished on %s\n",endtime_str; // tottime = (endtime - starttime); iter_per_sec = loopCounter/tottime; write,format="%f iterations/second on average\n",iter_per_sec; // Save the circular buffers: if (is_set(savecb)) { yao_fitswrite,YAO_SAVEPATH+"cbmes.fits",cbmes; yao_fitswrite,YAO_SAVEPATH+"cbcom.fits",cbcom; yao_fitswrite,YAO_SAVEPATH+"cberr.fits",cberr; write,"cbmes, cbcom and cberr are saved."; write,"You can run modal_gain_optimization() to optimize and update the gains"; } // End of loop calculations (fwhm, EE, Strehl): fairy = findfwhm(airy,saveram=1); if (!no_ee) e50airy= encircled_energy(airy,ee50); else e50airy=0.; strehl = imav(max,max,,)/sairy/(niterok+1e-5); psize = (float(sim.pupildiam)/sim._size)*(*target.lambda)/tel.diam/4.848e-3; write,format="\nPixel size in images (e.g. imav) = %.1f mas/pixel\n",psize; write,format="\n lambda XPos YPos FWHM[mas] Strehl E50d[mas]%s\n",""; for (jl=1;jl<=target._nlambda;jl++) { for (jt=1;jt<=target._ntarget;jt++) { fwhm(jt,jl) = findfwhm(imav(,,jt,jl),psize(jl),saveram=1); if (!no_ee) encircled_energy,imav(,,jt,jl),tmp; else tmp=0.; e50(jt,jl) = tmp*psize(jl); write,format= "Star#%2d % 5.2f % 6.1f % 6.1f %6.1f %.3f %6.1f\n", jt,(*target.lambda)(jl),(*target.xposition)(jt),(*target.yposition)(jt), fwhm(jt,jl),strehl(jt,jl),e50(jt,jl); } if (target._ntarget > 1){ write,format="Field Avg % 5.2f %6.1f %.3f %6.1f\n", (*target.lambda)(jl),fwhm(avg,jl),strehl(avg,jl),e50(avg,jl); write,format="Field rms % 5.2f %6.1f %.3f %6.1f\n", (*target.lambda)(jl),fwhm(rms,jl),strehl(rms,jl),e50(rms,jl); } } // Some logging of the results in file parprefix+".res": f = open(YAO_SAVEPATH+parprefix+".res","a+"); write,f,format= "\n lambda XPos YPos FWHM[mas] Strehl E50d[mas]%s\n",""; for (jl=1;jl<=target._nlambda;jl++) { for (jt=1;jt<=target._ntarget;jt++) { write,f,format= "Star#%2d % 6.2f % 6.1f % 5.1f %6.1f %.3f %6.1f\n", jt,(*target.lambda)(jl),(*target.xposition)(jt),(*target.yposition)(jt), fwhm(jt,jl),strehl(jt,jl),e50(jt,jl); } write,f,format="Field Avg % 5.2f %6.1f %.3f %6.1f\n", (*target.lambda)(jl),fwhm(avg,jl),strehl(avg,jl),e50(avg,jl); write,f,format="Field rms % 5.2f %6.1f %.3f %6.1f\n", (*target.lambda)(jl),fwhm(rms,jl),strehl(rms,jl),e50(rms,jl); } write,f,format="\nAverage images written in %s\n",parprefix+"-imav.fits"; write,f,format="Some other graphics in %s\n",parprefix+".ps"; write,f,format="\nOriginal parameter file: %s:\n",oparfile; fin = open(oparfile,"r"); while (1) { l = rdline(fin); if (!l) {break;}; write,f,l;} close,fin; write,f,"\n==== dump of structures ===="; write,f,print(sim); write,f,print(atm); write,f,print(wfs); write,f,print(dm); write,f,print(mat); write,f,print(tel); write,f,print(target); write,f,print(gs); write,f,print(loop); close,f; // create a header header = fitsBuildCard("WAVELENGTH", *target.lambda , "microns"); grow, header, fitsBuildCard("PIXSIZE", psize , "milliarcsec"); grow, header, fitsBuildCard("XPOSITION", *target.xposition , "arcsec"); grow, header, fitsBuildCard("YPOSITION", *target.yposition , "arcsec"); yao_fitswrite,YAO_SAVEPATH+parprefix+"-imav.fits",imav, header; // saved graphics window,7,display="",hcp=YAO_SAVEPATH+parprefix+".ps",wait=1,style="work.gs"; fma; hcpon; disp2d,im,*target.xposition,*target.yposition,1,zoom=*target.dispzoom,init=1; for (jl=1;jl<=target._nlambda;jl++) { disp2d,imav(,,,jl),*target.xposition,*target.yposition,1,power=0.5; } for (j=1;j<=nwfs;j++) { plg,wfs(j).gspos(2),wfs(j).gspos(1),marker='\2', type="none",marks=1,color="red"; } axisLegend,"arcsec","arcsec"; mypltitle=parprefix+"/ Average PSF"; if (strehlsp != []) { fma; limits; limits,square=0; plg,strehlsp,itv; if (strehllp!=[]) plg,strehllp,itv,color="red"; myxytitles,"Iterations","Strehl"; // hcp; } plt,sim.name,0.01,0.227,tosys=0; hcpoff; hcp_finish; gui_message,swrite(format="Dumping results in %s.res (ps,imav.fits)...DONE",YAO_SAVEPATH+parprefix); if (curw != -1) {window,curw;} // if (is_set(disp)) {window,style="boxed.gs";} return imav; } dtor = pi/180.; radeg = 1./dtor; //=================== // API compatibility: //=================== ZernikeWfs = zernike_wfs; PyramidWfs = pyramid_wfs; ShWfsInit = shwfs_init; multWfsIntMat = mult_wfs_int_mat; multWfs = mult_wfs; wfsCheckPixelSize = wfs_check_pixel_size; checkParameters = check_parameters; graphicConfig = graphic_config; modalGainOptimization = modal_gain_optimization; MakePupil = make_pupil; FindDmModes = build_dm_modes; disp2D = disp2d; ftcbAoSimul = ft_cb_ao_simul; make_curv_wfsSubs = make_curv_wfs_subs; ssNoise = ss_noise; ShWfs = sh_wfs; MakeCurvWfs = make_curv_wfs; CurvWfs = curv_wfs; doInter = do_imat; prepSVD = prep_svd; buildComMat = build_cmat; swapScreens = swap_screens; getTurbPhaseInit = get_turb_phase_init; getTurbPhase = get_turb_phase; getPhase2dFromDms = get_phase2d_from_dms; getPhase2dFromOptics = get_phase2d_from_optics; correctUpLinkTT = correct_uplink_tt; splitWfsVector = split_wfs_vector; splitDMCommandVector = split_dm_vector; MakePztIF = make_pzt_dm; MakeEltPztIF = make_pzt_dm_elt; MakeKLIF = make_kl_dm; MakeZernikeIF = make_zernike_dm; MakeDhIF = make_dh_dm; MakeBimorphIF = make_curvature_dm; MakeTipTiltIF = make_tiptilt_dm; projectAnisoIF = project_aniso_dm; MakeAnisoIF = make_aniso_dm; compDmShape = comp_dm_shape; controlScreen = control_screen; mcaoRayleigh = mcao_rayleigh; progressBar = progress_bar; PhaseStructFunc = phase_struct_func; CreatePhaseScreens = create_phase_screens; generateVKspectrum = generate_von_karman_spectrum; generatePhaseWithL0 = generate_phase_with_L0; plotMTF = plot_mtf; plotDphi = plot_dphi; userPlot = user_plot; yao-5.4.0/yao.info000066400000000000000000000014741234404334100137610ustar00rootroot00000000000000Package: yao Kind: plugin Version: 5.4.0 Revision: 1 Description: Adaptive Optics simulation package License: BSD Maintainer: Francois Rigaut OS: Depends: yorick(>=2.2.0), yutils(>=1.0), imutil(>=0.5) Source: http://www.maumae.net/yorick/packages/%o/tarballs/yao-%v-%o.tgz Source-MD5: Source-Directory: contrib/yao DocFiles: README TODO VERSION NEWS LEGAL doc/README:README.doc doc/FILE_FORMATS doc/*.doc doc/*.pdf doc/*.ps doc/*.tex Homepage: http://www.maumae.net/yorick/doc/plugins.php DescDetail: << Multi-usage adaptive optics Monte-Carlo simulation package. Can simulation versatile configs (classical, LGS, GLAO, MCAO) with Shack-Hartmann or curvature sensors. Fast. << DescUsage: << See yao/examples for a test suite. type yorick -i test-all.i in a terminal to run it. << DescPort: << << yao-5.4.0/yao.py000077500000000000000000000621741234404334100134650ustar00rootroot00000000000000#!/usr/bin/env python2 # # yao.py # # python functions: # - glade callback functions # - calls to yorick # # This file is part of the yao package, an adaptive optics simulation tool. # # Copyright (c) 2002-2013, Francois Rigaut # # 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 (to receive a copy of the GNU # General Public License, write to the Free Software Foundation, Inc., 675 # Mass Ave, Cambridge, MA 02139, USA). # import gtk import gtk.glade import sys import gobject import os, fcntl, errno from time import * class yao: def destroy(self, wdg, data=None): self.py2yo('yaopy_quit') # gtk.main_quit() def __init__(self,path2glade,dpi): self.path2glade = path2glade self.usercmd = 'STOP' self.glade = gtk.glade.XML(self.path2glade+'/yao.glade') self.window = self.glade.get_widget('window1') if (self.window): self.window.connect('destroy', self.destroy) self.glade.signal_autoconnect(self) self.editor = self.glade.get_widget('window2') if (self.editor): self.editor.connect('delete_event', self.on_editor_close_activate) self.editor2 = self.glade.get_widget('window4') if (self.editor2): self.editor2.connect('delete_event', self.on_editor2_close_activate) self.statusbar = self.glade.get_widget('statusbar') self.statusbar1 = self.glade.get_widget('statusbar1') self.progressbar = self.glade.get_widget('progressbar') self.aoinit_popup_menu = self.glade.get_widget('aoinit_popup_menu') self.aoinit_popup_button = self.glade.get_widget('aoinit_popup_button') self.aoinit_popup_button.connect_object("event", self.on_aoinit_popup_button_clicked, self.aoinit_popup_menu) self.aoloop_popup_menu = self.glade.get_widget('aoloop_popup_menu') self.aoloop_popup_button = self.glade.get_widget('aoloop_popup_button') self.aoloop_popup_button.connect_object("event", self.on_aoloop_popup_button_clicked, self.aoloop_popup_menu) # set stdin non blocking, this will prevent readline to block fd = sys.stdin.fileno() flags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) # add stdin to the event loop (yorick input pipe by spawn) gobject.io_add_watch(sys.stdin,gobject.IO_IN | gobject.IO_HUP,self.yo2py) self.wfs_panel_set_sensitivity(0,0) self.dm_panel_set_sensitivity(0) # self.glade.get_widget('wfs_and_dms').hide() # declare and set default (overwritten by gui_update) self.yuserdir = "./" self.yaopardir = "/" self.pyk_debug = 0 # set size of graphic areas: dsx = int(635.*dpi/75)+4 dsy = int(650.*dpi/75)+25 self.glade.get_widget('drawingarea1').set_size_request(dsx,dsy) # self.drawingarea_size_allocate(dpi) try: with open('user1.py') as f: sys.path.append('.') from user1 import user1 self.py2yo('write \"user1.py found and included\"') parent = self.glade.get_widget('user1_vbox') self.user1 = user1(os.getcwd(),parent=parent,py2yo=self.py2yo) self.glade.get_widget('user1_label').set_text(self.user1.label()) except IOError as e: self.py2yo('write \"No user GUI (user1.py) found\"') try: with open('user2.py') as f: sys.path.append('.') from user2 import user2 self.py2yo('write \"user2.py found and included\"') parent = self.glade.get_widget('user2_vbox') self.user2 = user1(os.getcwd(),parent=parent,py2yo=self.py2yo) self.glade.get_widget('user2_label').set_text(self.user2.label()) except IOError as e: pass # self.py2yo('write \"No user GUI (user2.py) found\"') # run gtk.main() dispflag = 1 init = 0 buffer = gtk.TextBuffer() buffer2 = gtk.TextBuffer() def on_about_activate(self,wdg): dialog = self.glade.get_widget('aboutdialog') dialog.run() dialog.hide() def on_debug_toggled(self,wdg): if (wdg.get_active()): self.pyk_debug=1 self.py2yo("pyk_set pyk_debug 1") else: self.pyk_debug=0 self.py2yo("pyk_set pyk_debug 0") def on_show_wfss_and_dms_toggled(self,wdg): show_state = self.glade.get_widget('show_wfss_and_dms').get_active() if (show_state): try: s = self.size except: s = 0 self.size = self.window.get_size() self.glade.get_widget('notebook1').show() if (s): self.window.resize(s[0],s[1]) else: s = self.size self.size = self.window.get_size() self.glade.get_widget('notebook1').hide() self.window.resize(s[0],s[1]) def on_create_phase_screens_activate(self,wdg): self.set_cursor_busy(1) self.py2yo("wrap_create_phase_screens") # # EDITORS # def on_modified_editor(self,wdg): self.editor.set_title(' * '+self.yaoparfile) def on_editor_save_activate(self,wdg): # get buffer content textarea = self.glade.get_widget('textarea') self.buffer = textarea.get_buffer() params=self.buffer.get_text(self.buffer.get_start_iter(),self.buffer.get_end_iter()) # contruct/set new yaoparfile #self.yaoparfile = self.get_yaoparfile_stamped() # set main window yaoparfile entry to the new name #self.glade.get_widget('yaoparfile').set_text(self.yaoparfile) # save file f = open(self.yaopardir+'/'+self.yaoparfile,'w') f.write(params) f.close() # refresh editor window title self.editor.set_title(self.yaoparfile) self.on_aoread_clicked(wdg) def on_editor_save_as_activate(self,wdg): chooser = gtk.FileChooserDialog(title='Save YAO parfile as...',action=gtk.FILE_CHOOSER_ACTION_SAVE,buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK)) res = chooser.run() if res == gtk.RESPONSE_CANCEL: chooser.destroy() return name = chooser.get_filename() self.yaopardir = os.path.dirname(name) self.yaoparfile = os.path.basename(name) chooser.destroy() # get buffer content textarea = self.glade.get_widget('textarea') self.buffer = textarea.get_buffer() params=self.buffer.get_text(self.buffer.get_start_iter(),self.buffer.get_end_iter()) # save the content in tmp.par f = open(self.yaopardir+'/'+self.yaoparfile,'w') f.write(params) f.close() # get new name # self.yaoparfile = self.get_yaoparfile_stamped() # set parfile name to yaoparfile in main window self.glade.get_widget('yaoparfile').set_text(self.yaoparfile) # apply (triger aoread()) self.on_aoread_clicked(wdg) def on_editor_close_activate(self,wdg,*args): self.editor.hide() return True def get_yaoparfile_stamped(self): tmp = self.yaoparfile.replace('.par','') tmp = tmp+'_'+strftime("%Y%B%d_%H%M%S",localtime())+'.par' return tmp def on_modified_editor2(self,wdg): self.editor2.set_title(' * yao.conf') def on_editor2_save_activate(self,wdg): # get buffer content textarea2 = self.glade.get_widget('textarea2') self.buffer2 = textarea2.get_buffer() params=self.buffer2.get_text(self.buffer2.get_start_iter(),self.buffer2.get_end_iter()) # save file f = open(self.yuserdir+'yao.conf','w') f.write(params) f.close() self.py2yo('read_conf') self.editor2.set_title('yao.conf') def on_editor2_close_activate(self,wdg,*args): self.editor2.hide() return True # # Main Panel Events Handlers # def on_yaoparfile_activate(self,wdg): self.glade.get_widget('edit').set_sensitive(1) self.glade.get_widget('aoread').set_sensitive(1) self.glade.get_widget('aoinit').set_sensitive(0) self.glade.get_widget('aoloop').set_sensitive(0) self.glade.get_widget('go').set_sensitive(0) self.glade.get_widget('pause').set_sensitive(0) self.glade.get_widget('step').set_sensitive(0) self.glade.get_widget('restart').set_sensitive(0) self.glade.get_widget('displays').set_sensitive(0) self.glade.get_widget('wfss').set_sensitive(0) self.glade.get_widget('dms').set_sensitive(0) self.glade.get_widget('seeingframe').set_sensitive(0) self.window.set_title(wdg.get_text()) self.glade.get_widget('aoread').grab_focus() def on_yaoparfile_select_clicked(self,wdg): chooser = gtk.FileChooserDialog(title='YAO parfile selection',action=gtk.FILE_CHOOSER_ACTION_OPEN,buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) filter = gtk.FileFilter() filter.add_pattern('*.par') filter.set_name('YAO parfiles') chooser.add_filter(filter) chooser.set_current_folder(self.yaopardir) res = chooser.run() if res == gtk.RESPONSE_OK: self.yaoparfile=chooser.get_filename() self.yaoparfile=self.yaoparfile.split('/')[-1] self.glade.get_widget('yaoparfile').set_text(self.yaoparfile) self.yaopardir = chooser.get_current_folder() self.window.set_title(self.yaoparfile) chooser.destroy() self.glade.get_widget('edit').set_sensitive(1) self.glade.get_widget('aoread').set_sensitive(1) self.glade.get_widget('aoinit').set_sensitive(0) self.glade.get_widget('aoloop').set_sensitive(0) self.glade.get_widget('go').set_sensitive(0) self.glade.get_widget('pause').set_sensitive(0) self.glade.get_widget('step').set_sensitive(0) self.glade.get_widget('restart').set_sensitive(0) self.glade.get_widget('displays').set_sensitive(0) self.glade.get_widget('wfss').set_sensitive(0) self.glade.get_widget('dms').set_sensitive(0) self.glade.get_widget('seeingframe').set_sensitive(0) self.glade.get_widget('aoread').grab_focus() def on_edit_clicked(self,wdg): self.editor.set_title(self.yaoparfile) self.editor.show() f = open(self.yaopardir+'/'+self.yaoparfile,'r') params = f.read() f.close() self.buffer.set_text(params) self.buffer.connect('changed',self.on_modified_editor) textarea = self.glade.get_widget('textarea') textarea.set_buffer(self.buffer) def on_edit2_activate(self,wdg): self.editor2.set_title('yao.conf') self.editor2.show() f = open(self.yuserdir+'yao.conf','r') params = f.read() f.close() self.buffer2.set_text(params) self.buffer2.connect('changed',self.on_modified_editor2) textarea2 = self.glade.get_widget('textarea2') textarea2.set_buffer(self.buffer2) def on_aoread_clicked(self,wdg): self.set_cursor_busy(1) yaoparfile=self.glade.get_widget('yaoparfile').get_text() self.py2yo('pyk_set yaopardir "%s"' % self.yaopardir) self.py2yo('pyk_set yaoparfile "%s"' % yaoparfile) self.py2yo('wrap_aoread') self.glade.get_widget('aoinit').set_sensitive(1) self.glade.get_widget('aoloop').set_sensitive(0) self.glade.get_widget('go').set_sensitive(0) self.glade.get_widget('pause').set_sensitive(0) self.glade.get_widget('step').set_sensitive(0) self.glade.get_widget('restart').set_sensitive(0) self.glade.get_widget('displays').set_sensitive(0) self.glade.get_widget('seeingframe').set_sensitive(0) self.glade.get_widget('aoinit').grab_focus() self.glade.get_widget('wfss').set_sensitive(1) self.glade.get_widget('dms').set_sensitive(1) self.progressbar.set_fraction(0.) self.progressbar.set_text('') self.init = 0 self.py2yo('pyk_set initdone 0') def on_aoinit_clicked(self,wdg): self.set_cursor_busy(1) self.set_aoinit_flags() self.py2yo('do_aoinit_disp') self.glade.get_widget('aoloop').set_sensitive(1) self.glade.get_widget('aoloop').grab_focus() self.progressbar.set_fraction(0.) self.progressbar.set_text('') self.init = 1 self.py2yo('pyk_set initdone 1') def on_aoinit_popup_button_clicked(self,wdg,event): if event.type == gtk.gdk.BUTTON_PRESS: wdg.popup(None, None, None, event.button, event.time) # Tell calling code that we have handled this event the buck return True # Tell calling code that we have not handled this event pass it on. return False def set_aoinit_flags(self): disp = self.glade.get_widget('aoinit_disp').get_active() clean = self.glade.get_widget('aoinit_clean').get_active() forcemat = self.glade.get_widget('aoinit_forcemat').get_active() svd = self.glade.get_widget('aoinit_svd').get_active() keepdmconfig = self.glade.get_widget('aoinit_keepdmconfig').get_active() self.py2yo('set_aoinit_flags %d %d %d %d %d' % (disp,clean,forcemat,svd,keepdmconfig)) def set_aoloop_flags(self): disp = self.glade.get_widget('aoloop_disp').get_active() savecb = self.glade.get_widget('aoloop_savecb').get_active() reinit = self.glade.get_widget('aoloop_no_reinit_wfs').get_active() self.py2yo('set_aoloop_flags %d %d %d' % (disp,savecb,reinit)) def on_aoloop_popup_button_clicked(self,wdg,event): if event.type == gtk.gdk.BUTTON_PRESS: wdg.popup(None, None, None, event.button, event.time) # Tell calling code that we have handled this event the buck return True # Tell calling code that we have not handled this event pass it on. return False def on_aoloop_clicked(self,wdg): self.set_cursor_busy(1) self.glade.get_widget('go').set_sensitive(1) self.glade.get_widget('pause').set_sensitive(1) self.glade.get_widget('step').set_sensitive(1) self.glade.get_widget('restart').set_sensitive(1) self.glade.get_widget('displays').set_sensitive(1) self.glade.get_widget('wfss').set_sensitive(1) self.glade.get_widget('dms').set_sensitive(1) self.glade.get_widget('seeingframe').set_sensitive(1) # self.glade.get_widget('loopgain').set_sensitive(1) # self.glade.get_widget('imlambda').set_sensitive(1) self.glade.get_widget('go').grab_focus() disprate = self.glade.get_widget('disp_rate').get_value() self.py2yo('do_aoloop_disp %d' % disprate) def on_go_clicked(self,wdg): #self.py2yo('toggle_animate 1') self.py2yo('cont') def on_pause_clicked(self,wdg): self.py2yo('stop') #self.py2yo('toggle_animate 0') def on_step_clicked(self,wdg): self.py2yo('go 1') def on_restart_clicked(self,wdg): self.glade.get_widget('go').set_sensitive(1) self.glade.get_widget('pause').set_sensitive(1) self.glade.get_widget('step').set_sensitive(1) self.py2yo('do_aoloop_disp') def aoloop_to_end(self): self.glade.get_widget('go').set_sensitive(0) self.glade.get_widget('pause').set_sensitive(0) self.glade.get_widget('step').set_sensitive(0) # # Display Panel Events Handlers # def disp_panel_set_sensitivity(self,sens): self.glade.get_widget('disp_rate').set_sensitive(sens) self.glade.get_widget('disp_label').set_sensitive(sens) self.glade.get_widget('instavg_label').set_sensitive(sens) self.glade.get_widget('instavg_hbox').set_sensitive(sens) def on_disp_pause_clicked(self,wdg): #self.py2yo('toggle_animate 0') self.py2yo('fma') self.py2yo('funcset dispFlag 10000') self.disp_panel_set_sensitivity(0) self.glade.get_widget('disp_pause').set_sensitive(0) self.glade.get_widget('disp_resume').set_sensitive(1) def on_disp_resume_clicked(self,wdg): self.py2yo('funcset dispFlag %d' % self.dispflag) #self.py2yo('toggle_animate 1') self.disp_panel_set_sensitivity(1) self.glade.get_widget('disp_pause').set_sensitive(1) self.glade.get_widget('disp_resume').set_sensitive(0) def on_image_disp_inst_clicked(self,wdg): if wdg.get_active(): self.py2yo('toggle_im_imav 0') def on_image_disp_avg_clicked(self,wdg): if wdg.get_active(): self.py2yo('toggle_im_imav 1') def on_disp_rate_value_changed(self,wdg): self.dispflag = wdg.get_value() self.py2yo('funcset dispFlag %d' % self.dispflag) # # General parameters Panel Events Handlers # def on_seeing_value_changed(self,wdg): self.py2yo('change_seeing %f' % wdg.get_value()) def on_loopgain_value_changed(self,wdg): if self.init: self.py2yo('set_loop_gain %f' % wdg.get_value()) def on_imlambda_value_changed(self,wdg): if self.init: self.py2yo('change_target_lambda %f' % wdg.get_value()) # # WFS parameters Panel Events Handlers # def on_subtract_background_toggled(self,wdg): if self.init: self.py2yo('wfs_subtract_background %d' % wdg.get_active()) def on_noise_toggled(self,wdg): if self.init: # if wdg.get_active(): # self.py2yo('set_wfs_noise 1') # else: # self.py2yo('set_wfs_noise 0') self.py2yo('set_wfs_noise %d' % wdg.get_active()) def on_correct_up_tt_toggled(self,wdg): if self.init: self.py2yo('wfs_set_uptt %d' % wdg.get_active()) def on_efd_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_efd %f' % wdg.get_value()) def on_pyr_mod_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_pyr_mod %f' % wdg.get_value()) def on_gsmag_value_changed(self,wdg): if self.init: self.py2yo('set_gs_mag %f' % wdg.get_value()) def on_gsalt_value_changed(self,wdg): if self.init: self.py2yo('set_gs_alt %f' % wdg.get_value()) def on_gsdepth_value_changed(self,wdg): if self.init: self.py2yo('set_gs_depth %f' % wdg.get_value()) def on_ron_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_ron %f' % wdg.get_value()) def on_sh_threshold_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_threshold %f' % wdg.get_value()) def on_sh_kernel_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_kernel %f' % wdg.get_value()) def on_ninteg_cycles_value_changed(self,wdg): if self.init: self.py2yo('set_wfs_nintegcycles %f' % wdg.get_value()) def y_set_nwfs(self,nwfs): self.nwfs = nwfs for i in range(nwfs): self.glade.get_widget('wfs'+str(i+1)).show() self.glade.get_widget('wfs'+str(i+1)).set_active(0) def on_wfs_select_toggled(self,wdg): for i in range(self.nwfs): ok = self.glade.get_widget('wfs'+str(i+1)).get_active() self.py2yo('set_okwfs %d %d' % (i+1,ok)) def wfs_panel_set_sensitivity(self,sens,wfstype): # sens = 0 or 1 # wfstype = 1 (sh), 2 (curvature) or 3 (pyramid) (0=undefined) self.glade.get_widget('subtract_background').set_sensitive(sens) self.glade.get_widget('noise').set_sensitive(sens) self.glade.get_widget('correct_up_tt').set_sensitive(sens) self.glade.get_widget('efd').set_sensitive(sens) self.glade.get_widget('pyr_mod').set_sensitive(sens) self.glade.get_widget('gsmag').set_sensitive(sens) self.glade.get_widget('gsalt').set_sensitive(sens) self.glade.get_widget('gsdepth').set_sensitive(sens) self.glade.get_widget('ron').set_sensitive(sens) self.glade.get_widget('sh_threshold').set_sensitive(sens) self.glade.get_widget('sh_kernel').set_sensitive(sens) self.glade.get_widget('ninteg_cycles').set_sensitive(sens) if (wfstype!=1): self.glade.get_widget('sh_threshold').set_sensitive(0) self.glade.get_widget('sh_kernel').set_sensitive(0) self.glade.get_widget('gsalt').set_sensitive(0) self.glade.get_widget('gsdepth').set_sensitive(0) self.glade.get_widget('correct_up_tt').set_sensitive(0) if (wfstype!=2): self.glade.get_widget('efd').set_sensitive(0) if (wfstype!=3): self.glade.get_widget('pyr_mod').set_sensitive(0) # # DM parameters Panel Events Handlers # def on_dmreset_clicked(self,wdg): self.py2yo('dm_reset') def on_dmflatten_clicked(self,wdg): self.py2yo('dm_flatten') def on_dmgain_value_changed(self,wdg): self.py2yo('dm_gain %f' % wdg.get_value()) def on_xmisreg_value_changed(self,wdg): self.py2yo('dm_xmisreg %f' % wdg.get_value()) def on_ymisreg_value_changed(self,wdg): self.py2yo('dm_ymisreg %f' % wdg.get_value()) def on_sat_voltage_value_changed(self,wdg): self.py2yo('dm_satvolt %f' % wdg.get_value()) def y_set_ndm(self,ndm): self.ndm = ndm for i in range(ndm): self.glade.get_widget('dm'+str(i+1)).show() self.glade.get_widget('dm'+str(i+1)).set_active(0) def on_dm_select_toggled(self,wdg): for i in range(self.ndm): ok = self.glade.get_widget('dm'+str(i+1)).get_active() self.py2yo('set_okdm %d %d' % (i+1,ok)) def dm_panel_set_sensitivity(self,sens): # sens = 0 or 1 self.glade.get_widget('dmreset').set_sensitive(sens) self.glade.get_widget('dmflatten').set_sensitive(sens) self.glade.get_widget('extrapolated').set_sensitive(sens) self.glade.get_widget('dmgain').set_sensitive(sens) self.glade.get_widget('xmisreg').set_sensitive(sens) self.glade.get_widget('ymisreg').set_sensitive(sens) self.glade.get_widget('sat_voltage').set_sensitive(sens) # # Yorick to Python Wrapper Functions # def y_parm_update(self,name,val): self.glade.get_widget(name).set_value(val) def y_text_parm_update(self,name,txt): self.glade.get_widget(name).set_text(txt) def y_set_checkbutton(self,name,val): self.glade.get_widget(name).set_active(val) def pyk_error(self,msg): dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,buttons=gtk.BUTTONS_OK,message_format=msg) dialog.run() dialog.destroy() def pyk_info(self,msg): dialog = gtk.MessageDialog(type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_OK,message_format=msg) dialog.run() dialog.destroy() def pyk_info_w_markup(self,msg): dialog = gtk.MessageDialog(type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_OK) dialog.set_markup(msg) # dialog.set_size_request(600,-1) dialog.run() dialog.destroy() def pyk_warning(self,msg): dialog = gtk.MessageDialog(type=gtk.MESSAGE_WARNING,buttons=gtk.BUTTONS_OK,message_format=msg) dialog.run() dialog.destroy() def on_quit1_activate(self,*args): # tell the ascam image server to quit (or not?) self.py2yo('yaopy_quit') # raise SystemExit def on_window1_map_event(self,wdg,*args): drawingarea = self.glade.get_widget('drawingarea1') mwid = drawingarea.window.xid; self.py2yo('yao_win_init %d' % mwid) # update parameters from yorick: self.py2yo('gui_update') # def on_drawingarea1_map_event(self,wdg,*args): # # only reparent once the widget is mapped. # # note this only need to happen once # mwid = wdg.window.xid; # self.py2yo('yao_win_init %d' % mwid) # # update parameters from yorick: # self.py2yo('gui_update') # return False # # minimal wrapper for yorick/python communication # def yo2py_flush(self): sys.stdin.flush() def py2yo(self,msg): # sends string command to yorick's eval sys.stdout.write(msg+'\n') sys.stdout.flush() def yo2py(self,cb_condition,*args): if cb_condition == gobject.IO_HUP: raise SystemExit, "lost pipe to yorick" # handles string command from yorick # note: individual message needs to end with /n for proper ungarbling while 1: try: msg = sys.stdin.readline() msg = "self."+msg # self.py2yo('\"%s\"' % msg) try: exec(msg) except Exception, e: sys.stderr.write('yo2py eval: '+str(e)+'\n') except IOError, e: if e.errno == errno.EAGAIN: # the pipe's empty, good break # else bomb out raise SystemExit, "yo2py unexpected IOError:" + str(e) except Exception, ee: raise SystemExit, "yo2py unexpected Exception:" + str(ee) # carefull with the ident here return True def set_cursor_busy(self,state): if state: self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) else: self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) if len(sys.argv) != 3: print 'Usage: yao.py path_to_glade dpi' raise SystemExit path2glade = str(sys.argv[1]) dpi = int(sys.argv[2]) top = yao(path2glade,dpi) yao-5.4.0/yao_disp.i000066400000000000000000000025251234404334100142730ustar00rootroot00000000000000/* yao_disp * Proof of concept to display yao data from an external * yao process dedicated to display * This should have 2 main advantages: * - it doesn't take resources from the main yao process * - it allows for a clean separation of both function, code-wise and * performance wise. Possibly allows for easiest coding of * display-on-demand, i.e. the user selects what he/she wants to * display (e.g. psf, phase) * Right now, this si just a test that display wfs image and residual * phase for wfs #1 (only for shwfs). But it works. Some sync issues, * plus I need to code how to launch this (probably with spawn within * a yao session, not sure) */ require,"svipc.i"; require,"yao.i"; shmkey=0x0badcafe; semkey=0x0badbeef; shm_init,shmkey; max_disp_freq = 1.; status = create_yao_window(); shm_var,shmkey,swrite(format="wfs%d_fimage",1),ffimage; shm_var,shmkey,swrite(format="wfs%d_phase",1),phase; loopCounter = shm_read(shmkey,"loop_counter")(1); func yao_disp(void) { extern loopCounter; lc = shm_read(shmkey,"loop_counter")(1); if (loopCounter==lc) { // no display, just wait some small amount of time after,0.1/max_disp_freq,yao_disp; return; } loopCounter = lc; write,format="Loop Counter = %d\n",loopCounter; fma; plsys,1; pli,phase; plsys,2; pli,ffimage; after,1./max_disp_freq,yao_disp; } yao-5.4.0/yao_dm.i000066400000000000000000001047201234404334100137340ustar00rootroot00000000000000/* * yao_dm.i * * Compilation of functions related to Deformable Mirrors * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ func make_pzt_dm(nm,&def,disp=) /* DOCUMENT function make_pzt_dm2(dm_structure,disp=) the influence functions are in microns per volt. */ { gui_progressbar_frac,0.; gui_progressbar_text,swrite(format="Computing Influence Functions for DM#%d",nm); coupling=dm(nm).coupling; // best parameters, as determined by a multi-dimensional fit // (see coupling3.i) a=[4.49469,7.25509,-32.1948,17.9493]; p1 = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; a = [2.49456,-0.65952,8.78886,-6.23701]; p2 = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; a = [1.16136,2.97422,-13.2381,20.4395]; irc = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; if (sim.debug>=2) write,format="p1=%f p2=%f ir=%f\n",p1,p2,irc; dim = dm(nm)._n2-dm(nm)._n1+1; size = sim._size; nxact = dm(nm).nxact; cobs = tel.cobs; cent = sim._cent; pitch = dm(nm).pitch; /* ir = pitch*1.2; ir = pitch*1.46; ir = pitch*1.65; c = 3.8; p1 = 3.9; p2 = 2.4; ir = pitch*1.20; // good. no. coupling 8% too low c = 3.8; p1 = 4; p2 = 2.4; ir = pitch*1.65; c = 3.75; p1 = 4.2; p2 = 2.5; ir = pitch*1.25; //ok, coupling=13% c = 3.74; p1 = 3.805; p2 = 2.451; ir = pitch*1.4; //good, coupling=17% c = 4; p1 = 3.84; p2 = 2.5; ir = pitch*1.5; //good, coupling=20% c = 3.74; p1 = 3.805; p2 = 2.451; ir = pitch*1.4; //good, coupling=17% */ ir = irc*pitch; bord = 0; cub = array(float,nxact+bord*2,nxact+bord*2,4); // make X and Y indices array: xy = indices(nxact+bord*2); // express "centered" coordinate of actuator in pixels: xy = (xy-1.-bord-(nxact-1.)/2.)*pitch; // fill cub (X coord and Y coord): cub(,,1) = xy(,,1); cub(,,2) = xy(,,2); if (dm(nm).xflip) cub(,,1) = cub(::-1,,1); if (dm(nm).yflip) cub(,,2) = cub(,::-1,2); // check on 2014feb07 that coordinates are updated too (somehow). dis = sqrt(cub(,,1)^2.+cub(,,2)^2.); if (dm(nm).pitchMargin == 0) { pitchMargin = 1.44; } else { pitchMargin = dm(nm).pitchMargin; } rad = ((nxact-1.)/2.+pitchMargin)*pitch; //+1.44 is the margin inbigcirc= where(dis < rad); // 1 if valid actuator, 0 if not: // selection is done after interaction matrix is done cub(,,3) = 1; // 1 if valid guard ring actuator, 0 if not: //cub(,,4) = (dis >= (pupr+extent*pitch)) & (dis < (pupr+(1.+extent)*pitch)); // I don't use extrapolation actuator anymore. cub(,,4) = 0.; // converting to array coordinates: cub(,,1) = cub(,,1)+cent; cub(,,2) = cub(,,2)+cent; cub = cub(*,); // cub now has two indices: first one is actuator number (valid or extrap) // second one is: 1:Xcoord, 2:Ycoord, 3:valid?, 4:extrapolation actuator? // filtering actuators outside of a disk radius = rad (see above) cub = cub(inbigcirc,); cubval = cub(where(cub(,3)),); nvalid = int(sum(cubval(,3))); xy = indices(size); // x = xy(,,2); y = xy(,,1); x = xy(,,1); y = xy(,,2); def = array(float,dim,dim,nvalid); dm(nm)._x = &(cubval(,1)); dm(nm)._y = &(cubval(,2)); x = x(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2); y = y(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2); if (sim.verbose != 0) {write,format="\nCreating Influence function for actuator #%s","";} tmp=pitch/abs(ir); c = (coupling - 1.+ tmp^p1)/(log(tmp)*tmp^p2); for (i=1;i<=nvalid;i++) { if (sim.verbose != 0) write,format="%d ",i; if (dm(nm).irexp==1) { irfact = dm(nm).irfact; tmp = sqrt( ((x-cubval(i,1))/ir*irfact)^2.+((y-cubval(i,2))/ir*irfact)^2. ); def(,,i) = exp(-(tmp)^1.5); } else if (dm(nm).irexp==2) { //IF fitted from Hadamard experimental iMat: // a_had = [0.2506,8.37,2.24497,26.2,0,0];//BETTER SET OF PARAM !!! a_had = [26.2,8.37]/8.*dm(nm).pitch; // make sure which sinc we're using: if (abs(sinc(1.))<1e-10) fact=1.; else fact=pi; def(,,i)= (sinc(fact * sqrt((x-cubval(i,1))^2.)/a_had(1))* \ sinc(fact * sqrt((y-cubval(i,2))^2.)/a_had(1))* \ exp(-((x-cubval(i,1))/a_had(2))^2. \ -((y-cubval(i,2))/a_had(2))^2. )); } else { if (coupling == 0){ tmpx = pitch - abs(abs(x)-cubval(i,1)); tmpy = pitch - abs(abs(y)-cubval(i,2)); tmp = tmpx*tmpy; def(,,i) = tmp*(tmpx > 0)*(tmpy > 0.); } else { tmpx = clip(abs((x-cubval(i,1))/ir),1e-8,2.); tmpy = clip(abs((y-cubval(i,2))/ir),1e-8,2.); tmp = (1.-tmpx^p1+c*log(tmpx)*tmpx^p2)* \ (1.-tmpy^p1+c*log(tmpy)*tmpy^p2); def(,,i) = tmp*(tmpx <= 1.)*(tmpy <= 1.); } } if ((disp == 1) && (sim.debug == 2)) {fma; pli,def(,,i);} } if (sim.verbose) write,""; tmp=pitch/abs(ir); coupling = 1.- tmp^p1 + c*log(tmp)*tmp^p2; if (sim.debug>=1) write,format="coupling=%.2f%% ",coupling*100; // look for extrapolation actuator stuff in v1.0.8 if needed fact = dm(nm).unitpervolt/max(def); def = float(def*fact); dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; if (sim.debug>=1) { piston=def(,,sum)*ipupil(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2); tv,piston; } if (dm(nm)._puppixoffset!=[]) { // ok, so for now we'll do the following: // influence functions are actually shifted in comp_dm_shape, // so that the offset can be used for all types of DM. // here we also propagate on the IF coordinates, for completeness. // this may seem weird to someone that look at the defs later, // and compare to the coordinates, but, ok... *dm(nm)._x += dm(nm)._puppixoffset(1) *dm(nm)._y += dm(nm)._puppixoffset(2) } clean_progressbar; return def; } //---------------------------------------------------- func make_pzt_dm_elt(nm,&def,disp=) /* DOCUMENT function make_pzt_dm_elt(dm_structure,disp=) the influence functions are in microns per volt. same as make_pzt_dm but returns only local IF and start indices */ { coupling=dm(nm).coupling; // best parameters, as determined by a multi-dimensional fit // (see coupling3.i) a=[4.49469,7.25509,-32.1948,17.9493]; p1 = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; a = [2.49456,-0.65952,8.78886,-6.23701]; p2 = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; a = [1.16136,2.97422,-13.2381,20.4395]; irc = a(1)+a(2)*coupling+a(3)*coupling^2+a(4)*coupling^3; if (sim.debug>=2) write,format="p1=%f p2=%f ir=%f\n",p1,p2,irc; dim = dm(nm)._n2-dm(nm)._n1+1; size = sim._size; nxact = dm(nm).nxact; cent = sim._cent; pitch = dm(nm).pitch; if (dm(nm).coupling == 0){ smallsize = long(2*pitch); dm(nm)._eltdefsize = smallsize; xy = indices(smallsize)-smallsize/2-0.5; x = xy(,,1); y = xy(,,2); tmpx = abs(abs(x)-pitch)/pitch; tmpy = abs(abs(y)-pitch)/pitch; def = tmpx*tmpy; } else { ir = irc*pitch; tmp=pitch/abs(ir); c = (coupling - 1.+ tmp^p1)/(log(tmp)*tmp^p2); // compute IF on partial (local) support: smallsize = long(ceil(2*ir+10)); dm(nm)._eltdefsize = smallsize; xy = indices(smallsize)-smallsize/2-0.5; x = xy(,,1); y = xy(,,2); tmpx = clip(abs(x/ir),1e-8,2.); tmpy = clip(abs(y/ir),1e-8,2.); tmp = (1.-tmpx^p1+c*log(tmpx)*tmpx^p2)*(1.-tmpy^p1+c*log(tmpy)*tmpy^p2); def = tmp*(tmpx <= 1.)*(tmpy <= 1.); } // compute location (x,y and i,j) of each actuator: cub = array(float,nxact,nxact,2); // make X and Y indices array: xy = indices(nxact); // express "centered" coordinate of actuator in pixels: xy = (xy-1.-(nxact-1.)/2.)*pitch; // fill cub (X coord and Y coord): cub(,,1) = xy(,,1); cub(,,2) = xy(,,2); if (dm(nm).xflip) cub(,,1) = cub(::-1,,1); if (dm(nm).yflip) cub(,,2) = cub(,::-1,2); // the following determine if an actuator is to be considered or not // relative to the pitchmargin parameter. dis = sqrt(cub(,,1)^2.+cub(,,2)^2.); if (dm(nm).pitchMargin == 0) { pitchMargin = 1.44; } else { pitchMargin = dm(nm).pitchMargin; } rad = ((nxact-1.)/2.+pitchMargin)*pitch; inbigcirc= where(dis < rad); // 1 if valid actuator, 0 if not: // converting to array coordinates: cub += cent; cub = cub(*,); // cub now has two indices: first one is actuator number // second one is: 1:Xcoord, 2:Ycoord // filtering actuators outside of a disk radius = rad (see above) cubval = cub(inbigcirc,); dm(nm)._nact = dimsof(cubval)(2); // following 4 lines changed on 2007apr19 to be consistent with order // with elt=0 (and thus consistent with how subapertures are numbered) dm(nm)._x = &(cubval(,1)); dm(nm)._y = &(cubval(,2)); dm(nm)._i1 = &(int(long(cubval(,1)-smallsize/2+0.5)-dm(nm)._n1)); dm(nm)._j1 = &(int(long(cubval(,2)-smallsize/2+0.5)-dm(nm)._n1)); def = def(,,-)*array(1.f,dm(nm)._nact)(-,-,); if (dm(nm)._puppixoffset!=[]) { // see comment above in make_pzt_dm *dm(nm)._x += dm(nm)._puppixoffset(1) *dm(nm)._y += dm(nm)._puppixoffset(2) } // look for extrapolation actuator stuff in v1.0.8 if needed fact = dm(nm).unitpervolt/max(def); def = float(def*fact); dm(nm)._def = &def; return def; } //---------------------------------------------------- func make_kl_dm(nm,&def,disp=) /* DOCUMENT function make_kl_dm,dm_number,ActIF,disp= */ { require,"yaokl.i"; gui_progressbar_frac,0.; gui_progressbar_text,swrite(format="Computing Influence Functions for DM#%d: KL",nm); dim = dm(nm)._n2-dm(nm)._n1+1; // nkllow = dm(nm).nklfiltered; nkllow = 1; nkl = dm(nm).nkl; cent = sim._cent; psize = tel.diam/sim.pupildiam; gsdist = sqrt((abs(wfs.gspos)^2.)(sum,)); patchDiam = long(ceil((sim.pupildiam+2*max(gsdist)* 4.848e-6*abs(dm(nm).alt)/psize)/2)*2); // prepzernike,dim,patchDiam,sim._cent-dm(nm)._n1+1,sim._cent-dm(nm)._n1+1; if (dm(nm).alt==0) { // enforce pupil to be system pupil. i1 = sim._size/2 - sim.pupildiam/2+1; i2 = sim._size/2 + sim.pupildiam/2; outpup = ipupil(i1:i2,i1:i2); //patchDiam should be good. write,format="KL: PatchDiam = %d, sim.pupildiam=%d\n",patchDiam,sim.pupildiam; cobs = tel.cobs; } else { outpup = []; cobs = 0.; patchDiam += 2; // margin } kl = float(make_kl(nkl,patchDiam,varkl,outbas,outpup,oc=cobs,nr=128)); // order them in a similar order as zernike: kl = order_kls(kl,patchDiam,upto=20); def = array(float,dim,dim,nkl-nkllow+1); n1 = dim/2-patchDiam/2+1; n2 = n1+patchDiam-1; for (i=nkllow;i<=nkl;i++) { def(n1:n2,n1:n2,i-nkllow+1) = kl(,,i); if (disp == 1) {fma; pli,def(,,i-nkllow+1);} } if (sim.verbose>=1) {write,format="Number of KL :%d\n",nkl-nkllow+1;} // the KL are normalized so that rms over surface = 1 unit // meaning the TT go from -2 to 2. // we'll use the same normalization as zernike, just for consistency // current: over tel.diam, we have 4 units, and a rms of 1 we want a // rms of 957nm = 0.957microns def = def * 0.957f * float(dm(nm).unitpervolt); dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; return def; } //---------------------------------------------------- func make_zernike_dm(nm,&def,disp=) /* DOCUMENT function make_zernike_dm,dm_structure,ActIF,disp= modified 2004jan22 to have scaled as tip-tilt (e.g. 1 arcsec/volt). */ { gui_progressbar_frac,0.; gui_progressbar_text,swrite(format="Computing Influence Functions for DM#%d: Zernikes",nm); dim = dm(nm)._n2-dm(nm)._n1+1; nzer = dm(nm).nzer; minzer = dm(nm).minzer; cobs = tel.cobs; cent = sim._cent; psize = tel.diam/sim.pupildiam; // below: bug discovered 2009mar24: << REDO mcao matrices // was using linear distance (abs(wfs.gspos), not working), not XY !!! gsdist = sqrt((abs(wfs.gspos)^2.)(sum,)); patchDiam = sim.pupildiam+2*max(gsdist)*4.848e-6*abs(dm(nm).alt)/psize; prepzernike,dim,patchDiam,sim._cent-dm(nm)._n1+1,sim._cent-dm(nm)._n1+1; def = array(float,dim,dim,nzer-minzer+1); for (i=1;i<=(nzer-minzer+1);i++) { def(,,i) = zernike_ext(i+minzer-1); if (disp == 1) {fma; pli,def(,,i);} gui_progressbar_frac,float(i)/(nzer-minzer+1.); } if (sim.verbose>=1) {write,format="Number of zernike :%d\n",nzer;} // normalization factor: one unit of tilt gives 1 arcsec: z2 = zernike_ext(2); current = z2(dim/2,dim/2)-z2(dim/2-1,dim/2); fact = (dm(nm).unitpervolt*tel.diam/sim.pupildiam)*4.848/current; def = float(def*fact); dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; clean_progressbar; return def; } //---------------------------------------------------- func make_dh_dm(nm,&def,disp=) /* DOCUMENT function make_diskharm_dm,dm_structure adapted on 2010jun from the modal zernike dm function above. */ { gui_progressbar_frac,0.; gui_progressbar_text,swrite(format="Computing Influence Functions for DM#%d: disk harmonics",nm); dim = dm(nm)._n2-dm(nm)._n1+1; cobs = tel.cobs; ndh = dm(nm).ndh; // create this variable in dm structure cent = sim._cent; psize = tel.diam/sim.pupildiam; gsdist = sqrt((abs(wfs.gspos)^2.)(sum,)); patchDiam = sim.pupildiam+2*max(gsdist)*4.848e-6*abs(dm(nm).alt)/psize; def = float(make_diskharmonic(dim,patchDiam,ndh,xc=cent-dm(nm)._n1+1,yc=cent-dm(nm)._n1+1)); if (sim.verbose>=1) {write,format="Number of DH modes :%d\n",ndh;} // I am not sure if the normalization factor is correct for DH, but I am leaving it! (aurea) // normalization factor: one unit of tilt gives 1 arcsec: // current = def(dim/2,dim/2,3)-def(dim/2-1,dim/2,3); // fact = (dm(nm).unitpervolt*tel.diam/sim.pupildiam)*4.848/current; fact = dm(nm).unitpervolt; def = float(def*fact); dm(nm)._nact = (dimsof(def))(4); // This is equal to ndh dm(nm)._def = &def; clean_progressbar; return def; } //---------------------------------------------------- func make_tiptilt_dm(nm,&def,disp=) /* DOCUMENT function make_tiptilt_dm,dm_structure,ActIF,disp= adapted from makeZernikeIF modified 2004jan22 to make it normalized at 1" */ { dim = dm(nm)._n2-dm(nm)._n1+1; nzer = 2; cobs = tel.cobs; cent = sim._cent; psize = tel.diam/sim.pupildiam; patchDiam = sim.pupildiam+2*max(abs(wfs.gspos))* 4.848e-6*abs(dm(nm).alt)/psize; prepzernike,dim,patchDiam,sim._cent-dm(nm)._n1+1,sim._cent-dm(nm)._n1+1; def = array(float,dim,dim,nzer); for (i=1;i<=nzer;i++) { def(,,i) = zernike_ext(i+1); if (disp == 1) {fma; pli,def(,,i);} } // normalization factor: one unit of tilt gives 1 arcsec: current = def(dim/2,dim/2,1)-def(dim/2-1,dim/2,1); fact = (dm(nm).unitpervolt*tel.diam/sim.pupildiam)*4.848/current; def = float(def*fact); dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; return def; } //---------------------------------------------------- func make_curvature_dm(nm,&def,disp=,cobs=) /* DOCUMENT: func make_curvature_dm,dm_structure,&def,disp= This function build up the curvature mirror influence functions dim = output dimension of arrays pupd = pupil diameter in pixels SupportRadius = Radius at which the support points are located CompDim = Array dimension used for Computations of IFs (usually 4-8 x pupd) NOT NORMALIZED IN ANY WAY (arbitrary divided by 50 so that one gets acceptable phase for imat with a few tens volts. */ { extern actNumIm; local WhichRing,ActThetaIn,ActThetaOut,ActRadiusIn,ActRadiusOut; gui_progressbar_frac,0.; gui_progressbar_text,"Computing Influence Functions"; dimdef = dm(nm)._n2-dm(nm)._n1+1; dim = sim._size; pupd = sim.pupildiam; psize = tel.diam/sim.pupildiam; // pixel in meter patchDiam = sim.pupildiam+2*max(abs(wfs.gspos))* 4.848e-6*abs(dm(nm).alt)/psize; SupportRadius = 2.2; CompDim = dim*2; NRing = sum(*(dm(nm).nelperring) != 0); // Number of Rings NActPerRing = (*(dm(nm).nelperring))(1:NRing); NAct = sum(NActPerRing); // Compute the internal and external radius of each rings // given the number of actuators per rings: SurfOneAct = pi/sum(NActPerRing); // Surface of one actuator RInRing = array(float,NRing); // Internal Radius ROutRing = array(float,NRing); // External Radius if (is_set(cobs)) {RInRing(1) = cobs;} // loop on ring number for (i=1;i<=NRing;i++) { ROutRing(i) = sqrt(NActPerRing(i)*SurfOneAct/pi+RInRing(i)^2.); if (i != NRing) RInRing(i+1) = ROutRing(i); } if (is_set(cobs)) {RInRing(1) = 0.;} ROutRing(NRing) = 1.6; // RInRing(NRing) = 1.05; // now we got to determine the inner and outer radius and angle for // each actuators: WhichRing = array(1,NActPerRing(1)); // Ring index per actuator for (i=2;i<=NRing;i++) {grow,WhichRing,array(i,NActPerRing(i));} // offset angle of first electrode in rings: if (*dm(nm).angleoffset==[]) angleoffset=array(0.,NRing); else angleoffset=(*dm(nm).angleoffset)*pi/180.; // if rint and rout are specified, use it instead: if ((*dm(nm).rint)!=[]) RInRing=*dm(nm).rint; if ((*dm(nm).rout)!=[]) ROutRing=*dm(nm).rout; if (dm(nm).supportRadius) SupportRadius=dm(nm).supportRadius; // loop to determine radiuses and angle: for (i=1;i<=NRing;i++) { dtheta = 2*pi/NActPerRing(i) for (j=1;j<=NActPerRing(i);j++) { t1 = (j-1.)*dtheta + angleoffset(i); t2 = t1+dtheta; grow,ActThetaIn,t1 ; grow,ActThetaOut,t2 ; grow,ActRadiusIn,RInRing(i) ; grow,ActRadiusOut,ROutRing(i) ; } } // Now build the actuator images: x = span(1,CompDim,CompDim)(,-:1:CompDim)-CompDim/2.-1; y = transpose(x); ang = atan(y,x); // ang = atan(x,y); ang1 = ang + (ang < 0)*2*pi; ang2 = (ang1+pi)%(2*pi)+pi; // rad = dist(CompDim)/(pupd/2.); rad = dist(CompDim)/(patchDiam/2.); d2 = clip(eclat(dist(CompDim)^2.),1e-5,); cpupil = rad < 1.; supportOffset=90.; if (dm(nm).supportOffset!=[]) supportOffset=dm(nm).supportOffset; supportOffset *= (pi/180.); tmp = abs(rad-SupportRadius)*5 + abs(ang1-0*pi/3-supportOffset) ; Support1 = where(tmp == min(tmp))(1); tmp = abs(rad-SupportRadius)*5 + abs(ang1-2*pi/3-supportOffset) ; Support2 = where(tmp == min(tmp))(1); tmp = abs(rad-SupportRadius)*5 + abs(ang1-4*pi/3-supportOffset) ; Support3 = where(tmp == min(tmp))(1); def = array(float,dimdef,dimdef,NAct); i1 = CompDim/2-dim/2+1; i2 = CompDim/2+dim/2; tmp = array(1.,CompDim,CompDim); tmp = tmp-0.5*cpupil tmp(Support1) = 0; tmp(Support2) = 0; tmp(Support3) = 0; if (disp == 1) {fma; pli, tmp; limits;} for (i=1;i<=NAct;i++) { // the following to avoid issues due to discontinuity of ang array at 0=2pi if (ActThetaOut(i)>(2*pi)) ang=ang2; else ang=ang1; Act = (rad >= ActRadiusIn(i)) * (rad < ActRadiusOut(i)) * \ (ang >= ActThetaIn(i)) * (ang < ActThetaOut(i)); if (i==1) { actNumIm = Act; } else { actNumIm += Act*i; } aif = fft(fft(eclat(long(Act)),1)/d2,-1); aif.re = eclat(aif.re); aif.im = eclat(aif.im); // aif = aif - (aif(Support2)-aif(Support3))*y/(y(Support2)-y(Support3)); // aif = aif - (aif(Support1)-aif(Support2))*x/(x(Support1)-x(Support2)); xdif = x(Support2)-x(Support3); if (xdif!=0.) aif = aif - (aif(Support2)-aif(Support3))*x/xdif; ydif = y(Support1)-y(Support2); if (ydif!=0.) aif = aif - (aif(Support1)-aif(Support2))*y/ydif; aif = aif - aif(Support3); aif = float(aif); tdef = aif(i1:i2,i1:i2); def(,,i) = tdef(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2); if (disp == 1) { fma; mypltitle,swrite(format="Influence Function %d/%d",i,NAct),[0.,-0.005],height=12; pli,def(,,i)*ipupil(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2); } gui_progressbar_text,swrite(format="Computing Influence Functions %d/%d",i,NAct); gui_progressbar_frac,float(i)/NAct; } def = def/max(def)*pi; //just to keep things within reasonable values. def *= dm(nm).unitpervolt; // adjustable normalization factor def = float(def/50.); // factor 50 arbitrary to scale roughtly as PZT IF dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; clean_progressbar; return def; } //---------------------------------------------------- func make_aniso_dm(nm,&def,disp=) /* DOCUMENT function make_aniso_dm,dm_structure,ActIF,disp= 2004jan22: implemented normalization as for zernikeIF, i.e. based on the same amplitude tip that gives 1" */ { dim = dm(nm)._n2-dm(nm)._n1+1; cobs = tel.cobs; cent = sim._cent; psize = tel.diam/sim.pupildiam; patchDiam = sim.pupildiam+2*max(abs(wfs.gspos))* 4.848e-6*abs(dm(nm).alt)/psize; prepzernike,dim,patchDiam,sim._cent-dm(nm)._n1+1,sim._cent-dm(nm)._n1+1; def = array(float,dim,dim,3); for (i=1;i<=3;i++) { def(,,i) = zernike_ext(i+3); if (disp == 1) {fma; pli,def(,,i);} } if (sim.verbose>=1) {write,format="Number of Anisoplanatism modes :%d\n",3;} // normalization factor: see make_zernike_dm and make_tiptilt_dm tip = zernike_ext(2); current = tip(dim/2,dim/2,1)-tip(dim/2-1,dim/2,1); fact = (dm(nm).unitpervolt*tel.diam/sim.pupildiam)*4.848/current; def = float(def*fact); dm(nm)._nact = (dimsof(def))(4); dm(nm)._def = &def; return def; } //---------------------------------------------------- func project_aniso_dm(nmaniso,nmlow,nmhigh,disp=) /* DOCUMENT func project_aniso_dm(nmaniso,nmlow,nmhigh,disp=) This function finds the actuator commands to apply on dmlow and dmhigh to produce the anisoplanatism modes (which upper part is in dm(nmaniso)). nmaniso: # indice of anisoplanatism DM nmlow: # indice of low DM (at 0 altitude) nmhigh: # indice of high DM (at non zero altitude) computes alow and ahigh, which are #actuator x #anisomode. also compute "comaniso", which is the alow and ahigh put into a global total_#_actuator x 3 matrix, which can be directly multiplied/added to the global system command vector (see aoloop). Store them in extern variables for future use. SEE ALSO: make_aniso_dm */ { extern alow,ahigh,comaniso; // we address here the zero altitude layer. The pupil is well defined. // cut a ipupil of the appropriate size: puplow = ipupil(dm(nmlow)._n1:dm(nmlow)._n2,dm(nmlow)._n1:dm(nmlow)._n2); w = where(puplow); // this transform def into a #spatial_point x nact array and retains only // the spatial point inside the pupil if (dm(nmlow).elt == 1) { n1 = dm(nmlow)._n1; n2 = dm(nmlow)._n2; sizedef=n2-n1+1; tabdef=array(float,sizedef,sizedef,sum(dm(nmlow)._nact)); command = array(float,dm(nmlow)._nact); for (i=1;i<=dm(nmlow)._nact;i++) { command *= 0.0f; command(i) = 1.0f; tabdef(,,i) = comp_dm_shape(nmlow,&command); } def=tabdef(*,)(w,); } else { def = (*dm(nmlow)._def)(*,)(w,); } // remove piston from the definition for (c1=1;c1<=(dimsof(def))(3);c1++)def(:,c1) -= def(avg,c1); // compute the IF covariance matrix defcov = def(+,)*def(+,); // now look at the anisoplanatism modes: // same, extract ipupil of appropriate dimension pupaniso = ipupil(dm(nmaniso)._n1:dm(nmaniso)._n2,\ dm(nmaniso)._n1:dm(nmaniso)._n2); w = where(pupaniso); // this transform def into a #spatial_point x nact array and retains only // the spatial points inside the pupil defa = -(*dm(nmaniso)._def)(*,)(w,); // remove piston from the definition for (c1=1;c1<=(dimsof(defa))(3);c1++)defa(:,c1) -= def(avg,c1); // compute the product act * mode: anisoproj = def(+,)*defa(+,); // command vector (matrices, 3 modes) to apply to DM to get a given mode piston_pen = max(defcov)*1e3; // need to penalize piston act_pen = unit(dimsof(defcov)(3))*max(diag(defcov))/1000.; alow = LUsolve(defcov+piston_pen+act_pen,anisoproj); // remove all piston // display: if (disp) { for (i=1;i<=3;i++) { if (dm(nmlow).elt == 1) { tv,tabdef(,,+)*alow(+,i)*puplow; } else tv,(*dm(nmlow)._def)(,,+)*alow(+,i)*puplow; hitReturn; } } // Now, the altitude DM: // it's basically the same thing, except now there is no well-defined pupil. // So we define here the pupil as the area which is controllable by the actuators. // that should be perfectly acceptable as the is the only area which will be seen // by any beam. if (dm(nmhigh).elt == 1) { n1 = dm(nmhigh)._n1; n2 = dm(nmhigh)._n2; sizedef=n2-n1+1; tabdef=array(float,sizedef,sizedef,sum(dm(nmhigh)._nact)); command = array(float,dm(nmhigh)._nact); for (i=1;i<=dm(nmhigh)._nact;i++) { command *= 0.0f; command(i) = 1.0f; tabdef(,,i) = comp_dm_shape(nmhigh,&command); } puphigh = (tabdef)(,,sum); if (max(-puphigh)>max(puphigh)) puphigh = -puphigh; puphigh = (puphigh > 0.8*max(puphigh)); w = where(puphigh); def=tabdef(*,)(w,); } else { //puphigh = (*dm(nmhigh)._def)(,,sum); puphigh = comp_dm_shape(nmhigh,&(array(1.0f,dm(nmhigh)._nact))); if (max(-puphigh)>max(puphigh)) puphigh = -puphigh; puphigh = (puphigh > 0.8*max(puphigh)); w = where(puphigh); def = (*dm(nmhigh)._def)(*,)(w,); } // remove piston from the definition for (c1=1;c1<=(dimsof(def))(3);c1++)def(:,c1) -= def(avg,c1); defcov = def(+,)*def(+,); pupaniso = array(float,[2,sim._size,sim._size]); pupaniso(dm(nmhigh)._n1:dm(nmhigh)._n2,dm(nmhigh)._n1:dm(nmhigh)._n2)=puphigh; pupaniso = pupaniso(dm(nmaniso)._n1:dm(nmaniso)._n2,\ dm(nmaniso)._n1:dm(nmaniso)._n2); w = where(pupaniso); defa = (*dm(nmaniso)._def)(*,)(w,); // remove piston from the definition for (c1=1;c1<=(dimsof(defa))(3);c1++)defa(:,c1) -= defa(avg,c1); anisoproj = def(+,)*defa(+,); act_pen = unit(dimsof(defcov)(3))*max(diag(defcov))/1000.; ahigh = LUsolve(defcov+piston_pen+act_pen,anisoproj); if (disp || (sim.debug == 2)) { for (i=1;i<=3;i++) { if (dm(nmhigh).elt == 1) { tv,tabdef(,,+)*ahigh(+,i)*puphigh; } else tv,(*dm(nmhigh)._def)(,,+)*ahigh(+,i)*puphigh; hitReturn; } } indexDm = array(long,2,ndm); indexDm(,1) = [1,dm(1)._nact]; for (nm=2;nm<=ndm;nm++) { indexDm(,nm) = [indexDm(2,nm-1)+1,sum(dm(1:nm)._nact)]; } comaniso = array(float,[2,sum(dm._nact),3]); comaniso(indexDm(1,nmlow):indexDm(2,nmlow),) = alow; comaniso(indexDm(1,nmhigh):indexDm(2,nmhigh),) = ahigh; } //-------------------------------------------------------------------------- func hysteresis(x,nm) { // Uses the method developed by Luc Gilles for TMT in MAOS // YAO implementation by Marcos van Dam, April 2013 // x = voltage commands; // n is the DM number output = array(float, dimsof(x)); // this is the output vector for (k=1;k<=dm(nm)._nact;k++){ // loop over all the actuators if ((*dm(nm)._signus)(k) == 0){ if ((x(k) - (*dm(nm)._x0)(k)) < 0){ (*dm(nm)._signus)(k) = -1; } else { (*dm(nm)._signus)(k) = 1; } } if ((*dm(nm)._signus)(k) == 1){ if ((x(k) - (*dm(nm)._x0)(k)) < 0){ (*dm(nm)._signus)(k) = -1; } } if ((*dm(nm)._signus)(k) == -1){ if ((x(k) - (*dm(nm)._x0)(k)) > 0){ (*dm(nm)._signus)(k) = 1; } } alpha = dm(nm)._alpha * (*dm(nm)._signus)(k); beta = dm(nm)._beta; y0 = (*dm(nm)._y0)(k,:); x0 = (*dm(nm)._x0)(k); y = array(float,3); for (i=1;i<=3;i++){ y(i) = x(k) - alpha(i)*beta(i) + (y0(i) - x0 + alpha(i)*beta(i))*exp(-(x(k)-x0)/alpha(i)); } (*dm(nm)._x0)(k) = x(k); (*dm(nm)._y0)(k,:) = y(:); // scale to the desired hysteresis level output(k) = dm(nm).hyst/0.17*1.5*sum(dm(nm)._w*y) + (1-dm(nm).hyst/0.17)*x(k); } return float(output); } func make_segmented_dm(nm,&def,disp=) { dim = dm(nm)._n2-dm(nm)._n1+1; // dim = sim._size; cent = sim._cent-dm(nm)._n1+1; // make large, unfiltered segment map: map = make_seg_hexa_grid(dm(nm).pitch,dm(nm).nxseg,dim,x,y,cent=cent); // keep only the one within the area of interest: if (dm(nm).fradius) f_rad = dm(nm).fradius; else f_rad = dm(nm).pitch*(dm(nm).nxseg)/2.; map = filt_seg_hexa_grid(map,x,y,f_rad,cent=cent); // repack/renumber map = renum_int_array(map); // number of segments nseg = max(map); // 3 degrees of freedom per segment (piston, tip and tilt) nact = 3*nseg; // allocate influence function data cube def = array(0.0f,[3,dim,dim,nact]); // build influence functions k = 1; for (i=1; i<=nseg; i++) { // piston def(,,k++) = float(map==i); // tip tmp = float(def(,,k-1)*\ tip1arcsec(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2)); w = where(def(,,k-1)); tmp(w) -= avg(tmp(w)); def(,,k++) = tmp; // tilt tmp = float(def(,,k-2)*\ tilt1arcsec(dm(nm)._n1:dm(nm)._n2,dm(nm)._n1:dm(nm)._n2)); w = where(def(,,k-2)); tmp(w) -= avg(tmp(w)); def(,,k++) = tmp; if (disp) tv,def(,,k-1); } dm(nm)._nact = nact; dm(nm)._def = &def; return map; } func make_seg_hexa_grid(pitch,nxseg,dim,&x,&y,cent=,rotby=) /* DOCUMENT func make_seg_hexa_grid(pitch,nxseg,dim,&x,&y,cent=,rotby=) pitch = Segment center to segment center pitch [pixels] nxseg = Number of segment in long axis (X) diameter nxseg must be integer, odd or even dim = Size of final maps (optional, default to (nxseg+2)*pitch) rotby = Angle in degrees to rotate maps by (optional) SEE ALSO: filt_seg_hexa_grid, renum_int_array Typical sequence: m = make_seg_hexa_grid(20,9,,x,y) // make segment grid fm = filt_seg_hexa_grid(m,x,y,20*9/2) you can call above as many time as you like until segment pattern outer figure is acceptable. then: map = renum_int_array(fm) */ { tic; if (!dim) dim = (long((nxseg+2)*pitch+1)/2)*2; if (odd(dim)) write,"Warning: make_segments_hexa(): dim is odd"; if (!cent) cent=dim/2; // compute coordinates of segment centers // we need to oversize as Y dimension is compressed // (ypitch = xpitch / (sqrt(3)/2.) nyseg = long(nxseg / (sqrt(3.)/2.)); if (odd(nyseg-nxseg)) nyseg++; // let's still oversize it a bit: nover = 4; xy = indices(nyseg+nover); // center it at (nxseg+nover)/2; xy = xy - 1 - (nyseg+nover)/2; // now let's shift X by 0.5 for all odd Y: xy(,,1) += odd(abs(xy(,,2)))*0.5; // adjust for the case nxseg = even (then no segment at exact center) xy += even(nxseg)*0.5; // scale X and Y by proper distances: x = xy(,,1)*pitch; y = xy(,,2)*pitch*sqrt(3.)/2.; // make vectors: x = x(*); y = y(*); if (debug) { write,format="nxseg = %d, nyseg = %d\n",nxseg,nyseg; fma; plp,y,x,symbol=4,size=0.3; limits,square=1; plmargin; hitReturn; } // rotate, if needed: if (rotby) { xy2 = mrot(rotby)(+,)*[x,y](,+); x = xy2(1,); y = xy2(2,); } // get rid of segments that will be completely, for sure, // outside of a circular aperture? //d = sqrt(x^2.+y^2.); //w = where(d<=(nxseg*pitch/2.+pitch/2.)); //if (numberof(w)==0) error,"Problem when filtering segments"; //x = x(w); //y = y(w); nseg = numberof(x); if (debug) { fma; plp,y,x,symbol=4,size=0.3; ang = span(0.,2*pi,100); plg,(nxseg*pitch)/2.*sin(ang),(nxseg*pitch)/2.*cos(ang); limits,square=1; plmargin; hitReturn; } if (debug) write,(t1=tac()); x += cent; y += cent; // build the segments at requested locations: // To not go overboard with memory allocation, I chose // to do it by chunk. There might be other ways, but this // is cheap and quick: maxram = 256; // in MB maxdim = long(sqrt(maxram*1e6/(nseg*4))); if (debug) write,format="Max dim = %d\n",maxdim; if (maxdim>=dim) { cube = array(0.0f,[3,dim,dim,nseg]); for (i=1;i<=nseg;i++) { cube(,,i) = float(dist(dim,xc=x(i),yc=y(i))); } map = cube(,,mnx); } else { sdim = dim; while (sdim>maxdim) sdim = long(ceil(sdim/2.)); ndim = long(ceil(dim*1./sdim)); map = array(long,[2,ndim*sdim,ndim*sdim]); cube = array(0.0f,[3,sdim,sdim,nseg]); for (i=1;i<=ndim;i++) { if (debug) write,format="%d out of %d\n",i,ndim; for (j=1;j<=ndim;j++) { for (k=1;k<=nseg;k++) { cube(,,k) = float(dist(sdim,xc=-(i-1)*sdim+x(k), yc=-(j-1)*sdim+y(k))); } // error; map(1+(i-1)*sdim:i*sdim,1+(j-1)*sdim:j*sdim) = cube(,,mnx); if (debug) tv,cube(,,mnx); } } map = map(1:dim,1:dim); } if (debug) write,(t2=tac())-t1; return map; } func filt_seg_hexa_grid(map,&x,&y,filter_radius,cent=) /* DOCUMENT func filt_seg_hexa_grid(map,x,y,filter_radius) Filter segments that are outside of area of interest map = map of segments (pixel value = segment number it belongs to). Generally built by make_seg_hexa_grid() x and y = coordinates of segment centers (in pixel, w.r.t center of map). Generally returned by make_seg_hexa_grid() filter_radius = segment will be filtered if distance to center is greater than this value (pixels) cent = center of coodinates (pixels, optional, default dim/2) SEE ALSO: make_seg_hexa_grid, renum_int_array */ { if (!cent) cent=dimsof(map)(2)/2; fmap = map; if (filter_radius) { d = sqrt((x-cent)^2.+(y-cent)^2.); // keep only valid x and y w = where(d<=filter_radius); if (numberof(w)==0) error,"Problem: 0 segment selected"; x = x(w); y = y(w); // zero out segments outside of defined radius: w = where(d>filter_radius); if (numberof(w)>0) { for (i=1;i<=numberof(w);i++) { ww = where(fmap==w(i)); if (numberof(ww)) fmap(where(fmap==w(i))) = 0; } } } return fmap; } func renum_int_array(map) /* DOCUMENT func renum_int_array(map) // re-assign segment numbers to get rid of missing subap/segments // in returned map, first segment/subap is 1, then 2, ... until Nmax SEE ALSO: */ { rmap = map; m = max(rmap); l = 1; for (i=1;i<=m;i++) { w = where(rmap==i); if (numberof(w)) rmap(w) = l++; } return rmap; } yao-5.4.0/yao_fast.c000066400000000000000000001534021234404334100142640ustar00rootroot00000000000000/* * yao_fast.c * * yao wavefront sensors engines * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ #define _GNU_SOURCE #include #include #include #include #include #include #include "ydata.h" #include "yapi.h" #include "play.h" // for p_wall_secs() and p_cpu_secs() //#define FFTWOPTMODE FFTW_ESTIMATE #define FFTWOPTMODE FFTW_MEASURE // use FFTW_PATIENT for thread optimization (see below): //#define FFTWOPTMODE FFTW_PATIENT // static int n_threads = 1; int use_sincos_approx_flag = 0; void _eclat_float(float *ar, int nx, int ny); void _poidev(float *xmv, long n); void _gaussdev(float *xmv, long n); // int Y__fftw_init_threads(void) // { // return fftwf_init_threads(); // } // // // void Y_fftw_set_n_threads(int nargs) // { // n_threads = ygets_i(0); // If you plan with FFTW_PATIENT, it will automatically // disable threads for sizes that don't benefit from parallelization. // fftwf_plan_with_nthreads(n_threads); // } // // void Y_fftw_get_n_threads(int nargs) // { // ypush_int(n_threads); // } void _set_sincos_approx(int flag) { use_sincos_approx_flag = flag; } void Y__get_sincos_approx(int nargs) { ypush_int(use_sincos_approx_flag); } float sine(float x) { const float pi = 3.141592653589793f; const float B = 4.0f/pi; const float C = -4.0f/(pi*pi); const float D = 2*pi; const float P = 0.225; x = x - roundf(x/D)*D; float y = B * x + C * x * fabsf(x); y = P * (y * fabsf(y) - y) + y; return y; } float cosine(float x) { const float hpi = 3.141592653589793f/2.0f; float y = sine(x+hpi); return y; } void _sinecosinef(float x, float *s, float *c) { float sc; *s = sine(x); *c = cosine(x); sc = (*c)*(*c) + (*s)*(*s); sc = 1.0f/sqrtf(sc); *s = *s * sc; *c = *c * sc; } #ifdef __APPLE__ extern float sinf(float x); extern float cosf(float x); void sincosf(float x, float *s, float *c) { *s = sinf(x); *c = cosf(x); } #endif int _import_wisdom(char *wisdom_file) { FILE *fp; int status; if((fp = fopen(wisdom_file, "r"))==NULL) return (1); status = 1-fftwf_import_wisdom_from_file(fp); fclose(fp); return status; } int _export_wisdom(char *wisdom_file) { FILE *fp; if((fp = fopen(wisdom_file, "w"))==NULL) return (1); fftwf_export_wisdom_to_file(fp); fclose(fp); return (0); } int _init_fftw_plans(int nlimit) { int n, size; fftwf_complex *inf,*outf; fftwf_plan p1, p2; size=1; for (n=0;n=outdy) break; joff *= outdx; for ( i=0 ; i=outdx) break; outim[ioff+joff] += inim[i+j*indx]; } } return 0; } int hx,hy; hx = indx/2; hy = indy/2; for ( j=0 ; j=outdy) break; joff *= outdx; for ( i=0 ; i=outdx) break; outim[ioff+joff] += inim[i+hx+(j+hy)*indx]; } } for ( j=hy ; j=outdy) break; joff *= outdx; for ( i=0 ; i=outdx) break; outim[ioff+joff] += inim[i+hx+(j-hy)*indx]; } } for ( j=0 ; j=outdy) break; joff *= outdx; for ( i=hx ; i=outdx) break; outim[ioff+joff] += inim[i-hx+(j+hy)*indx]; } } for ( j=hy ; j=outdy) break; joff *= outdx; for ( i=hx ; i=outdx) break; outim[ioff+joff] += inim[i-hx+(j-hy)*indx]; } } return 0; } /* Shack- Hartmann coded in C pass one phase array and a set of indices (start and end of each subapertures) then this routine puts the phase sections in one larger phase and does a serie of FFTs to compute the images. Then each image is binned according to the map "binindices". It then put these images back into a large image that contains all subaperture image, suitable for visualization. flow: - set up of a couple of constants and memory allocation - loop on subaperture number: - put pupil and phase in complex A[ns,ns] - do FFT - compute image as square(FFT result complex) (no eclat) - compute binned/resampled subaperture image using binindices (has to made up for the missing eclat at previous step). - compute X and Y centroids - optionaly stuff this image in a larger image (fimage) for display - free memory The array used in here are: pupil (dim*dim): pupil image, float phase (dim*dim): phase image, float virtual(nx*ny) : wavefront-let, i.e. part of the pupil/phase contained within the subaperture. A (ns*ns) : Complex array into which the amplitude and phase corresponding to one subaperture wavefront-let are placed. Dimension n2*n2 e.g. 16x16 if 5x5 pixels/subaperture simage (ns*ns) : Focal plane image obtained after FFT of A. ximage (nx*nx) : Extended focal plane array, into which simage is embedded (+ shifted) to allow extended field of view. bimage (nb*nb) : Image obtained after binning of ximage to take into account bigger pixels than the one delivered after the FFT. fimage (nf*nf) : Final image into which all the subaperture images have been placed at pre-defined positions (see imistart) */ int _shwfs_phase2spots( float *pupil, // input pupil float *phase, // input phase, in microns float phasescale, // phase scaling factor: microns -> radians @ wfs.lambda float *phaseoffset, // input phase offset int dim, // X or Y dim of phase. Used as stride for extraction int *istart, // vector of i starts of each subaperture int *jstart, // vector of j starts of each subaperture int nsx, // subaperture i size int nsy, // subaperture j size int nsubs, // # of subapertures int sdimpow2, // dimension of small array for FFTs, in power of 2 long domask, // go through amplitude mask loop (0/1). float *submask, // subaperture mask. Corresponds/applied to simage. float *kernel, // to convolve the (s)image with. dim nx*nx*nkernels // compute dynamically at each call, i.e. can change int nkernels, // number of plans in *kernel float *kernels, // to convolve the (s)image with, one per subaperture // dimension: 2^sdimpow2 * 2 * nsubs. FFTs precomputed // at init call. float *kerfftr, // real part of kernels FFT. dim: same as kernels float *kerffti, // imaginary part of kernels FFT. same dim as kerfftr int initkernels, // init kernels: pre-compute FFTs int kernconv, // convolve with kernel? int *binindices, // int 2d array containing the indices of the binned // subaperture image, i.e. to which pixel in the binned // image should one pixel in the FFT'd image be added. int nb, // dimension of binned subaperture image (bimage) int rebinfactor, // rebin factor from small to big pixels int nx, // dimension of extended subaperture image float *unittip, // nsx*nsy array with unit tip (1,2,3..) float *unittilt, // nsx*nsy array with unit tilt float *lgs_prof_amp, // vector of lgs profile amplitudes float *lgs_defocuses,// vector of lgs profile altitudes int n_in_profile, // dimension of lgs_prof_amp and lgs_prof_alt float *unit_defocus, // as it says, same dimsof as phase float *fimage, // final image with spots int *svipc_subok, // to skip (0) subap for svipc partial spot comput. int *imistart, // vector of i starts of each image int *imjstart, // vector of j starts of each image int fimnx, // final image X dimension int fimny, // final image Y dimension float *flux, // vector of flux (input), dim nsubs float *rayleighflux, // vector of flux for rayleigh (input), dim nsubs float *skyflux, // vector of flux for sky (input), dim nsubs float darkcurrent, // dark current, e-/pix/frame int rayleighflag, // enable rayleigh processing float *rayleigh, // rayleigh background, nx*nx*nsubs // here I separated background and rayleigh. the background includes // not only the rayleigh, but also the sky and the dark current. int bckgrdinit, // init background processing. fill bckgrdcalib int counter, // current counter (in number of cycles) int niter) // total # of cycles over which to integrate { /* Declarations */ fftwf_complex *A, *result, *Ax, *Kx, *Ker, *resultx; fftwf_plan fftps,fftpx,fftpxi; float *ptr,*ptr1,*ptr2; float *phase_scaled; float *simage; float *bimage; float *ximage; // extended image for one subap, un-rebinned float *bsubmask; float *brayleigh; float tot, totrayleigh, krp, kip, sky; float corfact; float dx,dxp,dy,dyp; float lgsdef,lgsamp,pp,ppsin,ppcos; long log2nr, log2nc, n, ns; int i,j,k,l,koff,kk,nalt; int idxp,idyp,ndx,ndy,dynrange; int debug=0; int nxdiff; double sys,cpu0,cpu1,cpu2,cpu3,cpu4,cpu5,cpu6; double cpu10,cpu21,cpu32,cpu43,cpu54,cpu65; const float pi = 3.141592653589793f; const float twopi = 2*pi; cpu10=0.0;cpu21=0.0;cpu32=0.0;cpu43=0.0;cpu54=0.0;cpu65=0.0; cpu0=0.0;cpu1=0.0;cpu2=0.0;cpu3=0.0;cpu4=0.0;cpu5=0.0;cpu6=0.0; //====================== // Global setup for FFTs: //====================== // fftwf_plan_with_nthreads((int)1); // Set the size of 2d FFT. log2nr = sdimpow2; log2nc = sdimpow2; n = 1 << ( log2nr + log2nc ); // total number of pixels in small array ns = 1 << log2nr; // side of small array, pixels, n=ns*ns // enlarge dynamical range? if (nx==ns) dynrange=0; else dynrange=1; // integrate = 1; // force to pass by the end (subap overlap upgrade) // if (niter > 1) {integrate = 1;} // we are in "integrating mode" if (debug>1) printf("here1 nx=%d ns=%d dynrange=%d\n",(int)nx,(int)ns,(int)dynrange); // Allocate memory for the input operands and check its availability. A = fftwf_malloc ( n * sizeof ( fftwf_complex ) ); result = fftwf_malloc ( n * sizeof ( fftwf_complex ) ); Ax = fftwf_malloc ( nx *nx * sizeof ( fftwf_complex ) ); Kx = fftwf_malloc ( nx *nx * sizeof ( fftwf_complex ) ); Ker = fftwf_malloc ( nx *nx * sizeof ( fftwf_complex ) ); resultx = fftwf_malloc ( nx *nx * sizeof ( fftwf_complex ) ); phase_scaled = ( float* ) malloc ( dim * dim * sizeof ( float ) ); simage = ( float* ) malloc ( ns * ns * sizeof ( float ) ); ximage = ( float* ) malloc ( nx * nx * sizeof ( float ) ); bimage = ( float* ) malloc ( nb * nb * sizeof ( float ) ); brayleigh = ( float* ) malloc ( nb * nb * sizeof ( float ) ); bsubmask = ( float* ) malloc ( nb * nb * sizeof ( float ) ); if ( A == NULL || result == NULL || Ax == NULL || \ Kx == NULL || Ker == NULL || resultx == NULL || phase_scaled == NULL || bimage == NULL || simage == NULL || ximage == NULL || brayleigh == NULL || bsubmask == NULL ) { return (1); } //Zero out final image if first iteration if (counter == 1) { // in fact, let's put the dark current value in there: //~ for (i=0;i<(fimnx*fimny);i++) { fimage[i] = 0.0f; } // these 2 lines temporarily disabled for svipc shm_var of ffimage: // FIXME (remove comments):FIXME FIXME FIXME //~ totdark = (float) niter * darkcurrent; //~ for (i=0;i<(fimnx*fimny);i++) { fimage[i] = totdark; } // 2012sep17: the problem above it seems is that the loop is over the // entire array. If several forks are accessing it, -> problem. // the simplest might be to add it at the yorick level before // calling _shwfs_spots2slopes(). } // compute scaled phase ( we do this operation several times below): for ( i=0 ; i= 0) { bsubmask[binindices[i]] += (float)submask[i]; } } corfact = 1.0f / (float)rebinfactor / (float)rebinfactor; for ( i=0 ; i1) printf("here2\n"); if (kernconv == 1) { // init resultx to (1,0) // we're starting from a non-filter. ptr = (void *)resultx; for ( i=0; i Kx // result in in Kx // Kx * resultx -> Ker: ptr1 = (void *)Kx; ptr2 = (void *)resultx; ptr = (void *)Ker; for ( i=0; i1)&&((idxp!=0)||(idyp!=0))) printf("idxp = %d, idyp = %d, dx=%f, dy=%f\n",idxp,idyp,dx,dy); } else { dx = 0.0f; dy = 0.0f; idxp = 0; idyp = 0; } // END section to allow larger dynamical range // (more below to add to phase and to shift imagelets) cpu1 = p_cpu_secs(&sys); cpu10 += cpu1-cpu0; // fill in the complex wavefront array for this subaperture: // cos & sin are very costly, so we use an aproximation: ptr = (void *)A; if (dynrange) { if (debug>1) printf("here, dynrange enabled\n"); for ( j=0; j1) printf("here, dynrange disabled\n"); for ( j=0; j1) printf("here3\n"); cpu2 = p_cpu_secs(&sys); cpu21 += cpu2-cpu1; // Carry out a Forward 2d FFT transform, check for errors. fftwf_execute(fftps); // A -> result // at this point result should contain the diffraction // of the subaperture + turbulence, but not kernel yet // compute image from complex image object: ptr = (void *)result; for ( i=0; i20) && ( l==10 ) ) printf("%f ",simage[i]); ptr +=2; } if ( (debug>1) && ( l==10 ) ) printf(" "); cpu3 = p_cpu_secs(&sys); cpu32 += cpu3-cpu2; // Embed (and add to) this simage into ximage, the extended field // of view image for this subaperture (with shifts computed above): if ( (debug>1) && (l==10) ) printf("\nns=%d nx=%d\n",(int)ns,(int)nx); embed_image(simage,ns,ns,ximage,nx,nx,(nx-ns)/2+idxp-nxdiff,(nx-ns)/2+idyp-nxdiff,1); } // END LOOP ON LGS PROFILE if ( (debug>1) && (l==10) ) printf("here4\n"); if ((debug>10)&&(l==10)) { FILE *fp; fp=fopen("xim-pre.dat", "w"); fprintf(fp, "%d\n",(int)nx); for ( i=0 ; inb*nb) { //~ printf("binindices[%d] = %d > nb*nb (%d). It shouldn't be so! (ns=%d, nx=%d, nb=%d)\n",i,binindices[i],nb*nb,ns,nx,nb); //~ return 1; //~ } bimage[binindices[i]] += ximage[i]; //~ if (ximage[i]==0) printf("ximage[%d]==0 ",i); } if ((debug>10)&&(l==10)) { FILE *fp; fp=fopen("sim.dat", "w"); fprintf(fp, "%d\n",(int)ns); for ( i=0 ; i0.0f) { tot = flux[l]/tot; for ( i=0 ; i=0) { brayleigh[binindices[i]] += rayleigh[i+l*nx*nx]; } } // NORMALIZE FLUX FOR RAYLEIGH if (debug) printf("here4-1\n"); totrayleigh = 0.0f; for ( i=0 ; i 0.0f) { totrayleigh = rayleighflux[l]/totrayleigh; for ( i = 0; i < nb*nb; i++ ) brayleigh[i] = brayleigh[i]*totrayleigh; } if (debug) printf("here4-2\n"); } // NORMALIZE FLUX FOR SKY // sky = skyflux[l] / (float)(nb); // sky per rebinned pixel, e-/frame sky = skyflux[l]; // sky per rebinned pixel, e-/frame if (debug) printf("here4-3\n"); for ( i=0 ; i1) printf("here5\n"); free ( ximage ); free ( bimage ); free ( brayleigh ); /* fixed memleak 2008nov18 */ free ( bsubmask ); if (debug>1) printf("here6\n"); /* all time used by loop, good: 1-0 0.000 2-1 0.000 3-2 73.329 4-3 0.000 */ return (0); } int _shwfs_spots2slopes( float *fimage, // final image with spots int *imistart2, // vector of i starts of each image int *imjstart2, // vector of j starts of each image int nsubs, // # of subapertures int binxy2, // side size of the image extracted from the // final image which only corresponds to the // subaperture (= wfs._npixels) int fimnx, // final image X dimension int fimny, // final image Y dimension int yoff, // y offset (to process only part of the image, when using svipc) float *centroidw, // centroid weight vector for centroid computations, X & Y long shthmethod, // threshold method (1: yao default, 2: podium, 3: brightest pixels) float *threshold, // vector of threshold (input), dim nsubs float *bias, // bias array, dim = nsubs*binxy*binxy, in e- float *flat, // flat array, dim = nsubs*binxy*binxy, normalized @ 1. float ron, // read-out noise long noise, // compute noise float *bckgrdcalib, // background calib array, binxy*binxy*nsubs int bckgrdinit, // init background processing. fill bckgrdcalib int bckgrdsub, // subtract background int *validsubs, // valid subaps within the set of subap // for which an image is computed (0/1) int *svipc_subok, // to skip (0) subap for svipc partial spot comput. int niter, // total # of cycles over which to integrate float *mesvec) // final measurement vector { /* Declarations */ const int sizeThArray = binxy2*binxy2; float *bimage2; float *fnoise; float centx, centy, centi, tmpf, thback; float val[sizeThArray]; float minval; long nb2; int i, j, k, l, koff, xyoff; int nvalidsubs, vsc; // vsc = valid sub counter int ind[sizeThArray]; int ii, kk, minind; int met3threshold; // Set the size of 2d FFT. nb2 = binxy2 * binxy2; vsc = -1; xyoff = yoff * fimnx; // printf("shthemthod = %ld\n",shthmethod); // Allocate memory for the input operands and check its availability. bimage2 = ( float* ) malloc ( nb2 * sizeof ( float ) ); fnoise = ( float* ) malloc ( fimnx * fimny * sizeof ( float ) ); if ( bimage2 == NULL || fnoise == NULL ) { return (1); } // how many valid subs? nvalidsubs = 0; for( i=0; i 0.0f) { mesvec[vsc] = centx/centi; mesvec[nvalidsubs+vsc] = centy/centi; } // otherwise stay at zero (init value) // vsc++; // increment valid subaperture counter } } // thresholding in case of "bright pixels" thresholding } else if (shthmethod == 3) { // OK, now let's finally compute the slopes over all subaps. for ( l=0 ; ltotal number of pixels in subap: if (met3threshold < 1) met3threshold = 1; if (met3threshold > nb2) met3threshold = nb2; if (validsubs[l]) vsc++; if (svipc_subok[l]==0) continue; // retrieve the final/integrated subaperture spot image from fimage // search for the brightest pixels // start putting back image where it belongs in large image // for displays by "zeroing" fimage koff = imistart2[l] + imjstart2[l]*fimnx; minval = fimage[koff]; minind = 0; val[0] = minval; ind[0] = minind; for ( j=0 ; j 0) { val[ii] = bimage2[ii]; ind[ii] = ii; if (val[ii] < minval) { minval = val[ii]; minind = ind[ii]; } // compare each following value of bimage2 to the min value of // val and if it is larger, replace it } else if (ii > 0 && bimage2[ii] > minval) { val[minind] = bimage2[ii]; ind[minind] = ii; // look for the minimum value of val and its subscript minind minval = val[0]; minind = 0; for ( kk=1 ; kk < met3threshold ; kk++) { if (val[kk] < minval) { minval = val[kk]; minind = kk; } } } // zero fimage before filling it by the brightest pixels fimage[k] = 0; } } centx = centy = centi = 0.0f; for (ii=0 ; ii < met3threshold ; ii++) { i = ind[ii]%binxy2; j = ind[ii]/binxy2; k = koff + i + j*fimnx; // fill fimage with the brightest pixels fimage[k] = val[ii]; // is that a valid subaperture? if (validsubs[l]) { // Compute centroids centx += centroidw[i]*val[ii]; centy += centroidw[j]*val[ii]; centi += val[ii]; } } // Compute measurements if (centi > 0.0f) { mesvec[vsc] = centx/centi; mesvec[nvalidsubs+vsc] = centy/centi; } // otherwise stay at zero (init value) } } // with respect to the noise in the outskirt of the fimage: // the threshold has been applied everywhere, but the condition // if (pixel<0) pixel=0 only has been applied in the valid // subapertures. Let's make sure it is applied everywhere here: for ( i = xyoff; i < (xyoff+fimnx*fimny); i++ ) { if (fimage[i] < 0.0f) fimage[i] = 0.0f; } free ( bimage2 ); free ( fnoise ); return (0); } int _shwfs_simple(float *pupil, // input pupil float *phase, // input phase float phasescale, // phase scaling factor float *phaseoffset,// input phase offset int dimx, // X dim of phase. Use as stride for extraction int dimy, // Y dim of phase. Use as stride for extraction int *istart, // vector of i starts of each subaperture int *jstart, // vector of j starts of each subaperture int nx, // subaperture i size int ny, // subaperture j size int nsubs, // # of subapertures float toarcsec, // conversion factor to arcsec float *mesvec) // final measurement vector { /* Declarations */ float avgx, avgy, avgi; int i,j,k,l,koff; // loop on subapertures: for ( l=0 ; l=dimx) & (i==(nx-1)) ) { // end of a row avgx += pupil[k] * phasescale * \ (phase[k]-phase[k-1]+phaseoffset[k]-phaseoffset[k-1]); } else if (pupil[k-1]==0) { // edge of the pupil avgx += pupil[k] * phasescale * \ (phase[k+1]-phase[k]+phaseoffset[k+1]-phaseoffset[k]); } else if (pupil[k+1]==0) { // edge of the pupil avgx += pupil[k] * phasescale * \ (phase[k]-phase[k-1]+phaseoffset[k]-phaseoffset[k-1]); } else { // then 2 neightbors derivative estimate avgx += pupil[k] * phasescale * \ (phase[k+1]-phase[k-1]+phaseoffset[k+1]-phaseoffset[k-1])/2.; } // same for y: if ( (jstart[l]==0) & (j==0) ) { // start of a column avgy += pupil[k] * phasescale * \ (phase[k+dimx]- phase[k]+phaseoffset[k+dimx]-phaseoffset[k]); } else if ( ((jstart[l]+ny)>=dimy) & (j==(ny-1)) ) { // end of a column avgy += pupil[k] * phasescale * \ (phase[k]- phase[k-dimx]+phaseoffset[k]-phaseoffset[k-dimx]); } else if (pupil[k-dimx]==0) { // edge of the pupil avgy += pupil[k] * phasescale * \ (phase[k+dimx]- phase[k]+phaseoffset[k+dimx]-phaseoffset[k]); } else if (pupil[k+dimx]==0) { // edge of the pupil avgy += pupil[k] * phasescale * \ (phase[k]- phase[k-dimx]+phaseoffset[k]-phaseoffset[k-dimx]); } else { avgy += pupil[k] * phasescale * \ (phase[k+dimx]- phase[k-dimx]+phaseoffset[k+dimx]-phaseoffset[k-dimx])/2.; } avgi += pupil[k]; } } if (avgi > 0.0f) { mesvec[l] = avgx/avgi*toarcsec; mesvec[nsubs+l] = avgy/avgi*toarcsec; } else { mesvec[l] = 0.0f; mesvec[nsubs+l] = 0.0f; } } return (0); } int _cwfs (float *pupil, // input pupil float *phase, // input phase float phasescale, // phase scaling factor float *phaseoffset,// input phase offset float *cxdef, // cos(defoc) float *sxdef, // sin(defoc) int dimpow2, // dim of phase in powers of 2 int *sind, // array containing the indices of subaperture#i int *nsind, // nsind(i) = number of valid pixels in sind(i) int nsubs, // number of subapertures float *fimage1, // final image1 with spots float *fimage2, // final image2 with spots float nphotons, // total number of photons, for noise float skynphotons, // total number of photons from sky, for noise float ron, // read-out noise, in case. float darkcurrent, // dark current, per detector/full sample // note it will be 1/2 of given value per image // ron and darkcurrent are only added if noise = 1 int noise, // enable noise ? float *mesvec) // final measurement vector { fftwf_complex *A, *B, *result; float *ptr,*ptr1; fftwf_plan p,p1; float *x1,*x2,*gnoise; float tot; long log2nr, log2nc, n, ns; int i,k,sindstride,koff; float pp,ppsin,ppcos; /* Global setup for FFTs: */ // fftwf_plan_with_nthreads(n_threads); sindstride = 0; for ( i=0 ; i sindstride) { sindstride = nsind[i];} } // Set the size of 2d FFT. log2nr = dimpow2; log2nc = dimpow2; n = 1 << ( log2nr + log2nc ); // total number of pixels in small array ns = 1 << log2nr; // total number of pixels in small array // Allocate memory for the input operands and check its availability. x1 = ( float* ) malloc ( nsubs * sizeof ( float ) ); x2 = ( float* ) malloc ( nsubs * sizeof ( float ) ); gnoise = ( float* ) malloc ( nsubs * sizeof ( float ) ); A = fftwf_malloc ( n * sizeof ( fftwf_complex ) ); B = fftwf_malloc ( n * sizeof ( fftwf_complex ) ); result = fftwf_malloc ( n * sizeof ( fftwf_complex ) ); if ( A == NULL || B == NULL || result == NULL ) { return (1); } for (i=0;i 0.0f) { tot = nphotons/2.0f/tot; // normalize so that sum(x1) = nphotons for ( i=0 ; i 0.0f) { // set up gaussian noise vector for ( i=0 ; i 0.0f) { tot = nphotons/2.0f/tot; for ( i=0 ; i 0.0f) { for ( i=0 ; i3) { write,"Na profile fit results:"; write,format="Depth = %f\n",a(1)*2.35; write,format="%s: ","altitudes"; fitalt; write,format="%s: ","amplitudes"; fitamp; } } //---------------------------------------------------- func foo_lgs_profile(x,a) { // x vector of altitude npt = (numberof(a)-1)/2; sig = a(1); amp = abs(a(2:npt+1)); pos = clip(a(npt+2:),min(x),max(x)); res = x*0; for (i=1;i<=npt;i++) { res += amp(i)*exp(-((x-pos(i))/sqrt(2.)/sig)^2.); } return res; } //---------------------------------------------------- func shwfs_comp_lgs_defocuses(ns) /* DOCUMENT shwfs_comp_lgs_defocuses,ns * This routine computes the defocus coefficients wfs._lgs_defocuses, * used by sh_wfs(), from the user-defined wfs.lgs_prof_alt vector. * Example: * wfs(1).lgs_prof_alt = &float([90,92,95,100,102]*1e3]); * shwfs_comp_lgs_defocuses,1; * add sync_wfs if using svipc. * Note that ns can be a vector: * shwfs_comp_lgs_defocuses,indgen(6); */ /* tests on 2012oct09: * diam=25, off-axis = 11.7m, delta_alt = 10km, sep should be 11.7/4.=2.92 * lambda=0.65, pixsize=0.2145, sep = 2.82 < yeah. * lambda=1.0, pixsize=0.1980, sep = 2.76 < yeah * lambda=2.0, pixsize=0.2640, sep =2.71 * I think we can say it works. let's try for larger pixsize: * lambda=2.0, pixsize=0.3960, sep=2.76, good. */ { extern wfs; for (i=1;i<=numberof(ns);i++) { // ok, so according to my calculations, we have: // a4[m] = D^2/(16*sqrt(3)) * 1/RoC // a4[rd] = a4[m]*2*pi/lambda = D^2/(16*sqrt(3)) * 2*pi/lambda * 1/RoC // and f = RoC/2 if ((*wfs(ns(i)).lgs_prof_alt==[])||(allof(*wfs(ns(i)).lgs_prof_alt==0.))) { if (sim.verbose>0) \ write,format="shwfs_comp_lgs_defocuses: wfs(%d).lgs_prof_alt undefined\n",ns(i); wfs(ns(i))._lgs_defocuses = &float([0.]); return; } tmp = tel.diam^2./(16*sqrt(3.)) * 2*pi/wfs(ns(i)).lambda/1e-6; a4s = tmp * 1./ *wfs(ns(i)).lgs_prof_alt; if (wfs(ns(i)).lgs_focus_alt==0) { wfs(ns(i)).lgs_focus_alt = sum(*wfs(ns(i)).lgs_prof_alt * (*wfs(ns(i)).lgs_prof_amp))/sum(*wfs(ns(i)).lgs_prof_amp); } a4cur = tmp * 1./ wfs(ns(i)).lgs_focus_alt; a4s = a4s-a4cur; wfs(ns(i))._lgs_defocuses = &float(a4s); } } //---------------------------------------------------- func comp_turb_lgs_kernel(ns,init=) /* DOCUMENT comp_turb_lgs_kernel(ns,init=) Compute the LGS object kernel correspoding to uplink seeing. takes 120 microsecond like this, probably not worth xferring to C. */ { extern wfs; llt_pscreen_dim = 256; if (init) { // first look up if this is not already an existing LLT: if ((ns>1)&&(sim.svipc==0)) { for (i=1;i %#20g) * */ require,"string.i"; require,"util_fr.i"; // for is_set func yao_fitshead(name, &phdr, &ehdr, extension=, hdu=) { yao_fitsread,name,phdr,ehdr,extension=,hdu=,onlyheader=1; return phdr; } func yao_fitsread(name, &phdr, &ehdr, extension= , hdu=, onlyheader= ) /* DOCUMENT data = yao_fitsread(filename, PrimaryHDR, ExtensionHDR, extension=, onlyheader=) Returns the Primary Data Array or an Extension (one based) Data Array of the FITS file FILENAME. Mandatory argument: - filename : Input, Name of the fits file Optional arguments: - PrimaryHDR : Output, Primary Header - ExtensionHDR : Output, Requested extension Header Optional keywords: - extension or hdu: Input, extension number (1 based, i.e. 1rst ext=1) - onlyheader : Input, if set, data is not read, only header. The header is returned as a string array. Values can be parsed using the routine fitsHdrValue. EXAMPLES: Read an image from the Primary Data Array: im = yao_fitsread("hrwfs.1.fits") Read the Primary Header and Primary Data Array: im = yao_fitsread("hrwfs.1.fits",hdr); Read only the Primary Header: im = yao_fitsread("hrwfs.1.fits",hdr,onlyheader=1); Read the Data in extension#2, primary and extension(#1) header: im = yao_fitsread("~/N20020926S0050.fits",hdr,ehdr,extension=1); SEE ALSO: fitsHdrValue. */ { if (!is_void(hdu)) extension=hdu; if (is_void(extension)) extension=0; /* (extension number starts at 1) */ file= open(name, "rb"); sun_primitives, file; address= 0L; /* First read the primary header: */ hdr= _fReadHeader(file,address); phdr= hdr; /* Some error checking */ if (!_fCheckPrimaryHeader(hdr)) { close,file; error,"Some standard fits keywords are missing in the primary header"; } if ((extension >= 1) && (!fitsHdrValue(hdr,"EXTEND",default=1))) { write,"WARNING: This FITS file is not supposed to contain fits Extensions"; write,"(Keyword EXTEND not present or set to 'F'). I will try anyway..."; } extn= 1; while (extn <= extension) { /* We have to deal with a fits extension. There is no point in reading the PDA (or previous extension data array), so we skip it and find the start address of the next Extension header. */ naxis= _fGetNaxis(hdr); dim= (naxis(1) > 0); /* In case NAXIS=0 */ dim= dim*abs(fitsHdrValue(hdr,"BITPIX"))/8; /* # of byte in type */ for (i=1;i<=naxis(1);i++) dim= dim*naxis(i+1); skip= long(ceil(dim/2880.)*2880); address+= skip; /* Now read the next extension header: */ hdr= _fReadHeader(file,address); if (!_fCheckExtensionHeader(hdr,XTtype)) { close,file; error,"Some standard fits keywords are missing in the Extension header"+extn; } ehdr= hdr; extn++; } /* return without data if this keyword has been set */ if (onlyheader) return; /* That's also a legal value and there might be no data */ if (fitsHdrValue(hdr,"NAXIS") == 0) {return 0.;} /* Build data array (including determination of array type) */ // data= _fBuildArray(hdr); // The above call was replaced by putting the function directly inside // the main program as it is slitghtly faster. naxis = _fGetNaxis(hdr); type = fitsHdrValue(hdr,"BITPIX"); /* Valid types: */ x= []; if (type == 8) {x = char();} /* 8 pixel values are unsigned bytes */ if (type == 16) {x = short();} /* 16 pixel values are signed 2-byte integers */ if (type == 32) {x = long();} /* 32 pixel values are signed 4-byte integers */ if (type == -32) {x = float();} /* -32 pixel values are 4-byte floating points */ if (type == -64) {x = double();} /* -64 pixel values are 8-byte floating points */ if (is_void(x)) { close,file; error,"Unrecognized BITPIX value"; } data = array(x,naxis); if (_read(file,address,data) != numberof(data)) { close,file; error,"EOF encountered before all data were read"; } /* Scaling of data */ bzero= fitsHdrValue(hdr,"BZERO",default=0.); bscale= fitsHdrValue(hdr,"BSCALE",default=1.); if (bscale != 1.) {data *= bscale;} if (bzero != 0.) {data += bzero;} /* We're done */ close,file; return data; } func fitsHdrValue2(hdr,keyword,&position,default=) /* DOCUMENT val = fitsHdrValue(hdr,keyword,&position,default=) Returns the value associated with a keyword in a fits header. Returns "Not a Keyword" if keyword is not found and no default was given. Mandatory parameters: hdr: (input) header, as returned by yao_fitsread (string array) keyword: (input) keyword name, string Optional parameters: position: (output) position of keyword in header Optional keyword: default: (input) default return value if keyword is not found in the header. SEE ALSO: yao_fitsread, _fGetKeyword, _fGetValue This was an attempt to find a faster procedure that the following function, but it's slightly slower (not by much though). */ { key= strtrim(strtoupper(keyword)); w=where(strtrim(_fGetKeyword(hdr)) == key); if (is_void(hdr(w)) & !is_void(default)) return default; if (is_void(hdr(w)) & is_void(default)) return []; position = w(1); return _fGetValue(hdr(position)); } func fitsHdrValue(hdr,keyword,&position,default=) /* DOCUMENT val = fitsHdrValue(hdr,keyword,&position,default=) Returns the value associated with a keyword in a fits header. Returns "Not a Keyword" if keyword is not found and no default was given. Mandatory parameters: hdr: (input) header, as returned by yao_fitsread (string array) keyword: (input) keyword name, string Optional parameters: position: (output) position of keyword in header Optional keyword: default: (input) default return value if keyword is not found in the header. SEE ALSO: yao_fitsread, _fGetKeyword, _fGetValue */ { key= strtrim(strtoupper(keyword)); position= -1; for (i=1;i<=numberof(hdr);i++) { if (strtrim(_fGetKeyword(hdr(i))) == key) { position = i; return _fGetValue(hdr(i)); } } if (!is_void(default)) return default; return "Not a Keyword"; } sxpar = fitsHdrValue; func _fGetKeyword(line) {return strtoupper(strpart(line,1:8));} func _fGetValue(line,&comment) { if (strpart(line,9:9) != "=") {return [];} /* This is not a line that contains a valid keyword+value */ vline = strpart(line,10:80); vline = strtok(vline,"/"); val = strtrim(vline(1)); comment = strtrim(vline(2)); value = val; /* Case logical */ if (value == "T" || value == "t") {return int(1);} if (value == "F" || value == "f") {return int(0);} /* Case string */ if (strpart(val,1:1) == "'") {return strpart(val,2:-1);} x = long(); if (sread(val,format="%i",x)) {value = x;} if (strmatch(val,".")) { x = double(); if (sread(val,format="%g",x)) {value = x;} } return value; } func fitsHdrComment(hdr) { /* Return a string array containing the comment cards in hdr */ comment = []; for (i=1;i<=numberof(hdr);i++) { if (strtrim(_fGetKeyword(hdr(i))) == "COMMENT") grow,comment,strpart(hdr(i),10:80); } return comment; } func fitsHdrHistory(hdr) { /* Return a string array containing the history cards in hdr */ history = []; for (i=1;i<=numberof(hdr);i++) { if (strtrim(_fGetKeyword(hdr(i))) == "HISTORY") grow,history,strpart(hdr(i),10:80); } return history; } func _fCheckPrimaryHeader(hdr) { /* Is the header conform to FITS standard ? Some mandatory keywords have to be there */ ok = ((strtrim(_fGetKeyword(hdr(1))) == "SIMPLE") && (strtrim(_fGetKeyword(hdr(2))) == "BITPIX") && (strtrim(_fGetKeyword(hdr(3))) == "NAXIS")); return ok; } func _fCheckExtensionHeader(hdr,&XTtype) { /* Is the header conform to FITS standard ? Some mandatory keywords have to be there */ if (strtrim(_fGetKeyword(hdr(1))) != "XTENSION") return 0; XTtype = strtrim(fitsHdrValue(hdr,"XTENSION")); if (XTtype == "IMAGE") { /* fits image extension */ return (strtrim(_fGetKeyword(hdr(1))) == "XTENSION" && strtrim(_fGetKeyword(hdr(2))) == "BITPIX" && strtrim(_fGetKeyword(hdr(3))) == "NAXIS" && (fitsHdrValue(hdr,"PCOUNT") == 0) && (fitsHdrValue(hdr,"GCOUNT") == 1)); } if (XTtype == "TABLE") { /* fits table extension */ return (strtrim(_fGetKeyword(hdr(1))) == "XTENSION" && (fitsHdrValue(hdr,"BITPIX") == 8) && (fitsHdrValue(hdr,"NAXIS") == 2) && strtrim(_fGetKeyword(hdr(4))) == "NAXIS1" && strtrim(_fGetKeyword(hdr(5))) == "NAXIS2" && (fitsHdrValue(hdr,"PCOUNT") == 0) && (fitsHdrValue(hdr,"GCOUNT") == 1) && strtrim(_fGetKeyword(hdr(8))) == "TFIELDS"); } if (XTtype == "BINTABLE") { /* fits binary table extension */ error,"Binary table not yet handle by yao_fitsread"; return (strtrim(_fGetKeyword(hdr(1))) == "XTENSION" && strtrim(_fGetKeyword(hdr(2))) == "BITPIX" && strtrim(_fGetKeyword(hdr(3))) == "NAXIS" && strtrim(_fGetKeyword(hdr(4))) == "NAXIS1" && strtrim(_fGetKeyword(hdr(5))) == "NAXIS2" && strtrim(_fGetKeyword(hdr(6))) == "PCOUNT" && strtrim(_fGetKeyword(hdr(7))) == "GCOUNT" && strtrim(_fGetKeyword(hdr(8))) == "TFIELDS"); } error,"XTENSION type not recognized"; } func _fGetNaxis(hdr) { /* determine # of axis and dimensions */ nax = fitsHdrValue(hdr,"NAXIS",position); naxis = nax; for (i=1;i<=nax;i++) { grow,naxis,_fGetValue(hdr(position+i)); } return naxis; } func _fBuildArray(hdr) { naxis = _fGetNaxis(hdr); type = fitsHdrValue(hdr,"BITPIX"); /* Valid types: */ x= []; if (type == 8) {x = char();} /* 8 pixel values are unsigned bytes */ if (type == 16) {x = short();} /* 16 pixel values are signed 2-byte integers */ if (type == 32) {x = long();} /* 32 pixel values are signed 4-byte integers */ if (type == -32) {x = float();} /* -32 pixel values are 4-byte floating points */ if (type == -64) {x = double();} /* -64 pixel values are 8-byte floating points */ if (is_void(x)) error,"Unrecognized BITPIX value"; data = array(x,naxis); return data; } func _fReadHeader(file,&address) { /* Internal function to read a header (HDU or extension) the atomic fits block is 2880 bytes long. */ hdr = []; buffer = array(char, 80, 36); buffer_size = 80*36; end_not_found = 1; do { if (_read(file, address, buffer) != buffer_size) { close,file; error, "cannot read header"; } address += buffer_size; for (i=1; i<=dimsof(buffer)(3) && end_not_found; i++) { line = string(&buffer(,i)); grow,hdr,line; keyword = strtoupper(strpart(line,1:3)); if (keyword == "END") { end_not_found=0; break; } } } while (end_not_found); return hdr; } /*----------------------------------------------------------*/ func yao_fitswrite(filename,data,header,exttype=,append=,rescale=) /* DOCUMENT yao_fitswrite(filename,data,header,exttype=,append=,rescale=) Write a fits file. Primary HDU and possible append extensions. Current valid extension = only image. Usage: yao_fitswrite,filename,data,header,exttype=,append=,rescale= filename: input; filename as a string data: data. Can be void, scalar or multidimensionnal header: header. mandatory keywords are overwritten. exttype: Extension type. "PRIMARY" (default), "IMAGE" rescale: rescale data array SEE ALSO: */ { if (is_void(exttype)) exttype="PRIMARY"; exttype= strtoupper(strtrim(exttype)); if (exttype != "PRIMARY" && exttype != "IMAGE" && exttype != "BINTABLE") error,"Not a valid Extension type. Type help,yao_fitswrite for valid type"; if (exttype != "PRIMARY") append=1; // Rescale the data if requested: bzero= 0.; bscale= 1.; if (is_set(rescale) & !is_void(data)) { if (structof(data) == float || structof(data) == double) { if (structof(data) == float) { bitpix= 16; // float -> short } else { bitpix= 32; // double -> long } data= _fRescale(data, bitpix, bscale, bzero); } else { error,"Can only use rescale on float and double"; } } // Build a core header from data type/size hdr = _fBuildCoreHeader(exttype,data); // append the newly determined bzero and bscale grow,hdr,fitsBuildCard("BZERO",bzero,); grow,hdr,fitsBuildCard("BSCALE",bscale,); // test provided header to append to core header: if ((!is_void(header)) && (typeof(header) != "string")) error,"Wrong header type."; // strip input header from core keywords: if (!is_void(header)) grow,hdr,_fStripCoreFromHeader(header); // Add the END keyword grow,hdr,_fEndCard(); // Open the file for writes: local address; if (append) { stream = open(filename, "ab"); } else { stream = open(filename, "wb"); } sun_primitives, stream; address= 0L; // write header: for (i=1;i<=numberof(hdr);i++) { line = *pointer(hdr(i)); _write, stream, address, line(1:80); address +=80; } // pad for address = % 2880 _fPadFits,stream,address; // writes data: if (data != []) { _write,stream,address,data; address += long(abs(numberof(data)*fitsHdrValue(hdr,"BITPIX"))/8.); _fPadFits,stream,address; } close, stream; // Yorick uses a Contents Log file, which should be removed... if (open(filename+"L", "", 1)) {remove, filename+"L";} } func _fPadFits(stream,&address) { /* DOCUMENT _fPadFits(stream,address) This function pads with blanks up to the next multiple of 2880 and update address. SEE ALSO: */ toad = long(ceil(address/2880.)*2880); lstr = toad-address; if (lstr != 0) { pad = string(&array('\x20',lstr)); _write, stream, address, (*pointer(pad))(1:lstr); } address = toad; } func _fBuildCoreHeader(exttype,data) /* DOCUMENT header = _fBuildCoreHeader(exttype,data) Build the bearbone header for a given type (primary, image xtension, table xtension. Valid type are "primary","image","bintable" I don't handle binary Extension yet SEE ALSO: */ { upxtype = strtoupper(exttype); bitpix= []; if (typeof(data) == "void") bitpix=8; if (typeof(data) == "char") bitpix=8; if (typeof(data) == "short") bitpix=16; if (typeof(data) == "long") bitpix=32; if (typeof(data) == "int") bitpix=32; if (typeof(data) == "float") bitpix=-32; if (typeof(data) == "double") bitpix=-64; if (is_void(bitpix)) error,"Unsupported data type"; if (data != []) {dim= dimsof(data);} else {dim=[0];} hdr= []; if (upxtype == "PRIMARY") { grow,hdr,fitsBuildCard("SIMPLE",int(1),"file conforms to FITS standard"); } if (upxtype == "IMAGE") { grow,hdr,fitsBuildCard("XTENSION","IMAGE","IMAGE extension"); } if (upxtype == "BINTABLE") { grow,hdr,fitsBuildCard("XTENSION","BINTABLE","BINARY TABLE extension"); } grow,hdr,fitsBuildCard("BITPIX",bitpix,"number of bits per data pixel"); grow,hdr,fitsBuildCard("NAXIS",dim(1),"number of data axes"); for (i=1;i<=dim(1);i++) grow,hdr,fitsBuildCard("NAXIS"+swrite(format="%i",i),dim(1+i), "length of axis"+swrite(format="%i",i)); if (upxtype == "PRIMARY") { grow,hdr,fitsBuildCard("EXTEND",int(1),"FITS dataset may contain extensions"); } if (upxtype == "IMAGE") { grow,hdr,fitsBuildCard("PCOUNT",0l,"required keyword; must = 0"); grow,hdr,fitsBuildCard("GCOUNT",1l,"required keyword; must = 1"); } return hdr; } func _fStripCoreFromHeader(hdr) /* DOCUMENT header = _fStripCoreFromHeader(hdr) Strip (existing) header from the core card (simply,naxis,...) to be able to combine it with the core generated with _fBuildCoreHeader. SEE ALSO: */ { mask = (_fGetKeyword(hdr) != "SIMPLE ") & (strpart(_fGetKeyword(hdr),1:5) != "NAXIS") & (_fGetKeyword(hdr) != "BITPIX ") & (_fGetKeyword(hdr) != "EXTEND ") & (_fGetKeyword(hdr) != "PCOUNT ") & (_fGetKeyword(hdr) != "GCOUNT ") & (_fGetKeyword(hdr) != "XTENSION") & (_fGetKeyword(hdr) != "BZERO ") & (_fGetKeyword(hdr) != "BSCALE ") & (_fGetKeyword(hdr) != "END "); return hdr(where(mask)); } func fitsDeleteCard(&hdr,keyword) /* DOCUMENT fitsDeleteCard(hdr,keyword) Delete the card label "keyword" in hdr Returns hdr SEE ALSO: fitsAddCard */ { mask = (strtrim(_fGetKeyword(hdr)) != strtoupper(keyword)); hdr = hdr(where(mask)); return hdr; } func fitsAddCard(&hdr,keyword,value,comment,type=,form=, after=,before=,first=,last=) /* DOCUMENT fitsAddCard(hdr,keyword,value,comment,type=,form=, after=,before=,first=,last=) Add a new entry (card) in existing header "hrd". All keywords are optional. type (string): to force type of value (e.g. for logical) form (string): format, e.g "%13.8f" after (string): keyword before which to insert new card in header (if it doesn't exist, new card will be inserted at the end) before (string): see after first (long, boolean): if set, new card will be inserted as first card in header last (long, boolean): if set, new card will be inserted as last card in header SEE ALSO: fitsBuildCard */ { line = fitsBuildCard(keyword,value,comment,type=type,form=form); if (noneof([is_set(first),is_set(last),is_set(before), is_set(after)])) last=1; if (is_set(first)) { hdr = _(line,hdr); return hdr; } if (is_set(last)) { hdr = _(hdr,line); return hdr; } // after or before are set. // set key to which ever is set key = (is_set(before) ? before : after); // find position in current header fitsHdrValue,hdr,key,pos; // if requested after/before keyword does not exist, append // at the end and return: // note: it is not a problem to append at the end, possibly // after the "END" keyword, as this will be cleaned up by // when it's written up (yao_fitswrite). if (pos == -1) return _(hdr,line); ncard = numberof(hdr); if ((is_set(before)) & (pos == 1)) { hdr = _(line,hdr); return hdr; } if ((is_set(after)) & (pos == ncard)) { hdr = _(hdr,line); return hdr; } if (is_set(before)) { hdr = _(hdr(1:pos-1),line,hdr(pos:)); return hdr; } if (is_set(after)) { hdr = _(hdr(1:pos),line,hdr(pos+1:)); return hdr; } } func fitsAddComment(&hdr,comment,after=,before=,first=,last=) /* DOCUMENT fitsAddComment(hdr,comment,after=,before=, first=,last=) Add a new comment entry in existing header "hrd". All keywords are optional. after (string): keyword before which to insert new card in header (if it doesn't exist, new card will be inserted at the end) before (string): see after first (long, boolean): if set, new card will be inserted as first card in header last (long, boolean): if set, new card will be inserted as last card in header SEE ALSO: fitsAddHistory, fitsAddCard */ { line = "COMMENT "+comment+string(&(array(' ',80))); line = strpart(line,1:80); if (noneof([is_set(first),is_set(last),is_set(before), is_set(after)])) last=1; if (is_set(first)) { hdr = _(line,hdr); return hdr; } if (is_set(last)) { hdr = _(hdr,line); return hdr; } // after or before are set. // set key to which ever is set key = (is_set(before) ? before : after); // find position in current header fitsHdrValue,hdr,key,pos; // if requested after/before keyword does not exist, append // at the end and return: // note: it is not a problem to append at the end, possibly // after the "END" keyword, as this will be cleaned up by // when it's written up (yao_fitswrite). if (pos == -1) { hdr = _(hdr,line);return hdr; } ncard = numberof(hdr); if ((is_set(before)) & (pos == 1)) { hdr = _(line,hdr) ; return hdr; } if ((is_set(after)) & (pos == ncard)) { hdr = _(hdr,line) ; return hdr; } if (is_set(before)) { hdr = _(hdr(1:pos-1),line,hdr(pos:)) ; return hdr; } if (is_set(after)) { hdr = _(hdr(1:pos),line,hdr(pos+1:)) ; return hdr; } } func fitsAddHistory(&hdr,comment,after=,before=,first=,last=) /* DOCUMENT fitsAddHistory(hdr,comment,after=,before=, first=,last=) Add a new history entry in existing header "hrd". All keywords are optional. after (string): keyword before which to insert new card in header (if it doesn't exist, new card will be inserted at the end) before (string): see after first (long, boolean): if set, new card will be inserted as first card in header last (long, boolean): if set, new card will be inserted as last card in header SEE ALSO: fitsAddHistory, fitsAddCard */ { line = "HISTORY "+comment+string(&(array(' ',80))); line = strpart(line,1:80); if (noneof([is_set(first),is_set(last),is_set(before), is_set(after)])) last=1; if (is_set(first)) { hdr = _(line,hdr); return hdr; } if (is_set(last)) { hdr = _(hdr,line); return hdr; } // after or before are set. // set key to which ever is set key = (is_set(before) ? before : after); // find position in current header fitsHdrValue,hdr,key,pos; // if requested after/before keyword does not exist, append // at the end and return: // note: it is not a problem to append at the end, possibly // after the "END" keyword, as this will be cleaned up by // when it's written up (yao_fitswrite). if (pos == -1) { hdr = _(hdr,line); return hdr; } ncard = numberof(hdr); if ((is_set(before)) & (pos == 1)) { hdr = _(line,hdr); return hdr; } if ((is_set(after)) & (pos == ncard)) { hdr = _(hdr,line); return hdr; } if (is_set(before)) { hdr = _(hdr(1:pos-1),line,hdr(pos:)); return hdr; } if (is_set(after)) { hdr = _(hdr(1:pos),line,hdr(pos+1:)); return hdr; } } func fitsBuildCard(keyword,value,comment,type=,form=) /* type optional, to force type of value (e.g. for logical) */ /* form= format, optional */ { if (is_void(comment)) comment=""; pad= string(&array('\x20',80)); line= strpart(swrite(format="%-8s",strtoupper(keyword)),1:8); if (is_void(value)) { line = strpart(line+pad,1:80); return line; } line+= "= "; if (!is_void(form)) { line+= swrite(format=form,value); } else { if (typeof(value) == "string") line+= swrite(format="%-20s",swrite(format="'%-8s'",value)); if (typeof(value) == "int") { if (value == 0) line+= swrite(format="%20s","F"); if (value == 1) line+= swrite(format="%20s","T"); } if (typeof(value) == "long") line+= swrite(format="%20i",value); if (typeof(value) == "float" || typeof(value) == "double") line+= swrite(format="%#20g",value); } line+= " / "+comment; line= strpart(line+pad,1:80); return line; } // remove below as it creates problem with the is_set of util_fr.i in yutils. //func is_set(arg) /* DOCUMENT is_set(arg) Returns 0 if element is void or equal to zero, 1 otherwise F.Rigaut 2002/06/03 SEE ALSO: is_void */ //{ // if (is_void(arg) | (arg == 0)) {return 0;} // else {return 1;} //} func _fRescale(data, bitpix, &bscale, &bzero, data_min=, data_max=) /* DOCUMENT rescaled_data= _fRescale(data, bitpix, bscale, bzero, data_min=, data_max=) Linearly rescale the values of input array DATA to fit into integers with BITPIX bits per value (i.e., `char', `short' or `long' for BITPIX being 8, 16 and 32 respectively). Arguments BSCALE and BZERO are optional and purely outputs passed by address. Their value will be set so that: DATA(i) = BZERO + BSCALE * RESCALED_DATA(i) where the equality may not be exact due to rounding errors. The difference is however the smallest possible, i.e., less than BSCALE / 2. Keywords DATA_MIN and DATA_MAX may be used to supply the maximum and minimum data values or to set brightness cutoffs. Originally from fitsRescale in the Yorick fits.i distrib. SEE ALSO: */ { if (bitpix == 8) { // assume ``char'' is 8 bits unsigned file_type= char; file_unsigned= 1N; } else if (bitpix == 16) { // assume ``short'' is 16 bits signed file_type= short; file_unsigned= 0N; } else if (bitpix == 32) { // assume ``long'' is 32 bits signed file_type= long; file_unsigned= 0N; } else { error, "bad BITPIX (should be 8, 16 or 32)"; } data_min= double((is_void(data_min)? min(data) : data_min)); data_max= double((is_void(data_max)? max(data) : data_max)); if (data_max < data_min) error, "bad DATA_MAX and DATA_MIN"; if (file_unsigned) { file_min= 0.; file_max= 2.^bitpix - 1.; } else { file_min= -2.^(bitpix - 1); file_max= 2.^(bitpix - 1) - 1.; } if (data_max == data_min) { bzero= double(data_min); return array(file_type(0), dimsof(data)); } bscale= (data_max - data_min) / (file_max - file_min); bzero= data_min - bscale * file_min; return file_type(min(file_max, max(file_min, (data - bzero) / bscale))); } func _fEndCard(void) {return "END ";} // lowercase equivalent: // fitshead = yao_fitshead; // fitsread = yao_fitsread; // fitswrite = yao_fitswrite; fitshdrvalue = fitsHdrValue; fitshdrcomment = fitsHdrComment; fitshdrhistory = fitsHdrHistory; fitsdeletecard = fitsDeleteCard; fitsaddcard = fitsAddCard; fitsaddcomment = fitsAddComment; fitsaddhistory = fitsAddHistory; fitsbuildcard = fitsBuildCard; yao-5.4.0/yao_setnsync.i000066400000000000000000000264221234404334100152040ustar00rootroot00000000000000/* * yao_setnsync.i * * Compilation of functions related to yao svipc process communication * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ local yao_setnsync; /* DOCUMENT yao_setnsync.i Implement setting of a selected number of important variables in an yao session, e.g., r0, wfs noise, wfs flux, etc... - Set the proper variables, and write in shared memory if need be. - Execute the needed action to effect the change (e.g. changing the Cn2 profile will need to re-run get_turb_phase_init() ) Implement syncing of the child, when in svipc mode. - read the shared memory structure - Execute the needed action to effect the change (e.g. changing the Cn2 profile will need to re-run get_turb_phase_init() ) SEE ALSO: yao, yao_svipc */ // UTILITY/GENERIC FUNCTIONS func init_sync(void) { for (i=1;i<=numberof(all_svipc_procname);i++) { shm_write,shmkey,"sync_"+all_svipc_procname(i),&sv2cv(""); } } func sync_child(void) { slotname = "sync_"+svipc_procname; mes = shm_read(shmkey,slotname); mes = cv2sv(mes)(1); // one at a time. FIXME if (mes!="") { if (smdebug) write,format="%s executing %s\n",svipc_procname,mes; include,["status = "+mes+"()"],1; shm_free,shmkey,slotname; shm_write,shmkey,slotname,&sv2cv(""); } } func broadcast_sync(targets,msg) { for (i=1;i<=numberof(targets);i++) { slotname = "sync_"+targets(i); shm_free,shmkey,slotname; shm_write,shmkey,slotname,&sv2cv(msg); } } /* struct setnsync { string prop; func set_generic(prop,value) { extern atm,opt,sim,wfs,dm,mat,tel,target,gs,loop,phi; local var; wfs.noise = noise_flag; if (sim.svipc) { targets = ["WFS","WFS1","WFS2","WFS3"]; // save the wfs structures var = vsave(wfs); // write in shm shm_write,shmkey,"wfs_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_noise"; } // no action to take. } */ // SETS & SYNCS FUNCTIONS // for the WFS forks: func sync_wfs_forks(pupsh) /* DOCUMENT sync_wfs_forks(pupsh) Must be invoqued from main process to sync wfs forks after any modification to the wfs structure has been done. This will sync the fork on the next call to sh_wfs SEE ALSO: */ { extern sync_init_done; if (pupsh==[]) pupsh=ipupil; // save the wfs structures var = vsave(wfs); // write in shm // if doing a shm_free, we need to protect with sem // as the client could try to read in between the shm_free // and the shm_write. not done. bug still open. if (sync_init_done) shm_free,shmkey,"wfs_structs"; shm_write,shmkey,"wfs_structs",&var; shm_write,shmkey,"pupsh",&ipupil; // broadcast message to children // increment shm variable each time a sync is done. for (ns=1;ns<=nwfs;ns++) { vname = swrite(format="sync_wfs%d_forks",ns); if ( (sync_init_done) && (wfs(ns)._svipc_init_done) ) { var = shm_read(shmkey,vname); } else { var = [0]; sync_init_done = 1; } shm_write,shmkey,vname,&(var+1); } } func sync_wfs_from_master(ns,nf) /* DOCUMENT sync_wfs_from_master(ns,nf) To be called from a wfs fork to sync itself with master process ns = wfs # nf = fork # SEE ALSO: */ { extern wfs; extern prev_sync_counter; extern pupsh; if (prev_sync_counter==[]) prev_sync_counter=0; vname = swrite(format="sync_wfs%d_forks",ns); sync_counter = shm_read(shmkey,vname)(1); if (sync_counter == prev_sync_counter) return; pupsh = shm_read(shmkey,"pupsh"); var = shm_read(shmkey,"wfs_structs"); restore,openb(var); prev_sync_counter = sync_counter; if (sim.debug>1) \ write,format="WFS sync'ed on WFS#%d fork#%d\n", ns, nf; if (sim.debug>20) \ write,format="%d thmethod=%d thres=%f\n",getpid(), wfs(ns).shthmethod, wfs(ns).shthreshold; } func set_noise(noise_flag) { extern wfs; local var; wfs.noise = noise_flag; if (sim.svipc) { //~ targets = ["WFS","WFS1","WFS2","WFS3"]; targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); // save the wfs structures var = vsave(wfs); // write in shm shm_write,shmkey,"wfs_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_noise"; } if (anyof(wfs.svipc)) { // save the wfs structures var = vsave(wfs); // write in shm shm_write,shmkey,"wfs_structs",&var; status = sync_wfs_forks(); } // no action to take. } func sync_noise(void) { extern wfs; if (sim.svipc) { var = shm_read(shmkey,"wfs_structs"); restore,openb(var); } write,format="Noise sync'ed on child %s\n",svipc_procname; // no action to take. } func set_dr0(dr0) { extern atm; local var; if (!is_scalar(dr0)) { write,"Usage: set_dr0, scalar value"; return; } atm.dr0at05mic = dr0 if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); targets = _(targets,"PSFs"); // save the atm structures var = vsave(atm); // write in shm shm_write,shmkey,"atm_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_dr0"; } // action to take. get_turb_phase_init,skipReadPhaseScreens=0; } func sync_dr0(void) { extern atm; if (sim.svipc) { var = shm_read(shmkey,"atm_structs"); restore,openb(var); } write,format="D/r0 sync'ed on child %s (D/r0=%.2f)\n",\ svipc_procname,atm.dr0at05mic; // action to take. get_turb_phase_init,skipReadPhaseScreens=0; } func set_cn2(layerfrac) { extern atm; local var; if (nallof(dimsof(layerfrac)==dimsof(*atm.layerfrac))) { write,format="Usage: set_cn2, layerfrac = %d element vector\n",\ numberof(*atm.layerfrac); return; } layerfrac = layerfrac/sum(layerfrac); *atm.layerfrac = layerfrac; if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); targets = _(targets,"PSFs"); // save the wfs structures var = vsave(atm); // write in shm shm_write,shmkey,"atm_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_cn2"; } // action to take. get_turb_phase_init,skipReadPhaseScreens=1; } func sync_cn2(void) { extern atm; if (sim.svipc) { var = shm_read(shmkey,"atm_structs"); restore,openb(var); } write,format="Cn2 sync'ed on child %s\n",svipc_procname; // action to take. get_turb_phase_init,skipReadPhaseScreens=1; } func set_misreg(misreg,nm=) { extern dm; local var; if (nm==[]) nm=1:3; dm(nm).misreg = misreg; if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); targets = ["WFS","WFS1","WFS2","WFS3"]; if ((sim.svipc>>1)&1) grow,targets,["DM1","DM2"]; // save the wfs structures var = vsave(dm); // write in shm shm_write,shmkey,"dm_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_misreg"; } // no action to take. } func sync_misreg(void) { extern dm; if (sim.svipc) { var = shm_read(shmkey,"dm_structs"); restore,openb(var); } write,format="Misreg sync'ed on child %s\n",svipc_procname; // no action to take. } func reset_strehl(void) { extern imav, niterok,strehls_inter,psf_child_started; if (sim.svipc) { targets = ["PSFs"]; // nothing to pass // broadcast message to children broadcast_sync,targets,"sync_reset_strehl"; } // no action to take. imav *= 0; niterok = 0; // shm_write,shmkey,"imlp",&imav; psf_child_started=0; // strehls_inter *= 0; } func sync_reset_strehl(void) { extern imav, niterok; imav *= 0; niterok = 0; } func set_ngs_geometry(wfsxpos,wfsypos) { extern wfs; ngs = numberof(wfsxpos); wfs(6:6+ngs-1).gspos(1,) = wfsxpos; wfs(6:6+ngs-1).gspos(2,) = wfsypos; if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); targets = _(targets,"PSFs"); // save the wfs structures var = vsave(wfs); // write in shm shm_write,shmkey,"wfs_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_ngs_geometry"; } get_turb_phase_init,skipReadPhaseScreens=1; } func sync_ngs_geometry(void) { extern wfs; if (sim.svipc) { var = shm_read(shmkey,"wfs_structs"); restore,openb(var); } write,format="NGS geometry sync'ed on child %s\n",svipc_procname; // no action to take. get_turb_phase_init,skipReadPhaseScreens=1; } func set_lgs_profile(amp,alt,lgs_focus_alt,ns) { extern wfs; if (numberof(amp)!=numberof(alt)) { write,"numberof(amp)!=numberof(alt)"; return; } for (i=1;i<=numberof(ns);i++) { if (amp!=[]) wfs(ns(i)).lgs_prof_amp = &float(amp); if (alt!=[]) wfs(ns(i)).lgs_prof_alt = &float(alt); if (lgs_focus_alt!=[]) wfs(ns(i)).lgs_focus_alt = lgs_focus_alt; \ shwfs_comp_lgs_defocuses,ns(i); } if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); // save the wfs structures var = vsave(wfs); // write in shm shm_write,shmkey,"wfs_structs",&var; // broadcast message to children broadcast_sync,targets,"sync_lgs_profile"; } } func sync_lgs_profile(void) { extern wfs; if (sim.svipc) { var = shm_read(shmkey,"wfs_structs"); restore,openb(var); } write,format="LGS profile sync'ed on child %s\n",svipc_procname; //~ for (i=1;i<=numberof(ns);i++) shwfs_comp_lgs_defocuses,ns(i); } // more generic functions: func sync_wfs(void) { if (sim.svipc) { targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); // save the wfs structures var = vsave(wfs); // write in shm shm_free,shmkey,"wfs_structs"; shm_write,shmkey,"wfs_structs",&var; // broadcast message to children broadcast_sync,targets,"child_sync_wfs"; } } func child_sync_wfs(void) { extern wfs; if (sim.svipc) { var = shm_read(shmkey,"wfs_structs"); restore,openb(var); } write,format="WFS structure sync'ed on child %s\n",svipc_procname; } func sync_opt(void) { if (opt==[]) return; if (!sim.svipc) return; targets = all_svipc_procname(where(strmatch(all_svipc_procname,"WFS"))); grow,targets,all_svipc_procname(where(strmatch(all_svipc_procname,"PSFs"))); // save the opt structures var = vsave(opt); // write in shm shm_free,shmkey,"opt_structs"; shm_write,shmkey,"opt_structs",&var; // broadcast message to children broadcast_sync,targets,"child_sync_opt"; } func child_sync_opt(void) { extern opt; if (opt==[]) return; if (!sim.svipc) return; var = shm_read(shmkey,"opt_structs"); restore,openb(var); write,format="OPT structure sync'ed on child %s\n",svipc_procname; } yao-5.4.0/yao_structures.i000066400000000000000000001022131234404334100155520ustar00rootroot00000000000000/* * yao_structures.i * * Definitions of yao structures * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ local yao_structures; /* DOCUMENT wfs, dm, atmospheric, etc.. structures: Main structures for the AO simul package parameters If additional parameters are needed, they should be entered in these structures definition and changes reflected in the parameter file (e.g. sh12.par) There are several type of entries: - long, float, string scalars: e.g. > atm.dr0at05mic = 33.; - pointers: These are pointers to variables that can have arbitrary number of elements. You have to define them in the following way: > wfs.nsubperring = &( [6,12,18] ); Structure members can be accessed in the following way: var = dm.type; var = *atm.layerfrac; // "*" dereference a pointer If there are several instance of a given structure: for instance, it is common to have a system with several dm: dm.type is thus a vector of the types of all instance of structure "dm" dm(1).type is a scalar *wfs(1).nsubperring is a vector. (*wfs(1).nsubperring)(1) is the first element of this vector. The variables with a "_" in frnt of them are internal variables. they are set and used while the program is running. You can still access them, and possibly modify them to reach a particular purpose. The following generic structures are instanced into structures of the same name, without the "_struct" appended, when the parameter file is read. For instance, "atm" will be the structure containing the atmospheric parameters as defined in the generic type atm_struct below. SYNTAX OF THE COMMENTS BELOW: For each entries, we give the type (scalar, vectorptr -vector pointer-, etc), what the parameter is, possible comments, whether the parameter is required or optional, and the default between []. As a general comment: when the structures are instanciated, all their elements get a default value. This is zero (0) for a float or long (scalar or vector), empty string for a string, and 0x0 for a pointer. modified 2004oct18 for aosimulv3.3 to 3.5 modified 2004july for aosimulv3.0 to 3.3 modified 2004jan-mar for aosimulv2.4 to 3.0 modified 2003dec20-24 for aosimul-v2.3 modified 2003dec19 for aosimul-v2.2 modified 2003feb19 for aosimul-v1.2 AUTHOR: F.Rigaut, beginning 2002 SEE ALSO: All ao simul functions (aoread, aoinit, aoloop). */ struct sim_struct { string name; // A name for this simulation run. Optional [none] long pupildiam; // Pupil diameter in pixels. Required [none] long pupilapod; // whether to use an apodized pupil (rolled off @ edges) for // some image calculations. Optional [0] long debug; // set the debug level (0:no debug, 1:some, 2: most). Optional [0] long verbose; // set the verbose level (0:none, 1: some, 2: most). Optional [0] long svipc; // set to the number of process for parallelization // 0 = no parallelization // bits effect // 0(1) WFS/DM global split (2 process) // 1(2) PSFs calculation parallelization // e.g. sim.svipc = 1 -> split WFS/DM // e.g. sim.svipc = 2 -> parallelize PSFs // e.g. sim.svipc = 3 -> WFS/DM & PSFs long svipc_wfs_nfork;// nb of forks when splitting WFSs (one or more WFS per // fork). if not set, will be min([nwfs,nprocessors]); pointer svipc_wfs_forknb;// sim.svipc_wfs_forknb is a vector, with nb of // elements = # of WFS, and which contains // the fork# for each WFS; e.g.: // sim.svipc_wfs_forknb = &([1,1,2,2,3]); // means run WFS 1 and 2 in WFS fork 1 // run WFS 3 and 4 in WFS fork 2 // and run WFS 5 in WFS fork 3. // as a special case, 0 means run in WFS // parent (the one from which all WFS // children were forked). To be implemented // at a later stage. If this vector is not // specified, we will spread the WFS evenly // (as best as possible) within the N // (=sim.svipc_wfs_nfork) WFS forks. long shmkey; // shared memory key (there's a default). // Change to run multiple simul in parallel. long semkey; // shared memory key (there's a default) // Internal keywords: long _size; // Internal. Size of the arrays [pixels] float _cent; // Internal. Pupil is centered on (_cent,_cent) }; struct atm_struct { float dr0at05mic; // Dr0 at sensing wavelength, at zenith. Required [none]. pointer screen; // string vectorptr. Screen file names. Required [none]. pointer layerfrac; // float vectorptr. Layer fraction. Sum to one is insured // in aoinit. Required [none] pointer layerspeed; // float vectorptr. Layer speed. Required [none] pointer layeralt; // float vectorptr. Layer altitude (m). Specified at Zenith. // Required [none] pointer winddir; // Wind dir (use 0 for now) // Internal variables pointer _layeralt; // float vectorptr. Actual layer altitude (m), from atm.alt & zen.angle }; struct opt_struct { string phasemaps; // filename of phasemap. Z scale should be in microns string path_type; // "common", "wfs" or "target", self explanatory I assume. pointer path_which; // pointer to vector containing index of affected objects in "path" // path_type="wfs" and path_which=&([1,3]) means only wfs1 and 3 see this optic // obviously, this works only if path_type is either "wfs" or "target". // if you want to apply the optic to some wfs *and* some target, // then you'll have to create 2 opt structures with the same optic, // one with path_type="wfs" and path_which, and the other path_type="target" // and path_which. float alt; // float. equivalent altitude in m. float misreg(2); // float vector. misreg. (similar to DM, see below) float scale; // convenient to scale the aberration, default=1.0 float _cent; // center of the phase maps arrays (similar to sim._cent) }; struct wfs_struct { string type; // valid type are "curvature", "hartmann", "dh", // "pyramid", "zernike" or "user_function" where user_function // is the name of a function defined by the user (see doc). // Required [none] long subsystem; // Subsystem this WFS belongs to. Optional [1] float lambda; // WFS wavelength in microns. Required [none] long noise; // Enable noise (photon noise/read out noise). Optional [0=no]. float ron; // Read out noise in electrons. If wfs.shmethod=1, this is the noise in arcseconds. Optional [0] float darkcurrent; // dark current in e-/sec/pixel or APD. Optional [0] float gspos(2); // This WFS guide star position (x=0. Optional [0] float shcalibseeing; // fraction of the seeing FWHM to be used in the iMat calibration float biasrmserror; // rms error on WFS bias in electron. Optional [0] float flatrmserror; // rms error on WFS flat, referenced to 1. Optional [0] // Typical value can be 0.01 string fsname; // fits file with subaperture amplitude mask. It should have // dimension 2^sdimpow2 square. can be float or long. string fstop; // "none", "square" or "round" are allowable values float fssize; // side (square) or diameter (round) of field stop [arcsec] float fsoffset(2); // offset (arcsec) in x and y (2 elements vector) float kernel; // FWHM in arcsec of WFS gaussian kernel. Optional. // Default is computed as a function of D/r0 int nintegcycles; // # of cycles/iterations over which to integrate. Optional [1] float fracIllum; // fraction illuminated to be valid. Optional [0.5] long centGainOpt; // Centroid Gain optimization flag. only for LGS (correctupTT and // filtertilt must be set). Optional [0] // SHWFS, LGS/LLT related parameters: float LLTxy(2); // 2 element vector with (x,y) of laser projector [m] int LLT_uplink_turb;// boolean. Set to 1 to model uplink seeing. float LLTr0; // r0 @ LLT @ laser wavelength [m] float LLTdiam; // LLT diameter [m]. float LLT1overe2diam; // LLT 1/e2 diameter [m] // float LLTlaserM2; // laser M2. Setting this will overwrite wfs.kernel to model M2 int rayleighflag; // set to one to take rayleigh into account float lgs_focus_alt; // LGS WFS current focusing altitude [m] pointer lgs_prof_amp; // vector of lgs profile (intensity, Arbitrary, renormlaized later using laserpower), same # as lgs_prof_alt pointer lgs_prof_alt; // vector of lgs profile (altitudes [m]), same # as lgs_prof_amp // zernike wfs only int nzer; // # of zernike sensed // DH wfs only int ndh; // # of dh sensed int ndhfiltered; // # of dh filtered. 2 would filter tip and tilt. // Internal keywords: int _initkernels; // put in wfs struct for svipc sync 2010jun25 int _svipc_init_done; // svipc init done for this wfs pointer _svipc_subok; // vector (length=nsub4disp) 0-> skip comput. of spot. 1->do it. pointer _fork_subs; // matrix signing which subap have to be processed by the various // wfs fork (dim=nforkxnsub). 0-> skip, 1-> process. pointer _fork_subs2; // same, but for call to _shwfs_spots2slopesa pointer _validsubs; // 0/1 mark invalid/valid, out of the ones selected for display float _origpixsize; // Internal. int _rebinfactor; // fft pixels to big pixels float _gsalt; // This WFS guide star altitude in meter. 0 for infinity. float _gsdepth; // This WFS GS depth in meter (e.g. Na layer thickness). int _nsub; // Internal. Tot # of valid subs. int _nsub4disp; // Internal. Tot # of subs to display. long _nmes; // internal. Tot # of measurements. pointer _sind; // Internal: see CurvWFS pointer _nsind; // Internal: see CurvWFS pointer _cxdef; // Internal: see CurvWFS pointer _sxdef; // Internal: see CurvWFS pointer _tiltsh; // Internal: see sh_wfs pointer _masks; // Internal: see sh_wfs pointer _fluxpersub; // Internal: see sh_wfs pointer _rayleighflux; // internal pointer _sodiumflux; // internal pointer _raylfluxpersub;// Internal: see sh_wfs pointer _skyfluxpersub; // Internal: see sh_wfs float _nphotons; // Internal: see WFS routines float _skynphotons; // Internal: see WFS routines float _tt(2); // Internal: WFS measured Tip and tilt float _lastvalidtt(2);// Internal: WFS measured Tip and tilt float _upttcommand(2);// Internal: pointer _refmes; // internal: reference measurement vector pointer _tiprefv; // internal: tip reference meas. vector pointer _tiltrefv; // internal: tilt reference meas. vector pointer _tiprefvn; // internal: tip reference meas. vector. normalized (norm=1) pointer _tiltrefvn; // internal: tilt reference meas. vector. normalized. pointer _reordervec; // To match with actual systems, one might want to re-order // at the lowest yao level. *wfs(n)._reorder contains a vector of indices int _npixels; // internal: final # of pixels in subaperture int _npb; // internal: number of pad pixel for extended field option (on each side) int _sdim; // dimension of simage in shwfs fast code int _nx; // dimension of extended array image int _nx4fft; // dimension of extended array image (for fft) pointer _istart; // pointer _jstart; // pointer _binindices; // int _binxy; // pointer _centroidw; // pointer _fimage; // pointer _fimage2; // pointer _imistart; // pointer _imjstart; // pointer _imistart2; // pointer _imjstart2; // pointer _unittip; // unit tip array (1,2,3,...) for enlarging dynamical range pointer _unittilt; // same for tilt pointer _lgs_defocuses; // vector of defocus values (in rd) corresponding to lgs_profile_alt pointer _unitdefocus; // as it says. float. dimsof [2,sim._size,sim._size] int _fimnx; // x dim of wfs._fimage int _fimny; // y dim of wfs._fimage pointer _fimny2; // y dim of (possibly split) wfs._fimage for _shwfs_spots2slopes (svipc) pointer _yoffset; // y offset of wfs._fimage for _shwfs_spots2slopes (svipc) pointer _bias; // internal: array of bias error pointer _flat; // internal: array of flat error long _domask; // internal. flag to do submask calculations in _shwfs pointer _submask; // internal: array. subaperture amplitude mask. pointer _kernel; // internal: kernel for _shwfs. use: dointer or LGS uplink im. pointer _kernels; // internal: subaperture dependant image kernel pointer _kerfftr; // internal: storage of FFTs of kernels pointer _kerffti; // internal: storage of FFTs of kernels int _kernelconv; // interal: convolve with kernel in _shwfs? int _cyclecounter; // counter in integration sequence (see nintegcycles above) pointer _dispimage; // image to display (same as fimage except if nintegcycles!=1) pointer _x; // shwfs: X positions of subaperture centers pointer _y; // shwfs: Y positions of subaperture centers float _centroidgain; // internal: centroid gain if dithering on pointer _rayleigh; // pointer to rayleigh images array for this sensor pointer _bckgrdcalib; // pointer to background array calibration int _bckgrdinit; // set to one to fill calibration array int _bckgrdsub; // set to one to subtract background (default) pointer _meashist; // measurement history, useful for nintegcycles > 1 float _zeropoint; // zeropoint for the wavefront sensor. pointer _pha2dhc; // projection matrix phase to DH coefs for this wfs pointer _wpha2dhc; // valid phase points indices int _n12(2); // int _LLT_use; // internal: don't duplicate turbulent kernel def, use # instead string _LLT_pscreen_name;// phase screen for the LLT uplink seeing. Will be created // if it is not found. Should be transparent to user. has // to be square for wrapping in both X and Y. Can be rather small, // say 256x256, as we're dealing with D/r0 of 2-3, and thus // we won't use a lot of pixels. pointer _LLT_pscreen; // pointer to the phase screen array float _LLT_pos(2); // current lower left position of phase to be extracted from _LLT_pscreen pointer _LLT_pupil; // LLT gaussian pupil pointer _LLT_phase; // actual phase pointer _LLT_kernel; // pointer to actual LLT spot image int _nkernels; // number of kernels in *wfs._kernel }; struct dm_struct { string type; // valid types are "bimorph", "stackarray" "tiptilt", // "dh", "zernike", "kl", "segmented", "aniso" or // "user_function", where user_function is the name of // a function provided by the user. Required [none] long subsystem; // Subsystem this DM belongs to. Optional [1] long virtual; // virtual DMs for tomography, don't correct wavefront pointer dmfit_which; // which tomographic virtual DMs are used to drive this DM string iffile; // Influence function file name. Leave it alone. float pitch; // Actuator pitch (pixel). stackarray/segmented only. Required [none] float alt; // Conjugation altitude in meter. Specified @ zenith! Optional [0] float hyst; // DM actuator hysteresis (0. to 0.25). Optional [0] float push4imat; // Voltage to apply for imat calibration. Optional [20]. // Note: the default is not OK for many configs. Change at will. float thresholdresp; // Normalized response threshold for an act. to be valid. Optional [0.3] float unitpervolt; // Influence function sensitivity in unit/volt. Optional [0.01] // Stackarray: mic/volt, Tip-tilt: arcsec/volt. float maxvolt; // Saturation voltage (- and +) in volt. Optional [none if not set] float gain; // loop gain for this DM (total = this x loop.gain). Optional [1] // alternatively, use numerator AND denominator to specify the controller // an integral controller with a loop gain of 0.5 and a leak of 0.01 is // numerator = &([0.5]); denominator = ([1.,-0.99]); pointer ctrlnum; // control law numerator, [z^0, z^-1, ...] pointer ctrlden; // control law denominator, [z^0, z^-1, ...] pointer _ctrlnum; // where to store the used values pointer _ctrlden; // where to store the used values float misreg(2); // dm misregistration (pixels). optional [0,0] long xflip; // flip influence functions left/right long yflip; // flip influence functions up/down float pupoffset(2); // global offset in pupil of whole actuator pattern [m] long disjointpup; // boolean. if set, dm(n) will be filtered by an array // disjointpup(,,n) that has to be defined by the user // see user_pupil(). Allow for GMT-type topology. pointer pegged; // pointer to a vector that contains index of pegged actuators // that is, dead actuators (index in valid numbering) pointer epegged; // same for extrapolated actuators (index in extrap numbering) long ncp; // boolean. if set, the mirror is on the non-common path for MOAO type correction string ncpfit_type; // whether to fit to a wfs or target to non-common path long ncpfit_which; // which target or wfs to fit to for non-common path long use_def_of; // don't compute defs but use the one computed for dm# use_def_of float ifunrot; // rotation of influence functions (degrees) float xscale; // rotation of influence functions (degrees) // Bimorph-only keywords: pointer nelperring; // long vectorptr. # of elec. per ring, e.g &([6,12,18]). Required [none] pointer angleoffset; // float vectorptr. offset angle for first electrode in ring. pointer rint; // float vectorptr. if set, specify the inner radius for each ring pointer rout; // float vectorptr. if set, specify the outer radius for each ring float supportRadius; // radius of support points, normalized in pupil radius float supportOffset; // angle offset of first support points, in degree (default=90) // Stackarray-only keywords: long nxact; // # of act. in pupil diameter. Required [none] float pitchMargin; // margin to include more corner actuators when creating inf.functions // optional [1.44] float coupling; // coupling coef in influence function. optional [0.2]. // valid values from 0.04 to 0.30. string ecmatfile; // valid to extrap. actuator matrix (extrap_com). Optional. long noextrap; // set to 1 if no extrapolated actuators whatsoever are to be used [0] long elt; // set to 1 if fast dmsum to be used long irexp; // use old/regular form (irexp=0) or // exp(-(d/irfact)^1.5) model (irexp=1) or // sinc*gaussian (irexp=2) float irfact; // use when irexp=1 (see above) long filtertilt; // Filter TT on this DM? Optional [0=no] // Zernike-only keywords: long nzer; // Number of modes, including piston. Required [none] long minzer; // lowest order zernike, default=1 (piston) // Disk-Harmonic only keywords long ndh; // number of DH modes // KL-only keywords: long nkl; // Number of modes, including piston. Required [none] // Segmented only keywords: long nxseg; // number of segments in long axis (X) float fradius; // segments are created over a wider area than the // nxseg defined above. Only segments which distance // to the (0,0) pupil coordinates is <= fradius // will be kept (pixels). default dm.pitch*dm.nxseg/2. // MMSE and sparse MMSE matrix reconstructor parameters: float regparam; // regularization parameter string regtype; // regulatization matrix generation method. pointer regmatrix; // matrix used in the regularization // Hysteresis variables float _alpha(3); float _beta(3); float _w(3); pointer _x0; pointer _xlast; pointer _ylast(3); pointer _y0; pointer _signus; // Internal keywords: long _puppixoffset(2); long _nact; // Internal. Tot # of actuators. pointer _def; // Internal: Pointer to IF data pointer _x; // Internal: x position of actuator in pixels pointer _y; // Internal: x position of actuator in pixels pointer _i1; // pointer _j1; // pointer _ei1; // pointer _ej1; // pointer _indval; // indices of valid actuators in pre-filtered DM vector pointer _indext; // indices of extrapolated actuators in pre-filtered DM vector string _eiffile; // Influence function file name for extrap. actuators pointer _edef; // Internal: Pointer to IF data for extrap. actuators pointer _ex; // Internal: x position of extrap. actuator in pixels pointer _ey; // Internal: x position of extrap. actuator in pixels long _enact; // Internal. Tot # of extrap. actuators. long _n1; // Internal: position of leftmost pixel in ao._size^2 array long _n2; // Internal: position of leftmost pixel in ao._size^2 array pointer _pupil; // Internal. Mask for display. pointer _command; // pointer to command vector pointer _flat_command; // pointer to command vector pointer _extrapcmat; // extrapolation matrix: extrap_com = extrapmat(,+)*valid_com(+) int _eltdefsize; // size of def in case elt=1 pointer _regmatrix; // regularization matrix used, if any pointer _fMat; // fitting matrix for tomography }; struct mat_struct { string method; // reconstruction method: "svd" (default), "mmse", "mmse-sparse" pointer condition; // float vecorptr. Condition numbers for SVD, per subsystem. Required [none] long sparse_MR; // maximum number of rows for sparse method long sparse_MN; // maximum number of elements for sparse method float sparse_thresh; // threshold for non-zero sparse elements float sparse_pcgtol; // tolerance for reconstruction, default = 1e-3 string file; // iMat and cMat filename. Leave it alone. // fitting parameters for tomographic reconstruction long fit_simple; // 0 or 1, default = 0. Simple optimizes on the optical axis and only works if the tomographic DM is the same as the corresponding virtual DMs, but is faster. // the following parameters only apply to "mmse" fitting long fit_subsamp; // subsampling the phase for fitting matrix (set to larger than 1 for speed), default = 1 string fit_type; // optimize for a target or wfs location long fit_which; // which target or wfs to optimize fitting for, default = 1 float fit_minval; // minimum value for sparse fitting matrix, default = 1e-2 }; struct tel_struct { float diam; // Telescope diameter in meters. Required [none] float cobs; // Central obstruction / telescope diameter ratio. Optional [0] // TIP vibrations parameters float tipvib_white_rms; // rms [arcsec] of vibration white noise float tipvib_1overf_rms; // rms [arcsec] of vibration 1/f noise (from 1 Hz to cutoff) pointer tipvib_peaks; // positions [Hz] of vibration peak in PSD pointer tipvib_peaks_rms; // rms [arcsec] of each vibration peaks (defined above) pointer tipvib_peaks_width; // width [Hz] of each vibration peaks (default 1 freq bin) // TILT vibrations parameters float tiltvib_white_rms; // rms [arcsec] of vibration white noise float tiltvib_1overf_rms; // rms [arcsec] of vibration 1/f noise (from 1 Hz to cutoff) pointer tiltvib_peaks; // positions [Hz] of vibration peak in PSD pointer tiltvib_peaks_rms; // rms [arcsec] of each vibration peaks (defined above) pointer tiltvib_peaks_width;// width [Hz] of each vibration peaks (default 1 freq bin) }; struct target_struct { pointer lambda; // float vectorptr. Image wavelengths in micron. Required [none] pointer xposition; // float vectorptr. X positions in arcsec. Required [none] pointer yposition; // float vectorptr. Y positions in arcsec. Required [none] pointer dispzoom; // float vectorptr. Display zoom (typically around 1.). Optional [1.] pointer ncpdm; // DM on the path of the targets, if any // Internal keywords long _ntarget; // Internal: # of target long _nlambda; // Internal: # of lambda }; struct gs_struct { float zeropoint; // Photometric zero point (#photons@pupil/s/full_aper, mag0 star). // Required [none] float zenithangle; // zenith angle. Optional [0.]. The zenith angle is used to compute: // - r0 off-zenith // - atmopheric turbulence layer altitude // - effective turbulence layer speed // - LGS altitude and thickness of Na Layer // - LGS brighness // note that dm altitude is unchanged. float lgsreturnperwatt;// Sodium LGS return in photons/cm2/s at entrance pupil. // Specified at zenith. Modified by gs.zenithangle. Optional [22.] // basically, you have to fold in this the sodium density // and your model of return. }; struct loop_struct { float gain; // Loop gain. Optional, but important! [0] float leak; // leak term (0 means no leak) [0] pointer gainho; // vector of higher order gains (starting at 2nd order) pointer leakho; // vector of higher order leaks (starting at 2nd order) long framedelay; // loop delay (# of frames). Optional [0] // Regular CCD 1 frame integration -> framedelay=1 // + readout & Calculation -> framedelay=2 long niter; // # of total iteration. Required [none] float ittime; // Iteration time in seconds. Required [none] long startskip; // # iter to skip before collecting statistics. Optional [10] long skipevery; // skip by "skipby" every "skipevery" iterations. Optional [0=none] long skipby; // see above. this is to get better statistical // coverage. Optional [10000] long stats_every; // compute stats every so many iteration (default 4) long jumps2swapscreen;//number of jumps (i.e. niter/skipevery) after which screens // will be swapped (rotation, 2->1, 3->2... 1->last string modalgainfile; // Name of file with mode gains. Optional. //float dithering; // TT dithering for centroid gain (volts). string method; // "closed-loop", "open-loop", "pseudo open-loop" }; yao-5.4.0/yao_svipc.i000066400000000000000000000665311234404334100144670ustar00rootroot00000000000000/* * yao_svipc.i * * yao svipc related functions * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * * SVIPC functions for parallelization * * principle and main actors: * if (sim.svipc>>0)&1 (1): * main process: * | svipc_start_forks() * ---------------------------- * | | * main 1 x topwfs_listen() * -> loop on mult_wfs() * * if (sim.svipc>>0)&1 and (sim.svipc>>2)&1 (1+4): * main process: * | svipc_start_forks() * --------------------------------------------- * | | | * main 1 x topwfs_listen() nwfs x wfs_listen(ns); * -> loop on svipc_mult_wfs() -> loop on svipc_single_wfs() * */ require,"svipc.i"; require,"yao_setnsync.i"; // use svipc_debug to set svipc debug nshm = 50; nsem = 80; sem4wfs = 50+2*indgen(20); func init_keys(void) { extern shmkey, semkey; if ( (sim.shmkey) || (sim.shmkey == 0) ) shmkey=0x0badcafe; \ else shmkey = sim.shmkey; if ( (sim.semkey) || (sim.semkey == 0) ) semkey=0x0badbeef; \ else semkey = sim.semkey; } status = init_keys(); func svipc_init(void) { extern shm_init_done; if (!shm_init_done) { if (shm_init(shmkey,slots=nshm)==0) { sem_init,semkey,nums=nsem; if (sim.verbose>0) write,format="%s\n","SVIPC initialized"; } // else already initialized by another process } shm_init_done = 1; shm_write,shmkey,"quit?",&([0]); // shm_write,shmkey,"reset_strehl?",&([0]); // what's in semaphores? // sem# content // 0 trigger WFS child calculation // 1 ready from WFS child // 3 psf: trigger child PSFs calculation // 4 psf: notify parent PSFs ready // 20-50 reserved for WFSs || // 50-80 reserved for WFS children } func svipc_wfs_init(phase,ns) { extern atm,wfs,dm,loop,mat,opt,tel,target,gs; extern pscreens,im,imav,mircube,cubphase; extern iMat,cMat,xposvec,yposvec; extern wfsxposcub, wfsyposcub, gsxposcub, gsyposcub; extern dmwfsxposcub, dmwfsyposcub, dmgsxposcub, dmgsyposcub; extern optwfsxposcub,optwfsyposcub,optgsxposcub,optgsyposcub; extern statsokvec, sphase, bphase, imtmp, imphase; extern strehllp, strehlsp, itv, commb, errmb; // extern nforks_per_wfs; if (sim.debug>=1) write,format="Entering svipc_wfs_init for WFS#%d\n",ns; // Just to make sure. no need for svipc in that case: if (wfs(ns).svipc<=1) return; // Bail out if init has already been done for this WFS if (wfs(ns)._svipc_init_done) { write,format="%s\n","WFS svipc init already done. Bailing out."; return; } // Make sure shm has been initialized if (!shm_init_done) status = svipc_init(); // if (nforks_per_wfs==[]) nforks_per_wfs = array(0,nwfs); // if (numberof(nforks_per_wfs)!=nwfs) // error,"You can't change the #wfs while using svipc, please restart yao"; // nforks_per_wfs(ns) = wfs(ns).svipc; // Initialize a few generic variable we're gonna need: // This one serves to indicate to the forks that a sync is needed shm_write,shmkey,swrite(format="sync_wfs%d_forks",ns),&([0]); // This one is used to quit the forks shm_write,shmkey,"quit_wfs_forks?",&([0]); // To avoid a shm_write/shm_read at each iter, I have opted to // share the variables (shm_var) fimage, phase and mesvec. // We need to create the slots (shm_write) first: // *wfs._fimage has necessarily been created in shwfs_init() shm_write,shmkey,swrite(format="wfs%d_fimage",ns),wfs(ns)._fimage; // phase exist as it has been passed as arg to sh_wfs() // write,format="%s: ","phase in svipc_wfs_init"; info,phase; shm_write,shmkey,swrite(format="wfs%d_phase",ns),&phase; // ... and we create mesvec: mesvec = array(float,2*wfs(ns)._nsub); shm_write,shmkey,swrite(format="wfs%d_mesvec",ns),&mesvec; // Compute which subapertures have to be dealt with by which forks: // Find subok for _shwfs_phase2spots() // The parallelization is for *spot* calculation, hence nsub4disp nsubsperforks = float(wfs(ns)._nsub4disp)/wfs(ns).svipc; tofork = long(floor((indgen(wfs(ns)._nsub4disp)-1)/nsubsperforks))+1; wfs(ns)._fork_subs = &array(int,[2,wfs(ns)._nsub4disp,wfs(ns).svipc]); // find yoffset, subok, ysize parameters for _shwfs_spots2slopes() wfs(ns)._fork_subs2 = &split_subok(ns,yoffset,ysize); wfs(ns)._fimny2 = &ysize; wfs(ns)._yoffset = &yoffset; if (sim.verbose>0) { write,format="WFS#%d, %d forks, %.1f subap/forks\n", ns,wfs(ns).svipc,nsubsperforks; } // usual thing: we can't fork() with windows open, so let's kill them wl = window_list(); if (wl!=[]) for (i=1;i<=numberof(wl);i++) winkill,wl(i); extern svipc_wfs_ns; svipc_wfs_ns = ns; // we'll need that too // leave a trace that we've gone through here. wfs(ns)._svipc_init_done = 1; // now we'll have to set the random_seed for the child to something // different than the parent and different for all children, // otherwise the next random numbers will be the same for // parent and all children. // However it should be the same each time we start over, otherwise // it'll be impossible to compare results for short sample length. // at least that's the philosophy I've been following with yao // since a long time. So let's do that this way: svipc_random_seeds = random(wfs(ns).svipc); // if the user decides to restart a run and wish to use the same // random seed, he should do // random_seed,x; ran1init; // x = ]0.,1.[ exclusive. // if the user decides to do that, then the svipc_random_seeds // will be the same as previously, if the random_seed is done // each time at the same "location" in the calling code. // thus the children will also be set with the same seed. for (nf=1;nf<=wfs(ns).svipc;nf++) { (*wfs(ns)._fork_subs)(,nf) = int(tofork==nf); if (nf<2) continue; // "nf=1" is main process. // fork: if (fork()==0) { // I'm the child // child: free resources atm = dm = mat = opt = tel = target = gs = []; pscreens = im = imav = mircube = cubphase = []; iMat = cMat = xposvec = yposvec = []; wfsxposcub = wfsyposcub = gsxposcub = gsyposcub = []; dmwfsxposcub = dmwfsyposcub = dmgsxposcub = dmgsyposcub = []; optwfsxposcub = optwfsyposcub = optgsxposcub = optgsyposcub = []; statsokvec = sphase = bphase = imtmp = imphase = []; strehllp = strehlsp = itv = commb = errmb = []; // set the random_seed determined above: random_seed,svipc_random_seeds(nf); if (sim.debug) write,format="WFS#%d child %d spawned with PID %d\n",ns,nf,getpid(); // start listening status = wfs_fork_listen(ns,nf); } } // restore windows if needed: if (anyof(wl==0)) status = create_yao_window(); return 0; } func wfs_fork_listen(ns,nf) /* DOCUMENT wfs_fork_listen(ns,nf) Main loop for yao wfs forks. - Init all variables as in sh_wfs() - loop forever waiting for trigger from main and executing _shwfs_phase2spots and _shwfs_spots2slopes() - at each iter, check if sync is needed. SEE ALSO: */ { if (sim.debug>0) write,format="WFS#%d fork#%d listening\n",ns,nf; // init the internal variables just as in sh_wfs() pupd = sim.pupildiam; size = sim._size; nxsub = wfs(ns).shnxsub(0); subsize = int(pupd/nxsub); if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; phasescale = float(2*pi/wfs(ns).lambda); sdim = long(2^ceil(log(subsize)/log(2)+1)); if (no_pad_simage) sdim = long(2^ceil(log(subsize)/log(2))); sdimpow2 = int(log(sdim)/log(2)); // to protect from a WFS sync, let's not put it in the wfs structure svipc_subok = (*wfs(ns)._fork_subs)(,nf); svipc_subok2 = (*wfs(ns)._fork_subs2)(,nf); yoffset = (*wfs(ns)._yoffset)(nf); fimny2 = (*wfs(ns)._fimny2)(nf); shm_var,shmkey,swrite(format="wfs%d_fimage",ns),ffimage; shm_var,shmkey,swrite(format="wfs%d_phase",ns),phase; shm_var,shmkey,swrite(format="wfs%d_mesvec",ns),mesvec; // then listen and execute ad libitum do { // wait for trigger: if (sim.debug>20) \ write,format="fork: Waiting for trigger from main on sem ns=%d\n",20+4*(ns-1); sem_take,semkey,20+4*(ns-1); if (sim.debug>20) write,format="fork: gotten sem %d\n",20+4*(ns-1); // check if we have to quit: if (shm_read(shmkey,"quit_wfs_forks?")(1)) { if (sim.verbose>0) { write,format="WFS#%d, fork#%d quitting\n> ",ns,nf; } yorick_quit; } // sync if needed: status = sync_wfs_from_master(ns,nf); // do our stuff: err = _shwfs_phase2spots( pupsh, phase, phasescale, *wfs(ns)._tiltsh, int(size), *wfs(ns)._istart, *wfs(ns)._jstart, int(subsize), int(subsize), wfs(ns)._nsub4disp, sdimpow2, wfs(ns)._domask, *wfs(ns)._submask, *wfs(ns)._kernel, wfs(1)._nkernels, *wfs(ns)._kernels, *wfs(ns)._kerfftr, *wfs(ns)._kerffti, wfs(ns)._initkernels, wfs(ns)._kernelconv, *wfs(ns)._binindices, wfs(ns)._binxy, wfs(ns)._rebinfactor, wfs(ns)._nx4fft, *wfs(ns)._unittip, *wfs(ns)._unittilt, *wfs(ns).lgs_prof_amp, *wfs(ns)._lgs_defocuses, int(numberof(*wfs(ns).lgs_prof_amp)), *wfs(ns)._unitdefocus, ffimage, svipc_subok, *wfs(ns)._imistart, *wfs(ns)._imjstart, wfs(ns)._fimnx , wfs(ns)._fimny, *wfs(ns)._fluxpersub, *wfs(ns)._raylfluxpersub, *wfs(ns)._skyfluxpersub, float(wfs(ns).darkcurrent*loop.ittime), int(wfs(ns).rayleighflag), *wfs(ns)._rayleigh, wfs(ns)._bckgrdinit, wfs(ns)._cyclecounter, wfs(ns).nintegcycles); // give trigger back: if (sim.debug>20) write,format="fork: giving trigger on sem %d\n",20+4*(ns-1)+1; sem_give,semkey,20+4*(ns-1)+1; sem_take,semkey,20+4*(ns-1)+2; if (sim.debug>20) write,format="fork: gotten sem %d\n",20+4*(ns-1)+2; threshold = array(float,wfs(ns)._nsub4disp+1)+wfs(ns).shthreshold; err = _shwfs_spots2slopes( ffimage, *wfs(ns)._imistart2, *wfs(ns)._imjstart2, wfs(ns)._nsub4disp, wfs(ns).npixels, wfs(ns)._fimnx, fimny2, yoffset, *wfs(ns)._centroidw, wfs(ns).shthmethod, threshold, *wfs(ns)._bias, *wfs(ns)._flat, wfs(ns).ron, wfs(ns).noise, *wfs(ns)._bckgrdcalib, wfs(ns)._bckgrdinit, wfs(ns)._bckgrdsub, *wfs(ns)._validsubs, svipc_subok2, wfs(ns).nintegcycles, mesvec); sem_give,semkey,20+4*(ns-1)+3; } while (1); } func split_subok(ns,&yoffset,&ysize) /* DOCUMENT split_subok(ns) Returns a matrix indicating which subap should be processed by which fork. wfs(ns).svipc rows. each rows has wfs._nsub4disp elements. In row N, 1 means it is to be processed by this process N, 0 means not process. The difficulty here is that in _shwfs_spots2slopes(), we add the noise to the image, so the subap for each forks have to span full rows. returns also the yoffsets and ysize (fimny) to be used in the call to _shwfs_spots2slopes() SEE ALSO: */ { nj = *wfs(ns)._jstart; // d=_(ni(where(ni(dif))),ni(0)); subsize = sim.pupildiam/wfs(ns).shnxsub; nj = nj/subsize; nj = nj-min(nj); nt = int(floor(nj/(wfs(ns).shnxsub*1./wfs(ns).svipc))); subok = array(int,[2,wfs(ns)._nsub4disp,wfs(ns).svipc]); yoffset = ysize = array(int,wfs(ns).svipc); for (i=1;i<=wfs(ns).svipc;i++) { subok(,i) = ((nt+1)==i); if (numberof(where(subok(,i)))==0) \ error,swrite(format="Too many threads, max # thread = number of row of subap (%d)\n",wfs(ns).shnxsub); yoffset(i) = (*wfs(ns)._imjstart2)(where(subok(,i))(1)); ysize(i) = (*wfs(ns)._imjstart2)(where(subok(,i))(0)) - \ yoffset(i)+wfs(ns).npixels; } return subok; } func svipc_wfs_profile(void) { tfork = rdcols("/tmp/fork.res"); tmain = rdcols("/tmp/main.res"); } func svipc_start_forks(void) { extern iMat,cMat,dm,atm,wfs,sim; extern fork_done; extern svipc_procname; extern all_svipc_procname; // sim.svipc bits (also see structure definition in yao_structure.i) // bit 0 (1): parallelize WFS/DM // bit 1 (2): parallelize PSFs // bit 2 (4): parallelize WFSs (1 fork per WFS) if (fork_done) { write,"forks() already done, ignoring"; return; } // usual thing: we can't fork() with windows open, so let's kill them wl = window_list(); // if (anyof(wl==0)) { // that should be the yao window // w0_dpi = window_geometry(0); // } if (wl!=[]) for (i=1;i<=numberof(wl);i++) winkill,wl(i); all_svipc_procname = []; // we need to defined stuff about forks here, *before* we fork the // main WFS child ! // how many WFS children processes? // if not specified in sim.svipc_wfs_nfork, set a value: if (!sim.svipc_wfs_nfork) sim.svipc_wfs_nfork = min([nwfs,nprocs()]); // sim.svipc_wfs_forknb: if not set by user, set a value: if (*sim.svipc_wfs_forknb==[]) { tmp = 1+long((indgen(nwfs)-1.) / nwfs * sim.svipc_wfs_nfork); sim.svipc_wfs_forknb = &tmp; } if (!pscreens_no_shm) shm_write,shmkey,"pscreens",&pscreens; // WFS CHILD // spawn just one process, the one taking care of wfsmes. // It could possibly spawn other process later (e.g. // for each of the WFS). if ((sim.svipc>>0)&1) { svipc_procname = "WFS"; grow,all_svipc_procname,svipc_procname; if (fork()==0) { // I'm the child if (sim.verbose>0) \ write,format="WFS child fork()ed with PID %d\n",getpid(); // get rid of what we don't need iMat = cMat = []; for (i=1;i<=ndm;i++) dm(i)._def = &[]; if (!pscreens_no_shm) { pscreens = []; shm_var,shmkey,"pscreens",pscreens; } // start listening //set_idler,topwfs_listen; status = topwfs_listen(); return; } svipc_procname = ""; // unassign for parent } // PSFs child if ((sim.svipc>>1)&1) { extern psf_child_started; psf_child_started = 0; svipc_procname = "PSFs"; grow,all_svipc_procname,svipc_procname; if (fork()==0) { // child write,format="PSFs child fork()ed with PID %d\n",getpid(); // get rid of what we don't need iMat = cMat = []; if (!pscreens_no_shm) { pscreens = []; shm_var,shmkey,"pscreens",pscreens; } // start listening // set_idler,psf_listen; status = psf_listen(); return; } svipc_procname = ""; // unassign for parent } // WFSs children if ((sim.svipc>>2)&1) { // sim.svipc_wfs_nfork -= 1; // the main WFS thread will take its share. for (nf=1;nf<=sim.svipc_wfs_nfork;nf++) { svipc_procname = swrite(format="WFSs fork %d",nf); grow,all_svipc_procname,svipc_procname; if (fork()==0) { //child write,format="WFS fork %d PID %d\n",nf,getpid(); // get rid of what we don't need iMat = cMat = []; for (i=1;i<=ndm;i++) dm(i)._def = &[]; if (!pscreens_no_shm) { pscreens = []; shm_var,shmkey,"pscreens",pscreens; } // start listening ns = where(*sim.svipc_wfs_forknb==nf); status = wfs_listen(nf,ns); // wfs_listen() will loop and not exit. } svipc_procname = ""; // unassign for parent } } fork_done = 1; // restore windows if needed: if (anyof(wl==0)) status = create_yao_window(); return 0; } yorick_quit = quit; func quit { if (catch(-1)) { write,format="%s\n","Caught problem with closing svipc, exit forced."; yorick_quit; } if (shm_init_done) { shm_write,shmkey,"quit?",&([1]); shm_write,shmkey,"quit_wfs_forks?",&([1]); // nforks = sum(clip(wfs.svipc-1,0,)); for (i=0;i<=nsem;i++) sem_give,semkey,i,count=100; usleep,50; status = svipc_clean(); } yorick_quit; } func quit_forks(void) { extern wfs,shm_init_done,fork_done; extern prev_sync_counter; extern sync_init_done; if (shm_init_done==0) return; if ( (sim!=[]) && (sim.svipc) ) { // a previous yao run initialized this and // started forks. we can close them. shm_write,shmkey,"quit?",&([1]); for (i=0;i<=19;i++) sem_give,semkey,i,count=100; for (i=51;i<=70;i++) sem_give,semkey,i,count=100; clean = 1; } if ( (wfs!=[]) && anyof(wfs.svipc>1) ) { shm_write,shmkey,"quit_wfs_forks?",&([1]); for (i=20;i<=50;i++) sem_give,semkey,i,count=100; wfs._svipc_init_done = 0; prev_sync_counter = []; sync_init_done = 0; clean = 1; } if (clean) { usleep,50; status = svipc_clean(); shm_init_done = 0; fork_done = 0; } } func quit_wfs_forks(void) { extern wfs; extern prev_sync_counter; extern sync_init_done; if (!shm_init_done) return; shm_write,shmkey,"quit_wfs_forks?",&([1]); // FIXME: only set sem for wfs forks for (ns=1;ns<=nwfs;ns++) { if ((wfs(ns).type=="hartmann")&&(wfs(ns).svipc>1)) { sem_give,semkey,20+4*(ns-1),count=wfs(ns).svipc-1; } } wfs._svipc_init_done = 0; prev_sync_counter = []; usleep,200; sync_init_done = 0; } func svipc_clean(void) /* DOCUMENT svipc_clean(void) Clean and close the shared memory segment + semaphore allocation SEE ALSO: */ { shm_cleanup,shmkey; sem_cleanup,semkey; } func topwfs_svipc(void) /* DOCUMENT topwfs_svipc(void) Routine called by *main* loop to get results (measurements) from parallelized WFS fork. SEE ALSO: */ { /* here: - sem_take sem_wfs_done - check that available data are indeed the one for iter we want - load back processed data in current session (mes and wfsimage) - load current phase, mircube, loopCounter, key into sharedmem - 1 sem_give sem_wfs_start to start wfs process - continue on the wfs side: - block on sem_wfs_start - once release, proceed to do calculations (mult_wfs) - store result data in sharemem, including mes, wfsimage - sem_give sem_wfs_done */ extern topwfs_svipc_first_time; // Block until slave done (skip for first iter) // if (topwfs_svipc_first_time) { if (loopCounter>1) { if (smdebug) { write,format="TOPWFS_SVIPC (it%d): waiting for child to be done\n",loopCounter; } sem_take,semkey,1; if (smdebug) write,"Child done, proceeding"; // get data from shm svipc_mes = shm_read(shmkey,"svipc_mes"); for (ns=1;ns<=nwfs;ns++) { wfs(ns)._fimage = &(shm_read(shmkey,swrite(format="wfs%d_image",ns))); } } else svipc_mes = array(0.0f,sum(wfs._nmes)); // now prepare for next shot: if (smdebug) write,"topwfs_svipc: loading data in shm"; shm_write,shmkey,"loop_counter",&[loopCounter]; shm_write,shmkey,"mircube",&mircube; // etc? // give start signal to slave: if (smdebug) write,"topwfs_svipc: Giving trigger to Child"; sem_give,semkey,0; topwfs_svipc_first_time=1; return svipc_mes; } func psf_listen(void) /* DOCUMENT psf_listen(void) The PSF forked process loop on this routine. It is triggered by a sem from the main process this routine execute the PSF calculation and then set a sem to notify the main process the PSF are ready. SEE ALSO: */ { extern mircube, loopCounter; extern im,imav; do { // wait for trigger from master if (smdebug) write,"psf_listen: waiting for trigger from parent"; sem_take,semkey,3; if (smdebug) write,"psf_listen: got trigger"; // check if we have to quit: if (shm_read(shmkey,"quit?")(1)) { write,format="%s child quitting\n",svipc_procname; yorick_quit; } // do we need to reset? (e.g. master has restarted aoloop) // if (shm_read(shmkey,"reset_strehl?")(1)) { // shm_write,shmkey,"reset_strehl?",&([0]); // write,format="%s reset strehl\n",svipc_procname; // imav *= 0; // } // anything to sync? status = sync_child(); // do the PSF calculations loopCounter = shm_read(shmkey,"loop_counter")(1); if (smdebug) write,"psf_listen: doing PSF calculations"; mircube = shm_read(shmkey,"mircube"); for (jl=1;jl<=target._nlambda;jl++) { for (jt=1;jt<=target._ntarget;jt++) { cubphase(,,jt) = get_phase2d_from_dms(jt,"target") + \ get_phase2d_from_optics(jt,"target") + \ get_turb_phase(loopCounter,jt,"target"); } // compute image cube from phase cube err = _calc_psf_fast(&pupil,&cubphase,&im,2^dimpow2, target._ntarget,float(2*pi/(*target.lambda)(jl)),1n); // Accumulate statistics: imav(,,,jl) = imav(,,,jl) + im; } // we're done. if (smdebug) write,"psf_listen: done, writing result in shm"; shm_write,shmkey,"imsp",&im; shm_write,shmkey,"imlp",&imav; if (smdebug) write,"psf_listen: Giving trigger back to master"; sem_give,semkey,4; } while (1); // if (smdebug) write,"psf_listen: calling oneself"; // set_idler,psf_listen; } func topwfs_listen(void) // for top WFS child { extern mircube,loopCounter; do { // wait for trigger from master if (smdebug) write,"topwfs_listen: waiting for trigger from master"; sem_take,semkey,0; if (smdebug) write,"topwfs_listen: got trigger"; // check if we have to quit: if (shm_read(shmkey,"quit?")(1)) { write,format="%s child quitting\n",svipc_procname; yorick_quit; } // anything to sync? status = sync_child(); // do the wfsing loopCounter = shm_read(shmkey,"loop_counter")(1); if (smdebug) write,"topwfs_listen: doing wfsing"; mircube = shm_read(shmkey,"mircube"); if ((sim.svipc>>2)&1) { // parallel WFSs mes = svipc_mult_wfs(loopCounter); } else { // single fork mes = mult_wfs(loopCounter); } // we're done. if (smdebug) write,"topwfs_listen: done, writing result in shm"; // wfs._tt // wfs._lastvalidtt shm_write,shmkey,"svipc_mes",&mes; if (smdebug) write,"topwfs_listen: Giving trigger back to master"; sem_give,semkey,1; } while (1); // if (smdebug) write,"topwfs_listen: calling oneself"; // set_idler,topwfs_listen; } func wfs_listen(nf,nsv) // for WFSs children { extern mircube; do { // wait for trigger from master if (smdebug) { write,format="WFS fork #%d listen: waiting for trigger from master\n",nf; } sem_take,semkey,sem4wfs(nf); if (smdebug) write,format="WFS fork #%d listen: got trigger\n",nf; // check if we have to quit: if (shm_read(shmkey,"quit?")(1)) { write,format="%s child quitting\n",svipc_procname; yorick_quit; } // anything to sync? status = sync_child(); // do something loopCounter = shm_read(shmkey,"loop_counter")(1); mircube = shm_read(shmkey,"mircube"); if (smdebug) { write,format="WFS fork#%d %s",nf,"doing wfsing of WFS "; for (i=1;i<=numberof(nsv)-1;i++) write,format="%d, ",nsv(i); write,format="%d\n",nsv(0); } for (i=1;i<=numberof(nsv);i++) { ns = nsv(i); mes = svipc_single_wfs(loopCounter,ns); shm_write,shmkey,swrite(format="wfs%d_mes",ns),&mes; shm_write,shmkey,swrite(format="wfs%d_image",ns),wfs(ns)._fimage; } if (smdebug) { write,format="wfs_listen, fork#%d: Giving trigger back to master\n",nf; } sem_give,semkey,sem4wfs(nf)+1; if (smdebug) write,"looping"; } while (1); } func svipc_single_wfs(iter,ns) { extern wfs; offsets = wfs(ns).gspos; phase = get_phase2d_from_optics(ns,"wfs"); phase += get_turb_phase(iter,ns,"wfs"); if (loop.method != "open-loop") { phase += get_phase2d_from_dms(ns,"wfs"); } if (wfs(ns).correctUpTT) { phase = correct_uplink_tt(phase,ns); } if (wfs(ns).LLT_uplink_turb) { tmp = comp_turb_lgs_kernel(ns); wfs(ns)._kernel = &float([(*wfs(ns)._kernel)(,,1),tmp]); wfs(ns)._nkernels = 2; } else wfs(ns)._nkernels = 1; // get the measurements: if (wfs(ns).type == "hartmann" ) { if (wfs(ns).disjointpup) { smes = sh_wfs(disjointpup(,,ns),phase,ns); } else { smes = sh_wfs(ipupil,phase,ns); } } else if (wfs(ns).type == "curvature") { smes = curv_wfs(pupil,phase,ns); } else if (wfs(ns).type == "pyramid") { smes = pyramid_wfs(pupil,phase,ns); } else if (wfs(ns).type == "zernike") { smes = zernike_wfs(ipupil,phase,ns); } else if (wfs(ns).type == "dh") { smes = dh_wfs(ipupil,phase,ns); } else { // assign user_wfs to requested function/type: cmd = swrite(format="user_wfs = %s",wfs(ns).type); include,[cmd],1; smes = user_wfs(ipupil,phase,ns); } // subtract the reference vector for this sensor: if (wfs(ns)._cyclecounter == 1) { smes = smes - *wfs(ns)._refmes; } // compute the TT and subtract if required: // wfs._tt is computed inside this fork, so all good. wfs(ns)._tt(1) = sum( smes * (*wfs(ns)._tiprefvn) ); wfs(ns)._tt(2) = sum( smes * (*wfs(ns)._tiltrefvn) ); if (wfs(ns).filtertilt) { smes = smes - wfs(ns)._tt(1) * (*wfs(ns)._tiprefv) \ - wfs(ns)._tt(2) * (*wfs(ns)._tiltrefv); } if (wfs(ns)._cyclecounter == 1) { wfs(ns)._lastvalidtt = wfs(ns)._tt; } return smes; } func svipc_mult_wfs(iter,disp=) /* DOCUMENT func svipc_mult_wfs(iter,disp=) svipc version of mult_wfs */ { mes = []; // parallelize main WFSs for (nf=1;nf<=sim.svipc_wfs_nfork;nf++) { // no data to send to slave (it will lookup mircube, // which is the only data needed, with iter) // send trigger sem_give,semkey,sem4wfs(nf); } // wait for the children to be done: for (nf=1;nf<=sim.svipc_wfs_nfork;nf++) sem_take,semkey,sem4wfs(nf)+1; // all semaphores have been released, collect the pieces: for (ns=1;ns<=nwfs;ns++) { smes = shm_read(shmkey,swrite(format="wfs%d_mes",ns)); grow,mes,smes; } return mes; } func cv2sv(charv) /* DOCUMENT cv2sv(charv): char vector to string vector SEE ALSO: sv2cv */ { if ((allof(charv==[0x00]))||(charv==[])) return ""; w = where(charv==0x00); i1 = _(1,w+1)(:-1); i2 = w; stringv = []; for (i=1;i<=numberof(w);i++) grow,stringv,string(&charv(i1(i):i2(i))); return stringv; } func sv2cv(stringv) /* DOCUMENT sv2cv(charv): string vector to char vector SEE ALSO: cv2sv */ { if (stringv==[]) return char([0x00]); charv = []; for (i=1;i<=numberof(stringv);i++) grow,charv,*pointer(stringv(i)); return charv; } // original_shm_read = shm_read; // func shm_read(key,id,subscribe=) // { // write,format="shm_read( %s )\n",id; // return original_shm_read(key,id,subscribe=subscribe); // } // original_shm_write = shm_write; // func shm_write(key,id,a,publish=) // { // write,format="shm_write, %s\n",id; // original_shm_write,key,id,a,publish=publish; // } // original_shm_free = shm_free; // func shm_free(key,id) // { // write,format="shm_free, %s\n",id; // original_shm_free,key,id; // } yao-5.4.0/yao_util.i000066400000000000000000000656731234404334100143260ustar00rootroot00000000000000/* * yao_util.i * * A collection of routines for general purpose for yao * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ require,"style.i"; require,"pkg_mngr.i"; // kinput require,"util_fr.i"; // nprint, wheremin, wheremax, typeReturn, exist require,"linalg.i"; func escapechar(s) { s=streplace(s,strfind("_",s,n=20),"!_"); s=streplace(s,strfind("^",s,n=20),"!^"); return s; } //--------------------------------------------------------- func zernumero(zn) /* DOCUMENT zernumero(zn) * Returns the radial degree and the azimuthal number of zernike * number zn, according to Noll numbering (Noll, JOSA, 1976) * SEE ALSO: prepzernike, zernike */ { j = 0; for (n=0;n<=100;n++) { for (m=0;m<=n;m++) { if (even(n-m)) { j = j+1; if (j == zn) {return [n,m];} if (m != 0) { j = j+1; if (j == zn) {return [n,m];} } } } } } //--------------------------------------------------------- func gamma(arg) /* DOCUMENT gamma(arg) * Gamma function. * SEE ALSO: gamma.i in yorick/i/ */ { if (arg == 0.) { return 1.; } else { return exp(ln_gamma(arg)); } } //--------------------------------------------------------- func factoriel(arg) /* DOCUMENT factoriel(arg) * Return factoriel of the argument * SEE ALSO: */ { if (arg == 0) { return 1.; } else { res = 1.; for (i=1;i<=arg;i++) res = res*i; return res; } } //--------------------------------------------------------- func zernike(zn) /* DOCUMENT zernike(zn) * Returns the zernike number zn, defined on a 2D array as per * the prepzernike function. * These zernikes follow the Noll (JOSA, 1976) numbering and * definition (rms of 1 over the pupil) * Example: * > prepzernike,128,100 * > pli,zernike(6) * SEE ALSO: prepzernike, zernumero */ { extern zdim,zr,zteta,zmask,zrmod,zmaskmod; z = array(float,zdim,zdim); znm = zernumero(zn) ; n=znm(1) ; m=znm(2); for (i=0;i<=(n-m)/2;i++) { z = z + (-1.)^i*zr^(n-2.*i)*factoriel(n-i)/ (factoriel(i)*factoriel((n+m)/2-i)*factoriel((n-m)/2-i)); } if (odd(zn)) { if (m == 0) { z = z*sqrt(n+1.); } else { z = z*sqrt(2*(n+1.))*sin(m*zteta); } } else { if (m == 0) { z = z*sqrt(n+1.); } else { z = z*sqrt(2*(n+1.))*cos(m*zteta); } } return z*zmask; } //--------------------------------------------------------- func zernike_ext(zn) /* DOCUMENT zernike_ext(zn) * Same as the zernike function, except that the function is not masked * at R=1. This might be useful for some WFS codes where the derivative * of the wavefront is needed (and therefore a pixel outside of the * pupil is used to compute the derivatives). * These zernikes follow the Noll (JOSA, 1976) numbering and * definition (rms of 1 over the pupil) * Example: * > prepzernike,128,100 * > pli,zernike(6) * SEE ALSO: zernike, prepzernike, zernumero */ { extern zdim,zr,zteta,zmask,zrmod,zmaskmod; z = array(float,zdim,zdim); znm = zernumero(zn) ; n=znm(1) ; m=znm(2); for (i=0;i<=(n-m)/2;i++) { z = z + (-1.)^i*zrmod^(n-2.*i)*factoriel(n-i)/ (factoriel(i)*factoriel((n+m)/2-i)*factoriel((n-m)/2-i)); } if (odd(zn)) { if (m == 0) { z = z*sqrt(n+1.); } else { z = z*sqrt(2*(n+1.))*sin(m*zteta); } } else { if (m == 0) { z = z*sqrt(n+1.); } else { z = z*sqrt(2*(n+1.))*cos(m*zteta); } } return z*zmaskmod; } //--------------------------------------------------------- func prepzernike(size,diameter,xc,yc) /* DOCUMENT prepzernike(size,diameter,xc,yc) * Call this function to set up the geometry for subsequent calls * to the zernike function. * size : size of the 2d array on which future "zernike" will be returned * diameter : diameter of the pupil in pixel in the array * xc, yc (optional) : Coordinates (in pixels of the center of the pupil) * Example: * > prepzernike,128,100 * > pli,zernike(6) * SEE ALSO: zernike,zernike_ext,zernumero */ { extern zdim,zr,zteta,zmask,zrmod,zmaskmod; if (xc == []) {xc = size/2+1;} if (yc == []) {yc = size/2+1;} radius= (diameter+1.)/2.; zdim = size; zr = dist(zdim,xc=xc,yc=yc)/radius; zmask = (zr <= 1.); zmaskmod = (zr <= 1.2); zrmod = zr*zmaskmod; zr = zr*zmask; x = float(span(1,zdim,zdim)(,-:1:zdim)); y = transpose(x); zteta = atan(y-yc,x-xc); } //--------------------------------------------------------- func jpg_write_color(im,filename,cmin=,cmax=,quality=,noflip=) /* DOCUMENT jpg_write_color(im,filename,cmin=,cmax=,quality=,noflip=) * Wrapper for the jpg_write procedure. * Reads out the current palette and uses it as color table to write * the image "im" in a jpg file. * Flags and keywords as in jpeg_write. * SEE ALSO: jpg_write, jpg_read, jpg_info */ { dimx = dimsof(im)(2); dimy = dimsof(im)(3); palette,r,g,b,query=1; bytim = bytscl(im); cubim= array(char,[3,3,dimx,dimy]); cubim(1,,) = r(bytim+1); cubim(2,,) = g(bytim+1); cubim(3,,) = b(bytim+1); jpg_write,cubim,filename,cmin=cmin,cmax=cmax,quality=quality,noflip=noflip; } //--------------------------------------------------------- func log00(void){logxy,0,0;} func log11(void){logxy,1,1;} /* DOCUMENT log00() and log11() * Shortcuts for logxy,0,0 and logxy,1,1 * SEE ALSO: logxy */ //--------------------------------------------------------- func tbget(fh,dataptr,keyword) { nfields = numberof(dataptr); fields = array(string,nfields); for (i=1;i<=nfields;i++) { fields(i) = fits_get(fh,swrite(format="TTYPE%d",i)); } t = transpose(*dataptr(where(fields == keyword)(1))); if (numberof(t) == max(dimsof(t)(2:))) { t = t(*);} return t; } //--------------------------------------------------------- func mrot(ang) /* DOCUMENT mrot(angle) * returns the matrix of rotation for a given angle. * It has to be used as follow: * If you want to rotate a vector of two coefficients xy=[x,y], * You should do rotated vector = mrot(+,)*xy(+,); * Angle is in degrees. * SEE ALSO: */ { dtor=pi/180.; return [[cos(ang*dtor),-sin(ang*dtor)],[sin(ang*dtor),cos(ang*dtor)]]; } //--------------------------------------------------------- func clmfit(y,x,&a,function,&yfit) /* DOCUMENT clmfit(y,x,&a,function,&yfit) * Useful wrapper for the lmfit procedure. * y = the data to fit vs x * a = the output coefficients (may have initial value on input) * function = a string containing the function definition where * x and a must be used as variable and coefficients name * e.g. "a(1)+a(2)*cos(x)" * yfit = optional output. Best fit. * SEE ALSO: lmfit */ { system,"rm /tmp/foo.i"; f = open("/tmp/foo.i","w"); write,f,"func foo(x,a) {return "+function+";}"; close,f; include,"/tmp/foo.i",10; require,"lmfit.i"; r= lmfit(foo,x,a,y); yfit = foo(x,a); return a; } //--------------------------------------------------------- func bin2(image) /* DOCUMENT bin2(image) * Returns the input image, binned by a factor of 2. * That is, a 512x512 image is transformed in a 256x256 image. * one output pixel is the average of the 4 corresponding input ones, * so that it conserves the total intensity. * SEE ALSO: */ { d = dimsof(image); if (d(1) != 2) { error,"Bin only accepts images"; } if (((d(2) % 2) != 0) || ((d(3) % 2) != 0)) { error,"Bin only accepts dimensions with even # of pixels"; } sim= image+roll(image,[-1,-1])+roll(image,[-1,0])+roll(image,[0,-1]); return sim(::2,::2); } //--------------------------------------------------------- func extractImage(image,dimx,dimy,method=) /* DOCUMENT extractImage(image,dimx,dimy,method=) * Interactively extract a subimage from a larger one. * dimx[,dimy] are the dimensions of the subimage (not used for method 2) * method = 1 center is selected with mouse * method = 2 use mouse to click and drag to define subimage * NOTE: The image has to be displayed before calling the rountine. * This allows the user to arrange cuts and zoom level. * SEE ALSO: */ { if (!is_set(method)) {method = 1;} if (is_void(dimy)) { if (is_void(dimx)) { method = 2; // all is done with mouse } else { dimy = dimx; method = 1; // only center is selected with mouse } } s = dimsof(image); if (exist(dimx) && dimx > s(2)) {write,"X dimension too large";} if (exist(dimy) && dimy > s(3)) {write,"Y dimension too large";} if (method == 1) { beg: co = mouse(1,0,"Click on center of image to extract"); co1 = long(round(co(1:2)-[dimx/2.,dimy/2.]+1)); co2 = co1 + [dimx,dimy]-1; xc = [co1(1),co2(1)]; yc = [co1(2),co2(2)]; if (anyof(xc <=0) || anyof(xc > s(2))) { write,"Out of bound in X"; goto beg; } if (anyof(yc <=0) || anyof(yc > s(2))) { write,"Out of bound in Y"; goto beg; } sim = image(xc(1):xc(2),yc(1):yc(2)); } if (method == 2) { co = long(round(mouse(1,1,"Click and drag to select image to extract")+0.5)); xc = [co(1),co(3)]; yc = [co(2),co(4)]; xc = xc(sort(xc)); yc = yc(sort(yc)); sim = image(xc(1):xc(2),yc(1):yc(2)); } return sim; } //--------------------------------------------------------- func surface(image,shade=) /* DOCUMENT surface(image,shade=) * Simple wrapper to get a simple mesh (or shaded) of the input array. * SEE ALSO: */ { if (!exist(image)) { text = \ "For the equivalent of the IDL 'surface' routine, you should use : \n\ #include \"plwf.i\" \n\ window,style=\"nobox.gs\"; // Possibly \n\ orient3,-35*pi/180.,25*(pi/180.); // for instance \n\ light3, diffuse=.5, specular=1., sdir=[1,.5,1]; // defines lighting\n\ xy = indices(dimsof(image)); \n\ plwf,image,xy(,,1),xy(,,2); \n\ or \n\ plwf,image,xy(,,1),xy(,,2),edges=0,shade=1; for 'shade_surf'\n\n\ Or Just call this function \n\ \"> surface,image,shade=0/1\" and this function will do the job"; write,text; } else { require,"plwf.i"; window,style="nobox.gs"; orient3,-35*pi/180.,25*(pi/180.); light3, diffuse=.5, specular=1., sdir=[1,.5,1]; xy = indices(dimsof(image)); if (is_set(shade)) {plwf,image,xy(,,1),xy(,,2),edges=0,shade=1;} else {plwf,image,xy(,,1),xy(,,2);} } } //--------------------------------------------------------- func __sinc(ar) /* DOCUMENT sinc(ar) * Return the sinus cardinal of the input array * F.Rigaut, 2002/04/03 * SEE ALSO: Eric Thiebault wrote a sinc which is probably better. */ { local ar; ar = double(ar); w = where(abs(ar) < 1e-8); if (exist(w)) {ar(w) = 1e-8;} return sin(ar)/ar; } if (!is_func(sinc)) sinc=__sinc; //--------------------------------------------------------- func window2(dummy) /* DOCUMENT window2() * Create a window with style "myboxed.gs" * F.Rigaut 2002/04/03 * SEE ALSO: window, window3 */ {window,wait=1,style="/Users/frigaut/Yorick/Francois/myboxed.gs";} //--------------------------------------------------------- func uint(arg) /* DOCUMENT uint(arg) * Return the unsigned version of an integer of long argument. * Sorry, I neede this for some fits files. There is a uint type * in yorick-mb, beware. * F.Rigaut, 2001/10 * SEE ALSO: */ { arg = long(arg); tmp = where(arg < 0); if (numberof(tmp) > 0) {arg(tmp) = arg(tmp) + 65536;} return arg; } //--------------------------------------------------------- func decimal_time(str,delim) /* DOCUMENT decimal_time(str,delim) * Returns the decimal time (in hours) from string like "20:33:12" * or "21&32&01" or "06 55 32". You can specify a delimiter. * F.Rigaut 2001/10 * OBSOLETE. THIS ROUTINE IS SUPERSEEDED BY "ParseTime". * SEE ALSO: */ { local res; for (i=1;i<=numberof(str);i++) { v = grow(strtok(str(i),delim)(1),strtok(strtok(str(i),delim)(2),delim)); hh = mm = ss = 0.; sread,v,hh,mm,ss; grow,res,hh+mm/60.+ss/3600.; } return res; } //--------------------------------------------------------- func fftfit(yin,fraccut,nsig) /* DOCUMENT fftfit(yin,fraccut,nsig) * routine of iterative fit by FT, discarding aberrant points * yin = input vector to fit * fraccut = cut in the fourier plane in fraction of cut-off frequency * nsig = number of sigma for rejection of aberrant points * F.Rigaut 2001/10 * SEE ALSO: */ { n = numberof(yin); v = grow(yin,yin(::-1)); np = 1; iter = 0; while ((np != 0) && (iter <= 20)) { iter= iter+1; f = fft(v,1); mask = float(f)*0.; mask(1:long(n*fraccut)) = 1; mask = mask(::-1); mask(1:long(n*fraccut+1)) = 1; vfit = float(fft(f*mask,-1))/(2*n); // fma;plg,v;plg,vfit,type=2; pause,500; sig = (v-vfit)(rms); w = where(abs(v-vfit) > nsig*sig); np = numberof(w); // print,np; if (is_array(w) == 0) {np=0;} if (np != 0) {v(w) = vfit(w);} } if (iter >= 20) {print,"Max number of iteration reach. Exiting.";} yout = vfit(1:n); return yout; } //--------------------------------------------------------- func rfftconvol(image,kernel) /* DOCUMENT rfftconvol(image,kernel) * Not specialy optimized fft convolution. * Inputs are two real positive arrays (images) of identical size. * Output is a real array. The output is Normalized in flux. * F.Rigaut, 2002/04/04 * SEE ALSO: convol */ { sz = dimsof(image); if (anyof(dimsof(kernel)-sz)) { error,"Image and kernel should have the same size !"; } return float(fft(fft(image,1)*fft(kernel,1),-1))/sz(2)^2.; } //--------------------------------------------------------- func convol2d(image,kernel) /* DOCUMENT convol2d(image,kernel) * For small kernel. Not FT based. Really slow ! use only for small images. * you can use convVE if you are running yao on a mac (see yao_veclib/yao_fast.i) * F.Rigaut, 2001 * NOTE: name changed as of yorick-1.6.01. used to be named convol * SEE ALSO: rfftconvol */ { local im; s = dimsof(image); sk = dimsof(kernel); im = array(float,s(2)+sk(2),s(3)+sk(3)); im(1:s(2),1:s(3)) = image; imac = im*0.; mask = im*0.; mask(1:s(2),1:s(3)) = 1.; maskac= mask*0.; for (i=1;i<=sk(2);i++) { for (j=1;j<=sk(3);j++) { imac = imac+roll(im,[i,j])*kernel(i,j); maskac = maskac+roll(mask,[i,j])*kernel(i,j); } } imac = imac/clip(maskac,1e-4,); // return maskac; // return imac; return imac(sk(2)/2+2:sk(2)/2+s(2)+1,sk(3)/2+2:sk(3)/2+s(3)+1); } //--------------------------------------------------------- extern _nowtime; _nowtime = array(double,10); //--------------------------------------------------------- func myxytitles(xtitle,ytitle,xyoff,font=,height=) { l = viewport(); xdim = l(2)-l(1); ydim = l(4)-l(3); if (is_void(xyoff)) {xyoff=[0.,0.];} // coordinate of X axis label xx = l(1)+xdim/2.; xy = l(3)-ydim/9.+xyoff(2); plt,xtitle,xx,xy,height=height,font=font,tosys=0,justify="CC"; // coordinate of Y axis label yx = l(1)-xdim/6.+xyoff(1); yy = l(3)+ydim/2.; plt,ytitle,yx,yy,height=height,font=font,tosys=0,orient=1,justify="CC"; } //--------------------------------------------------------- func mypltitle(title,xyoff,font=,height=) { l = viewport(); xdim = l(2)-l(1); ydim = l(4)-l(3); if (is_void(xyoff)) {xyoff=[0.,0.];} // coordinate of title xx = l(1)+xdim/2.+xyoff(1); xy = l(4)+ydim/15.+xyoff(2); plt,title,xx,xy,height=height,font=font,tosys=0,justify="CC"; } //--------------------------------------------------------- func axisLegend(xtext,ytext,xyoff=,yxoff=) /* DOCUMENT axisLegend(xtext,ytext,xyoff=,yxoff=) * plot the axis captions. works for myboxed.gs graphic style. * F.Rigaut, 2001/11/10. */ { if (!is_set(xyoff)) {xyoff=0.;} if (!is_set(yxoff)) {yxoff=0.;} plt,xtext,0.42,0.39+xyoff,justify="CC",font="helvetica"; plt,ytext,0.12+yxoff,0.65,justify="CC",font="helvetica",orient=1; } //--------------------------------------------------------- func fftshift(image,xs,ys) /* DOCUMENT fftshift(image,xs,ys) * Shift the input array by an arbitrary amount (xs,ys) in pixel units. * Of course xs and ys can be fractional. This rountine shift the * image by passing in the Fourier plane. All the usual restrictions * apply: * - The image should be well sampled (Nyquist) * - There should not be discontinuities at the edges, etc... * The input array can be 1D or 2D * SEE ALSO: fftrebin */ { s = dimsof(image); if (s(1) == 2) // case 2D { xy = indices(s); x = xy(,,1)-s(2)/2.-1.; y = xy(,,2)-s(3)/2.-1.; // normalisation factor: tilt = 64.*0.098174773*(xs*x/s(2)+ys*y/s(3)); fsh = array(complex,s); fsh.re = roll(cos(tilt)); fsh.im = roll(sin(tilt)); sim = float(fft(fft(image,-1)*fsh,1)); sim = sim/sum(sim)*sum(image); } if (s(1) == 1) // case 1D { x = indgen(s(2))-s(2)/2.-1.; tilt = 64*0.09817*xs*x/s(2); fsh = array(complex,s); fsh.re = roll(cos(tilt)); fsh.im = roll(sin(tilt)); sim = float(fft(fft(image,-1)*fsh,1)); sim = sim/sum(sim)*sum(image); } return sim; } //--------------------------------------------------------- func fftrebin(image,nreb) /* DOCUMENT fftrebin(image,nreb) * Returns "image" rebinned nreb times (nreb should be an integer, * power of 2, i.e. 2, 4, 8, ...) using a Fourier technique (basically, * extention of the support in the Fourier plane by zero values. * F.Rigaut, 2001/11/10. * SEE ALSO: fft, fft_setup, fft_inplace */ { dim = (dimsof(image))(2); ndim = nreb*dim; imout = array(complex,ndim,ndim); imfft = fft(eclat(image),1); imfft.re = eclat(imfft.re); imfft.im = eclat(imfft.im); imout(1:dim,1:dim) = imfft; imout = roll(imout,[-dim/2,-dim/2]); return eclat(float(fft(imout,-1))/dim/dim/nreb^2); } //--------------------------------------------------------- // December 2003:This function is superseeded by the clip function that call the // clip C rountine. Much faster than this one. see yorickfr.i // 2004mar03: I realized that the custom yorick version may not be available // on all machines I have installed yorick on. So here I provide a substitute // if clip is not defined. func oldclip(arg,lt,ht) /* DOCUMENT pli, clip(arg, mini, maxi); * Returns the argument, which has been "clipped" to mini * and maxi, i.e. in which all elements lower than "mini" * have been replaced by "mini" and all elements greater * than "maxi" by "maxi". Array is converted to float. * Either "mini" and "maxi" can be ommited, in which case * the corresponding mini or maxi is not clipped. * Equivalent to the IDL ">" and "<" operators. * F.Rigaut, 2001/11/10. * SEE ALSO: */ { require,"utils.i"; // from yutils local imo; imo = double(arg); if (lt == []) lt=min(imo); if (ht == []) ht=max(imo); if (is_scalar(imo)) { if (max(imo) > ht) imo=ht; if (min(imo) < lt) imo=lt; return imo; } if (max(imo) > ht) imo(where(imo > ht)) = ht; if (min(imo) < lt) imo(where(imo < lt)) = lt; return imo; } if (clip == []) {clip = oldclip;} //--------------------------------------------------------- func strInt(ivec,nchar) /* DOCUMENT strInt(ivec,nchar); * Create a string array which elements are the string * equivalent of each elements of "ivec", with as many * heading "0" added to fill a string of length nchar. * example: * print,strInt(indgen(10:12),4) * ["0010","0011","0012"] * F.Rigaut, 2001/11/10. * SEE ALSO: str routines in string.i */ {return strpart("00000000000000"+swrite(ivec,format="%i"),-(nchar-1):0);} //--------------------------------------------------------- func medianCube(cube) /* DOCUMENT medianCube(cube) * Returns a 2D array which elements are the median along the * 3rd dimension of the input variable "cube". * F.Rigaut, 2001/11/10. * SEE ALSO: median. */ {return median(cube,3);} //--------------------------------------------------------- // this function is superseeded by the call to the C function distraw // see yorickfr.i // 2004mar03: same remark as for clip (see above). Superseeded by the faster // dist in yorickfr.i, but as this custom version is not always available, // I provide this one as backup. func olddist(dim,xc=,yc=) /* DOCUMENT dist(size,xc=,yc=) * Returns an array which elements are the distance to (xc,yc). xc and * yc can be omitted, in which case they are defaulted to size/2+1. * F.Rigaut, 2001/11/10. * SEE ALSO: indices */ { dim = long(dim); if (xc == []) xc = int(dim/2)+1; if (yc == []) yc = int(dim/2)+1; x = float(span(1,dim,dim)(,-:1:dim)); y = transpose(x); d = float(sqrt((x-xc)^2.+(y-yc)^2.)); d = clip(d,1e-5,); return d; } if (dist == []) {dist = olddist;} //--------------------------------------------------------- // 2004mar03: same remark as for clip (see above). Superseeded by the faster // eclat in yorickfr.i, but as this custom version is not always available, // I provide this one as backup. func oldeclat(image) /* DOCUMENT eclat(image) * Equivalent, but slightly faster (?) than roll. Transpose the four main * quadrants of a 2D array. Mostly used for FFT applications. * F.Rigaut, 2001/11/10. * SEE ALSO: roll. */ { d = dimsof(image); dx = d(2); dy = d(3); x1=1; x2=dx/2 ; x3=x2+1 ; x4=dx; y1=1; y2=dy/2 ; y3=y2+1 ; y4=dy; out = image*0.; out(x1:x2,y1:y2) = image(x3:x4,y3:y4); out(x3:x4,y1:y2) = image(x1:x2,y3:y4); out(x1:x2,y3:y4) = image(x3:x4,y1:y2); out(x3:x4,y3:y4) = image(x1:x2,y1:y2); return out; } if (eclat == []) {eclat = oldeclat;} //--------------------------------------------------------- func calcpsf(pupil,phase,init=) /* DOCUMENT calcpsf(pupil,phase,init=) * Compute psfs from pupil and phase using FFT. * F.Rigaut, 2001/11/10. * SEE ALSO: fft, rfftconvol */ { extern calcPsfWorkSpace; if ((calcPsfWorkSpace = []) || (is_set(init))) { // write,"\nSetting up FFT workspace for calcpsf"; workspace= fft_setup(dimsof(pupil),1); } dim = (dimsof(pupil))(2); p = array(complex,dim,dim); p.re = pupil*cos(phase); p.im = pupil*sin(phase); psf = eclat(abs(fft(p,1,setup=calcPsfWorkSpace)))^2.; return psf; } //--------------------------------------------------------- func apod(length,degree) /* DOCUMENT apod(length,degree) * Returns apodization functions for 1D Fourier transforms. * degree = 1 to 3 : apodization functions for the FTS * degree = 4 : sinc * degree = 5 : Bartlett filter (cf NR p 547) * degree = 6 : Hann filter * degree = 7 : Welch filter * SEE ALSO: */ { if ((degree < 0) || (degree > 7)) { print,"Apodization degree should be 0, 1, 2, 3, 4, 5, 6 or 7"; return -1; } if ((degree >= 0) && (degree <= 3)) { c = transpose([[1.,0.,0.,0.], // matrix of the coefficients of [0.548,-0.0833,0.5353,0.], // the apodization fonction. [0.26,-0.154838,0.894838,0.], // c(2,*) = vector of coef for weak apod [0.09,0.,0.5875,0.3223]]); // c(4,*) = " " " " strong " u = 2.*(indgen(length)-1.)/length-1.; ffil=u*0.; for (i=1;i<=4;i++) {ffil = ffil + c(degree,i)*(1-u^2.)^i;} } if (degree == 4) { x = 2.*pi*(((indgen(length)-1.)/(length-1.))-0.5); ffil = 1.4914*sinc(x); } n = indgen(length)-1.; if (degree == 5) {ffil = 1. - abs((n-0.5*length)/(0.5*length));} if (degree == 6) {ffil = 0.5*(1 - cos(2*pi*n/length));} if (degree == 7) {ffil = 1. - ((n-0.5*length)/(0.5*length))^2.;} return ffil; } //--------------------------------------------------------- func psd(s, length, step=, filter=, samp=, db=,noplot=,overplot=, sqroot=,roddier=,xtitre=,ytitre=,silent=,color=,type=,hist=) /* DOCUMENT psd(s, length, step=, filter=, samp=, db=,noplot=,overplot=, * sqrt=,roddier=,xtitre=,ytitre=) * Procedure PSD : Compute the Power Spectral Density of a vector * s = variable on which the PSD has to be computed * length = length of the subsample for FFTs * step = shift in pixels between subsamples * filter = apodization function as in apod.pro (usually 6) * samp = sampling time * db = plots in dB :10*alog10(dsp) * noplot = do not plot * overplot= over plot * sqroot = returns the sqrt of the dsp * roddier = plots the psd roddier style * SEE ALSO: */ { extern psdnumberofoverplots; if (is_void(s)) { write,"psd,data,fftlength,step=,filter=,samp=,db=,noplot=,overplot=,sqrt=,roddier=,xtitre=,ytitre=,silent="; return; } if (is_void(step)) { step = length/2; } if (is_void(filter)) { filter = 0; } if (is_void(samp)) { samp = 1; } if (is_void(noplot)) { noplot = 0; } if (is_void(xtitre)) { xtitre = "Frequency"; } if (is_void(ytitre)) { ytitre = ""; } if (is_set(roddier)) { ytitre = ytitre+"[freq * PSD]";} else {ytitle = ytitre+"[PSD]"; } if (length > numberof(s)) { error,"length > number of element in vector!!!"; } if (!is_set(silent)) { print,"Stdev of input PSD vector (in psd.i) : ",s(rms); } nb = long((numberof(s) - length)/step)+1; if (!is_set(silent)) { write,format="Averaging %2d sample of length %5d shifted by %5d\n", \ nb,length,step; } dsp = array(double,length); if (filter == -1) { fil = array(1.,length); } else { fil = apod(length,filter); } fn = sum(abs(fft(fil,1))^2.)/length^2.; for (i=0;i<=nb-1;i++) { tmp = s(i*step+1:i*step+length); tmp = tmp-avg(tmp); dsp = dsp + abs(fft(tmp*fil,1))^2./length/fn; } dsp = dsp/nb; dsp = dsp(1:length/2); f = (indgen(length/2)-1.)/samp/2./(length/2-1.); f = (indgen(length/2)-1.)/samp/2./(length/2); if (!is_set(silent)) { write,format="Freq. Max = %8.6e\n",max(f); } dsp = dsp*2.; // _x2 because negative part omitted dsp = dsp/length*(length/2./max(f)); // to get in unit^2/Hz if (!is_void(sqroot)) { dsp = sqrt(dsp); } if (db) dsp = 10.*log10(dsp); if (roddier) dsp = f*dsp; if (!noplot) { if (!overplot) { if (hist) plh,dsp(2:),f(2:),color=color,type=type; else plg,dsp(2:),f(2:),color=color,type=type; psdnumberofoverplots=0; } if (overplot) { psdnumberofoverplots++; cols = ["red","blue","green","magenta"]; if (hist) { plh,dsp(2:),f(2:),color=cols(psdnumberofoverplots),color=color,type=type; } else { plg,dsp(2:),f(2:),color=cols(psdnumberofoverplots),color=color,type=type; } } myxytitles,xtitre,ytitre; limits; if (roddier) { logxy,1,0; } else if (db) { logxy,1,0; } else { logxy,1,1; } } return [f,dsp]; } //--------------------------------------------------------- man=help; hitReturn=typeReturn; encircledEnergy=encircled_energy; findFiles = findfiles; yao-5.4.0/yao_utils.i000066400000000000000000000051531234404334100144740ustar00rootroot00000000000000/* * yao_utils.i * * wrapper for the compiled functions in yao_utils.c * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ require,"imutil.i"; extern usleep; extern _mynoop2 /* PROTOTYPE int _mynoop2(pointer in, int nx, int ny, pointer out, int fx, int fy, int binfact) */ /* The following are wrapper to C routines that have no Yorick call functions. They are used in yao for specific operations */ extern _dmsum /* PROTOTYPE void _dmsum(pointer def, int nxdef, int nydef, int nzdef, pointer coefs, pointer outphase) */ extern _dmsum2 /* PROTOTYPE void _dmsum2(pointer def, pointer inddef, long ninddef, long ndef, pointer coefs, pointer outphase, long ndmshape) */ extern _dmsumelt /* PROTOTYPE void _dmsumelt(pointer def, int nxdef, int nydef, int nzdef, pointer i1, pointer j1, pointer coefs, pointer outphase, int outnx, int outny) */ extern _get2dPhase /* PROTOTYPE int _get2dPhase(pointer pscreens, int psnx, int psny, int nscreens, pointer outphase, int phnx, int phny, pointer ishifts, pointer xshifts, pointer jshifts, pointer yshifts) */ func cosf(array) /* DOCUMENT func cosf(array) Returns the cos of the argument. Input and output are float type. SEE ALSO: */ { if (typeof(array) != "float") { error,"This function is for float types!"; } res = array; _cosf,&res,numberof(array); return res; } extern _cosf /* PROTOTYPE int _cosf(pointer data, int size) */ func sinf(array) /* DOCUMENT func sinf(array) Returns the sin of the argument. Input and output are float type. SEE ALSO: */ { if (typeof(array) != "float") { error,"This function is for float types!"; } res = array; _sinf,&res,numberof(array); return res; } extern _sinf /* PROTOTYPE int _sinf(pointer data, int size) */ // comment following line to have a deterministic random (!) start... ran1init; // init random function for poidev. yao-5.4.0/yao_wfs.i000066400000000000000000002413701234404334100141360ustar00rootroot00000000000000/* * yao_wfs.i * * Compilation of functions related to Wavefront Sensors * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ func shwfs_init(pupsh,ns,silent=,imat=,clean=) /* DOCUMENT func shwfs_init(pupsh,ns,silent=,imat=) pupsh: pupil image. Should be 1/0 for SHWFS. dimension sim._size ns: WFS # (for multi-wfs systems, if not, put 1) silent: be silent (except for error messages of course) imat: will be used for imat computation (will use kernel) clean: force recomputing everything (in particular rayleight maps) SEE ALSO: sh_wfs */ { if (silent==[]) silent = (sim.verbose==0); // wfs._initkernels = array(1n,nwfs); if (is_void(ns)) {ns=1;} // default to wfs#1 for one WFS work. if (typeof(pupsh) != "float") {error,"pupsh was not float !";} pupd = sim.pupildiam; size = sim._size; nxsub = wfs(ns).shnxsub(0); subsize = pupd/nxsub; if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; fracsub = wfs(ns).fracIllum; sdim = long(2^ceil(log(subsize)/log(2)+1)); if (no_pad_simage) sdim = long(2^ceil(log(subsize)/log(2))); sdimpow2 = int(log(sdim)/log(2)); wfs(ns)._centroidgain = 1.f; // if (anyof(wfs.svipc>1)) status = quit_wfs_forks(); //==================================================================== // WORK OUT THE NUMBER OF PHOTONS COLLECTED PER SUBAPERTURE AND SAMPLE //==================================================================== // this is modified to take into account the actual surface area of the // telescope, rather than the telescope area for a circular telescope with // no central obscuration telSurf = sum(pupil)*(tel.diam/sim.pupildiam)^2; // from the guide star (computed here as used in wfs_check_pixel_size): if (wfs(ns).gsalt == 0) { wfs(ns)._nphotons = wfs(ns)._zeropoint*10^(-0.4*wfs(ns).gsmag)* wfs(ns).optthroughput* // include throughput to WFS (tel.diam/wfs(ns).shnxsub)^2./telSurf* // for unobstructed subaperture loop.ittime; // per iteration } else { // we are dealing with a LGS wfs(ns)._nphotons = gs.lgsreturnperwatt*cos(dtor*gs.zenithangle)* // detected by WFS wfs(ns).laserpower* // ... for given power wfs(ns).optthroughput* // include throughput to WFS (tel.diam/wfs(ns).shnxsub)^2.*1e4* // for unobstructed subaperture loop.ittime; // per iteration } // see below for # of photons from sky //============================================================= // LGS ELONGATION FROM DEFOCUS METHOD (NOT KERNEL CONVOLUTION) //============================================================= // existence of lgs_prof_amp and alt have been done in check_parameters() // Compute the defocus coef. wfs._lgs_defocuses from wfs.lgs_prof_alt: shwfs_comp_lgs_defocuses,ns; // compute wfs(ns)._unitdefocus, used in the extended field defocus method: if (wfs(ns).type=="hartmann") { xyc = sim._cent; xyc += wfs(ns).LLTxy*sim.pupildiam/tel.diam; wfs(ns)._unitdefocus = &float(2*sqrt(3.)*(dist(sim._size,xc=xyc(1),\ yc=xyc(2))/(sim.pupildiam/2.))^2.); dyn_range_correct = (numberof(*wfs(ns).lgs_prof_amp)>0); tmp = float(indices(subsize)); wfs(ns)._unittip = &(tmp(,,1)*dyn_range_correct); wfs(ns)._unittilt = &(tmp(,,2)*dyn_range_correct); } //================================== // COMPUTE ISTART AND JSTART VECTORS //================================== // they are vectors containing the start // indices (X and Y) of the subapertures is = size/2+1-pupd/2; if (wfs(ns).npixpersub) { is = size/2+1-(subsize*nxsub)/2; } if (wfs(ns).pupoffset!=[]) { puppixoffset = long(round(wfs(ns).pupoffset/tel.diam*sim.pupildiam)); } else puppixoffset = [0,0]; nsubs = nxsub*nxsub; istart = ((indgen(nsubs)-1)%nxsub)*subsize + is + puppixoffset(1); jstart = ((indgen(nsubs)-1)/nxsub)*subsize + is + puppixoffset(2); xsub = (((indgen(nsubs)-1)%nxsub)+0.5)*tel.diam/nxsub-tel.diam/2.; ysub = ((indgen(nsubs)-1)/nxsub+0.5)*tel.diam/nxsub-tel.diam/2.; //========================================================== // COMPUTE WHICH SUBAPERTURES ARE ENABLED (FLUX > THRESHOLD) //========================================================== fluxPerSub = array(float,nsubs); for (i=1;i<=nsubs;i++) { fluxPerSub(i) = sum(pupsh(istart(i):istart(i)+subsize-1, jstart(i):jstart(i)+subsize-1)); } fluxPerSub = fluxPerSub/subsize^2.; // indices of the enabled subapertures: gind // gind = where(fluxPerSub > fracsub); // changed 2009oct07: we display *all* subaps for which there is flux // this is to have a more realistic display (wfs._fimage) // however, now we have 2 sets of valid subapertures: // - the one for which we want to compute an image in _shwfs() -> _nsub4disp // - the really valid ones, for which we will compute the slope information -> _nsub if (wfs(ns).shmethod==2) { gind = where(fluxPerSub > 0); } else { // shmethod=1 -> geometrical SH. // for these, it makes no sense to differentiate display and slope/valid // subapertures. We'll make them the same gind = where(fluxPerSub > fracsub); } // then out of these, we will only compute mesvec for the "valid": tmp = fluxPerSub; tmp = tmp(gind); wfs(ns)._validsubs = &(int(tmp > fracsub)); istart = istart(gind); jstart = jstart(gind); xsub = xsub(gind); ysub = ysub(gind); fluxPerSub = fluxPerSub(gind); // stuff some of wfs structure for WFS "ns": wfs(ns)._istart = &(int(istart-1)); // -1n 'cause C is 0 based wfs(ns)._jstart = &(int(jstart-1)); wfs(ns)._x = &(xsub); wfs(ns)._y = &(ysub); wfs(ns)._nsub4disp = int(numberof(gind)); wfs(ns)._nsub = int(sum(*wfs(ns)._validsubs)); // compute other setup variables for _shwfs: //================================ // SUBAPERTURE SIZE AND PIXEL SIZE //================================ wfs_check_pixel_size,ns,sdim,rebinFactor,actualPixelSize,\ printheader=0,silent=1; sdimpow2 = int(log(sdim)/log(2)); // 2004mar22: added a guard pixel for each subaperture for the display // 2009oct06: removed it, in the process of implementing the optical // coupling between subapertures // extended field of view stuff, work out npb: // we want to pad wfs.npixels by a integer number of pixel on each side // to get as close as possible to the requested extfield: //~ if (!wfs(ns)._npixels) wfs(ns)._npixels = wfs(ns).npixels; tmp = (wfs(ns).extfield-wfs(ns).npixels*wfs(ns).pixsize)/wfs(ns).pixsize; wfs(ns)._npb = clip(2*lround(tmp/2.),0,); // pixel to add as "b"order for extended fov, binned pixels wfs(ns)._npixels = wfs(ns).npixels+wfs(ns)._npb; // [binned pixels, extended image] wfs(ns)._nx = wfs(ns)._npixels*rebinFactor; // [small pixels] // note that nx can actually be smaller than sdim, as we are xfering into the // ximage and the xfer is bound checked. wfs(ns).extfield = wfs(ns)._npixels*wfs(ns).pixsize; // now let's find if there are better dimension for the fft: if ((wfs(ns)._npb>0)&&(wfs(ns).shmethod==2)&&(optimize_nx)) { // determine prime factors for _nx and above. take first integer which // prime factors are all <= 7: _nx = wfs(ns)._nx-1; do pf = prime_factors(++_nx); while (anyof(pf>7)); wfs(ns)._nx4fft = _nx; if (sim.verbose) { write,format="FFTW: Best dim for ximage = %d, up from %d\n", \ wfs(ns)._nx4fft,wfs(ns)._nx; } } else wfs(ns)._nx4fft = wfs(ns)._nx; // call optimizer for this size FFTW: if (wfs(ns).shmethod==2) { _init_fftw_plan,int(wfs(ns)._nx4fft); if (_export_wisdom(expand_path(fftw_wisdom_file))) \ write,format=" Warning: Can't export FFTW wisdom to %s\n", \ expand_path(fftw_wisdom_file); } // now compute _shwfs C routine internal array size: // for bimage (trimmed and rebinned simage): wfs(ns)._rebinfactor = rebinFactor; nbigpixels = long(wfs(ns)._nx/rebinFactor); // check eveness of nbigpixels is same as wfs.npixels: if (even(wfs(ns)._npixels)!=even(nbigpixels)) nbigpixels--; // subsize of sdim that we will use in bimage: rdim = long(wfs(ns)._nx); xy = long(indices(rdim)-1.); tmp = xy(,,1)/rebinFactor + xy(,,2)/rebinFactor*nbigpixels; // what's the rebinned pixels size (in small fft pixels)? // answer -> rebinFactor // how many integer big pixels can we fit in sdim (which ought to be // a power of 2)? // answer = long ( sdim/rebinFactor ) // the number of rebinned pixels in the final subaperture is wfs.npixels // (1) if wfs.npixels is even, the spot has to be in the center of the subap // image // (2) if wfs.npixel is odd, the spot has to be in the center of the center // rebinned pixel. // remember the spot is shifted by one half fft pixels left and down, // so it can fall in between original pixels hence in between rebinned // pixels. thus by playing here we can only accomodate: // (1) wfs.npixel even, both rebinfactor odd and even // (2) wfs.npixel odd, only rebinfactor even. // (3) with wfs.npixel odd and rebinfactor odd, the spot would have to // be centered on the central rebinned pixel, which has and odd number // of fft pixels, thus would have to be centered on a fft pixel, which is // not originally the case. will have to modify tiltsh for that. // for now let's take care of how to dimension binindices for all those // cases. after the fft, and 1/2 pixel shift, the spot is centered on // the 2^n x 2^n fft array. binindices = array(-1l,[2,wfs(ns)._nx4fft,wfs(ns)._nx4fft]); binindices(1:rdim,1:rdim) = tmp; ss = ceil((wfs(ns)._nx-rdim)/2.); //~ binindices = roll(binindices,[ss,ss]); //~ binindices = int(eclat(binindices)); // stuff some more of wfs structure for WFS "ns": wfs(ns)._binindices = &(int(binindices)); // checked, it seems to work. wfs(ns)._binxy = nbigpixels; if (stop_at==43) error; // centroid reference vector, after final extraction of subimage: centroidw = indgen(wfs(ns)._npixels)-1.-(wfs(ns)._npixels/2.-0.5); // we might as well express it in arcsec: centroidw = float(centroidw*actualPixelSize); wfs(ns)._centroidw = ¢roidw; //~ write,format="nbigpixels = %d, wfs._npixels = %d, wfs._npb=%d\n",\ //~ nbigpixels,wfs(ns)._npixels,wfs(ns)._npb; // just for print out to screen if needed: wfs_check_pixel_size,ns,sdim,rebinFactor,actualPixelSize,\ printheader=(ns==1),silent=silent; wfs(ns)._sdim = sdim; if (wfs(ns).spotpitch==0) wfs(ns).spotpitch = wfs(ns)._npixels; imistart = (istart-min(istart))/subsize*(wfs(ns).spotpitch); imjstart = (jstart-min(jstart))/subsize*(wfs(ns).spotpitch); wfs(ns)._imistart = &(int(imistart)); wfs(ns)._imjstart = &(int(imjstart)); wfs(ns)._imistart2 = &(int(imistart)); wfs(ns)._imjstart2 = &(int(imjstart)); //~ fimdim = long(nxsub*wfs(ns)._npixels+(nbigpixels-wfs(ns)._npixels)+wfs(ns)._npb); fimdim = long((nxsub-1)*wfs(ns).spotpitch+wfs(ns)._npixels); wfs(ns)._fimage = &(array(float,[2,fimdim,fimdim])); wfs(ns)._dispimage = &(array(float,[2,fimdim,fimdim])); wfs(ns)._fimnx = int(fimdim); wfs(ns)._fimny = int(fimdim); if (stop_at==44) error; // This is the tilt to add to the input phase so that // the individual subaperture images fall in between // the pixels of the quadcell xy = indices(sim._size); wfs(ns)._tiltsh = &(float((-64.)*0.098174773*(xy(,,1)+xy(,,2))* \ 0.5/sdim*wfs(ns).lambda/(2*pi)*(wfs(ns).shmethod == 2))); // This tilt array is intended to bring the spot back inbetween 4 pixels // instead of centered on dim/2+1 as a result of the regular FFT. // In other words, added to the subaperture phase, it will shift the // image 1/2 FFT pixel left and down. // this is an achromatic factor of course that just depends on the // dimension of the array. // the lambda/2pi factor is thus to compensate the x by 2pi/lambda // in _shwfs, making tiltsh achromatic. // If the number of (rebinned) pixels (wfs.npixels) is odd, // and if the rebinFactor (number of small FFT pixels in a rebinned one) // is also odd, then the spot should be centered on a small FFT pixel, // not in between 4 of them. if (odd(rebinFactor) && odd(wfs(ns).npixels) && (wfs(ns).shmethod==2)) { *wfs(ns)._tiltsh *= 0; } //===================================== // CONVOLUTION KERNELS INITIALIZATIONS: //===================================== // if there is no explicit request for an extended kernel // and we are not using LGS (or the depth = 0) then we disable // the kernel convolution is _shwfs to gain time (and accuracy) // this behavior is overriden in MultWfsIntMat anyway for the purpose // of computing the iMat with the correct kernel (to simulate for // the extended "seeing" spot wfs(ns)._kernelconv = 1n; if ((wfs(ns).kernel==0) && (wfs(ns)._gsdepth==0)) wfs(ns)._kernelconv = 0n; if (wfs(ns).shmethod==1) wfs(ns)._kernelconv = 0n; //======================================================================= // INITIALIZE COMMON KERNEL TO CONVOLVE _SHWFS IMAGE FOR IMAT CALIBRATION //======================================================================= shwfs_init_common_kernel,ns,imat=imat; //============================== // UPLINK SEEING INITIALIZATIONS //============================== if (wfs(ns).LLT_uplink_turb) comp_turb_lgs_kernel,ns,init=1; //============================================================================= // INITIALIZE WFS IMAGE KERNELS: SUBAPERTURE DEPENDENT. USED FOR LGS ELONGATION //============================================================================= // if kernelconv is 0, then the _shwfs routine does not use wfs._kernels: shwfs_init_lgs_kernels,ns; //================================================= // INITIALIZE RAYLEIGH STUFF: SUBAPERTURE DEPENDENT //================================================= if (wfs(ns).rayleighflag) { shwfs_init_rayleigh,ns; if (filter_rayleigh_sub) { mrf = max(*wfs(ns)._rayleighflux); if (mrf>0.) { *wfs(ns)._validsubs *= ((*wfs(ns)._rayleighflux/mrf)1) \ write,format="Dimension for optional amplitude mask: %d\n",wfs(ns)._nx; // reads out the amplitude mask for the subaperture: if (wfs(ns).fsname) { // read the amplitude image tmp = yao_fitsread(YAO_SAVEPATH+wfs(ns).fsname); // check that dims are OK: if (anyof(dimsof(tmp)!=[2,wfs(ns)._nx,wfs(ns)._nx])) { error,swrite(format="Bad dimensions for %s. Should be %d, found %d\n", wfs(ns).fsname,wfs(ns)._nx,dimsof(tmp)(2)); } // check of mask is centered (can be a common cause of mistake): f1x = sum(tmp(1:wfs(ns)._nx/2,)); f2x = sum(tmp(wfs(ns)._nx/2+1:,)); f1y = sum(tmp(,1:wfs(ns)._nx/2)); f2y = sum(tmp(,wfs(ns)._nx/2+1:)); if ((f1x!=f2x)||(f1y!=f2y)) { write,format="%s\n","\nWARNING!"; write,format="%s\n","The SHWFS amplitude mask is not centered. This can create"; write,format="%s\n","a bias in the slope calculation. A centered mask should be"; write,format="%s\n","centered on the 4 central pixels of the mask, not on"; write,format="%s\n","the (0,0) of the FFT transform. If you did not do that on "; write,format="%s\n\n","purpose, you should correct your mask."; } // modify as required: tmp4fft = array(0.0f,[2,wfs(ns)._nx4fft,wfs(ns)._nx4fft]); tmp4fft(1:wfs(ns)._nx,1:wfs(ns)._nx) = tmp; wfs(ns)._submask = &(float(tmp4fft)); wfs(ns)._domask = 1l; } else if (strlen(wfs(ns).fstop)>0) { // make the field stop with wfs.fstop, wfs.fssize and wfs.fsoffset make_fieldstop,ns; wfs(ns)._domask = 1l; } else wfs(ns)._domask = 0l; // compute # of photons from the sky as above for guide star. // skymag is per arcsec, so we have to convert for // the subaperture size computed in wfs_check_pixel_size.; // changed on 2009oct12: now _skynphotons is normalized // *per rebinned pixel*. subsize = sim.pupildiam/wfs(ns).shnxsub(0); if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; // subsize in meters: subsize_m = subsize * tel.diam/sim.pupildiam; wfs(ns)._skynphotons = wfs(ns)._zeropoint*10^(-0.4*wfs(ns).skymag)* // #photons/tel/sec/arcsec^2 subsize_m^2./telSurf* // -> per full subaperture loop.ittime* // -> per iteration wfs(ns).optthroughput* // -> include throughput to WFS wfs(ns).pixsize^2.; // -> per rebinned pixel if ( wfs(ns).skymag == 0) { wfs(ns)._skynphotons = 0.; } // if skymag not set if (sim.verbose == 2) { write,format="wfs(%d)._skynphotons = %f\n\n",ns,wfs(ns)._skynphotons; } // for guide star, total "useful" signal per subap. wfs(ns)._fluxpersub = &(float(fluxPerSub*wfs(ns)._nphotons)); if (sim.verbose > 0) { gstype = ( (wfs(ns).gsalt>0)?"LGS":"NGS" ); tmp = fluxPerSub(where(*wfs(ns)._validsubs))*wfs(ns)._nphotons; if (min(tmp)>10) fmt="%.0f"; else fmt="%.1f"; write,format="%s#%d flux varies between "+fmt+" and "+fmt+ " photon/subap/it\n",gstype,ns,min(tmp),max(tmp); } // for rayleigh, if any: if (wfs(ns).rayleighflag) { wfs(ns)._raylfluxpersub = &(*wfs(ns)._fluxpersub* \ float(*wfs(ns)._rayleighflux / *wfs(ns)._sodiumflux)); } else wfs(ns)._raylfluxpersub = &float(*wfs(ns)._fluxpersub*0.0f+1.0f); // for sky (see above, in photon/subap/it/rebinned pixel) wfs(ns)._skyfluxpersub = &(float(fluxPerSub*wfs(ns)._skynphotons)); // changed 2009oct13: now compute bias and flat for entire _fimage: wfs(ns)._bias = &(wfs(ns).biasrmserror * gaussdev([2,wfs(ns)._fimnx,wfs(ns)._fimny])); wfs(ns)._flat = &(1.0f + wfs(ns).flatrmserror * gaussdev([2,wfs(ns)._fimnx,wfs(ns)._fimny])); //same here, take background calib image for entire _fimage wfs(ns)._bckgrdcalib = &(array(float,[2,wfs(ns)._fimnx,wfs(ns)._fimny])); if (sim.verbose == 2) { write,format="Dark current wfs#%d / iter / pixel=%f\n",ns, float(wfs(ns).darkcurrent*loop.ittime); } // CALIBRATE BACKGROUND IMAGES (have to run sh_wfs for that): bckgrdsub = wfs(ns)._bckgrdsub; wfs(ns)._bckgrdsub = 0; // it doesn't matter wfs(ns)._bckgrdinit = 1; // call sh_wfs for calibration of the background // remove the noise when calculating the origins noiseOrig = wfs.noise; wfs.noise *= 0; // first sync if needed (svipc) if (wfs(ns).svipc>1) status = sync_wfs_forks(); for (i=1;i<=wfs(ns).nintegcycles;i++) sh_wfs,pupsh,pupsh*0.0f,ns; wfs.noise=noiseOrig; wfs(ns)._bckgrdinit = 0; wfs(ns)._bckgrdsub = bckgrdsub; // the following fixes a bug we have since 4.7.1: // wfs(ns)._bckgrdcalib = &(*wfs(ns)._fimage); // here we need to re-sync to restore bckgrd properties to forks: if (wfs(ns).svipc>1) status = sync_wfs_forks(); if (show_background) { fma; plsys,1; pli,*wfs(ns)._bckgrdcalib; pltitle,swrite(format="Calibrated background for WFS#%d",ns); hitReturn; } // DISPLAY OF WFS CONFIG (put that somewhere else so it can be // called independently) if ( (sim.debug>=1) && (!silent) && (wfs(ns).shmethod==2) ){ sh_wfs,pupsh,pupsh*0.0f,ns; fma; plsys,2; pli,*wfs(ns)._fimage; // limits; cn = 80; for (i=1;i<=wfs(ns)._nsub4disp;i++) { if ((*wfs(ns)._validsubs)(i)==0) continue; x1 = (*wfs(ns)._imistart2)(i)+wfs(ns)._npb/2; y1 = (*wfs(ns)._imjstart2)(i)+wfs(ns)._npb/2; l1 = wfs(ns).npixels; plg,_(y1,y1,y1+l1,y1+l1,y1),_(x1,x1+l1,x1+l1,x1,x1),color=[cn,cn,cn],marks=0; plt,swrite(format="%d",i),x1,y1,tosys=1,color=[cn,cn,cn],height=lround(pltitle_height*0.75); } // display the full extent of this example subap FoV // to show the user how it overlaps with neightbors // first let's highlight the subaperture we're talking about here: i = where(*wfs(ns)._validsubs)(1); x1 = (*wfs(ns)._imistart2)(i); y1 = (*wfs(ns)._imjstart2)(i); l1 = wfs(ns)._npixels; plg,_(y1,y1,y1+l1,y1+l1,y1),_(x1,x1+l1,x1+l1,x1,x1),color="green",width=3; // then display the whole subaperture field of view x1 = (*wfs(ns)._imistart)(i); y1 = (*wfs(ns)._imjstart)(i); l1 = wfs(ns)._binxy; //*wfs(ns)._rebinfactor; plg,_(y1,y1,y1+l1,y1+l1,y1),_(x1,x1+l1,x1+l1,x1,x1),color="red"; // field stop: if (*wfs(ns)._submask!=[]) { // fs = roll(*wfs(ns)._submask); fs = *wfs(ns)._submask; xyc = indices(dimsof(fs)); xyc = (xyc-1.)/(dimsof(fs)(2)-1)*(wfs(ns)._binxy)+0.; xyc(,,1) += x1+0.5; xyc(,,2) += y1+0.5; plc,fs,xyc(,,2),xyc(,,1),levs=[0.001],color="magenta",width=3; } require,"plvp.i"; // for plmargin plmargin; xytitles_vp,"pixels","pixels",[0.015,0.015]; pltitle_vp,escapechar(swrite(format="wfs(%d)._fimage",ns)),0.005; limits; plsys,0; ybase = 0.90; deltay = 0.03; deltayt = 0.005; x1 = 0.04; x2 = x1 + 0.03; x3 = x2 + 0.01; plg,_(ybase,ybase),_(x1,x2),color=[cn,cn,cn],width=3; plt,"Valid subapertures",x3,ybase-deltayt,tosys=0 ybase -= deltay; plg,_(ybase,ybase),_(x1,x2),color="green",width=3; plt,"Highlighted subap.",x3,ybase-deltayt,tosys=0 ybase -= deltay; plg,_(ybase,ybase),_(x1,x2),color="red",width=3; plt,"Highlighted subap. total FoV (overlap)",x3,ybase-deltayt,tosys=0 ybase -= deltay; if (*wfs(ns)._submask!=[]) { plg,_(ybase,ybase),_(x1,x2),color="magenta",width=3; plt,"Highlighted subap. field stop",x3,ybase-deltayt,tosys=0; } else { plt,"NO field stop defined",x3,ybase-deltayt,tosys=0 } plsys,2; redraw; if (sim.debug>1) { write,"Hit return to continue..."; hitReturn; } } // and let's just re-sync for good measure: if (anyof(wfs.svipc>1)) status = sync_wfs_forks(); return 1; } //---------------------------------------------------- func shwfs_init_common_kernel(ns,imat=) { extern wfs; if (is_set(imat)) { // we are in iMat computation. we want // the kernel FWHM = seeing + requested kernel fwhm (quadratically) // factor 1.5 to crudely compensate for the fact that the spot is // tilt compensated at the focus of the lenslet dr0 = atm.dr0at05mic*(0.5/wfs(ns).lambda)^1.2/cos(gs.zenithangle*dtor)^0.6; fwhmseeing = wfs(ns).lambda/ (tel.diam/sqrt(wfs(ns).shnxsub^2.+(dr0*wfs(ns).shcalibseeing)^2.))/4.848; kernelfwhm = sqrt(fwhmseeing^2.+wfs(ns).kernel^2.); } else { // we are in regular aoloop. no further convolution to account for seeing. // However, we want to avoid dividing by zero in makegaussian, // so we floor fwhm: kernelfwhm = clip(wfs(ns).kernel,1e-8,); } if ( (sim.verbose >= 1) && (!is_set(silent)) ) { write,format="Kernel FWHM for the iMat calibration = %f\n",kernelfwhm; } quantumPixelSize = wfs(ns).lambda/(tel.diam/sim.pupildiam)/4.848/wfs(ns)._sdim; tmp = eclat(makegaussian(wfs(ns)._nx4fft,kernelfwhm/quantumPixelSize, xc=wfs(ns)._nx4fft/2.+1,yc=wfs(ns)._nx4fft/2.+1)); tmp(1,1) = 1.; // this insures that even with fwhm=0, the kernel is a dirac tmp = tmp/sum(tmp); wfs(ns)._kernel = &(float(tmp)); wfs(ns)._nkernels = 1; } //---------------------------------------------------- func shwfs_init_lgs_kernels(ns) /* DOCUMENT shwfs_init_lgs_kernels(ns) * COMPUTE WFS IMAGE KERNELS: SUBAPERTURE DEPENDENT. * USED FOR LGS ELONGATION */ { extern wfs; quantumPixelSize = wfs(ns).lambda/(tel.diam/sim.pupildiam)/4.848/wfs(ns)._sdim; // coordinate array in arcsec: xy = (indices(wfs(ns)._nx4fft)-wfs(ns)._nx4fft/2.-1)*quantumPixelSize; if (sim.verbose >= 1) write,format="%s\n","Pre-computing Kernels for the SH WFS"; kall = []; gui_progressbar_frac,0.; gui_progressbar_text,swrite(format="Precomputing subaperture kernels, WFS#%d",ns); for (l=1; l<=wfs(ns)._nsub4disp; l++) { // for each subaperture, we have to find the elongation and the angle. xsub = (*wfs(ns)._x)(l); ysub = (*wfs(ns)._y)(l); xllt = wfs(ns).LLTxy(1); yllt = wfs(ns).LLTxy(2); d = sqrt((xsub-xllt)^2. +(ysub-yllt)^2.); if (d == 0) { elong = ang = 0.; } else { elong = atan((wfs(ns)._gsalt+wfs(ns)._gsdepth)/d)-atan(wfs(ns)._gsalt/d); elong /= 4.848e-6; // now in arcsec ang = atan(ysub-yllt,xsub-xllt); // fixed 2004aug02 } angp90 = ang+pi/2.; expo = 4.; alpha = elong/(2.*log(2)^(1/expo)); beta = 2*quantumPixelSize/(2.*log(2)^(1/expo)); alpha = clip(alpha,0.5*quantumPixelSize,); beta = clip(beta,0.5*quantumPixelSize,alpha); tmp = exp(-((cos(ang)*xy(,,1)+sin(ang)*xy(,,2))/alpha)^expo); tmp *= exp(-((cos(angp90)*xy(,,1)+sin(angp90)*xy(,,2))/beta)^expo); tmp = tmp/sum(tmp); grow,kall,float((eclat(tmp))(*)); s2 = tel.diam/wfs(ns).shnxsub*0.9/2.; gui_progressbar_frac,float(l)/wfs(ns)._nsub4disp; } clean_progressbar; wfs(ns)._kernels = &(float(kall)); wfs(ns)._kerfftr = &(float(kall*0.0f)); wfs(ns)._kerffti = &(float(kall*0.0f)); kall = []; wfs(ns)._initkernels = 1n; } //---------------------------------------------------- func shwfs_init_rayleigh(ns) { extern wfs; if (sim.verbose > 0) {write,format="%s\n","Pre-computing Rayleigh for the SH WFS";} rayleighflux = array(0.0f,wfs(ns)._nsub4disp); sodiumflux = array(1.0f,wfs(ns)._nsub4disp); quantumPixelSize = wfs(ns).lambda/(tel.diam/sim.pupildiam)/4.848/wfs(ns)._sdim; // coordinate array in arcsec xy = (indices(wfs(ns)._nx4fft)-wfs(ns)._nx4fft/2.-1)*quantumPixelSize; kall = []; rayfname = parprefix+"-rayleigh-wfs"+swrite(format="%d",ns)+"-zen"+ swrite(format="%d",long(gs.zenithangle))+".fits"; isthere = fileExist(YAO_SAVEPATH+rayfname); fov = quantumPixelSize*wfs(ns)._nx4fft; aspp = quantumPixelSize; if ( (isthere) && (!clean) ) { kall = yao_fitsread(YAO_SAVEPATH+rayfname)*1e6; rayleighflux = yao_fitsread(YAO_SAVEPATH+rayfname,hdu=1); sodiumflux = yao_fitsread(YAO_SAVEPATH+rayfname,hdu=2); } else { for (l=1; l<=wfs(ns)._nsub4disp; l++) { xsub = (*wfs(ns)._x)(l); ysub = (*wfs(ns)._y)(l); tmp = mcao_rayleigh(ns,ysub,xsub,fov=fov,aspp=aspp,zenith=gs.zenithangle); rayleighflux(l) = sum(tmp(,,1)); sodiumflux(l) = sum(tmp(,,2)); tmp = transpose(tmp(,,1)); // the switch of xsub <-> ysub and transpose are to accomodate the // C vs yorick 0 vs 1 start array index. // tmp = tmp/sum(tmp); grow,kall,(eclat(tmp))(*); } yao_fitswrite,YAO_SAVEPATH+rayfname,kall; yao_fitswrite,YAO_SAVEPATH+rayfname,rayleighflux,append=1,exttype="image"; yao_fitswrite,YAO_SAVEPATH+rayfname,sodiumflux,append=1,exttype="image"; } if (sim.verbose > 0) { write,"From Rayleigh calculations:"; write,format="Rayleigh / Sodium ratio in worse/best subapertures: %f, %f\n", max(rayleighflux/sodiumflux),min(rayleighflux/sodiumflux); write,format="Rayleigh flux varies between %f and %f /cm2/looptime\n", min(rayleighflux),max(rayleighflux); write,format="Sodium flux varies between %f and %f /cm2/looptime\n", min(sodiumflux),max(sodiumflux); } wfs(ns)._rayleigh = &(float(kall)); wfs(ns)._rayleighflux = &float(rayleighflux); wfs(ns)._sodiumflux = &float(sodiumflux); kall = []; } //---------------------------------------------------- func wfs_check_pixel_size(ns,&sdim,&rebinFactor,&actualPixelSize,printheader=,silent=) /* DOCUMENT wfs_check_pixel_size(ns,&sdim,&rebinFactor,&actualPixelSize,printheader=,silent=) Finds the pixel size for the requested WFS configuration. There are constraints: - First, the pixel size can not be arbitrary. It is defined by lambda_wfs/pixel_size_in_pupil_space/sdim. - Second, the max subaperture size is lambda_wfs/pixel_size_in_pupil_space I could have preserved wfs.npixels as a strong constraint, but it lead to complicated algorithms. Instead, I am finding the closest pixel size to wfs.pixsize and then derive the number of pixel and subaperture size. In addition, I only allow an even number of pixels in the subaperture (otherwise I have to check many more things, as for instance an odd number of pixels in the subaperture combined with a odd rebinFactor cause problems. < now solved (2009oct07) This routine fills and returns binindices and centroidw (now located in shwfs_init, 2009oct07) SEE ALSO: sh_wfs */ { extern wfs; //~ if (wfs(ns).shmethod==1) return; pupd = sim.pupildiam; nxsub = wfs(ns).shnxsub(0); subsize = pupd/nxsub; if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; // sdim is the dimension of "simage" in _shwfs(), // i.e. if 2^l is the smallest array size that can contains the subaperture // sdim is 2^(l+1) sdim = long(2^ceil(log(subsize)/log(2)+1)); if (no_pad_simage) sdim = long(2^ceil(log(subsize)/log(2))); err = 0; desiredPixelSize = wfs(ns).pixsize; desiredNpixels = wfs(ns).npixels; quantumPixelSize = wfs(ns).lambda/(tel.diam/sim.pupildiam)/4.848/sdim; rebinFactor = long(round(desiredPixelSize/quantumPixelSize)); if ( rebinFactor == 0 ) {rebinFactor = 1l;} actualPixelSize = rebinFactor*quantumPixelSize; wfs(ns).pixsize = actualPixelSize; while ( (rebinFactor*wfs(ns).npixels) > sdim ) { wfs(ns).npixels -= 2; err = 1; } if (!is_set(silent)) { f = open(YAO_SAVEPATH+parprefix+".res","a+"); if (is_set(printheader)) { write,"WFS# | Pixel sizes | Subaperture size | Numb of pixels | #photons"; write," | Desired Quantum Actual | Max Actual Extd | Desired Actual | /sub/iter"; write,f,"\nWFS# | Pixel sizes | Subaperture size | Numb of pixels | #photons"; write,f," | Desired Quantum Actual | Max Actual Extd | Desired Actual | /sub/iter"; } npext = max([wfs(ns).npixels,wfs(ns)._npixels]); write,format="%2d %.4f %.4f %.4f %4.2f %4.2f %4.2f %2dx%2d %2dx%2d %.1f\n", ns,desiredPixelSize,quantumPixelSize,actualPixelSize,quantumPixelSize*sdim, actualPixelSize*wfs(ns).npixels,actualPixelSize*npext,desiredNpixels, desiredNpixels,wfs(ns).npixels,wfs(ns).npixels,wfs(ns)._nphotons; write,f,format="%2d %.4f %.4f %.4f %4.2f %4.2f %4.2f %2dx%2d %2dx%2d %.1f\n", ns,desiredPixelSize,quantumPixelSize,actualPixelSize,quantumPixelSize*sdim, actualPixelSize*wfs(ns).npixels,actualPixelSize*npext,desiredNpixels, desiredNpixels,wfs(ns).npixels,wfs(ns).npixels,wfs(ns)._nphotons; close,f; } // if (err == 1) { // write,format=" WARNING: #pixel/subaperture reduced to %d\n",wfs(ns).npixels; // } if (wfs(ns).npixels == 0) { write,format="\nWFS#%2d: The desired pixel size is too large.\n",ns; write," I can not even fit 2x2 pixels."; write," Reduce pixel size in parfile or use a larger sim.pupildiam.\n"; exit; } // write,format=" Final config: %dx%d pixels, pixsize = %f\","+ // " updated in RAM but not in parfile.\n", // wfs(ns).npixels,wfs(ns).npixels,wfs(ns).pixsize; return err; } //---------------------------------------------------- func sh_wfs(pupsh,phase,ns) /* DOCUMENT func sh_wfs(pupsh,phase,ns) pupsh: pupil (dimension sim._size, 0 or 1). Must be of type "float" phase: phase. same dim as pupil. Must be of type "float" ns: WFS# (for multi WFS systems, default to 1) SEE ALSO: shwfs_init */ { if (is_void(ns)) {ns=1;} // default to wfs#1 for one WFS work. // bail out if bad type (otherwise error in C function call) if (typeof(pupsh) != "float") {error,"pupsh was not float !";} if (typeof(phase) != "float") {error,"Phase was not float !";} // shorthand pupd = sim.pupildiam; size = sim._size; nxsub = wfs(ns).shnxsub(0); subsize = int(pupd/nxsub); if (wfs(ns).npixpersub) subsize = wfs(ns).npixpersub; // The phase is in microns. this scaling factor restore it in radian // at the wfs lambda phasescale = float(2*pi/wfs(ns).lambda); // wfs.lambda in microns // fast method (geometrical SHWFS) if (wfs(ns).shmethod == 1) { toarcsec = float(wfs(ns).lambda/2.0/pi/(tel.diam/sim.pupildiam)/4.848); // define mesvec (alloc space for C function) current_mes = array(float,2*wfs(ns)._nsub); err = _shwfs_simple(pupsh, phase, phasescale, *wfs(ns)._tiltsh, int(size), int(size), *wfs(ns)._istart, *wfs(ns)._jstart, int(subsize), int(subsize), wfs(ns)._nsub, toarcsec, current_mes); if (wfs(ns).nintegcycles == 1){ mesvec = current_mes; if ((wfs(ns).noise == 1) && (wfs(ns).ron > 0)){ mesvec += random_n(wfs(ns)._nmes)*wfs(ns).ron; } } else { // here we implement the averaging over a larger number of cycles // we use wfs._meashist to keep track of previous values of the measurement if (wfs(ns)._cyclecounter == 1){ wfs(ns)._meashist = &array(0.0f,dimsof(current_mes)); } *wfs(ns)._meashist += current_mes/wfs(ns).nintegcycles; if (wfs(ns)._cyclecounter == wfs(ns).nintegcycles){ wfs(ns)._cyclecounter = 1; mesvec = *wfs(ns)._meashist; // add noise if ((wfs(ns).noise == 1) && (wfs(ns).ron > 0)){ mesvec += random_n(wfs(ns)._nmes)*wfs(ns).ron; } } else { wfs(ns)._cyclecounter += 1; mesvec = array(0.0f, dimsof(current_mes)); } } //if (ns == 2){print, current_mes(10), mesvec(10);} // Full diffraction SHWFS } else { // size of array in which to embed phase image of 1 subaperture sdim = long(2^ceil(log(subsize)/log(2)+1)); if (no_pad_simage) sdim = long(2^ceil(log(subsize)/log(2))); // sdimpow2 such that sdim = 2^sdimpow2 sdimpow2 = int(log(sdim)/log(2)); threshold = array(float,wfs(ns)._nsub4disp+1)+wfs(ns).shthreshold; // "feature" noticed on 2010apr16 (thanks to Yann Clenet): // the threshold was correctly applied to the valid subap, // but not to the background surrounding the valid subap (fimage // unused pixels). This has no effect on the simulation, but // 1) may be surprising/misleading for the user // 2) thresholding these pixels may be useful for the user to // decide on a threshold value. // hence, on v4.5.2, I have upgraded yao_fast.c to also threshold // these pixels. But as we are passing now a array of thresholds // (one per subap, in case in the future we want to upgrade the // code to allow this as input), which value to chose? solution: // have a vector of threshold of dim # of subap + 1 (the last one // value is the one to apply to these outside pixels/area). // by default for now, we apply of course the same value as the // given scalar wfs.shthreshold. Hence the +1 in the formula above. // simple check to see if wfs(ns).svipc has been changed: // if ((nforks_per_wfs!=[]) && (nforks_per_wfs(ns)!=wfs(ns).svipc)) \ // status = quit_wfs_forks(); // init in case we use svipc: if (wfs(ns).svipc>1) { if (!wfs(ns)._svipc_init_done) { require,"yao_svipc.i"; status = svipc_wfs_init(phase,ns); wfs(ns)._svipc_subok = &((*wfs(ns)._fork_subs)(,1)); } shm_var,shmkey,swrite(format="wfs%d_phase",ns),shmphase; shm_var,shmkey,swrite(format="wfs%d_mesvec",ns),mesvec; shm_var,shmkey,swrite(format="wfs%d_fimage",ns),ffimage; shmphase(,) = phase; if (wfs(ns)._cyclecounter==1) ffimage(,) = 0; mesvec() = 0; yoffset = (*wfs(ns)._yoffset)(1); fimny = (*wfs(ns)._fimny2)(1); subok2 = (*wfs(ns)._fork_subs2)(,1); // give trigger if (sim.debug>20) write,format="main: Giving trigger on sem %d\n",2*ns; sem_give,semkey,20+4*(ns-1),count=wfs(ns).svipc-1; } else { mesvec = array(float,2*wfs(ns)._nsub); wfs(ns)._svipc_subok = &array(1n,wfs(ns)._nsub4disp); subok2 = array(1n,wfs(ns)._nsub4disp); eq_nocopy,ffimage,*wfs(ns)._fimage; if (wfs(ns)._cyclecounter==1) ffimage(,) = 0; yoffset = 0n; fimny = wfs(ns)._fimny; } if (stop_at==42) error; // C function calls // phase to spot image (returned in ffimage) err = _shwfs_phase2spots( pupsh, phase, phasescale, *wfs(ns)._tiltsh, int(size), *wfs(ns)._istart, *wfs(ns)._jstart, int(subsize), int(subsize), wfs(ns)._nsub4disp, sdimpow2, wfs(ns)._domask, *wfs(ns)._submask, *wfs(ns)._kernel, wfs(ns)._nkernels, *wfs(ns)._kernels, *wfs(ns)._kerfftr, *wfs(ns)._kerffti, wfs(ns)._initkernels, wfs(ns)._kernelconv, *wfs(ns)._binindices, wfs(ns)._binxy, wfs(ns)._rebinfactor, wfs(ns)._nx4fft, *wfs(ns)._unittip, *wfs(ns)._unittilt, *wfs(ns).lgs_prof_amp, *wfs(ns)._lgs_defocuses, int(numberof(*wfs(ns).lgs_prof_amp)), *wfs(ns)._unitdefocus, ffimage, *wfs(ns)._svipc_subok, *wfs(ns)._imistart, *wfs(ns)._imjstart, wfs(ns)._fimnx , wfs(ns)._fimny, *wfs(ns)._fluxpersub, *wfs(ns)._raylfluxpersub, *wfs(ns)._skyfluxpersub, float(wfs(ns).darkcurrent*loop.ittime), // darkcurrent not applied in there anymore (2012sep17) int(wfs(ns).rayleighflag), *wfs(ns)._rayleigh, wfs(ns)._bckgrdinit, wfs(ns)._cyclecounter, wfs(ns).nintegcycles); if ( wfs(ns).svipc>1 ) { if (sim.debug>20) write,format="main: waiting fork ready sem %d\n",2*ns+1; sem_take,semkey,20+4*(ns-1)+1,count=wfs(ns).svipc-1; sem_give,semkey,20+4*(ns-1)+2,count=wfs(ns).svipc-1; } // spot image to slopes: if (wfs(ns)._cyclecounter==wfs(ns).nintegcycles) { ffimage += wfs(ns).darkcurrent*loop.ittime*wfs(ns).nintegcycles; xysof = (wfs(ns)._npixels-wfs(ns).npixels-wfs(ns)._npb/2); xtmp = int(*wfs(ns)._imistart2+xysof); ytmp = int(*wfs(ns)._imjstart2+xysof); // write,format="imistart, x=%d y=%d\n",xtmp(1),ytmp(1); if (stop_at==421) error; err = _shwfs_spots2slopes( ffimage, xtmp, ytmp, wfs(ns)._nsub4disp, wfs(ns).npixels, wfs(ns)._fimnx , fimny, yoffset, *wfs(ns)._centroidw, wfs(ns).shthmethod, threshold, *wfs(ns)._bias, *wfs(ns)._flat, wfs(ns).ron, wfs(ns).noise, *wfs(ns)._bckgrdcalib, wfs(ns)._bckgrdinit, wfs(ns)._bckgrdsub, *wfs(ns)._validsubs, subok2, wfs(ns).nintegcycles, mesvec); } else mesvec *= 0; //write,format="%d %f ",wfs(ns)._cyclecounter,sum(*wfs(ns)._fimage),mesvec(ptp); if ( wfs(ns).svipc>1 ) { sem_take,semkey,20+4*(ns-1)+3,count=wfs(ns).svipc-1; } // new, cause of svipc to keep *all* forks results in this var: // commented out on sept 16, 2010. This was released with 4.7 and // is a bug. Thanks Yann Clenet for pointing out this bug. // if (wfs(ns)._bckgrdinit) *wfs(ns)._bckgrdcalib = ffimage; // if (wfs(ns)._refmes) write,mesvec-*wfs(ns)._refmes; // else write,mesvec; wfs(ns)._fimage = &ffimage; if (wfs_disp_crop_edges) { xysof = long(wfs(ns)._npixels-wfs(ns).spotpitch)/2; tmp = ffimage(1+xysof:-xysof,1+xysof:-xysof); } else tmp = ffimage; wfs(ns)._dispimage = &tmp; wfs(ns)._initkernels = 0n; // FIXME: pass cyclecounter to child. wfs(ns)._cyclecounter += 1; if (wfs(ns)._cyclecounter > wfs(ns).nintegcycles) {wfs(ns)._cyclecounter = 1;} } if (err != 0) {error,"problem in _shwfs";} mesvec *= wfs(ns)._centroidgain; mesvec2 = mesvec; // this one was painful, lost hours on it: // have to shm_unvar, obviously: if ((wfs(ns).shmethod==2)&&(wfs(ns).svipc>1)) { shm_unvar,shmphase; shm_unvar,mesvec; shm_unvar,ffimage; } if (stop_at==45) hitReturn; if (*wfs(ns)._reordervec!=[]) mesvec2 = mesvec2(*wfs(ns)._reordervec); // return measurement vector in arcsec (thanks to centroiw): return mesvec2; } //---------------------------------------------------- func curv_wfs(pupil,phase,ns,init=,disp=,silent=) /* DOCUMENT curv_wfs(pupil,phase,ns,init=,disp=,silent=) This function computes the signal from a Curvature WFS for a given phase and pupil input and WFS config (WFS #ns) */ { if (is_void(ns)) {ns=1;} // default sensor#1 for one WFS work size = sim._size; dimpow2 = int(log(size)/log(2)); if (init == 1) { if ( (sim.verbose>=1) && (!is_set(silent)) ) {write,"> Initializing curv_wfs\n";} fratio= 60.; defoc = (pi*wfs(ns).lambda*1e-6/(sim._size^2.*(tel.diam/sim.pupildiam)^2.))* eclat(dist(sim._size)^2.); x = fratio*tel.diam*(fratio*tel.diam-wfs(ns).l)/wfs(ns).l; defoc= defoc*x; wfs(ns)._cxdef= &(float(cos(defoc))); wfs(ns)._sxdef= &(float(sin(defoc))); wfs(ns)._tiltsh = &(float(defoc*0.)); wfs(ns)._fimage = &(float(defoc*0.)); wfs(ns)._fimage2 = &(float(defoc*0.)); // Work out the total NUMBER OF PHOTONS per sample // from star if (wfs(ns).gsalt == 0) { wfs(ns)._nphotons = wfs(ns)._zeropoint*10^(-0.4*wfs(ns).gsmag)* wfs(ns).optthroughput* // include throughput to WFS loop.ittime; // per iteration time } else { // we are dealing with a LGS // modified to use the actual telescope surface area telsurface = sum(pupil)*(tel.diam/sim.pupildiam)^2*1e4; wfs(ns)._nphotons = gs.lgsreturnperwatt*cos(dtor*gs.zenithangle)*wfs(ns).laserpower*telsurface*loop.ittime; } // from sky, over field stop wfs(ns)._skynphotons = wfs(ns)._zeropoint*10^(-0.4*wfs(ns).skymag)* wfs(ns).optthroughput* // include throughput to WFS loop.ittime*pi/4*wfs(ns).fieldstopdiam^2.; if ( wfs(ns).skymag == 0) { wfs(ns)._skynphotons = 0.; } // if skymag not set if ( (sim.verbose>=1) && (!is_set(silent)) ) { write,format="NPhotons/iter from star = %f\n",wfs(ns)._nphotons; write,format="NPhotons/iter from sky = %f\n",wfs(ns)._skynphotons; } return defoc; } mesvec = array(float,wfs(ns)._nsub); if (typeof(phase) != "float") { print,"Phase was not float"; phase = float(phase); } phasescale = float(2*pi/wfs(ns).lambda); // wfs.lambda in microns err = _cwfs( ipupil, phase, phasescale, *wfs(ns)._tiltsh, *wfs(ns)._cxdef, *wfs(ns)._sxdef, dimpow2, *wfs(ns)._sind, *wfs(ns)._nsind, wfs(ns)._nsub, *wfs(ns)._fimage, *wfs(ns)._fimage2, float(wfs(ns)._nphotons), float(wfs(ns)._skynphotons), float(wfs(ns).ron), float(wfs(ns).darkcurrent*loop.ittime), int(wfs(ns).noise), mesvec); wfs(ns)._dispimage = wfs(ns)._fimage; if (*wfs(ns)._reordervec!=[]) mesvec = mesvec(*wfs(ns)._reordervec); return mesvec; } //---------------------------------------------------- func pyramid_wfs(pup,phase,ns,init=,disp=) /* DOCUMENT pyramid_wfs(pup,phase,ns,init=,disp=) Simulate pyramid sensor. In the interest of computation time, here is how we do it: 1) (pupil,phase) + tilt for modulation -> FFT -> image complex amplitude 2) Extract 4 quadrant imagelet (complex amplitude) corresponding to the 4 pyramid faces 3) 4 imagelets -> FFT^2 -> re-imaged pupil images (intensity) * The modulation is done sequentially (i.e. in a loop), and we add the re-imaged pupil images. * Modulation can be done before or after the field stop (wfs.pyr_mod_loc) * The dimension of the imagelet is based on the final desired rebin factor (wfs.npixpersub) and the desired wfs field stop size (wfs.fssize). * Depending on the case, further rebinning of the re-imaged pupil may be needed (see bin2d at the end). * A final filter to take into account the pixel size spatial averaging is performed on the final re-imaged pupil images. Relevant parameters in wfs structure: wfs.shnxsub : # of subaperture in pupil diameter [unitless] wfs.pyr_ampl : Modulation amplitude radius [arcsec]. Modulation is along a circle. wfs.pyr_npts : Total number of points for modulation [unitless] wfs.pyr_padding: Pad the pupil image to reduce spatial aliasing. A pad of 1 means adding wfs.npixpersub pixels on each side of the pupil image. Typical 0 to 4. wfs.pyr_mod_loc: location of modulation ("before" or "after" the field stop). + photometry parameters, and others, common to all WFS. Authors: Marcos van Dam, Francois Rigaut SEE ALSO: */ /* TO DO (at 4.8.1) - multi lambda -> found by Marcos to not be necessary - parameter guidance for optimal speed/perf. */ { extern wfs; extern sky_frame; extern pyr_binfact, pyr_npix, pyr_focmask; local padding, npixpersub, binfact, npix; // This is necessary to keep light centered if (wfs(ns).pyr_mod_npts==1) wfs(ns).pyr_mod_ampl=0.; // shortcuts definitions: padding = wfs(ns).pyr_padding; npixpersub = wfs(ns).npixpersub; shnxsub = wfs(ns).shnxsub; nintegcycles = wfs(ns).nintegcycles; if (init) nintegcycles = 1; // extract subarrays from input pupil & phase: npup = sim.pupildiam + 2*padding*npixpersub; ii = sim._size/2-sim.pupildiam/2+1-padding*npixpersub; if (ii<1) error,"Padding is too large"; ii = ii:ii+(shnxsub+2*padding)*npixpersub-1; pup = pup(ii,ii); phase = phase(ii,ii); // compute pixel size and related variables: psize = (sim.pupildiam*1.0/npup)*wfs(ns).lambda/tel.diam/4.848; mod_ampl_pixels = wfs(ns).pyr_mod_ampl/psize; // modulation in pixels if (init) { if (wfs(ns).pyr_denom != "median"){wfs(ns).pyr_denom = "subap";} x = double(sim.pupildiam)/shnxsub; if (x!=long(x)) error,swrite(format="sim.pupildiam not multiple of wfs(%i).shnxsub",ns); x = wfs(ns).pyr_mod_npts/4.; if (x!=long(x) && wfs(n).pyr_mod_ampl != 0.) error,swrite(format="wfs(%i).pyr_mod_npts not multiple of 4",ns); // compute size of small complex amp image based on field stop size // To save computing time, we will extract a subimage from // the intermediate image complex amplitude (IICA) // OK, so we have several conditions to fulfill. // 1. Remember we are using only one quadrant of the IICA, // thus of dimension npup/2. // 2. We're going to extract a subimage from the IICA (SIICA). // The SIICA eventually will form, after FFT, the reimaged-pupil (RP). // 3. The RP has to have final dimension shnxsub + 2*padding. // 4. Thus, the SIICA has to have dimension N * (shnxsub + 2*padding). // 5. The SIICA has to be big enough that it includes all the field mask fssize_radius_pixels = long(wfs(ns).fssize / psize / 2.); if (fssize_radius_pixels == 0) error,swrite(format="Field stop size too small. Increase wfs(%i).fssize", ns); // npix is the minimum size of the SIICA npix = (shnxsub+2*padding); // possible value for npix, as per condition 4 above: npix_ok = npix*indgen(100); npix_ok = npix_ok(where(npix_ok<=(npup/2.))); // now we want the quadrant image dim to be > fssize_radius_pixels: w = where(npix_ok>=fssize_radius_pixels); if (numberof(w)==0) { maxfs = npix_ok(0)*2*psize; error,swrite(format="wfs(%i).fssize too large (max=%.3f\")!",ns,maxfs); } npix_ok = npix_ok(w(1)); pyr_binfact = binfact = npix_ok/npix; pyr_npix = npix_ok; // ok, done with pyr_npix calculations // build the field stop mask: if (wfs(ns).fstop=="round") { focmask = dist(npup,xc=npup/2.+0.5,yc=npup/2.+0.5)<(fssize_radius_pixels); field_stop_area = pi * (wfs(ns).fssize/2.)^2.; } else if (wfs(ns).fstop=="square") { xy = indices(npup)-(npup+1.)/2.; focmask = ( abs(xy(,,1)) <= (fssize_radius_pixels) ) * \ ( abs(xy(,,2)) <= (fssize_radius_pixels) ); field_stop_area = wfs(ns).fssize^2.; } else error,swrite(format="wfs(%i).fstop must be round or square",ns); // let's save pyr_focmask whatever the method is, as we will // use it for photometry calculation: pyr_focmask = roll(focmask); if (wfs(ns).pyr_mod_loc !="after") { tmp = array(0,[3,pyr_npix,pyr_npix,4]); tmp(,,1) = pyr_focmask(npup-pyr_npix+1:,npup-pyr_npix+1:); tmp(,,2) = tmp(,,1)(::-1,); tmp(,,3) = tmp(,,1)(,::-1); tmp(,,4) = tmp(,,1)(::-1,::-1); wfs(ns)._submask = &tmp; } else wfs(ns)._submask = &(pyr_focmask); // find out which pixels in the reimaged pupil have to be // retained for the final signal calculation: pupreb = bin2d(pup*1.,npixpersub)/npixpersub^2.; sky_frame = pupreb/sum(pupreb)/4.; wfs(ns)._nphotons = wfs(ns)._zeropoint*2.51189^(-wfs(ns).gsmag)* loop.ittime*wfs(ns).optthroughput; if (wfs(ns).skymag == 0){ wfs(ns)._skynphotons = 0; } else { wfs(ns)._skynphotons = wfs(ns)._zeropoint*2.51189^(-wfs(ns).skymag)*loop.ittime*wfs(ns).optthroughput*field_stop_area; } // calculate a dark frame with sky and dark current dark_frame = array(wfs(ns).darkcurrent*loop.ittime,dimsof(sky_frame)); wfs(ns)._bckgrdcalib = &(dark_frame+wfs(ns)._skynphotons*sky_frame); // initialize the counter for nintegcycles wfs(ns)._cyclecounter = 1; if (sim.verbose) { write,format="%s\n","Pyramid WFS initialization"; write,format="npup=%d, pyr_npix = %d, shnxsub=%d, npixpersub=%d, binfact=%d, padding=%d\n", npup,pyr_npix,shnxsub,npixpersub,binfact,padding; write,format="Field stop size set to %0.3f arcsec (max %0.3f\")\n", \ wfs(ns).fssize,npup*psize; } } else binfact = pyr_binfact; // transform phase (microns) to rd at WFS wavelength: phase_rad = phase*2*pi/wfs(ns).lambda; // build pupil complex amplitude: wfs_pupil = roll( pup * exp(1i*phase_rad) ); // prepare shift by half a pixel so that the image is centered xy = indices(npup)-(npup+1)/2.; phase_shift = roll( exp(1i*2*pi*(0.5*xy(,,sum))/npup) ); // above, +0.5 because fft(,-1) // complex amplitude in image plane, properly shifted: complex_amplitude = fft(wfs_pupil*phase_shift,-1); // for the photometry, let's simplify our life. Instead of // tracking the total count through all the calculations, // let's see how much of the star flux goes through the // field mask aperture, and postnormalize reimaged_pupil // at the end: tmp = abs(complex_amplitude)^2.; phot_norm_factor = sum(tmp*pyr_focmask)/sum(tmp); // apply field stop if needed: if (wfs(ns).pyr_mod_loc=="after") complex_amplitude *= *wfs(ns)._submask; reimaged_pupil = array(double,[3,pyr_npix,pyr_npix,4]); // prepare arrays to shift re-imaged pupil xy = indices(pyr_npix)-(pyr_npix+1)/2.; coef1 = ( odd(wfs(1).shnxsub*binfact) ? 0.0:-0.5 ); coef2 = ((odd(wfs(1).shnxsub)&&odd(npixpersub*binfact)) ? 1.0:0.5 ); pshift = exp(1i*2*pi*(coef1/pyr_npix+ coef2*binfact/npixpersub/pyr_npix)*xy(,,sum)); roll,pshift; // offsets to extract the four quadrant in image plane: // note that quadrant are defined as follow (coordinates // origin is at bottom left): // 3 4 // 1 2 xoffset = [1,0,1,0]*pyr_npix; yoffset = [1,1,0,0]*pyr_npix; if (pyr_disp) { modim = array(0.,[2,2*pyr_npix,2*pyr_npix]); modim_xoff = [0,1,0,1]*pyr_npix; modim_yoff = [0,0,1,1]*pyr_npix; } // find the modulation positions if not user defined if (*wfs(ns).pyr_mod_pos == []){ cx = lround(mod_ampl_pixels*sin(indgen(wfs(ns).pyr_mod_npts)*2.*pi/wfs(ns).pyr_mod_npts)); cy = lround(mod_ampl_pixels*cos(indgen(wfs(ns).pyr_mod_npts)*2.*pi/wfs(ns).pyr_mod_npts)); mod_npts = wfs(ns).pyr_mod_npts; } else { if (init && sim.verbose) write,format="%s\n", "Using user-defined positions for the pyramid modulation"; // user defined positions cx = lround((*wfs(ns).pyr_mod_pos)(:,1)/psize); cy = lround((*wfs(ns).pyr_mod_pos)(:,2)/psize); mod_npts = dimsof(cx)(2); } // loop on modulation positions: for (k=1;k<=mod_npts;k++){ // loop on 4 quadrants: for (i=1;i<=4;i++) { // extract subimage from large image complex amplitude array: ca = roll(complex_amplitude,[cx(k)+xoffset(i),cy(k)+yoffset(i)]); if (wfs(ns).pyr_mod_loc !="after") { small_comp_amp = ca(1:pyr_npix,1:pyr_npix)*(*wfs(ns)._submask)(,,i); roll,small_comp_amp; } else small_comp_amp = roll(ca(1:pyr_npix,1:pyr_npix)); // re-imaged pupil: reimaged_pupil(,,i) += abs(fft(small_comp_amp*pshift,1))^2; // misc display: if (pyr_disp) { mim = array(0.,[2,2*pyr_npix,2*pyr_npix]); mim(1:pyr_npix,1:pyr_npix) = abs(ca(1:pyr_npix,1:pyr_npix)); roll,mim,[modim_xoff(i),modim_yoff(i)]; modim += mim; if (pyr_disp>=2) { fma; plsys,1; pli,abs(small_comp_amp); limits; limits,square=1; plsys,2; pli,roll(reimaged_pupil(,,i)); limits; limits,square=1; if (hitReturn()=="s") return; } } } } if (aoinit){ // spatial filtering by the pixel extent: // *2/2 intended. min should be 0.40 = sinc(0.5)^2. xy2 = xy/(pyr_npix-1)*2/2; // sinc usual issue: sinc is defined both in yeti and yutils, but not // with the same def. yeti defines sinc(1.)=0., while yutils defines // sinc(pi)=0. Use yutils definition. //~ require,"util_fr.i"; //~ sincar = roll(__sinc(pi*xy2(,,1))*__sinc(pi*xy2(,,2))); // above: that's bad. require does not necessarily do it if it has // already been included. Instead, do: include,"util_fr.i",1; extern __sincar; __sincar = roll(__sinc(pi*xy2(,,1))*__sinc(pi*xy2(,,2))); } if (pyr_disp) { plsys,4; pli,__sincar; limits; limits,square=1;} // perform the actual spatial filtering: for (i=1;i<=4;i++) { tmp = fft(reimaged_pupil(,,i),-1); tmp *= __sincar; reimaged_pupil(,,i) = abs(fft(tmp,1)); } if (pyr_disp) { plsys,1; pli,modim; limits; limits,square=1; } // roll the re-imaged pupil: // beware, roll without argument rolls *all* dimension (incl. third) roll,reimaged_pupil,dimsof(reimaged_pupil)(2:3)/2; // if we used binfact>1, perform the actual rebinning: if (binfact>1) { tmp = array(0.,[3,pyr_npix/binfact,pyr_npix/binfact,4]); for (i=1;i<=4;i++) tmp(,,i) = bin2d(reimaged_pupil(,,i),binfact); reimaged_pupil = tmp; npix = pyr_npix/binfact; } else npix = pyr_npix; if (init){ subapint = reimaged_pupil(,,sum); // sum of all the subaperture intensities medianint = median(subapint(*)); wfs(ns)._validsubs = &(where(subapint>=wfs(ns).fracIllum*medianint)); wfs(ns)._nmes = 2*numberof(*wfs(ns)._validsubs); } // photometry and noise: totflux = sum(reimaged_pupil); reimaged_pupil *= phot_norm_factor*wfs(ns)._nphotons/totflux; if (nintegcycles > 1){ // reset the intensity measurement if (wfs(ns)._cyclecounter == 1) wfs(ns)._meashist = &array(0.0f,dimsof(reimaged_pupil)); *wfs(ns)._meashist += reimaged_pupil; if (wfs(ns)._cyclecounter == nintegcycles){ wfs(ns)._cyclecounter = 1; reimaged_pupil = *wfs(ns)._meashist; } else { wfs(ns)._cyclecounter += 1; return array(float,wfs(ns)._nmes); // return the reference measurement, which is later subtracted } } if (wfs(ns).noise) { // poisson distribution of star flux reimaged_pupil = poidev(reimaged_pupil); // add CCD RON reimaged_pupil += wfs(ns).ron*random_n(dimsof(reimaged_pupil)); // add sky noise for (i=1;i<=4;i++) reimaged_pupil(,,i) += poidev(array(sky_frame)*wfs(ns)._skynphotons*nintegcycles); // add dark current reimaged_pupil += poidev(array(wfs(ns).darkcurrent*loop.ittime*nintegcycles, dimsof(reimaged_pupil))); // subtract the calibrated frame from each subimage reimaged_pupil -= *wfs(ns)._bckgrdcalib*nintegcycles; } // Put the re-imaged pupil into a single array for display: tmp = array(0.,[2,2*npix+3,2*npix+3]); ii1 = 2:npix+1; ii2 = npix+3:2*npix+2; tmp(ii1,ii1) = reimaged_pupil(,,1); tmp(ii2,ii1) = reimaged_pupil(,,2); tmp(ii1,ii2) = reimaged_pupil(,,3); tmp(ii2,ii2) = reimaged_pupil(,,4); wfs(ns)._fimage = &tmp; // save this to display wfs(ns)._dispimage = &tmp; // save this to display if (pyr_disp) { plsys,4; pli,tmp; limits; limits,square=1;} // extract the illuminated pixels: pixels = reimaged_pupil(*,)(*wfs(ns)._validsubs,); // threshold the pixels pixels = max(pixels,wfs(ns).shthreshold); // determine the denominator if (wfs(ns).pyr_denom == "median"){ denom = (pixels(avg,sum)); } else { denom = pixels(,sum)+1e-6; } // compute the final signal, using quadcell formula: sigx = (pixels(,[2,4])(,sum)-pixels(,[1,3])(,sum))/denom; sigy = (pixels(,[3,4])(,sum)-pixels(,[1,2])(,sum))/denom; mesvec = _(sigx,sigy); if (*wfs(ns)._reordervec!=[]) mesvec = mesvec(*wfs(ns)._reordervec); return mesvec; } //---------------------------------------------------- func zernike_wfs(pupsh,phase,ns,init=) /* DOCUMENT Zernike WFS. Returns Zernike coefficients, expansion of the input phase onto Zernike modes. pupsh = pupil phase = phase ns = WFS yao # init = set to init the WFS. has to be called at least once. SEE ALSO: */ { // the phase at the input (call from multwfs) is in microns. // I have chosen to return coefficients of zernikes in nm (rms) extern pwfs_zer,pwfs_wzer,pzn12; if (init) { if ((pwfs_zer==[])||(numberof(pwfs_zer)!=nwfs)) { pwfs_zer = array(pointer,nwfs); pwfs_wzer = array(pointer,nwfs); pzn12 = array(pointer,nwfs); } pupd = sim.pupildiam; size = sim._size; nzer = wfs(ns).nzer(1); wfs(ns)._nmes = wfs(ns).nzer; cent = sim._cent; prepzernike,size,pupd,sim._cent,sim._cent; wfs_wzer = where(zernike(1)*ipupil); wfs_zer = array(float,[2,numberof(wfs_wzer),nzer]); for (i=1;i<=nzer;i++) wfs_zer(,i) = zernike_ext(i)(*)(wfs_wzer); wfs_zer = LUsolve(wfs_zer(+,)*wfs_zer(+,),transpose(wfs_zer)); // wfs_zer(nzer,npt in pupil) tmp = where(zernike(1)(avg,)); zn12 = minmax(tmp); pwfs_zer(ns) = &wfs_zer; pwfs_wzer(ns) = &wfs_wzer; pzn12(ns) = &zn12; if (sim.verbose>=1) write,"Zernike wfs initialized"; return; } zn12 = *pzn12(ns); wfs_zer = *pwfs_zer(ns); wfs_wzer = *pwfs_wzer(ns); wfs(ns)._fimage = wfs(ns)._dispimage = \ &((phase*pupsh)(zn12(1):zn12(2),zn12(1):zn12(2))); mesvec = wfs_zer(,+)*phase(*)(wfs_wzer)(+); // returns microns rms (checked 2008apr10) ??? see above comment if (*wfs(ns)._reordervec!=[]) mesvec = mesvec(*wfs(ns)._reordervec); return mesvec; } //---------------------------------------------------- func dh_wfs(pupsh,phase,ns,init=) { // the phase at the input (call from multwfs) is in microns. // return coefficients of dh in nm (rms) << no, see below extern wfs; if (init) { require,"yaodh.i"; pupd = sim.pupildiam; size = sim._size; ndh = wfs(ns).ndh(1); wfs(ns)._nmes = wfs(ns).ndh; cent = sim._cent; // use definition for previous wfs is identical: // all other parameters to define DHs here are global for this run, // so we just need to check wfs.ndh if (ns>1) wdhok = where(wfs(1:ns-1).ndh==wfs(ns).ndh) if (numberof(wdhok)) { wfs(ns)._pha2dhc = wfs(wdhok(1))._pha2dhc; wfs(ns)._wpha2dhc = wfs(wdhok(1))._wpha2dhc; wfs(ns)._n12 = wfs(wdhok(1))._n12; if (sim.verbose>=1) write,format="Disk Harmonic wfs initialized (copied from wfs%d)\n",wdhok(1); } else { def = float(make_diskharmonic(size,pupd,ndh,xc=cent,yc=cent)); wfs_wdh = where(ipupil); wfs(ns)._wpha2dhc = &wfs_wdh; def = def(*,)(wfs_wdh,); wfs_dh = LUsolve(def(+,)*def(+,),transpose(def)); wfs(ns)._pha2dhc = &wfs_dh; tmp = where(pupsh(avg,)); zn12 = minmax(tmp); wfs(ns)._n12 = zn12; if (sim.verbose>=1) write,"Disk Harmonic wfs initialized"; } return; } zn12 = wfs(ns)._n12; wfs(ns)._fimage = wfs(ns)._dispimage = &((phase*pupsh)(zn12(1):zn12(2),zn12(1):zn12(2))); mes = (*wfs(ns)._pha2dhc)(,+)*phase(*)(*wfs(ns)._wpha2dhc)(+); mesvec = (*wfs(ns)._pha2dhc)(,+)*phase(*)(*wfs(ns)._wpha2dhc)(+); if (wfs(ns).ndhfiltered) mesvec(1:wfs(ns).ndhfiltered) *=0; // shouldn't it be ndhf + 1? if (*wfs(ns)._reordervec!=[]) mesvec = mesvec(*wfs(ns)._reordervec); // returns microns rms (checked 2008apr10) return mesvec; } //---------------------------------------------------- func mult_wfs_int_mat(disp=,subsys=) /* DOCUMENT func mult_wfs_int_mat(disp=,subsys=) as mult_wfs but special for IntMat acquisition for speed in aoloop If DM subsystem is passed, then only WFS measurements associated with that subsystem are recorded SEE ALSO: */ { extern wfs; mes = []; for (ns=1;ns<=nwfs;ns++) { filterTiltOrig = wfs(ns).filtertilt; wfs(ns).filtertilt = 0; phase = get_phase2d_from_dms(ns,"wfs"); // uncomment if needed: // phase += get_phase2d_from_optics(ns,"wfs"); wfs(ns)._nkernels = 1; // do the wavefront sensing: if (wfs(ns).type == "hartmann" ) { if (wfs(ns).disjointpup) { smes = sh_wfs(disjointpup(,,ns),phase,ns); } else { smes = sh_wfs(ipupil,phase,ns); } } else if (wfs(ns).type == "curvature") { smes = curv_wfs(pupil,phase,ns); } else if (wfs(ns).type == "pyramid") { smes = pyramid_wfs(pupil,phase,ns); } else if (wfs(ns).type == "zernike") { smes = zernike_wfs(ipupil,phase,ns); } else if (wfs(ns).type == "dh") { smes = dh_wfs(ipupil,phase,ns); } else { // assign user_wfs to requested function/type: cmd = swrite(format="user_wfs = %s",wfs(ns).type); include,[cmd],1; smes = user_wfs(ipupil,phase,ns); } // subtract the reference vector for this sensor: smes = smes - *wfs(ns)._refmes; // compute the TT and subtract if required: if (wfs(ns).filtertilt) { wfs(ns)._tt(1) = sum( smes * (*wfs(ns)._tiprefvn) ); wfs(ns)._tt(2) = sum( smes * (*wfs(ns)._tiltrefvn) ); smes = smes - wfs(ns)._tt(1) * (*wfs(ns)._tiprefv) \ - wfs(ns)._tt(2) * (*wfs(ns)._tiltrefv); } if (subsys != []) { if (subsys != wfs(ns).subsystem){ smes *= 0; // different subsystem, so no influence } } grow,mes,smes; wfs(ns).filtertilt = filterTiltOrig; } return mes; } //---------------------------------------------------- func mult_wfs(iter,disp=) /* DOCUMENT func mult_wfs(iter,disp=) Goes through all WFS and concatenate the resulting measurement vectors. SEE ALSO: */ { mes = []; for (ns=1;ns<=nwfs;ns++) { offsets = wfs(ns).gspos; phase = get_phase2d_from_optics(ns,"wfs"); phase += get_turb_phase(iter,ns,"wfs"); // only look at DMs if not running in open loop if (loop.method != "open-loop") { phase += get_phase2d_from_dms(ns,"wfs"); } if (wfs(ns).correctUpTT) { phase = correct_uplink_tt(phase,ns); } if (wfs(ns).LLT_uplink_turb) { tmp = comp_turb_lgs_kernel(ns); wfs(ns)._kernel = &float([(*wfs(ns)._kernel)(,,1),tmp]); wfs(ns)._nkernels = 2; } else wfs(ns)._nkernels = 1; // get the measurements: if (wfs(ns).type == "hartmann" ) { if (wfs(ns).disjointpup) { smes = sh_wfs(disjointpup(,,ns),phase,ns); } else { smes = sh_wfs(ipupil,phase,ns); } } else if (wfs(ns).type == "curvature") { smes = curv_wfs(pupil,phase,ns); } else if (wfs(ns).type == "pyramid") { smes = pyramid_wfs(pupil,phase,ns); } else if (wfs(ns).type == "zernike") { smes = zernike_wfs(ipupil,phase,ns); } else if (wfs(ns).type == "dh") { smes = dh_wfs(ipupil,phase,ns); } else { // assign user_wfs to requested function/type: cmd = swrite(format="user_wfs = %s",wfs(ns).type); include,[cmd],1; smes = user_wfs(ipupil,phase,ns); } if (sim.svipc) { // hack, this has nothing to do here. FIXME shm_write,shmkey,swrite(format="wfs%d_image",ns),wfs(ns)._fimage; } // subtract the reference vector for this sensor: if (wfs(ns)._cyclecounter == 1) { smes = smes - *wfs(ns)._refmes; } // compute the TT and subtract if required: wfs(ns)._tt(1) = sum( smes * (*wfs(ns)._tiprefvn) ); wfs(ns)._tt(2) = sum( smes * (*wfs(ns)._tiltrefvn) ); if (wfs(ns).filtertilt) { smes = smes - wfs(ns)._tt(1) * (*wfs(ns)._tiprefv) \ - wfs(ns)._tt(2) * (*wfs(ns)._tiltrefv); } if (wfs(ns)._cyclecounter == 1) { wfs(ns)._lastvalidtt = wfs(ns)._tt; } grow,mes,smes; } return mes; } func slope_offset_defocus(arcsec_per_meter,ns) /* DOCUMENT slope_offset_defocus(arcsec_per_meter,ns) * Compute and add a defocus to the reference slopes for wfs ns * Note that this is an offset. * Example: * slope_offset_defocus,0.05,[1,2]; * will add an offset of 0.05 arcsec/m off-axis, radially. * which means that for a 25m telescope, the outer subaperture will * see a radial slope change of 25/2.*0.05 = 0.625 arcsec * Do not forget the sync_wfs if using svipc: * slope_offset_defocus,0.05,[1,2]; sync_wfs; */ { extern wfs; for (i=1;i<=numberof(ns);i++) { valid = where(*wfs(ns(i))._validsubs); x = (*wfs(ns(i))._x)(valid); // in [m] y = (*wfs(ns(i))._y)(valid); ref = _(x,y)*arcsec_per_meter; *wfs(ns(i))._refmes += float(ref); } } //---------------------------------------------------- func shwfs_tests(name, clean=, wfs_svipc=, debug=, dpi=, verbose=, batch=) /* DOCUMENT shwfs_tests(void,clean=,wfs_svipc=,debug=,dpi=, verbose=,batch=) Use to check that sh_wfs looks allright (NGS and LGS). Test a variety of features (sky, bias, flats, etc...) + background subtraction for each case. Use wfs_svipc= to test wfs.svipc. You might have to quit the yorick session between each test as somehow with these tests the svipc sometimes ends up in a non-correct state. Notes to myself (FR): For NGS, everything seems to be OK. For LGS, the Rayleight looks allright, except that apparently the shadow by the central obstruction is not taken into account. SEE ALSO: */ { thispdiam = 120; //180 //240 pltitle_height=12; //=========================== if (name==[]) name="shwfs-tests.par"; aoread,name; sim.pupildiam = thispdiam; sim.debug = (debug?debug:0); sim.verbose = (verbose?verbose:0); wfs.svipc = (wfs_svipc?wfs_svipc:0) wfs(1).gsmag = 8; wfs(1).skymag = 0; wfs(1).fstop = "round"; wfs(1).fssize = 1.9; wfs(1).spotpitch = 12; sim.verbose = 1; dpi = (dpi?dpi:(default_dpi?default_dpi:90)); if (quit_forks) quit_forks(); if (clean==[]) clean=1; aoinit,dpi=dpi,clean=clean; winkill; window,0,wait=1,dpi=dpi,width=0,height=0; wfs(1).noise=0; shwfs_tests_plots,"NGS w/o sky, w/o noise",batch=batch; wfs(1).noise=1; wfs(1).ron=0; shwfs_tests_plots,"NGS w/o sky, w/ noise but no RON",batch=batch; wfs(1).ron=4; shwfs_tests_plots,"NGS w/o sky, w/ noise",batch=batch; write,"ADDING SKY"; wfs(1).skymag = 10; sim.debug = 0; if (quit_forks) quit_forks(); aoinit; wfs(1).noise=0; shwfs_tests_plots,"NGS w/ sky, w/o noise",batch=batch; wfs(1).noise=1; wfs(1).ron=0; shwfs_tests_plots,"NGS w/ sky, w/ noise but no RON",batch=batch; wfs(1).ron=4; shwfs_tests_plots,"NGS w/ sky, w/ noise",batch=batch; "TURNING OFF STAR"; wfs(1).gsmag = 30; wfs(1).skymag = 10; sim.debug = 0; if (quit_forks) quit_forks(); aoinit; wfs(1).noise=0; shwfs_tests_plots,"(almost) NO NGS w/ sky, no noise",batch=batch; wfs(1).noise=1; wfs(1).ron=0; shwfs_tests_plots,"(almost) NO NGS w/ sky, w/ noise but no RON",batch=batch; wfs(1).ron=4; shwfs_tests_plots,"(almost) NO NGS w/ sky, w/ noise",batch=batch; write,"W/ BIAS"; wfs(1).gsmag = 8; wfs(1).skymag = 10; wfs(1).biasrmserror = 50.; sim.debug = 0; if (quit_forks) quit_forks(); aoinit; wfs(1).noise=0; shwfs_tests_plots,"NGS w/ sky, w/o noise, BIAS error",batch=batch; wfs(1).noise=1; wfs(1).ron=0; shwfs_tests_plots,"NGS w/ sky, w/ noise but no RON, BIAS error",batch=batch; wfs(1).ron=4; shwfs_tests_plots,"NGS w/ sky, w/ noise, BIAS error",batch=batch; write,"W/ FLAT"; wfs(1).gsmag = 8; wfs(1).skymag = 10; wfs(1).biasrmserror = 0.; wfs(1).flatrmserror = 0.3; sim.debug = 0; if (quit_forks) quit_forks(); aoinit; wfs(1).noise=0; shwfs_tests_plots,"NGS w/ sky, w/o noise, FLAT error",batch=batch; wfs(1).noise=1; wfs(1).ron=0; shwfs_tests_plots,"NGS w/ sky, w/ noise but no RON, FLAT error",batch=batch; wfs(1).ron=4; shwfs_tests_plots,"NGS w/ sky, w/ noise, FLAT error",batch=batch; //=========================== aoread,"shwfs-tests.par"; loop.niter = 200; sim.debug = (debug?debug:0); sim.verbose = (verbose?verbose:0); wfs.svipc = (wfs_svipc?wfs_svipc:0) sim.pupildiam = thispdiam; wfs.gsalt = 90000; wfs.gsdepth = 10000; wfs.laserpower= 10.; wfs.rayleighflag = 1; if (quit_forks) quit_forks(); aoinit,disp=1,dpi=dpi,clean=clean; shwfs_tests_plots,"2 LGSs with Rayleigh",batch=batch; wfs.noise=0; shwfs_tests_plots,"2 LGSs with Rayleigh no noise",batch=batch; } func shwfs_tests_plots(name,batch=) { if (batch && (batch>1)) ptime=batch; else ptime=1000; wfs(1)._bckgrdsub = 0; if (anyof(wfs.svipc>1)) status=sync_wfs_forks(); if (wfs(1).disjointpup) { sh_wfs,disjointpup(,,1),pupsh*0.0f,1; } else sh_wfs,ipupil,ipupil*0.0f,1; tv,*wfs(1)._fimage; pltitle,name; stat,*wfs(1)._fimage; if (!batch) { r = strcase(0,kinput("Proceed/Spydr/show Bckgrdinit/Exit","P")); if (r=="s") { spydr,*wfs(1)._fimage; exit; } //~ if (r=="p") return; if (r=="e") exit; } else pause,ptime; wfs(1)._bckgrdsub = 1; if (anyof(wfs.svipc>1)) status=sync_wfs_forks(); if (wfs(1).disjointpup) { sh_wfs,disjointpup(,,1),pupsh*0.0f,1; } else sh_wfs,ipupil,ipupil*0.0f,1; tv,*wfs(1)._fimage; pltitle,name+" w/ bcksub=1"; stat,*wfs(1)._fimage; if (batch) pause,ptime; else hitReturn; // /* im = *wfs(1)._fimage; wfs(1)._bckgrdsub = 1; wfs(1)._bckgrdinit = 1; oldnoise = wfs(1).noise; wfs(1).noise = 0; // call sh_wfs for calibration of the background sh_wfs,ipupil,ipupil*0.0f,1; wfs(1)._bckgrdinit = 0; wfs(1).noise = oldnoise; tv,*wfs(1)._fimage; pltitle,name+" / bkgr calib"; stat,*wfs(1)._fimage; hitReturn; tv,im-*wfs(1)._fimage; pltitle,name+" / image - bkgr calib"; stat,im-*wfs(1)._fimage; hitReturn; */ } func pyramid_wfs_checks(nchecks) { if (!nchecks) nchecks=10; if (findfiles("test5.par")==[]) { error,"no test5.par in cwd. pls cd where test5.par is"; } aoread,"test5.par"; randomize; loop.niter = 100; sim.verbose = 1; sim.debug = 0; for (n=1;n<=nchecks;n++) { wfs(1).shnxsub = long(5+random()*13); wfs(1).npixpersub = long(4+random()*10); sim.pupildiam = wfs(1).shnxsub * wfs(1).npixpersub; npup = (wfs(1).shnxsub+2*wfs(1).pyr_padding)*wfs(1).npixpersub; psize = (double(sim.pupildiam)/npup) * wfs(1).lambda/tel.diam/4.848; wfs(1).pyr_padding = long(random()*5); wfs(1).pyr_mod_npts= long(2+random()*3)*4; wfs(1).pyr_mod_ampl= 0.15+(random()*0.1); wfs(1).fssize = npup*psize*0.8; atm.dr0at05mic = sim.pupildiam/2.5; dm(1).nxact = wfs(1).shnxsub+1; dm(1).pitch = wfs(1).npixpersub; write,format="\n\nPYRAMID CHECK #%d\n",n; write,format="Modulation = %.2f\" (%d pts)\n",wfs(1).pyr_mod_ampl,\ wfs(1).pyr_mod_npts; write,format="Padding = %d, nxsub=%d, npixpersub=%d\n\n",wfs(1).pyr_padding,\ wfs(1).shnxsub,wfs(1).npixpersub; pause,500; aoinit,disp=1,clean=1; aoloop,disp=1; go,all=1; } } func sh_wfs_speed_tests(case,png=) { if (case==[]) { write,"sh_wfs_speed_tests,case with case=1,2,3,4,.."; return; } if (case==0) { for (i=1;i<=6;i++) { sh_wfs_speed_tests,i,png=png; pause,100; } return; } if (case==1) { // first dependency on pupildiam: cname = "pupildiam"; cunit = "pixels"; in = [32,48,64,80,96,128,160,256]; tim = in*0.; pfit = 1; pzero = 1; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; wfs(1).shnxsub = 8; wfs(1).pixsize=0.001; wfs(1).npixels=6; wfs(1).noise = 0; atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; sim.pupildiam = in(i); aoinit,disp=0; tic; for (j=1;j<=100;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./100.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["wfs(1).shnxsub", \ "wfs(1).pixsize","wfs(1).npixels","wfs(1).noise", \ "wfs(1).extfield","wfs(1)._nx"]); } } else if (case==2) { cname = "wfs.npixels"; cunit = "pixels"; in = [2,4,6,8,10,12,14,16]; tim = in*0.; pfit = 0; pzero = 0; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; wfs(1).shnxsub = 8; sim.pupildiam = 256; wfs(1).pixsize=0.1; wfs(1).noise = 0; atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; wfs(1).npixels=in(i); aoinit,disp=0; in(i) = wfs(1).npixels; tic; for (j=1;j<=10;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./10.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["sim.pupildiam","wfs(1).shnxsub", \ "wfs(1).pixsize","wfs(1).noise", \ "wfs(1).extfield","wfs(1)._nx"]); } } else if (case==3) { cname = "shnxsub"; cunit = "#sub"; in = [2,4,8,16,32]; tim = in*0.; pfit = 0; pzero = 0; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; wfs(1).shnxsub = in(i); sim.pupildiam = 256; wfs(1).pixsize=0.1; wfs(1).noise = 0; atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; wfs(1).npixels=6; aoinit,disp=0; tic; for (j=1;j<=10;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./10.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["sim.pupildiam", \ "wfs(1).pixsize","wfs(1).npixels","wfs(1).noise", \ "wfs(1).extfield","wfs(1)._nx"]); } } else if (case==4) { cname = "extended_field_w_kernel"; cunit = "wfs._npb=pixels"; in = [0,2,4,6,8,10.]; tim = in*0.; pfit = 0; pzero = 0; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; sim.verbose = 1; wfs(1).extfield = in(i); wfs(1).shnxsub = 8; sim.pupildiam = 256; wfs(1).pixsize=0.1; wfs(1).npixels=6; wfs(1).noise = 0; wfs(1).kernel = 0.2; atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; aoinit,disp=0; in(i) = wfs(1)._npb; tic; for (j=1;j<=100;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./100.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["sim.pupildiam","wfs(1).shnxsub", \ "wfs(1).pixsize","wfs(1).npixels","wfs(1).noise"]); } } else if (case==5) { cname = "lgsprofile"; cunit = "#points"; in = [2,4,8,16,32]; tim = in*0.; pfit = 0; pzero = 0; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; wfs(1).extfield = 10.; wfs(1).shnxsub = 64; sim.pupildiam = 256; wfs(1).pixsize=0.5; wfs(1).npixels=6; wfs(1).noise = 0; wfs(1).gsalt = 90000.; wfs(1).laserpower=30.; wfs(1).lgs_prof_amp = &array(1.0f,in(i)); wfs(1).lgs_prof_alt = &float(span(92000.,100000,in(i))); atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; aoinit,disp=0; tic; for (j=1;j<=10;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./10.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["sim.pupildiam","wfs(1).shnxsub", \ "wfs(1).pixsize","wfs(1).npixels","wfs(1).noise", \ "wfs(1).extfield","wfs(1)._nx"]); } } else if (case==6) { cname = "extended_field_wo_kernel"; cunit = "wfs._npb=pixels"; in = [0,2,4,6,8,10.]; tim = in*0.; pfit = 0; pzero = 0; for (i=1;i<=numberof(in);i++) { aoread,"sh6x6.par"; wfs(1).extfield = in(i); wfs(1).shnxsub = 8; sim.pupildiam = 256; wfs(1).pixsize=0.1; wfs(1).npixels=6; wfs(1).noise = 0; wfs(1).kernel = 0.0; atm.screen = &(Y_USER+"data/verywide"+["1","2","3","4"]+".fits"); atm.dr0at05mic=0.; aoinit,disp=0; in(i) = wfs(1)._npb; tic; for (j=1;j<=100;j++) sh_wfs,pupil,pupil*0.0f,1; now = tim(i) = 1000./100.*tac(); write,format="pupd=%d SH%dx%d, npixels=%d, time/call=%.1fms\n", sim.pupildiam, wfs(1).shnxsub, wfs(1).shnxsub, wfs(1).npixels, now; label = yao_struct_member_to_string(["sim.pupildiam","wfs(1).shnxsub", \ "wfs(1).pixsize","wfs(1).npixels","wfs(1).noise"]); } } winkill,0; window,0,dpi=120,wait=1; plot,tim,in; plmargin; plp,tim,in,symbol=20,size=0.3; limits,0.,,0.; if (pzero) plg,[0.,tim(1)],[0.,in(1)],type=2; // compare with n^2: if (pfit) { fit = tim(0)/in(0)^2*in^2; plg,fit,in,color="red"; } pltitle,escapechar(swrite(format="sh_wfs() exec time vs %s (%s)",cname,yao_version)); xytitles,escapechar(cname+" ["+cunit+"]"),escapechar("sh_wfs() exec time [ms]"),[-0.01,0.]; l = limits(); plt,escapechar(label),l(2),l(3),tosys=1,justify="RB",height=10; if (png) png_write,"shwfs_exec_time_vs_"+cname+"_v"+yao_version+".png",rgb_read(); } func yao_struct_member_to_string(name) { str = ""; for (i=1;i<=numberof(name);i++) { include,[swrite(format="tmp = %s",name(i))],1; if ((structof(tmp)==int)||(structof(tmp)==long)) fmt="%d"; if ((structof(tmp)==float)||(structof(tmp)==double)) fmt="%.3f"; str += swrite(format="%s = "+fmt,name(i),tmp); if (i1) status = quit_wfs_forks(); } write,msg; return; } nproc = nprocs(); nfork_max = nproc+2; write,format="\n>>> Found %d processor, using nfork_max = %d\n\n",nproc,nfork_max; } aoread,parfile; sim.verbose = sim.debug =0; aoinit; tim = []; for (nf=1;nf<=nfork_max;nf++) { grow,tim,svipc_time_sh_wfs(svipc=nf,nit=nit)(0); if (nf>1) status = quit_wfs_forks(); } if (doplot) { plot,tim; xytitles,"Number of threads","Median execution time [ms]"; pltitle,"svipc timing"; limits,square=0; limits; plmargin; } } yao-5.4.0/yaodh.i000066400000000000000000000474131234404334100135750ustar00rootroot00000000000000/* * yaodh.i * * A collection of routines related to Disk Harmonic modes. * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * Original in MatLab: Norman Mark Milton (August 25, 2005) * Adapted to Yorick by Aurea Garcia Rissmann (May 23, 2010) * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ local yaodh; /* dh: disk harmonic func Library dh_alt_elem - disk harmonic elements (alternate order) dh_alt_index - disk harmonic func index (alternate order) dh_alt_num - disk harmonic func numbers (alternate order) dh_bjprime_zero - disk harmonic BesselJ' zero dh_cos_coeff - disk harmonic func cos wave coefficient dh_dh - disk harmonic func evaluation dh_dhfast - disk harmonic func evaluation (fast) dh_dhindex - disk harmonic radial and azimuthal index dh_elem - disk harmonic elements dh_flip_x_coeff - disk harmonic func reflect (about y-axis) coefficient dh_flip_y_coeff - disk harmonic func reflect (about x-axis) coefficient dh_index - disk harmonic func index dh_norm - disk harmonic normalization constant dh_num - disk harmonic func numbers dh_rotate_coeff - disk harmonic func rotated coefficient dh_scale_coeff - disk harmonic func rescaled coefficient dh_shift_coeff - disk harmonic func shifted coefficient dh_sin_coeff - disk harmonic func sin wave coefficient dh_var - disk harmonic variance load_dh_bjprime_zero_tab - load init file prepdiskharmonic - prepares the frame with pupil Original in MatLab: Norman Mark Milton (August 25, 2005) Adapted to Yorick by Aurea Garcia Rissmann (May 23, 2010) */ require,"bessel.i"; // require,"hdf5.i"; /* how to use it: Example: prepdiskharmonic,128,100; load_dh_bjprime_zero_tab; p = dh_dhindex(2,1); // DH n=2,m=1, n always >= m. image = dh_dh(p(1),p(2),zr,ztheta); window,1; pli,image; */ func make_diskharmonic(size,diameter,ndhmodes,xc=,yc=,disp=) /* DOCUMENT: * make_diskharmonic(size,diameter,ndhmodes,xc=,yc=,disp=) * shortcut to prepdiskharmonic. return data cube. */ { prepdiskharmonic,size,diameter,xc,yc; load_dh_bjprime_zero_tab; max_order = zernumero(ndhmodes)(1)+1; ndh=0; //ntmodes = sum(indgen(max_order+1)); for (i=0;i<=max_order;i++) { for (k=0;k<=i;k++) { ndh = ndh+1; if (ndh == 1) { dh_tab = array(float,size,size,1); } else { grow,dh_tab,array(float,size,size,1); } p = dh_dhindex(i,k); dh_tab(,,ndh) = dh_dh(p(1),p(2),zr,ztheta); if (disp == 1) {fma; pli,dh_tab(,,ndh);} } } return dh_tab(,,1:ndhmodes); } //=========================================================================== func prepdiskharmonic(size,diameter,xc,yc) /* DOCUMENT prepdiskharmonic(size,diameter,xc,yc) * Call this function to set up the geometry for subsequent calls * to the diskharmonic functions. This is excatly the same function * as prepzernike; I just included it here with another name for * completeness of this disk harmonics file. * size : size of the 2d array on which future "diskharmonic" will be returned * diameter : diameter of the pupil in pixel in the array * xc, yc (optional) : Coordinates (in pixels of the center of the pupil) * Example: * > prepdiskharmonic,128,100 * SEE ALSO: */ { extern zdim,zr,ztheta,zmask,zrmod,zmaskmod; if (xc == []) {xc = size/2+1;} if (yc == []) {yc = size/2+1;} radius= (diameter+1.)/2.; zdim = size; zr = dist(zdim,xc=xc,yc=yc)/radius; zmask = (zr <= 1.); zmaskmod = (zr <= 1.2); zrmod = zr*zmaskmod; zr = zr*zmask; x = float(span(1,zdim,zdim)(,-:1:zdim)); y = transpose(x); ztheta= atan(y-yc,x-xc); } //============================================================================ func dh_alt_elem(order) { /* DOCUMENT: dh_alt_elem: disk harmonic elements (alternate order) order - disk harmonic order number returns: number of disk harmonic basis funcs from order 0 through order o */ if (order < 0) { error,"dh_alt_elem: invalid order number"; } else { n = (2 * order^2) + order + 1; } return n; } //====================================================================================== func dh_norm(dhn,dhm) { /* DOCUMENT: dh_norm: disk harmonic normalization constant dhn - Zero number dhm - Bessel order number returns: normalization constant for disk harmonic func */ if (dhn < 0) error,"dh_norm: invalid zero number"; if ((dhn == 0) && (dhm != 0)) error,"dh_norm: invalid Bessel number for order zero"; if (dhn == 0){ a = 1; } else { mabs = abs(dhm); l = dh_bjprime_zero(dhn,dhm); k = 2*pi *l; a = sqrt(1/((1-(mabs/k)^2) * bessj(mabs,k)^2)); } return a; } //======================================================================================== func dh_dh(dhn,dhm,r,theta) { /* DOCUMENT: dh_dh: disk harmonic func evaluation dhn - Zero number dhm - Bessel order number r - radial coordinate theta - azimuthal angle coordinate returns: value of disk harmonic func at specified point (real part) */ if (dhn < 0) error,"dh_dh: invalid zero number"; d = dh_dhfast(dhm,dh_bjprime_zero(dhn,dhm),dh_norm(dhn,dhm),r,theta); return d; } //======================================================================================== func dh_bjprime_zero(dhn,dhm) { /* DOCUMENT: dh_bjprime_zero: disk harmonic BesselJ' zero dhn - Zero number dhm - Bessel order number returns: dhn'th zero to first derivative of dhm'th order BesselJ func (first kind) */ extern dh_bjprime_zero_tab; if (dhn < 0) error,"dh_bjprime_zero: invalid zero number"; mabs = abs(dhm); if (dhn == 0) { l = 0; } else { r = dimsof(dh_bjprime_zero_tab)(2); c = dimsof(dh_bjprime_zero_tab)(3); if (dhn>c) { error,"dh_bjprime_zero: invalid zero number"; } else { if ((mabs+1) > r) { error,"dh_bjprime_zero: invalid order number"; } else { l = dh_bjprime_zero_tab(mabs+1,dhn) } } } return l; } //===================================================================================== func dh_dhfast(dhm,l,a,r,theta) { /* DOCUMENT: dh_dhfast: disk harmonic func evaluation (fast) dhm - Bessel order number l - disk harmonic spatial frequency a - disk harmonic normalization constant r - radial coordinate theta - azimuthal angle coordinate returns: value of disk harmonic func at specified point (real part) */ write,"teste2"; mabs = abs(dhm); k = 2*pi*l; d = a*bessj(mabs,k*r); if (dhm > 0) { d = sqrt(2)*d*sin(mabs*theta); } else if (dhm < 0) d = sqrt(2)*d*cos(mabs*theta); // matrix elem-by-elem // multiplication return d; } //======================================================================================== func dh_alt_index(o,n,m) { /* dh_alt_index: disk harmonic func index (alternate order) o - disk harmonic maximum order number n - Zero number m - Bessel order number returns: index of disk harmonic basis func with zero n and order m */ if (o < 0) error,"dh_alt_index: invalid maximum order number"; if (o < n) error,"dh_alt_index: invalid zero number"; if (o < abs(m)) error,"dh_alt_index: invalid order number"; if ((n == 0) && (m == 0)) { i = 1; } else { i = ((2 * o) + 1) * (n - 1) + 2; mabs = abs(m); if (m != 0) { i = i + (2 * (mabs - 1)); if (m > 0) { i = i + 1; } else { i = i + 2; } } } return i; } //======================================================================================== func dh_alt_num(o,i) { /* DOCUMENT: dh_alt_num: disk harmonic func numbers (alternate order) i - disk harmonic func index number returns: [n,m] func numbers disk harmonic basis func with index i with maximum order o */ if (o < 0) error,"dh_alt_num: invalid order number"; if (i < 1) error,"dh_alt_num: invalid func index"; if (i == 1) { n = 0; m = 0; } else { i = i - 2; per_n = (2*o)+1; n = floor(i/per_n) + 1; m = i - ((n - 1) * per_n); if (m > 0) if (m%2==0) { // arrumar esta funcao m = -floor(m/2); } else { m = floor((m - 1)/2) + 1; } } return [n,m]; } //======================================================================================== func dh_cos_coeff(dhm, dhnb, dhmb, k) { /* DOCUMENT: dh_cos_coeff: disk harmonic func cos wave coefficient dhm - Bessel order number dhnb - Zero number (basis) dhmb - Bessel order number (basis) k - sin wave spatial frequency returns: value of disk harmonic coefficient for cos wave */ if (dhm == dhmb) { if ((dhm <= 0) & (dhm%2 == 0)) { c = 2*cos(abs(dhm)*pi/2); } else { c = 0; } if (c != 0) { abnm = dh_norm(dhnb,dhm); kbnm = 2*pi*dh_bjprime_zero(dhnb,dhm); c = c*abnm*bess_integral(dhm,k,kbnm); if (dhm != 0) { c = sqrt(2)*c; } } } else { c = 0; } return c; } //======================================================================================== func load_dh_bjprime_zero_tab(void) { /* DOCUMENT: dh_init: Initialize disk harmonic global variables */ extern dh_bjprime_zero_tab; // require,"hdf5.i"; // dh_bjprime_zero_tab = h5read("besseljprimezeros200.h5","/data"); dh_bjprime_zero_tab = yao_fitsread(Y_SITE+"data/besseljprimezeros200.fits"); //clear besseljprimezeros200; return; } //===================================================================================== func dh_dhindex(n,k) { /* DOCUMENT: dh_dhindex: disk harmonic radial and azimuthal index n - disk harmonic order number k - disk harmonic mode number returns: return DH indices (dhn, dhm) */ /* assume n and k are valid % if n < 0 % error('dh_dhindex: invalid order number'); % end % if (k < 0) | (k > n) % error('dh_dhindex: invalid mode number'); % end */ dhm = n - (2 * k); if (dhm == 0) { dhn = floor(n/2); } else if (dhm > 0) { dhn = k + 1; } else { dhn = n - k + 1; } return int([dhn,dhm]); } //====================================================================================== func dh_flip_x_coeff(n,m,nb,mb) { /* dh_flip_x_coeff: disk harmonic func reflect (about y-axis) coefficient n - disk harmonic order number m - disk harmonic azimuthal order number nb - disk harmonic order number (basis) mb - disk harmonic azimuthal order number (basis) returns: value of disk harmonic coefficient with reflection (about y-axis) */ c = dh_flip_y_coeff(n,m,nb,mb)*dh_rotate_coeff(n,m,nb,mb,pi); return c; } //====================================================================================== func dh_flip_y_coeff(n,m,nb,mb) { /* dh_flip_y_coeff: disk harmonic func reflect (about x-axis) coefficient n - disk harmonic order number m - disk harmonic azimuthal order number nb - disk harmonic order number (basis) mb - disk harmonic azimuthal order number (basis) returns: value of disk harmonic coefficient with reflection (about x-axis) */ if (n == nb) { if (m == mb) { if (mb > 0) { c = -1; } else { c = 1;} } else { c = 0;} } else { c = 0;} return c; } //======================================================================================= func dh_rotate_coeff(dhn,dhm,dhnb,dhmb,theta) { /* DOCUMENT: dh_rotate_coeff: disk harmonic func rotated coefficient dhn - Zero number dhm - Bessel order number dhnb - Zero number (basis) dhmb - Bessel order number (basis) theta - rotation angle (radians) returns: value of disk harmonic coefficient with rotation */ mabs = abs(dhmb); if (dhn == dhnb) { if (dhm == 0) { if (dhmb == 0) { c = 1; } else { c = 0; } } else if (dhm < 0) { // cos(a - b) = cos(a)cos(b) + sin(a)sin(b) if (dhm == dhmb) { c = cos(mabs*theta); } else if (dhm == -dhmb) { c = sin(mabs*theta); } else { c = 0; } } else { // sin(a - b) = sin(a)cos(b) - sin(b)cos(a) if (dhm == dhmb) { c = cos(mabs*theta); } else if (dhm == -dhmb) { c = -sin(mabs*theta); } else { c = 0; } } } else c = 0; return c; } //============================================================================= func dh_scale_coeff(dhn,dhm,dhnb,dhmb,scale) { /* DOCUMENT: dh_scale_coeff: disk harmonic func rescaled coefficient dhn - Zero number dhm - Bessel order number dhnb - Zero number (basis) dhmb - Bessel order number (basis) scale - radial coordinate scale factor returns: value of disk harmonic coefficient with radial rescaling */ if (dhm == dhmb) { anm = dh_norm(dhn,dhm); abnm = dh_norm(dhnb,dhm); a = 2*pi*dh_bjprime_zero(dhn,dhm)*scale; b = 2*pi*dh_bjprime_zero(dhnb,dhm); c = 2*abnm*anm*bess_integral(dhm,a,b); } else c = 0; return c; } //================================================================================= func dh_shift_coeff(dhn,dhm,dhnb,dhmb,r0,theta0) { /* dh_shift_coeff: disk harmonic func shifted coefficient dhn - Zero number dhm - Bessel order number dhnb - Zero number (basis) dhmb - Bessel order number (basis) r0 - radial coordinate of shift (unit circle) theta0 - azimuthal coordinate of shift (rad) returns: value of disk harmonic coefficient with origin shift */ // dhnb = n, dhmb = m, dhn = n', dhm = m' where s + m' = m or s = m - m' mabs = abs(dhm); mbabs = abs(dhmb); sminus = mbabs - mabs; splus = mbabs + mabs; if (dhm == 0) { if (dhmb == 0) d = dh_shift_term(mbabs,dhn,dhm,dhnb,dhmb,r0,theta0,0); if (dhmb < 0) d = sqrt(2) * dh_shift_term(mbabs,dhn,dhm,dhnb,dhmb,r0,theta0,-1); if (dhmb > 0) d = sqrt(2) * dh_shift_term(mbabs,dhn,dhm,dhnb,dhmb,r0,theta0,1); } if (dhm < 0) { if (dhmb == 0) d = sqrt(2)*((-1)^mabs)* dh_shift_term(mabs,dhn,dhm,dhnb,dhmb,r0,theta0,-1); if (dhmb < 0) { d1 = dh_shift_term(sminus,dhn,dhm,dhnb,dhmb,r0,theta0,-1); d2 = dh_shift_term(splus,dhn,dhm,dhnb,dhmb,r0,theta0,-1); d = d1 + (((-1)^mabs)*d2); } if (dhmb > 0) { d1 = dh_shift_term(sminus,dhn,dhm,dhnb,dhmb,r0,theta0,1); d2 = dh_shift_term(splus,dhn,dhm,dhnb,dhmb,r0,theta0,1); d = d1 + (((-1)^mabs)*d2); } } if (dhm > 0) { if (dhmb == 0) d = sqrt(2)*((-1)^mabs)* dh_shift_term(mabs,dhn,dhm,dhnb,dhmb,r0,theta0,1); if (dhmb < 0) { d1 = dh_shift_term(sminus,dhn,dhm,dhnb,dhmb,r0,theta0,1); d2 = dh_shift_term(splus,dhn,dhm,dhnb,dhmb,r0,theta0,1); d = - d1 + (((-1)^mabs) * d2); } if (dhmb > 0) { d1 = dh_shift_term(sminus,dhn,dhm,dhnb,dhmb,r0,theta0,-1); d2 = dh_shift_term(splus,dhn,dhm,dhnb,dhmb,r0,theta0,-1); d = d1 - (((-1)^mabs)*d2); } } return d; } //========================================================================================= func dh_shift_term(s,dhn,dhm,dhnb,dhmb,r0,theta0,trig) { anm = dh_norm(dhn,dhm); abnm = dh_norm(dhnb,dhmb); knm = 2*pi*dh_bjprime_zero(dhn, dhm); kbnm = 2*pi*dh_bjprime_zero(dhnb, dhmb); d = 2*abnm*anm*bess_integral(abs(dhmb),knm,kbnm) * bessj(s,knm*r0); if (trig > 0) { d = d*sin(s*theta0); } else if (trig < 0) d = d*cos(s*theta0); return d; } //========================================================================================= func dh_sin_coeff(dhm,dhnb,dhmb,k) { /* DOCUMENT: dh_sin_coeff: disk harmonic func sin wave coefficient dhm - Bessel order number dhnb - Zero number (basis) dhmb - Bessel order number (basis) k - sin wave spatial frequency returns: value of disk harmonic coefficient for sin wave */ if (dhm == dhmb) { if ((dhm < 0) & (dhm%2 != 0)) { c = 2*sin(abs(dhm)*pi/2); } else { c = 0; } if (c != 0) { abnm = dh_norm(dhnb,dhm); kbnm = 2*pi*dh_bjprime_zero(dhnb,dhm); c = c*abnm*bess_integral(dhm,k,kbnm); if (dhm != 0) c = sqrt(2.)*c; } } else { c = 0;} return c; } //=============================================================================== func bess_integral(m,f1,f2) { /* DOCUMENT: calculates the Bessel integral over unit circle */ if (f1==f2) { c = 0.5*(bessj(m,f1)^2-bessj(m-1,f1)*bessj(m+1,f1)) } else { c = (f2*bessj(m-1,f2)*bessj(m,f1)-f1*bessj(m-1,f1)*bessj(m,f2))/(f1^2-f2^2); } return c; } //============================================================================================== func dh_var(dhn,dhm,D,r0,oscale,vonKarman) { /* DOCUMENT: dh_var: disk harmonic variance dhm - bessel order number dhn - bessel zero number D - aperture diameter (m) r0 - coherence length (m) oscale - outer scale (m) vonKarman - use von Karman spectrum instead of Kolmogorov returns: variance of mode (dhn, dhm) for aperture D and coherence length r0 */ if (dhn < 0) error,"dh_var: invalid zero number"; /* % dh_alpha = 0.023 / (2.0^(5.0 / 3.0)); % dh_alpha = 0.023 / (2.0^(3.0 / 2.0)); % dh_alpha = 0.023 / pi; % dh_alpha = 0.023 / (pi^4); % dh_alpha = 2.8 * 10^(-4); */ dh_alpha = 2.6*10^(-4); lnm = dh_bjprime_zero(dhn,dhm); anm = dh_norm(dhn,dhm); if (vonKarman == 1) { f0 = 1.0/(2.0*oscale); // scaled to radius not diameter lscale = ((lnm^2 + f0^2)^(-11.0/6.0))/lnm; } else { lscale = lnm^(-14.0/3.0); } // v = dh_alpha / (pi^3) * ((D / r0)^(5.0 / 3.0)) * anm^2 * lscale; v = dh_alpha*((D/r0)^(5.0/3.0))*anm^2*lscale; return v; } func dh_dhfast(dhm,l,a,r,theta) { /* DOCUMEMNT: dh_dhfast: disk harmonic function evaluation (fast) dhm - Bessel order number l - disk harmonic spatial frequency a - disk harmonic normalization constant r - radial coordinate theta - azimuthal angle coordinate returns: value of disk harmonic function at specified point (real part) */ mabs = abs(dhm); k = 2*pi*l; d = a * bessj(mabs,k*r); if (dhm > 0) { d = sqrt(2)*d*sin(mabs*theta); } else if (dhm < 0) d = sqrt(2)*d*cos(mabs*theta); return d; } func dh_bjprime_zero(dhn,dhm) { /* DOCUMENT: dh_bjprime_zero: disk harmonic BesselJ' zero dhn - Zero number dhm - Bessel order number returns: dhn'th zero to first derivative of dhm'th order BesselJ function (first kind) */ extern dh_bjprime_zero_tab; if (dhn < 0) error,"dh_bjprime_zero: invalid zero number"; mabs = abs(dhm); if (dhn == 0) { l = 0; } else { r = dimsof(dh_bjprime_zero_tab)(2); c = dimsof(dh_bjprime_zero_tab)(3); if (dhn > c) { error,"dh_bjprime_zero: invalid zero number"; } else if (mabs+1 > r) { error,"dh_bjprime_zero: invalid order number"; } else { l = dh_bjprime_zero_tab(mabs+1,dhn); } } return l; } yao-5.4.0/yaokl.i000066400000000000000000001131361234404334100136040ustar00rootroot00000000000000/* * yaokl.i * * A collection of routines related to Karhuenen Loeve modes. * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * Copyright (c) 2006, Damien Gratadour * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ local yaokl; /* yaokl Collection of routines for building the KL of a Kolmogorov statistics Derived from a collection of routines developped both at ESO and ONERA The main routine is the last one ... for a Kolmogorov statistics : res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64); or res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="kolmo"); for a Von Karman statistics : res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="karman"); or res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="karman",outscl=3); default is : an outter scale of 3 times the size of the telescope res is a 128x128x150 array containing the 150 first KL of a kolmogorov or Von Karman stat D. Gratadour Feb 2006 Available functions: func dblindgen(n) func polar_coord(r,&mask,&rho,&phi,&pts,occ=,xcent=,ycent=,\ func radii(nr,np,ri) func polang(r) func setpincs(ax,ay,px,py,ri,&pincx,&pincy,&pincw) func pcgeom (nr,np,ncp,ri,ncmar,ap) func set_pctr(bas, ncp =, ncmar=) func pol2car(cpgeom,pol,mask=) func kolstf(dvec) func karmanstf(dvec,outscl=) func gkl_radii(nr,ri) func gkl_mkker(ri,nr,rad,funct=,outscl=) func piston_orth(nr) func gkl_fcom(kers,ri,nf,&evals,&nord,&npo,&ord,&rabas) func gkl_mkazi(nord, np) func gkl_bas(ri=,nr=,np=,nfunc=,verbose=,funct=,outscl=) func gkl_sfi(bas, i) func make_kl(nmax,dim,&var,&outpolarbase,&pupil,oc=,nr=,nopup=,\ func kl_basis_in_dm_space_4extrap(nm, n_rm_modes); func kl_basis_in_dm_space(nm,n_rm_modes,&eigen_val); */ //require,mcao_i_dir+"lib/libgenutil.i"; //require,"digit2.i"; func dblindgen(n) /*DOCUMENT res=dblindgen(size) D. Gratadour Feb 2006 This routine returns a size x size array containing increasing indices from 1 to size x size. SEE ALSO : indgen, indices */ { n=long(n); return reform(indgen(n*n),[2,n,n]); } func polar_coord(r,&mask,&rho,&phi,&pts,occ=,xcent=,ycent=,\ verbose=,leq=,btw4pix=,sizemin=,dbprec=) /* DOCUMENT polar_coord,radius,mask,rho,phi; or polar_coord,radius,mask,rho,phi,pts,sizemin=1; D. Gratadour Jan 2006 Calculation of polar coordinates rho and phi and an intensity mask (the pupil) of a telescope of radius r Derived from an IDL routine (polaire2.pro) written by L. Mugnier INPUTS : r = the radius of the mask OUTPUT : mask = the intensity mask (2d image) rho = the width coordinate (2d image) phi = the angle coordinate (rad) (2d image) pts = (optional) indices of valid (non null) points of the pupil (1d vector) if flag sizemin is set OPTIONAL : occ = the occultation level (<=1) xcent = the x position of the center point of the mask xcent = the y position of the center point of the mask verbose = flag to get info on the process (0/1) leq = flag to set the limits of the mask (<= radius or < radius) btw4pix = flag to set the center of the mask on 1 pixel or in between 4 pixels (0/1) sizemin = flag to set the outputs in a minimum size arrays (null points are eliminated) (0/1) SEE ALSO : ... */ { if (r==[]) r=128; if (!is_set(occ)) occ=0.0; if (!btw4pix) diam=long(2*floor(r)+1); else diam=long(2*round(r)); if (!is_set(xcent)) xcent=float((diam-1)/2.); if (!is_set(ycent)) ycent=float((diam-1)/2.); if (verbose) { write,format="Pupil diameter : %d\n",diam; if (xycent!=[]) { write,format="Pupil X center : %f\n",xycent(1); write,format="Pupil Y center : %f\n",xycent(2); } } x=float(((indices(diam))(,,1)-1.0) % diam); y=transpose(x); x-=xcent; y-=ycent; if (dbprec) { rho=double(sqrt(x^2+y^2))/double(r); phi=double(atan(y,x+(rho==0))); } else { rho=float(sqrt(x^2+y^2))/float(r); phi=float(atan(y,x+(rho==0))); } if (leq) mask=((rho<=1) & (rho>=occ)); else { if (dbprec) mask=double((rho<1) & (rho>=occ)); else mask=float((rho<1) & (rho>=occ)); } if (sizemin) { if (verbose) write,"We will keep only the non-null points"; pts=where(mask != 0.); if (dimsof(pts) != []) { sizepts=(dimsof(pts))(2); if (verbose) write,"Number of null points : ",sizepts; rho=rho(pts); phi=phi(pts); mask=mask(pts); } else { if (verbose) write,"All points are non-null !"; } } } struct gkl_basis_struct { long nr; long ni; long np; long nfunc; float ri; pointer radp; pointer evals; long nord; pointer npo; pointer ord; pointer rabas; pointer azbas; }; struct geom_struct { pointer px; pointer py; pointer cr; pointer cp; pointer pincx; pointer pincy; pointer pincw; pointer ap; long ncp; long ncmar; }; func radii(nr,np,ri) /*DOCUMENT res=radii(NumberOfR,NumberOfPhi,Dim) D. Gratadour Feb 2006 This routine generates an nr x np array with np copies of the radial coordinate array. Radial coordinate span the range from r=ri to r=1 with successive annuli having equal areas (ie, the area between ri and 1 is divided into nr equal rings, and the points are positioned at the half-area mark on each ring). There are no points on the border. SEE ALSO : polang */ { r2 = ri^2 +(float(indgen(nr)-1)+0.)/nr*(1.0 - ri^2); rs = sqrt(r2); return rs*array(1.,np)(-,); } func polang(r) /*DOCUMENT res=polang(RadialCoordArray) D. Gratadour Feb 2006 This routine generates an array with the same dimensions as r, but containing the azimuthal values for a polar coordinate system. SEE ALSO : radii */ { s = dimsof(r); nr = s(2); np = s(3); phi1 = float(indgen(np)-1)/float(np)*2.*pi; return phi1(-,)*array(1.,nr); } func setpincs(ax,ay,px,py,ri,&pincx,&pincy,&pincw) /*DOCUMENT res=polang(RadialCoordArray) D. Gratadour Feb 2006 This routine determines a set of squares for interpolating from cartesian to polar coordinates, using only those points with ri < r < 1 SEE ALSO : pcgeom */ { s = dimsof(ax); nc = s(2); s = dimsof(px); nr = s(2); np = s(3); dcar = (ax(nc) - ax(1)) / (nc-1); ofcar = ax(1,1); rlx = (px - ofcar)/dcar; rly = (py - ofcar)/dcar; lx = long(rlx); ly = long(rly); shx = rlx - lx; shy = rly - ly; pincx=[lx,lx+1,lx+1,lx]+1; pincy=[ly,ly,ly+1,ly+1]+1; pincw=[(1-shx)*(1-shy),shx*(1-shy),shx*shy,(1-shx)*shy]; axy = ax^2 + ay^2; axyinap = clip(axy,ri^2.+1.e-3,0.999); sizeaxyinap=(dimsof(axyinap))(2); pincw = pincw*axyinap(pincx+(pincy-1)*sizeaxyinap); pincw = pincw*(1.0/pincw(,,sum))(,,-); } func pcgeom (nr,np,ncp,ri,ncmar,ap) /*DOCUMENT geom=pcgeom(nr, np, ncp, ri, ncmar,ap) D. Gratadour Feb 2006 This routine builds a geom_struct. px and py are the x and y coordinates of points in the polar arrays. cr and cp are the r and phi coordinates of points in the cartesian grids. ncmar allows the possibility that there is a margin of ncmar points in the cartesian arays outside the region of interest SEE ALSO : setpincs, set_pctr */ { nused = ncp - 2*ncmar; ff = 0.5 * nused; hw = float(ncp-1)/2; r = radii(nr,np,ri); p = polang(r); px0 = r * cos(p); py0 = r * sin(p); px = ff * px0 + hw; py = ff * py0 + hw; ax = float(dblindgen(ncp)-1) % ncp - 0.5 * (ncp-1); ax = ax / (0.5 * nused); ay = transpose(ax); setpincs, ax, ay, px0, py0, ri,pincx, pincy, pincw; dpi = 2 * pi; cr2 = (ax^2 + ay^2); ap = clip(cr2,ri^2+1.e-3,0.999); //cr = (cr2 - ri^2) / (1 - ri^2) * nr - 0.5; cr = (cr2 - ri^2) / (1 - ri^2) * nr; cp = (atan(ay, ax) + dpi) % dpi; cp = (np / dpi) * cp; cr = clip(cr,1.e-3,nr-1.001); //fudge -----, but one of the less bad ones cp = clip(cp,1.e-3,np -1.001); //fudge ----- this is the line which //gives that step in the cartesian grid //at phi = 0. geom = geom_struct(); geom.px=&px; geom.py=&py; geom.cr=&cr; geom.cp=&cp; geom.pincx=&pincx; geom.pincy=&pincy; geom.pincw=&pincw; geom.ap=≈ geom.ncp=ncp; geom.ncmar=ncmar; return geom; } func set_pctr(bas, ncp =, ncmar=) /*DOCUMENT geom=set_pctr(bas, ncp =, ncmar=) D. Gratadour Feb 2006 This routine calls pcgeom to build a geom_struct with the right initializations. bas is a gkl_basis_struct built with the gkl_bas routine. SEE ALSO : pcgeom, setpincs, gkl_bas */ { if (!is_set(ncmar)) ncmar = 2; if (!is_set(ncp)) ncp = 128; return pcgeom(bas.nr,bas.np,ncp,bas.ri,ncmar,ap); } func pol2car(cpgeom,pol,mask=) /*DOCUMENT cart=pol2car(cpgeom, pol, mask=) D. Gratadour Feb 2006 This routine is used for polar to cartesian conversion. pol is built with gkl_bas and cpgeom with pcgeom. However, points not in the aperture are actually treated as though they were at the first or last radial polar value -- a small fudge, but not serious ?******* SEE ALSO : pcgeom, gkl_bas */ { if (sae) error; cd = bilinear(pol, *cpgeom.cr+1, *cpgeom.cp+1); if (mask!=[]) cd = cd*(*cpgeom.ap); return cd; } func kolstf(dvec) /*DOCUMENT var=kolstf(dvec) D. Gratadour Feb 2006 This routine returns the kolmogorov phase variance at spatial dimension (inverse of the spatial frequency) dvec SEE ALSO : */ { return 6.88 * dvec^(5./3.); } func karmanstf(dvec,outscl=) /*DOCUMENT var=kolstf(dvec) D. Gratadour Feb 2006 This routine returns the Von Karman phase variance at spatial dimension (inverse of the spatial frequency) dvec. Same as kolstf but with a correcting factor to account for the outter scale. The latter should be in units of telescope diameter SEE ALSO : */ { if (dimsof(outscl)==[]) outscl = 3.; return 6.88 * dvec^(5./3.)*(1-1.485*(dvec/outscl)^(1./3.)+\ 5.383*(dvec/outscl)^(2)-6.281*\ (dvec/outscl)^(7./3.)); } func gkl_radii(nr,ri) /*DOCUMENT rad=gkl_radii(nr,ri) D. Gratadour Feb 2006 This routine generates an array of radial polar coordinates along which the KL are generated. nr is the number of elements and ri is the maximum radius. SEE ALSO : */ { d = (1.-ri*ri)/nr; // rad2 = ri^2 + d/2. + d * float(indgen(nr)-1); // rad2 = ri^2 + d * float(indgen(nr)-1); rad2 = ri^2 +d/16.+ d * float(indgen(nr)-1); // rad2 = ri^2 +d/14.+ d * float(indgen(nr)-1); // nr=64,128 // rad2 = ri^2 +d/10.+ d * float(indgen(nr)-1); rad = sqrt(rad2); return rad; } func gkl_mkker(ri,nr,rad,funct=,outscl=) /*DOCUMENT D. Gratadour Feb 2006 This routine generates the kernel used to find the KL modes. The kernel constructed here should be simply a discretization of the continuous kernel. It needs rescaling before it is treated as a matrix for finding the eigen-values. The outter scale should be in units of the diameter of the telescope. SEE ALSO : */ { nth = 5*nr; kers = array(float,[3,nr, nr, nth]); cth = cos(float(indgen(nth)-1)*(2.*pi/nth)); dth = 2.*pi/nth; fnorm = -1./(2*pi*(1.-ri^2))*0.5; //the 0.5 is to give the r^2 kernel, not //the r kernel for (i =1;i<=nr;i++) { for (j=1;j<=i;j++) { te = 0.5*sqrt(rad(i)^2+rad(j)^2-(2*rad(i)*rad(j))*cth); //te in units of the diameter, not the radius if (funct=="kolmo") te = kolstf(te); if (funct=="karman") te = karmanstf(te,outscl=outscl); if ((funct!="kolmo") & (funct!="karman")) { write,"The statistics is not known !"; error; } kelt = fnorm * dth * float (fft(te,-1)); kers (i, j,) = kelt; kers (j, i,) = kelt; } if (is_set(verbose)) write, i; } if (is_set (verbose)) write," "; return kers; } func piston_orth(nr) { s = array(float,[2,nr,nr]); for (j=1;j<=nr-1;j++) { rnm = 1./sqrt (float((j)*(j+1))); s(1:j,j) = rnm; s(j+1,j)= -1*(j)*rnm; } rnm = 1./sqrt (nr); s(,nr) = rnm; return s; } func gkl_fcom(kers,ri,nf,&evals,&nord,&npo,&ord,&rabas) /*DOCUMENT D. Gratadour Feb 2006 This routine does the work : finding the eigenvalues and corresponding eigenvectors. Sort them and select the right one. It returns the KL modes : in polar coordinates : rabas as well as the associated variance : evals. It also returns a bunch of indices used to recover the modes in cartesian coordinates (nord, npo and ord). SEE ALSO : gkl_bas */ { s = dimsof(kers); nr = s(2); nt = s(4); nxt = 1; fktom = (1.-ri^2)/nr; fevtos = sqrt(2*nr); evs = array(float,[2,nr,nt]); //ff isnt used - the normalisation for //the eigenvectors is straightforward: //integral of surface^2 divided by area = 1, //and the cos^2 term gives a factor //half, so multiply zero order by //sqrt(n) and the rest by sqrt (2n) //zero order is a special case... //need to deflate to eliminate infinite eigenvalue - actually want //evals/evecs of zom - b where b is big and negative zom = kers(,,1); s = piston_orth(nr); ts =transpose(s); b1 = ((ts(,+)*zom(+,))(,+)*s(+,))(1:nr-1, 1:nr-1); newev = SVdec(fktom*b1,v0,vt); v1 = array(float,[2,nr, nr]); v1(1:nr-1,1:nr-1) = v0; v1(nr,nr) = 1; vs = s(,+)*v1(+,); grow,newev,0; evs(,nxt) = float(newev); kers (,, nxt) = sqrt(nr)*vs; // the rest are more straightforward nxt = 2; do { newev = SVdec(fktom*kers(,,nxt),vs,vt); evs(,nxt) = float(newev); kers (,,nxt) = sqrt(2.*nr)*vs; mxn = max(float(newev)); egtmxn = floor(evs(, 1:nxt)>mxn); nxt = nxt + 1; } while ((2*sum(egtmxn)-sum(egtmxn(,1))) < nf); nus = nxt - 1; kers = kers (,,1:nus); evs = reform (evs (, 1:nus), nr*nus); a = (sort(-1.*evs))(1:nf); //every eigenvalue occurs twice except //those for the zeroth order mode. This //could be done without the loops, but //it isn't the stricking point anyway... no = 1; ni = 1; oind = array(long,nf+1); do { if (a(ni) < nr+1) { oind(no) = a(ni); no = no + 1; } else { oind(no) = a(ni); oind(no+1) = a(ni); no = no + 2; } ni = ni + 1; } while (no < (nf+1)); oind = oind (1:nf); tord = (oind-1)/nr+1; odd = ((long(indgen(nf)-1) % 2) == 1); pio = (oind-1) % nr +1; evals = evs(oind); ord = 2 *(tord-1) - floor(tord>1 & (odd))+1; nord = max(ord); rabas = array(float,[2,nr, nf]); sizenpo=long(max(ord)); npo = array(long,sizenpo); for (i=1;i<=nf;i++) { npo(long(ord(i))) = npo(long(ord(i))) + 1; rabas(, i) = kers (, pio(i), tord(i)); } } func gkl_mkazi(nord, np) { gklazi = array(float,[2,long(1+nord), np]); th = float(indgen(np)-1)*(2.*pi/ np); gklazi (1,) = 1.0; for (i = 2; i<=nord;i+=2) gklazi (i,) = cos (((i-1)/2+1) * th); for (i = 3; i<=nord;i+=2) gklazi (i,) = sin (((i-1)/2) * th); return gklazi; } func gkl_bas(ri=,nr=,np=,nfunc=,verbose=,funct=,outscl=) /*DOCUMENT D. Gratadour Feb 2006 This routine uses the output of gkl_fcom to fill the gkl_base_struct. SEE ALSO : gkl_fcom */ { if (!is_set(ri)) ri = 0; if (!is_set(nr)) nr = 40; if (!is_set(np)) np = long(5*nr); if (!is_set(nfunc)) nfunc = 500L; nr = long(nr); np = long(np); if ((nr * np)/ nfunc < 8) { if (is_set(verbose)) write,"warning: you may need a finer ",\ "radial sampling "; if (is_set(verbose)) write, "(ie, increased nr) to generate ",\ nfunc, " functions"; } else if ((nr * np)/ nfunc > 40) { if (is_set(verbose)) write,"note, for this size basis ",\ "radial discretization on ", nr; if (is_set(verbose)) write, "points is finer than necessary",\ "-it should work, but you "; if (is_set(verbose)) write, "could take a smaller nr without",\ "loss of accuracy"; } radp = gkl_radii(nr, ri); kers = gkl_mkker(ri, nr, radp,funct=funct,outscl=outscl); gkl_fcom,kers,ri,nfunc,evals,nord,npo,ord,rabas; azbas = gkl_mkazi(nord, np); gklbasis = gkl_basis_struct(); gklbasis.nr=nr; gklbasis.np=np; gklbasis.nfunc=nfunc; gklbasis.ri=ri; gklbasis.radp=&radp; gklbasis.evals=&evals; gklbasis.nord=nord; gklbasis.npo=&npo; gklbasis.ord=⩝ gklbasis.rabas=&rabas; gklbasis.azbas=&azbas; return gklbasis; } func gkl_sfi(bas, i) /*DOCUMENT D. Gratadour Feb 2006 This routine returns the i'th function from the generalised KL basis bas. bas must be generated first with gkl_bas. SEE ALSO : gkl_bas */ { if (i>bas.nfunc) { write, "the basis only contains ", nfunc, "functions"; return 0; } nr = bas.nr; np = bas.np; ordp = *bas.ord; ord=long(ordp(i)); rabasp=*bas.rabas; rabas=rabasp(,i); azbasp=*bas.azbas; azbas=azbasp(ord, ); sf1=array(double,[2,nr,np]); sf1(,*)=rabas; sf2=array(float,[2,np,nr]); sf2(,*)=azbas; sf = sf1*transpose(sf2); return sf; } func make_kl(nmax,dim,&var,&outpolarbase,&pupil,oc=,nr=,nopup=,funct=,outscl=,verbose=) /* DOCUMENT for a Kolmogorov statistics : res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64); or res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="kolmo"); for a Von Karman statistics : res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="karman"); or res=make_kl(150,128,varkl,outbas,pup1,oc=0.12,nr=64,funct="karman",outscl=5); the outter scale is in units of the telescope diameter default is : an outter scale of 3 times the size of the telescope D. Gratadour Feb 2006 This routine is the main program. It returns nmax generalized KL in an array dim x dim x nmax. It also returns the associated variance as well as the pupil and the polar base used for their calculation. Optional keywords includes any occultation, the number of samples for the radial coordinate and a flag to avoid pupil multiplication. SEE ALSO : polar_coord, gkl_bas, set_pctr */ { if (pupil==[]) polar_coord,dim/2.,pup,rho,phi,occ=oc,btw4pix=1; else pup=pupil; if (!is_set(nr)) nr=64; if (dimsof(funct)==[]) { write,"using the Kolmogorov model"; funct="kolmo"; } polarbase = gkl_bas(ri=oc,nr=nr,np=(2*pi*nr),nfunc=nmax,\ funct=funct,outscl=outscl,verbose=verbose); outpolarbase = polarbase; pc1 = set_pctr(polarbase, ncp= dim); kl = array(float,[3,long(dim),long(dim),nmax]); if (is_set(nopup)) { for (i=1;i<=nmax;i++) kl(,,i)=pol2car(pc1, gkl_sfi(polarbase,i)); } else { for (i=1;i<=nmax;i++) { sae=0; // if (i==8) sae=1; kl(,,i)=pol2car(pc1, gkl_sfi(polarbase,i))*pup; } } pupil = pup; var = *polarbase.evals; return kl; } func kl_basis_in_dm_space(nm,n_rm_modes,&eigen_val,extrap=) /* DOCUMENT calcule la base optimale vis a vis des fonctions d'influence du mirroir deformable et des conditions de turbulence. To be used then for instance to compute MMSE reconstructors. kl2dm = array(pointer,3); ei_val = array(pointer,3); filt_tab = [3,3,3]; for(nm=1;nm<=3;nm++) { b=kl_basis_in_dm_space(nm, filt_tab(nm),eigen,extrap="extrap_kl.mat"); kl2dm(nm) = &(b); ei_val(nm) = &(eigen);} mat_kl2dm = array(float, [2,684,684]); mat_kl2dm(1:240,1:240) = *kl2dm(1); mat_kl2dm(241:564,241:564) = *kl2dm(2); mat_kl2dm(565:,565:) = *kl2dm(3); yao_fitswrite, "mat_kl2dm_filt111.fits",mat_kl2dm; tab_ei_val = float(684); tab_ei_val = _(*ei_val(1),*ei_val(2),*ei_val(3)); yao_fitswrite, "tab_ei_val_filt111.fits",tab_ei_val; b = kl_basis_in_dm_space(1, 3,eigen,extrap="extrap_kl.mat"); will return a 240x240 array plot, b(,1); //first mode = Astig (piston/TT have been filtered) to see the modes: inf_fun = yao_fitsread("KLDMmodes_DM1_IF_nrmodes3.fits"); if_nb = dimsof(inf_fun)(4);//nb of IF dim = dimsof(inf_fun)(2);//size of the support dm_mode = b(+,)*(inf_fun(*,))(,+); dm_mode2 = reform(dm_mode,if_nb,dim,dim); tv,dm_mode2(1,,); nmodes = 40; aff_kldm_basis,dm_mode2,nmodes,puptel=[]; eigen = eigenvalues associated with each mode window,1;nm=1; xx = indgen(mcaodm(nm).nvalid); plot,eigen,xx; plg,xx^(-11./6.)*45.,xx,color="red"; logxy,1,1; */ { coeffi = [1.,1.24,1.47];//factor to take into account D vs h L0 = 25.; r0 = 0.4; k = 2;//oversampling factor for fft of IF //2 should be enough, larger than 2 takes a while //inf_fun = 3D array of influence functions inf_fun = get_mInfluence_withextrap(nm,extrap=extrap); if_nb = dimsof(inf_fun)(4);//nb of IF dim = dimsof(inf_fun)(2);//size of the support //----Step0 : Modes Filtering----------------- nnn = dimsof(ipupil)(2); if(nm == 1) { puptel = ipupil(nnn/2-dim/2+1:nnn/2+dim/2,nnn/2-dim/2+1:nnn/2+dim/2); prepzernike,dim,sim.pupildiam,dim/2+0.5,dim/2+0.5; pupkl = zernike(1); } if(nm > 1) { pup = inf_fun(,,sum); wp = where(pup >= max(pup)*0.75); pup2 = pup*0.;pup2(wp)=1.; dim2=(where(pup2(,dim/2)==1)(0)-where(pup2(,dim/2)==1)(1)+1); prepzernike,dim,dim2,dim/2+0.5,dim/2+0.5; pupkl = zernike(1); puptel = pupkl; } //define IF on the pupil only for(cpt=1;cpt<=if_nb;cpt++){ inf_fun(,,cpt) = inf_fun(,,cpt)*puptel; } if (numberof(n_rm_modes) != 0) { if(n_rm_modes > 0) { for(cpt=1;cpt<=if_nb;cpt++){ cmpnt = 0.0; for(kj=1;kj<=n_rm_modes;kj++){ polz = zernike(kj); coef = sum(inf_fun(,,cpt)*polz)/sum(polz*polz); cmpnt = cmpnt + polz*coef; } inf_fun(,,cpt) = inf_fun(,,cpt) - cmpnt; } } } //save influence functions for latter: if(n_rm_modes == []) n_rm_modes = 0; name=swrite(format="KLDMmodes_DM%d_IF_nrmodes%d.fits",nm,n_rm_modes(1)); yao_fitswrite,name,inf_fun; //------------------------------------------------------- //Step1 : Computing geometrique covariance matrix ... Delta_IF = array(float,[2,if_nb, if_nb]); Spup = numberof(where(puptel)); nrm = Spup;//pupil surface in pixel; tmp = inf_fun(*,); Delta_IF = (tmp(+,)*tmp(+,))/nrm; tmp = []; write, "-> Géometrique Covariance, DONE !"; //--------------------------------------------------------- //Step2 : Calcul des TF des fction d'influence phase_variance = (gamma(11./6.)*gamma(5./6.)/(2.*pi^(8./3.)))* (24.*gamma(6./5.)/5.)^(5./6.)* (L0/r0)^(5./3); kdpix = long(dim/2.+10.)*k;//at least 2 times pupil size ! if(kdpix <= dim) write, "ATTENTION!" //------------------------------------- D = 8.*coeffi(nm); //sp_freq = dist(kdpix)/(k*D*float(dim2)/float(sim.pupildiam));//FIXME //This is not good! should be in real pix/m sp_freq = dist(kdpix)/(k*D); //------------------------------------ f = sp_freq; cst = (gamma(11./6.)^2/(2.*pi^(11./3.)))*(24.*gamma(6./5.)/5.)^(5./6.) ; phase_spectrum = eclat(cst*r0^(-5./3.)*(f^2+(1/L0)^2)^(-11./6.)) ; print, "Variance theorique [rd^2]: ", (phase_variance); phase_variance_from_spectrum = sum(double(phase_spectrum))/(k*D)/(k*D); print, "Variance from dsp [rd^2]: ", (phase_variance_from_spectrum); support = array(float,[2,kdpix, kdpix]); FT_inf_fun = array(complex,[3,kdpix, kdpix, if_nb]); for(i=1;i<=if_nb;i++){ support(1:dim,1:dim) = inf_fun(,,i); FT_inf_fun(,,i) = fft(support,1)*sqrt(phase_spectrum); } write, "-> TF des IF, DONE !"; inf_fun = support = []; //--------------------------------------------------------- //Step3 : correlation statistique des fonctions d'influence H_IF = array(float,[2,if_nb, if_nb]); nrm = (Spup*Spup)*(k*D)*(k*D); tmp = FT_inf_fun(*,); FT_inf_fun = []; H_IF = float(tmp(+,)*conj(tmp)(+,))/nrm; write, "-> Correlation Statistiques, DONE !"; //------------------------------------------------------------- //Step4 : Double Diagonalisation D2 = SVdec(Delta_IF, Mp); print,"conditionning:",max(D2)/min(D2); M = transpose(Mp/sqrt(D2)(-,)); Hp = M(,+)*(H_IF(,+)*M(,+))(+,); Lp = SVdec(Hp,A); print,"conditionning:",max(Lp)/min(Lp); Bp = M(+,)*A(+,); eigen_val = Lp; write, "-> Double Diago, DONE !"; return Bp; /* //----------------------------------- mcao_restore_dm,mysttop+"/mystInitFiles/mcao-prod.ybin"; nnm = 1; spup=ipupil(dm(nnm)._n1:dm(nnm)._n2,dm(nnm)._n1:dm(nnm)._n2); i=1; tv,comp_dm_shape(nnm,&(float((*kl2dm(nnm))(,i))),extrap=0); */ } func kl_basis_in_dm_space_4extrap(nm, n_rm_modes) /* DOCUMENT calcule la base optimale vis a vis des fonctions d'influence du mirroir deformable et des conditions de turbulence. To be used then for instance with gen_extrap_klopt b = kl_basis_in_dm_space_4extrap(1, 1); will return a 293x293 array */ { //----------------------------------- //Get Influence Functions WITH extrapolated //and on a large array inf_fun = get_mInfluence_large(nm);//it includes extrap and valids if_nb = dimsof(inf_fun)(4);//nb of IF dim = dimsof(inf_fun)(2);//size of the support def1 = def2 = def3 = def4 = def5 = []; edef1 = edef2 = edef3 = edef4 = edef5 = []; dm(1)._def = &def1;dm(2)._def = &def2;dm(3)._def = &def3; dm(4)._def = &def4;dm(5)._def = &def5;dm(1)._edef = &edef1; dm(2)._edef = &edef2;dm(3)._edef = &edef3; //-------------------------------------------- //Step0 : Modes Filtering //First, we have to define a pupil... pup = inf_fun(,,sum); pup = sign(pup(wheremax(abs(pup))(1)))*pup; pup = (pup > 0.8*max(pup)); dim2=where(pup(,dim/2)==1)(0)-where(pup(,dim/2)==1)(1)+1; prepzernike,dim,dim2,dim/2+0.5,dim/2+0.5; pupkl = zernike(1); //define IF on the pupil only for(cpt=1;cpt<=if_nb;cpt++){ inf_fun(,,cpt) = inf_fun(,,cpt)*pupkl; } if (numberof(n_rm_modes) != []) { if(n_rm_modes > 0) { for(cpt=1;cpt<=if_nb;cpt++){ cmpnt = 0.0 for(kj=1;kj<=n_rm_modes;kj++){ polz = zernike(kj) coef = sum(inf_fun(,,cpt)*polz)/sum(polz*polz) cmpnt = cmpnt + polz*coef } inf_fun(,,cpt) = inf_fun(,,cpt) - cmpnt; } } } polz = []; //------------------------------------------------------- //Step1 : Computing geometrique covariance matrix ... Delta_IF = array(float,[2,if_nb, if_nb]); Spup = numberof(where(pupkl)); nrm = Spup;//pupil surface in pixel; tmp = inf_fun(*,);//(w,); Delta_IF = (tmp(+,)*tmp(+,))/nrm; write, "-> Géometrique Covariance, DONE !"; tmp = []; //--------------------------------------- //Step1b: Spectre turbulent: k = 2;//2 should be enough kdpix = long(dim/2.+10.)*k;//at least 2 times pupil size ! if(kdpix <= dim) write, "ATTENTION!"; L0 = 25.; r0 = 0.4; phase_variance = (gamma(11./6.)*gamma(5./6.)/(2.*pi^(8./3.)))* (24.*gamma(6./5.)/5.)^(5./6.)* (L0/r0)^(5./3); coeffi = [1.,1.24,1.47];//factor to take into account D vs h D = 8.*coeffi(nm); sp_freq = dist(kdpix)/(k*D); f = sp_freq; cst = (gamma(11./6.)^2/(2.*pi^(11./3.)))*(24.*gamma(6./5.)/5.)^(5./6.) ; phase_spectrum = eclat(cst*r0^(-5./3.)*(f^2+(1/L0)^2)^(-11./6.)) ; print, "Variance theorique [rd^2]: ", (phase_variance); phase_variance_from_spectrum = sum(double(phase_spectrum))/(k*D)/(k*D); print, "Variance from dsp [rd^2]: ", (phase_variance_from_spectrum); //--------------------------------------------------------- //Step2 : Calcul des TF des fonction d'influence FT_inf_fun = calc_FT_inf_fun(inf_fun,kdpix,if_nb,phase_spectrum); /*support = array(float,[2,kdpix, kdpix]); FT_inf_fun = array(complex,[3,kdpix, kdpix, if_nb]); for(i=1;i<=if_nb;i++){ support(1:dim,1:dim) = inf_fun(,,i); FT_inf_fun(,,i) = fft(support,1)*sqrt(phase_spectrum); } write, "-> Calcul des TFs, DONE !";*/ inf_fun = support = phase_spectrum = f = sp_freq = []; //--------------------------------------------------------- //Step3 : correlation statistique des fonctions d'influence H_IF = array(float,[2,if_nb, if_nb]); nrm = (Spup*Spup)*(k*D)*(k*D); tmp = FT_inf_fun(*,); FT_inf_fun = []; H_IF = float(tmp(+,)*conj(tmp)(+,))/nrm; write, "-> Correlation Statistiques, DONE !"; //------------------------------------------------------------- //Step4 : Double Diagonalisation D2 = SVdec(Delta_IF, Mp); print,"conditionning:",max(D2)/min(D2); M = transpose(Mp/sqrt(D2)(-,)); Hp = M(,+)*(H_IF(,+)*M(,+))(+,); Lp = SVdec(Hp,A); print,"conditionning:",max(Lp)/min(Lp); Bp = M(+,)*A(+,); eigen_val = Lp; write, "-> Double Diago, DONE !"; return Bp; /*To check that the extrapolator is really doing what we want: mmm = 2; nb_modes = 150; condy = 5000; //and compute the extrapolator: bval = b(*mcaodm(nm).valid_ptr,1:nb_modes); bext = b(*mcaodm(nm).extrap_ptr,1:nb_modes); bval_i = (svd_inverse(bval(+,)*bval(+,),condy))(,+) * bval(,+); bval_i = LUsolve(bval(+,)*bval(+,)),transpose(bval)); extrapbn = bext(,+)*bval_i(+,); //Lets try to test it ? com1 = bval(,mmm); ecom = extrapbn(,+)*com1(+); comtot = array(float,mcaodm(nm).nact); comtot(*mcaodm(nm).valid_ptr)=com1; comtot(*mcaodm(nm).extrap_ptr)=ecom; comref = b(,mmm); window,0; plot, comref; plg, comtot,color = "red"; window,1; plot, abs(comref - comtot); */ } func aff_kldm_basis(dm_mode2,nmodes,puptel=) /* DOCUMENT Display zernike, KL or KLDM modes */ { window, 49; winkill,49; window,49,dpi=120,style="nobox.gs"; if(nmodes <= 5){ n1=long(nmodes); n2=1;} if(nmodes > 5){ n1=5; n2=nmodes/n1;} if(nmodes > 40){ n1=8; n2=nmodes/n1;} if(nmodes > 100){ n1=12; n2=nmodes/n1;} if(nmodes > 200){ n1=16; n2=nmodes/n1;} if(nmodes > 300){ n1=18; n2=nmodes/n1;} if(puptel == []) puptel = array(float,[2,dimsof(dm_mode2)(3),dimsof(dm_mode2)(3)])+1.; tab = array(float,[2,dimsof(dm_mode2)(3)*n1,dimsof(dm_mode2)(3)*n2]); for(i=1;i<=n2;i++){ for(j=1;j<=n1;j++){ if((i-1)*n1+j > dimsof(dm_mode2)(2)) { tab((j-1)*dimsof(dm_mode2)(3)+1:j*dimsof(dm_mode2)(3),(i-1)*dimsof(dm_mode2)(3)+1:i*dimsof(dm_mode2)(3)) = 0.*puptel;} if((i-1)*n1+j <= dimsof(dm_mode2)(2)) { tab((j-1)*dimsof(dm_mode2)(3)+1:j*dimsof(dm_mode2)(3),(i-1)*dimsof(dm_mode2)(3)+1:i*dimsof(dm_mode2)(3)) = dm_mode2((i-1)*n1+j,,)*puptel; } } } tv,tab; limits, square=1; palette,"stern.gp"; } func klmodes_4extrap(nm, n_rm_modes,nsamp) /* DOCUMENT Compute the kl-dm modes for DM #nm, following J-P. Veran approach. We compute covariance matrices from turbulence based on random samples. So nsamp should be large to make the covariance matrices to converge. It returns directly the Extrap Matrix fo DM #nm: E = klmodes_4extrap(1,0,10000); */ { inf_fun = get_mInfluence_large(nm);//it includes extrap and valids if_nb = dimsof(inf_fun)(4);//nb of IF dim = dimsof(inf_fun)(2);//size of the support //----------------------- //Step0 : Modes Filtering //First, we have to define a pupil... pup = inf_fun(,,sum); pup = sign(pup(wheremax(abs(pup))(1)))*pup; pup = (pup > 0.8*max(pup)); dim2=where(pup(,dim/2)==1)(0)-where(pup(,dim/2)==1)(1)+1; prepzernike,dim,dim2,dim/2+0.5,dim/2+0.5; pupkl = zernike(1); if (numberof(n_rm_modes) != []) { if(n_rm_modes > 0) { for(cpt=1;cpt<=if_nb;cpt++){ cmpnt = 0.0 for(kj=1;kj<=n_rm_modes;kj++){ polz = zernike(kj) coef = sum(inf_fun(,,cpt)*polz)/sum(polz*polz) cmpnt = cmpnt + polz*coef } inf_fun(,,cpt) = inf_fun(,,cpt) - cmpnt; } } } //------------------------------------------------------- //Step1 : Computing the projection matrix: Delta_IF = array(float,[2,if_nb, if_nb]); w = where(pupkl); Spup = numberof(w); nrm = Spup;//pupil surface in pixel; tmp = inf_fun(*,)(w,); Delta_IF = (tmp(+,)*tmp(+,))/nrm; tmp2 = svd_inverse(Delta_IF,10000,e1); MatProj = tmp2(+,)*tmp(,+); write, "-> MatProj, DONE !"; //------------------------------------------------------- //Step2 : Projection of turbulent screens on Influence Functions. l0 = 25;//en metre l0 = dim*l0/8.;//conversion en PIXELS Proj=array(float,[2,if_nb,nsamp]); if (nsamp == []) nsamp = 1000; if(dim >= 256) dimp = 512 ; if(dim < 256) dimp = 256 ; for (i=1;i<=nsamp;i++) { phase=generate_phase_with_L0(dimp*2,l0,nalias=1)(1:dim,1:dim,1); phaseb=phase-avg(phase); // substraction of the piston phase=phaseb(*)(w); Proj(,i)=MatProj(,+)*phase(+); // projection on the actuators write,format="Still %d samples \r",nsamp-i+1; } VectValid = Proj(*mcaodm(nm).valid_ptr,); VectExtrap = Proj(*mcaodm(nm).extrap_ptr,); mat1 = VectValid(,+)*VectExtrap(,+)/nsamp; mat2 = VectValid(,+)*VectValid(,+)/nsamp; dims = (dimsof(mat2))(2); mat2_inv = LUsolve(mat2,unit(dims)); // compatible with LAPACK //------------------------------------------------------- //Step4 : Compute the Extrapolator E = mat1(+,)*mat2_inv(,+); return E; } func calc_FT_inf_fun(inf_fun,kdpix,if_nb,phase_spectrum) { support = array(float,[2,kdpix, kdpix]); FT_inf_fun = array(complex,[3,kdpix, kdpix, if_nb]); for(i=1;i<=if_nb;i++){ support(1:dim,1:dim) = inf_fun(,,i); FT_inf_fun(,,i) = fft(support,1)*sqrt(phase_spectrum); } write, "-> Calcul des TFs, DONE !"; //inf_fun = support = []; return FT_inf_fun; } func order_kls(kl,pupd,&cp,&ord,&sig,upto=) /* DOCUMENT order_kls(kl,pupd,&cp,&ord,&sig,upto=) kl is a datacube. Each plan is a map of a KL, computed with make_kl. The problem with make_kl is that the KL are ordered by eigenvalues, and as the same radial order has nearly equal eigenvalues, sometimes the order can change within a radial order. Here, we use the correlation with the zernike modes to re-order the KLs. upto: Only order up to this kl number. SEE ALSO: make_kl, zernike */ { // save current zernike state (might already be // initialized within yao for some other use. extern zdim,zr,zteta,zmask,zrmod,zmaskmod; zdim2 = zdim; zr2 = zr; zmask2 = zmask; zrmod2 = zrmod; zmaskmod2 = zmaskmod; local kl; nklmax = dimsof(kl)(0); dim = dimsof(kl)(2); if (upto==[]) upto = floor_to_radial_order_kl(nklmax); else upto = floor_to_radial_order_kl(min([upto,nklmax])); write,format="Ordering KLs up to #%d\n",upto; prepzernike,dim,pupd-1,dim/2+0.5,dim/2+0.5; w = where(zernike(1)); kll = kl(*,)(w,:upto); zern = array(float,numberof(w),upto); // +1 to cover exactly same radial order than kls. // -1 because we exclude piston. upto+1-1 = upto... for (i=1;i<=dimsof(zern)(0);i++) zern(,i) = zernike(i+1)(w); cp = zern(+,) * kll(+,); zern = kll = []; ord = sig = array(long,upto); for (i=1;i<=upto;i++) { ord(i) = wheremax(abs(cp(i,))); sig(i) = sign(cp(i,ord(i))); } // ord = abs(ord); // zeq = ord(mxx,); klo = kl; klo(,,1:upto) = klo(,,ord); klo(,,1:upto) = klo(,,1:upto)*sig(-,-,); // restore prepzernike zdim = zdim2; zr = zr2; zmask = zmask2; zrmod = zrmod2; zmaskmod = zmaskmod2; return klo; } func floor_to_radial_order_zernike(n) /* DOCUMENT floor_to_radial_order_zernike(n) Returns the largest number of zernike, lower or equal to n, that contain a full set of radial order. i.e. floor_to_radial_order_zernike(5) = 3 (piston, Tip, tilt) floor_to_radial_order_zernike(6) = 6 (up to astigmatism included) SEE ALSO: */ { i=nrad=0; do { nrad++; i += nrad; } while (n>=i); return i-nrad; } func floor_to_radial_order_kl(n) /* DOCUMENT floor_to_radial_order_kl(n) Similar to floor_to_radial_order_zernike, but for KLs. There is no piston in KLs, so kl(1)=tip In that sense it differs from floor_to_radial_order_zernike by one unit. SEE ALSO: */ { i=0; nrad=1; do { nrad++; i += nrad; } while (n>=i); return i-nrad; } func disp_kls(n,invert_background=) { n = floor_to_radial_order_kl(n); pup=[]; kl=make_kl(n,128,varkl,outbas,pup,oc=0.,nr=64); kl = order_kls(kl,128); fma; limits; limits,square=1; npo = (indgen(50)+1)(cum)(2:); // radial order limits // npo = [2,5,9,14,20,27,35,44,54,65... // pup = (kl(,,rms)!=0); x = y = 0; for (i=1;i<=n;i++) { klm = kl(,,i); if (invert_background) klm = (klm-max(klm))*pup; else klm = (klm-min(klm))*pup; pli,klm,x,y,x+0.9,y+0.9; x++; if (anyof(i==npo)) { y++; x = 0; } } l = limits(); range,l(4),l(3); } func disp_zernikes(n,invert_background=) { n = floor_to_radial_order_zernike(n); pup=[]; prepzernike,128,128,64.5,64.5; fma; limits; limits,square=1; npo = (indgen(50))(cum)(2:); // radial order limits // npo = [1,3,6,10,15,21,28,.. pup = zernike(1); x = y = 0; for (i=1;i<=n;i++) { zm = clip(zernike(i),-2.5,2.5); if (invert_background) zm = (zm-max(zm))*pup; else zm = (zm-min(zm))*pup; if (i==1) { if (invert_background) zm = -zernike(1); else zm = zernike(1); } pli,zm,x,y,x+0.9,y+0.9; x++; if (anyof(i==npo)) { y++; x = 0; } } l = limits(); range,l(4),l(3); } yao-5.4.0/yaopy.i000066400000000000000000000504731234404334100136320ustar00rootroot00000000000000/* * yaopy.i * * Main function to call the pygtk GUI to yao. * syntax: yorick -i yaopy.i [yaoparfile] * * This plugin requires yao.py and yao.glade. These are looked for, but * the path can be forced setting Y_PYTHON and Y_GLADE * * This file is part of the yao package, an adaptive optics simulation tool. * * Copyright (c) 2002-2013, Francois Rigaut * * 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 (to receive a copy of the GNU * General Public License, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA). * */ // PATH to yao.py and yao.glade: require,"pathfun.i"; Y_PYTHON = get_env("Y_PYTHON"); Y_GLADE = get_env("Y_GLADE"); Y_CONF = get_env("Y_CONF"); y_user = streplace(Y_USER,strfind("~",Y_USER),get_env("HOME")) if (noneof(Y_PYTHON)) \ Y_PYTHON="./:"+y_user+":"+pathform(_(y_user,Y_SITES,Y_SITE)+"python/"); if (noneof(Y_GLADE)) \ Y_GLADE="./:"+y_user+":"+pathform(_(y_user,Y_SITES,Y_SITE)+"glade/"); if (noneof(Y_CONF)) \ Y_CONF="./:"+y_user+":"+pathform(_(y_user,Y_SITES,Y_SITE)+"conf/"); // try to find yao.py path2py = find_in_path("yao.py",takefirst=1,path=Y_PYTHON); if (is_void(path2py)) { // not found. bust out write,format="Can't find yao.py in %s nor in %s\n",Y_PYTHON; error,"Aborting"; } path2py = dirname(path2py); write,format=" Found yao.py in %s\n",path2py; // try to find yao.glade path2glade = find_in_path("yao.glade",takefirst=1,path=Y_GLADE); if (is_void(path2glade)) { // not found. bust out write,format="Can't find yao.glade in %s nor in %s\n",Y_GLADE; error,"Aborting"; } path2glade = dirname(path2glade); write,format=" Found yao.glade in %s\n",path2glade; require,"pyk.i"; require,"yao.i"; // set default save path YAO_SAVEPATH=Y_USER+"yao/"; // try to find yao.conf path2conf = find_in_path("yao.conf",takefirst=1,path=Y_CONF); if (!is_void(path2conf)) { path2conf = dirname(path2conf)+"/"; write,format=" Found and included yao.conf in %s\n",path2conf; require,path2conf+"yao.conf"; } yaopy=1; // used in yao.i to know if using pygtk GUI if (pyk_debug==[]) pyk_debug=0; //sleep=200; if (default_dpi==[]) default_dpi=70; dpi = default_dpi; initdone=0; func yaopy_quit(void) { pyk,"gtk.main_quit()"; write,"<< Python interface exited, quitting >>"; quit; } func read_conf(void) { include,path2conf+"yao.conf",1; mkdirp,YAO_SAVEPATH; } func save_conf(void) { extern path2conf; if (is_void(path2conf)) path2conf=Y_USER; if (catch(0x02)) { pyk_error,swrite(format="Can not create %syao.conf. Permission problem?",path2conf); return; } mkdirp,Y_USER; f=open(path2conf+"yao.conf","w"); write,f,"/* yao.conf"; write,f," * this file is included by yaopy.i"; write,f," * definition of the path and possibly other variables"; write,f," * e.g. pyk_debug=1"; write,f," */"; // write,f,"extern YAO_SAVEPATH;\n"; write,f,format="YAO_SAVEPATH=\"%s\";\n",YAO_SAVEPATH; close,f; write,format="Configuration saved in %syao.conf\n",path2conf; gui_message,swrite(format="Configuration saved in %syao.conf",path2conf); mkdirp,YAO_SAVEPATH; } func yao_win_init(parent_id) { extern yao_pyk_parent_id; // above: for further use if we need to reopen the graphic window yao_pyk_parent_id = parent_id; window,0,style="yao.gs",dpi=dpi,width=long(635*(dpi/75.)), \ height=long(650*(dpi/75.)),wait=1,parent=parent_id,xpos=-2,ypos=-2; if ( (xft!=[]) && (xft()) ) { get_style, landscape, systems, legends, clegends; systems.ticks.vert.textStyle.height(4)*=1.5; systems.ticks.horiz.textStyle.height(4)*=1.5; set_style, landscape, systems, legends, clegends; } } func wrap_create_phase_screens(void) { if (atm) prefix=dirname((*atm.screen)(1)); else prefix=Y_USER+"data"; if (catch(0x02)) { pyk_error,swrite(format="Can not create %s. Permission problem?",prefix); clean_progressbar; pyk,"set_cursor_busy(0)"; return; // error,swrite(format="Can not create %s. Permission problem?",prefix); } mkdirp,prefix; l=2048; w=256; gui_message,swrite(format="Creating phase screens %dx%d in %s",l,w,prefix); write,format="Creating phase screens %dx%d in %s",l,w,prefix; create_phase_screens,2048,256,prefix=prefix+"/screen"; gui_message,swrite(format="Done: Phase screens created in %s",prefix); write,format="Done: Phase screens created in %s\n",prefix; pyk,"set_cursor_busy(0)"; } func clean_progressbar(void) { gui_progressbar_text,""; gui_progressbar_frac,0.; } func gui_progressbar_frac(frac) { pyk,swrite(format="progressbar.set_fraction(%f)",float(clip(frac,0.,1.))); } func gui_progressbar_text(text) { pyk,swrite(format="progressbar.set_text('%s')",text); } func gui_message(msg) { pyk,swrite(format="statusbar.push(1,'%s')",msg); } func gui_message1(msg) { pyk,swrite(format="statusbar1.push(1,'%s')",msg); } statusbar1_visible=0; func gui_show_statusbar1(void) { extern statusbar1_visible; if (statusbar1_visible) return; pyk,"statusbar1.show()"; statusbar1_visible=1; } func gui_hide_statusbar1(void) { extern statusbar1_visible; if (!statusbar1_visible) return; pyk,"statusbar1.hide()"; statusbar1_visible=0; } func okvec2str(okvec) { if (allof(okvec == 0)) return "-1"; return "["+strtrim(strJoin(swrite(format="%d",where(okvec)),","))+"]"; } // wrapper functions func set_aoinit_flags(disp,clean,forcemat,svd,keepdmconfig) { extern aoinit_disp,aoinit_clean,aoinit_forcemat,aoinit_svd,aoinit_keepdmconfig; aoinit_disp=disp; aoinit_clean=clean; aoinit_forcemat=forcemat; aoinit_svd=svd; aoinit_keepdmconfig=keepdmconfig; } func set_aoloop_flags(disp,savecb,reinit) { extern aoloop_disp,aoloop_savecb,aoloop_no_reinit_wfs; aoloop_disp=disp; aoloop_savecb=savecb; aoloop_no_reinit_wfs=reinit; } func set_loop_gain(gain) { extern loop; loop.gain=gain; } func toggle_im_imav(imavg) { extern dispImImav; if (imavg) dispImImav=imavg; else dispImImav=1-dispImImav; } func change_target_lambda(lambda) { extern target; (*target.lambda)(0)=lambda; if (target._ntarget==1) { *target.dispzoom=(*target.lambda)(0)*1e-6/4.848e-6/tel.diam*sim.pupildiam/2; disp2d,im,*target.xposition,*target.yposition,1,zoom=*target.dispzoom,init=1,nolimits=1; } } func change_zenith_angle(zen) { extern gs; gs.zenithangle=zen; aoinit; } func change_dr0(dr0) { extern atm; atm.dr0at05mic=dr0; if (initdone) get_turb_phase_init; } func change_seeing(seeing) { //seeing at 550 (V band) if (seeing>0) { r0at500 = (0.500e-6/seeing/4.848e-6)*(500./550.)^0.2; atm.dr0at05mic = tel.diam/r0at500; // propagate to child if svipc: if (set_dr0!=[]) set_dr0,atm.dr0at05mic; } else atm.dr0at05mic = 0.; if (initdone) get_turb_phase_init; } func do_inter_disp(void) { do_imat,disp=1,sleep=sleep; } func do_aoinit_disp(void) { stop; // in case we are running another loop. aoinit,dpi=default_dpi; pyk,"set_cursor_busy(0)"; } func do_aoloop_disp(disprate) { aoloop,dpi=default_dpi,disp=disprate; plsys,1; animate,0; animate,1; pyk,"set_cursor_busy(0)"; } func toggle_animate(state) { // now done from stop/cont // plsys,1; // if (state==0) fma; // if (state!=[]) animate,state; else animate; } func set_okdm(dmnum,ok) { extern okdm,okwfs; okdm(dmnum)=ok; if (sum(okdm)==0) pyk,"dm_panel_set_sensitivity(0)"; else pyk,"dm_panel_set_sensitivity(1)"; pyk,"yo2py_flush"; } func set_okwfs(wfsnum,ok) { extern okdm,okwfs; extern wfs; okwfs(wfsnum)=ok; if (sum(okwfs)==0) { pyk,"wfs_panel_set_sensitivity(0,0)"; } else { w1 = where(okwfs)(1); if (wfs(w1).type=="hartmann") pyk,"wfs_panel_set_sensitivity(1,1)"; \ else if (wfs(w1).type=="curvature") pyk,"wfs_panel_set_sensitivity(1,2)"; else if (wfs(w1).type=="pyramid") pyk,"wfs_panel_set_sensitivity(1,3)"; gui_update_wfs,w1; } // usleep,50 pyk,"yo2py_flush"; } func dm_reset(void) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) dm(i)._command=&((*dm(i)._command)*0.f); } wfsMesHistory*=0.0f; } func dm_flatten(void) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) dm(i)._command=&((*dm(i)._command)*0.f); } } func dm_hyst(hystval) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) dm(i).hyst=hystval/100.; } } func dm_gain(gainval) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) dm(i).gain=gainval; } } func dm_xmisreg(xmisreg) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) { dm(i).misreg(1)=xmisreg*sim.pupildiam; } } } func dm_ymisreg(ymisreg) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) { dm(i).misreg(2)=ymisreg*sim.pupildiam; } } } func dm_satvolt(satvolt) { extern okdm,okwfs; extern dm; if (noneof(okdm)) return; for (i=1;i<=ndm;i++) { if (okdm(i)) { dm(i).maxvolt=satvolt; } } } func set_wfs_noise(nse) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) { if (okwfs(i)) wfs(i).noise=nse; } } func set_gs_alt(gsalt) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; wfsvec = where(okwfs); wfs(wfsvec).gsalt=wfs(wfsvec).gsalt*0+gsalt; if (initdone) { get_turb_phase_init,skipReadPhaseScreens=1; for(ll=1;ll<=nwfs;ll++) { if (wfs(ll).disjointpup) { shwfs_init,disjointpup(,,ll),ll,silent=1; } else shwfs_init,ipupil,ll,silent=1; } } } func set_gs_depth(gsdepth) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; wfsvec = where(okwfs); wfs(wfsvec).gsdepth=wfs(wfsvec).gsdepth*0+gsdepth; if (initdone) { get_turb_phase_init,skipReadPhaseScreens=1; for(ll=1;ll<=nwfs;ll++) { if (wfs(ll).disjointpup) { shwfs_init,disjointpup(,,ll),ll,silent=1; } else shwfs_init,ipupil,ll,silent=1; } } } func set_gs_mag(gsmag) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) { if (okwfs(i)) { wfs(i).gsmag=gsmag; if (initdone) { if (wfs(i).type=="curvature") curv_wfs,,,i,init=1,disp=0,silent=1; else if (wfs(i).type=="hartmann") { if (wfs(i).disjointpup) { shwfs_init,disjointpup(,,i),i,silent=1; } else shwfs_init,ipupil,i,silent=1; } } } } } func set_wfs_ron(ron) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) if (okwfs(i)) wfs(i).ron=ron; } func wfs_subtract_background(state) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; wfsvec = where(okwfs); wfs(wfsvec)._bckgrdsub=state; } func wfs_set_uptt(state) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; wfsvec = where(okwfs); wfs(wfsvec).correctUpTT=state; } func set_wfs_kernel(value) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; wfsvec = where(okwfs); wfs(wfsvec).kernel=wfs(wfsvec).kernel*0+value; if (initdone) { for(ll=1;ll<=nwfs;ll++) { if (wfs(ll).disjointpup) { shwfs_init,disjointpup(,,ll),ll,silent=1; } else shwfs_init,ipupil,ll,silent=1; } } } func set_wfs_threshold(threshold) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) if (okwfs(i)) wfs(i).shthreshold=threshold; } func set_wfs_nintegcycles(nic) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) if (okwfs(i)) wfs(i).nintegcycles=nic; } func set_wfs_efd(efd) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) { if (okwfs(i)) { wfs(i).l=efd; if (initdone) curv_wfs,,,i,init=1,disp=0,silent=1; } } } func set_wfs_pyr_mod(pyr_mod) { extern okdm,okwfs; extern wfs; if (noneof(okwfs)) return; for (i=1;i<=nwfs;i++) { if (okwfs(i)) { wfs(i).pyr_mod_ampl=pyr_mod; // if (initdone) curv_wfs,,,i,init=1,disp=0,silent=1; } } } func gui_update_wfs(num) { pyk,swrite(format="y_set_checkbutton('subtract_background',%d)",long(wfs(num)._bckgrdsub)); pyk,swrite(format="y_set_checkbutton('noise',%d)",long(wfs(num).noise)); pyk,swrite(format="y_set_checkbutton('correct_up_tt',%d)",long(wfs(num).correctUpTT)); pyk,swrite(format="y_parm_update('efd',%f)",float(wfs(num).l)); pyk,swrite(format="y_parm_update('pyr_mod',%f)",float(wfs(num).pyr_mod_ampl)); pyk,swrite(format="y_parm_update('gsmag',%f)",float(wfs(num).gsmag)); pyk,swrite(format="y_parm_update('gsalt',%f)",float(wfs(num).gsalt)); pyk,swrite(format="y_parm_update('gsdepth',%f)",float(wfs(num).gsdepth)); pyk,swrite(format="y_parm_update('ron',%f)",float(wfs(num).ron)); pyk,swrite(format="y_parm_update('sh_threshold',%f)",float(wfs(num).shthreshold)); pyk,swrite(format="y_parm_update('sh_kernel',%f)",float(wfs(num).kernel)); pyk,swrite(format="y_parm_update('ninteg_cycles',%f)",float(wfs(num).nintegcycles)); } record_shot=0; window3_created=0; func plot_mtf(i,init=) { extern mtf_reference,mtf_airy,record_shot; extern airy,window3_created; if (init) { if (window3_created==0) { dimwin=450*default_dpi/80; window,3,height=dimwin,width=dimwin,dpi=default_dpi,wait=1; window3_created=1; } window,0; mtf=eclat(abs(fft(airy,1))); mtf=cart2pol(mtf); mtf=mtf/mtf(1); mtf_airy=mtf(,avg); return; } if (dispImImav==2) { mtf=eclat(abs(fft(imav(,,1),1))); } else { mtf=eclat(abs(fft(im(,,1),1))); } mtf=cart2pol(mtf); if (mtf(1)==0) return; mtf=mtf/mtf(1); if (record_shot) { mtf_reference=mtf(,avg); record_shot=0; } window,3; fma; plg,mtf(,avg); range,0.,1.; if (mtf_reference!=[]) plg,mtf_reference,color="red"; plg,mtf_airy,color="green"; xytitles,"spatial frequency","MTF"; window,0; } func toggle_userplot_mtf { extern user_plot; if (user_plot!=[]) user_plot=[]; else { user_plot=plot_mtf; plot_mtf,init=1; } } func plot_dphi(i,init=) { extern dphi_reference,mtf_airy,dphi_atmos,record_shot; extern airy,imax,dphi_x,window3_created; if (init) { if (window3_created==0) { dimwin=450*default_dpi/80; window,3,height=dimwin,width=dimwin,dpi=default_dpi,wait=1; window3_created=1; } window,0; mtf=eclat(abs(fft(airy,1))); mtf=cart2pol(mtf); mtf=mtf/mtf(1); mtf_airy=mtf(,avg); imax=max(where(mtf_airy>1e-5)); dphi_x=span(0.,tel.diam,imax); clip,mtf_airy,1e-5,; dphi_atmos=6.88*(dphi_x/tel.diam*atm.dr0at05mic*0.5/(*target.lambda)(0))^1.666; return; } if (dispImImav==2) { mtf=eclat(abs(fft(imav(,,1),1))); } else { mtf=eclat(abs(fft(im(,,1),1))); } mtf=cart2pol(mtf); if (mtf(1)==0) return; mtf=mtf/mtf(1); mtf=mtf(,avg); mtf=mtf/mtf_airy; dphi=-2*log(mtf); if (record_shot) { dphi_reference=dphi; record_shot=0; } window,3; fma; plg,dphi(1:imax),dphi_x; range,0.,10.; if (dphi_reference!=[]) plg,dphi_reference,color="red"; plg,dphi_atmos,dphi_x,color="green"; xytitles,"separation","Dphi"; window,0; } func toggle_userplot_dphi { extern user_plot; if (user_plot!=[]) user_plot=[]; else { user_plot=plot_dphi; plot_dphi,init=1; } } func wrap_aoread(void) { extern wfstype; stop; // in case we are running another loop. aoread,yaopardir+"/"+yaoparfile; gui_update; // usleep,100; // why do I have to do that for it to work ???? pyk,"set_aoinit_flags()"; pyk,"set_aoloop_flags()"; pyk,"set_cursor_busy(0)"; wfstype=0; if (wfs(1).type=="curvature") wfstype = 1; if (wfs(1).type=="hartmann") wfstype = 2; if (wfs(1).type=="pyramid") wfstype = 3; // pyk,swrite(format="wfs_panel_set_sensitivity(1,%d)",wfstype); // pyk,"dm_panel_set_sensitivity(1)"; } func gui_update(void) { extern dispImImav,okdm,okwfs; pyk,swrite(format="pyk_debug = %d",pyk_debug); pyk,swrite(format="glade.get_widget('debug').set_active(%d)",pyk_debug); if (is_void(path2conf)) save_conf; write,format="Results will be saved in %s\n",YAO_SAVEPATH; gui_message,swrite(format="Results will be saved in %s",YAO_SAVEPATH); require,"string.i"; pyk,swrite(format="yuserdir = '%s'",streplace(Y_USER,strfind("~",Y_USER),get_env("HOME"))); pyk,swrite(format="yaopardir = '%s'",yaopardir); if (strlen(yaoparfile)) { pyk,swrite(format="y_text_parm_update('yaoparfile','%s')",yaoparfile); pyk,swrite(format="yaoparfile = '%s'",yaoparfile); } else { pyk,"glade.get_widget('aoread').set_sensitive(0)"; } // usleep,100; // why do I have to do that for it to work ???? // pyk,"yo2py_flush"; if (wfs==[]) return; // then aoread has not yet occured. sim.debug=0; dispImImav = 1; ditherAmp = 0.1; ditherPeriod = 10; disp = 10; // wfsMesHistory = 0; for (i=1;i<=ndm;i++) {dm(i)._command = &([0]);} okwfs = array(0.,nwfs); okdm = array(0.,ndm); // pyk,swrite(format="nwfs=%d",nwfs); r0at500 = tel.diam/atm.dr0at05mic; seeing = (0.500e-6/r0at500/4.848e-6)*(500./550.)^0.2; pyk,"glade.get_widget('edit').set_sensitive(1)"; pyk,"glade.get_widget('aoread').set_sensitive(1)"; // pyk,"glade.get_widget('aoread').grab_focus()"; pyk,swrite(format="y_text_parm_update('yaoparfile','%s')",yaoparfile); pyk,swrite(format="window.set_title('%s')",yaoparfile); pyk,swrite(format="y_parm_update('seeing',%f)",float(seeing)); pyk,swrite(format="y_parm_update('loopgain',%f)",float(loop.gain)); pyk,swrite(format="y_parm_update('imlambda',%f)",float((*target.lambda)(0))); gui_update_wfs,1; pyk,swrite(format="y_parm_update('dmgain',%f)",float(dm(1).gain)); pyk,swrite(format="y_parm_update('xmisreg',%f)",float(dm(1).misreg(1))); pyk,swrite(format="y_parm_update('ymisreg',%f)",float(dm(1).misreg(2))); pyk,swrite(format="y_set_ndm(%d)",ndm); pyk,swrite(format="y_set_nwfs(%d)",nwfs); // usleep,100; // why do I have to do that for it to work ???? pyk,swrite(format="y_parm_update('sat_voltage',%f)",float(dm(1).maxvolt)); /* tyk,"set ndm "+swrite(format="%d",ndm); tyk,"set centg "+swrite(format="%d",wfs(1).centGainOpt); tyk,"set hyst "+swrite(format="%f",dm(1).hyst); */ // pyk,"set_cursor_busy(0)"; } func pyk_info(msg) { if (numberof(msg)>1) msg=sum(msg+"\\n"); // or streplace(msg,strfind("\n",msg),"\\n") pyk,swrite(format="pyk_info('%s')",msg) } func pyk_info_w_markup(msg) { if (numberof(msg)>1) msg=sum(msg+"\\n"); // or streplace(msg,strfind("\n",msg),"\\n") pyk,swrite(format="pyk_info_w_markup('%s')",msg) } func pyk_error(msg) { if (numberof(msg)>1) msg=sum(msg+"\\n"); pyk,swrite(format="pyk_error('%s')",msg) } func pyk_warning(msg) { if (numberof(msg)>1) msg=sum(msg+"\\n"); pyk,swrite(format="pyk_warning('%s')",msg) } arg = get_argv(); if (numberof(arg)>=4) { if (anyof((w=strmatch(arg,"--dpi")))) { w = where(w)(0); sread,arg(w+1),default_dpi; dpi = default_dpi; } yaoparfile = arg(0); yaopardir = dirname(yaoparfile); if (yaopardir==".") yaopardir=get_cwd(); yaoparfile = basename(yaoparfile); if (noneof(findfiles(yaopardir+"/"+yaoparfile))) error,"Can't find "+yaoparfile; // aoread,yaoparfile; } else { yaoparfile=""; parpath="./:"+pathform(_(Y_USER,Y_SITES,Y_SITE)); tmp = find_in_path("sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("data/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) tmp=find_in_path("share/yao/examples/sh6x6.par",takefirst=1,path=parpath); if (tmp==[]) { parpath="/usr/share/doc/yorick-yao/examples/"; tmp = find_in_path("sh6x6.par",takefirst=1,path=parpath); } if (tmp!=[]) yaopardir = dirname(tmp); else yaopardir=get_cwd(); } // spawned gtk interface python_exec = path2py+"/yao.py"; pyk_cmd=[python_exec, \ swrite(format="%s",path2glade), \ swrite(format="%d",long(default_dpi))]; // span the python process, and hook to existing _tyk_proc (see pyk.i) _pyk_proc = spawn(pyk_cmd, _pyk_callback); yao-5.4.0/yorick_yao.fedora.spec000066400000000000000000000056331234404334100166000ustar00rootroot00000000000000%define name yorick-yao %define version 4.8.3 %define release gemini2010sep16 Summary: yorick adaptive optics simulation package Name: %{name} Version: %{version} Release: %{release} Source0: %{name}-%{version}.tar.bz2 License: BSD Group: Applications/Engineering Packager: Francois Rigaut Url: http://www.maumae.net/yorick/doc/plugins.php BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot Requires: yorick >= 2.1 yorick-imutil >= 0.5 yorick-yutils >= 1.0 fftw %description Multi-usage adaptive optics Monte-Carlo simulation package. Can simulate versatile configs (classical, LGS, GLAO, MCAO) with Shack-Hartmann or curvature sensors. Fast. From version 4.0, yao has now a gtk interface. %prep %setup -q %build yorick -batch make.i make if [ -f check.i ] ; then mv check.i %{name}_check.i fi; %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/lib mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/i0 mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/i mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/g mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/glade mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/python mkdir -p $RPM_BUILD_ROOT/usr/share/doc/yorick-yao mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1 mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/packages/installed install -m 755 yao.so $RPM_BUILD_ROOT/usr/lib/yorick/lib install -m 755 yao $RPM_BUILD_ROOT/usr/bin install -m 644 yao_fast.i $RPM_BUILD_ROOT/usr/lib/yorick/i0 install -m 644 yao_utils.i $RPM_BUILD_ROOT/usr/lib/yorick/i0 install -m 644 *.i $RPM_BUILD_ROOT/usr/lib/yorick/i install -m 644 *.gs $RPM_BUILD_ROOT/usr/lib/yorick/g install -m 644 yao.glade $RPM_BUILD_ROOT/usr/lib/yorick/glade install -m 755 yao.py $RPM_BUILD_ROOT/usr/lib/yorick/python install -m 644 LICENSE $RPM_BUILD_ROOT/usr/share/doc/yorick-yao install -m 644 README $RPM_BUILD_ROOT/usr/share/doc/yorick-yao install -dm 755 examples $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 examples/*.par $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 examples/*.i $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 755 examples/testclean $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 doc/yao.1 $RPM_BUILD_ROOT/usr/share/man/man1 install -m 644 yao.info $RPM_BUILD_ROOT/usr/lib/yorick/packages/installed rm $RPM_BUILD_ROOT/usr/lib/yorick/i/yao_fast.i rm $RPM_BUILD_ROOT/usr/lib/yorick/i/yao_utils.i %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/lib/yorick/lib/yao.so /usr/bin/yao /usr/lib/yorick/i0/*.i /usr/lib/yorick/i/*.i /usr/lib/yorick/g/*.gs /usr/lib/yorick/glade/yao.glade /usr/lib/yorick/python/yao.py* /usr/share/doc/yorick-yao /usr/share/man/man1 /usr/lib/yorick/packages/installed/* %changelog * Tue Jan 09 2008 - included the info file for compat with pkg_mngr * Mon Dec 31 2007 - new distro directory structure - updated to cvs yao-5.4.0/yorick_yao.mandriva.spec000066400000000000000000000056411234404334100171400ustar00rootroot00000000000000%define name yorick-yao %define version 4.8.3 %define release gemini2010sep16 Summary: yorick adaptive optics simulation package Name: %{name} Version: %{version} Release: %{release} Source0: %{name}-%{version}.tar.bz2 License: BSD Group: Applications/Engineering Packager: Francois Rigaut Url: http://www.maumae.net/yorick/doc/plugins.php BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot Requires: yorick >= 2.1 yorick-imutil >= 0.5 yorick-yutils >= 1.0 libfftw3 %description Multi-usage adaptive optics Monte-Carlo simulation package. Can simulate versatile configs (classical, LGS, GLAO, MCAO) with Shack-Hartmann or curvature sensors. Fast. From version 4.0, yao has now a gtk interface. %prep %setup -q %build yorick -batch make.i make if [ -f check.i ] ; then mv check.i %{name}_check.i fi; %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/lib mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/i0 mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/i mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/g mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/glade mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/python mkdir -p $RPM_BUILD_ROOT/usr/share/doc/yorick-yao mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1 mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/packages/installed install -m 755 yao.so $RPM_BUILD_ROOT/usr/lib/yorick/lib install -m 755 yao $RPM_BUILD_ROOT/usr/bin install -m 644 yao_fast.i $RPM_BUILD_ROOT/usr/lib/yorick/i0 install -m 644 yao_utils.i $RPM_BUILD_ROOT/usr/lib/yorick/i0 install -m 644 *.i $RPM_BUILD_ROOT/usr/lib/yorick/i install -m 644 *.gs $RPM_BUILD_ROOT/usr/lib/yorick/g install -m 644 yao.glade $RPM_BUILD_ROOT/usr/lib/yorick/glade install -m 755 yao.py $RPM_BUILD_ROOT/usr/lib/yorick/python install -m 644 LICENSE $RPM_BUILD_ROOT/usr/share/doc/yorick-yao install -m 644 README $RPM_BUILD_ROOT/usr/share/doc/yorick-yao install -dm 755 examples $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 examples/*.par $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 examples/*.i $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 755 examples/testclean $RPM_BUILD_ROOT/usr/share/doc/yorick-yao/examples install -m 644 doc/yao.1.gz $RPM_BUILD_ROOT/usr/share/man/man1 install -m 644 yao.info $RPM_BUILD_ROOT/usr/lib/yorick/packages/installed rm $RPM_BUILD_ROOT/usr/lib/yorick/i/yao_fast.i rm $RPM_BUILD_ROOT/usr/lib/yorick/i/yao_utils.i %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/lib/yorick/lib/yao.so /usr/bin/yao /usr/lib/yorick/i0/*.i /usr/lib/yorick/i/*.i /usr/lib/yorick/g/*.gs /usr/lib/yorick/glade/yao.glade /usr/lib/yorick/python/yao.py /usr/share/doc/yorick-yao /usr/share/man/man1 /usr/lib/yorick/packages/installed/* %changelog * Tue Jan 09 2008 - included the info file for compat with pkg_mngr * Mon Dec 31 2007 - new distro directory structure - updated to cvs yao-5.4.0/yorick_yao.spec000066400000000000000000000046231234404334100153370ustar00rootroot00000000000000%define name yorick_yao %define version 4.8.3 %define release 01gemini %define yorick_version 2.2 Summary: yorick adaptive optics simulation package Name: %{name} Version: %{version} Release: %{release} Source0: %{name}-%{version}.tar.bz2 License: BSD Group: Development/Languages Applications/Engineering Packager: Francois Rigaut Url: http://www.maumae.net/yorick/doc/plugins.php BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot Requires: yorick = %{yorick_version} yorick_imutil >= 0.5 yorick_utils >= 1.0 libfftw3 %description Multi-usage adaptive optics Monte-Carlo simulation package. Can simulate versatile configs (classical, LGS, GLAO, MCAO) with Shack-Hartmann or curvature sensors. Fast. From version 4.0, yao has now a gtk interface. %prep %setup -q %build yorick -batch make.i make if [ -f check.i ] ; then mv check.i %{name}_check.i fi; %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/lib mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/bin mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/i0 mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/g mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/glade mkdir -p $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/python mkdir -p $RPM_BUILD_ROOT/usr/share/doc mkdir -p $RPM_BUILD_ROOT/usr/bin install -dm 755 examples $RPM_BUILD_ROOT/usr/share/yao/examples install -m 644 examples/*.par $RPM_BUILD_ROOT/usr/share/yao/examples install -m 644 examples/*.i $RPM_BUILD_ROOT/usr/share/yao/examples install -m 755 examples/testclean $RPM_BUILD_ROOT/usr/share/yao/examples install -m 755 yao.so $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/lib install -m 644 *.i $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/i0 install -m 644 *.gs $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/g install -m 644 yao.glade $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/glade install -m 755 yao.py $RPM_BUILD_ROOT/usr/lib/yorick/%{yorick_version}/python install -m 644 README $RPM_BUILD_ROOT/usr/share/yao install -m 755 yaogtk $RPM_BUILD_ROOT/usr/bin %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/lib/yorick/%{yorick_version}/lib/yao.so /usr/bin/yaogtk /usr/lib/yorick/%{yorick_version}/i0/*.i /usr/lib/yorick/%{yorick_version}/g/*.gs /usr/lib/yorick/%{yorick_version}/glade/yao.glade /usr/lib/yorick/%{yorick_version}/python/yao.py /usr/share/yao %changelog