pax_global_header00006660000000000000000000000064122020041160014476gustar00rootroot0000000000000052 comment=0ef845a04f57cbd8f9ada5ca658c62055ba9b3ae tilem-2.0/000077500000000000000000000000001220200411600124515ustar00rootroot00000000000000tilem-2.0/CHANGELOG000066400000000000000000000507571220200411600137010ustar00rootroot00000000000000/* This file only contains the changelog for the gui/doc/data, some things could be missing (core changes...)*/ /* This changelog was started when I started to work on TilEm2 */ /* contra-sh : * ---18/08/09--- * - Draw the TI83 * - Copy from testemu.c : Create the savname, Open the Rom, Get the model, Draw the lcdscreen (no animation for the moment) * - Function event OnDestroy * - Modification of the Makefile (I hope it's good !? If you can control this... thx) * - LEARNING HOW COMMIT !! :D * ---19/08/09--- * - New structure TilemCalcSkin : define the different filenames for the SkinSet (4 pieces). * - Draw the other models _automatically_ . ;D * ---20/08/09--- * - Create skin.c * - Create gui.h (equivalent of tilem.h for the gui directory) * - Move the code struct in gui.h and TilemCalcSkin* tilem_guess_skin_set(TilemCalc* calc) into skin.c (only one call in the main file to define the skin set) ;D * - Detect a keyboard event (function keyboard_event() in skin.c actually).No treatment. * - Detect an event click on mouse * ---21/08/09--- * - Get the x and y values when click on mouse (now it will be easy to know how key is click on the pixmap, todo in priority : detect right click) * ---24/08/09--- * - Detect right click. * ---26/08/09--- * - New function : TilemKeyMap* tilem_guess_key_map(int id).Choose a TilemKeyMap with an id given in parameter. * ---27/08/09--- * - Extract the choice of the key_map from the mouse_event function.Execute only one time and it's more properly (and it will be easier to add the possibility to manage many skins and many keymaps). * ---01/09/09--- * - Choose automatically the key_list. The TilemKeyList is already included in the TilemKeyMap structure... * - New structure TilemKeyCoord (old TilemKeyMap).TilemKeyMap already contains TilemKeyCoord and TilemKeyList... * ---08/09/09--- * - New function tilem_set_coord to change the keypad coord. * - New file event.c to group the GDKevent handling. * - New function tilem_set_skin to change the skin. * ---10/09/09--- * - Add the right click menu :D (0 signal connected without OnDestroy).Largely inspired from Tilem 0.973 and http://www.linux-france.org/article/devl/gtk/gtk_tut-11.html was a great inspiration too. * ---21/09/09--- * - Aouch I had seen that the left click doesn't work now! Problem : two callback for the only one button_press_event. (sorry for this version...) * ---22/09/09--- * - Correction : only one callback now. mouse_event contains the create_menu and the gtk_menu_popup. (lot of time was spent on this problem)* * ---23/09/09--- * - Change TilemKeyCoord to the 82 stats skin.Change Event.c too. * ---06/10/09--- * - Beginning the correction : change the method for testing coordinates clicks (one line now) . The coordinates will be imported from a file soon. * ---20/11/09--- * - After 1 week to learn Tiemu skin format...I have made my own Tilem skin Generator.Inspired from skinedit.It just generate compatible file with 0 coordinates values, and an default lcd coordinates.Not really necessary but very useful for testing and for learning how this f****** skin format works.It will be called skintool for the moment. * ---27/11/09--- * - After blocking a problem for a week grrr... I succeed to adapt the TiEmu skinloader to TilEm (skinops.c and skinops.h).Little modifications * ---28/11/09--- * - The mouse_event function now use a SKIN_INFOS struct. So delete TilemKeyCoord struct. * ---02/12/09--- * - Add a GtkFileSelection (access by right click menu) and try to load another skin with this method. * ---03/12/09--- * - Create a GLOBAL_SKIN_INFOS that contains a KEY_LIST struct (old TilemKeyList) and a SKIN_INFOS struct. * ---04/12/09--- * - Delete the TilemKeyCoord, TilemKeyMap, TilemCalcSkin and TilemKeyList structs... * ---05/12/09--- * - The GtkWidget *pWindow creation was moved from testemu2.c to event.c .The function is called GtkWidget* Draw_Screen(GLOBAL_SKIN_INFOS *gsi); * ---07/12/09--- * - New feature : TilEm could load a skin by the right_click_menu ! It use GtkWidget* ReDraw_Screen(GLOBAL_SKIN_INFOS *gsi) in event.c. WAOUH ! * ---08/12/09--- * - Move Draw_Screen, ReDraw_Screen and create_menus in a new screen.c file. Change Makefile. * ---14/12/09--- * - New feature : add a popup rom type selector (radio button) at the start of tilem. Showed but not used for the moment. * - Connect the thread (no animation yet). Thanks to the "battle programming" 's spirit (hey bob ^^) * ---18/12/09--- * - Launch the interactivity with emulation core. Could print into the draw area. * ---09/03/10--- * - Restart working on this program ;D * ---11/03/10--- * - I finally succeeded to connect the core. To print something into the lcd screen ! WahoOO ! This day is a great day ! * - I succeded to type numbers etc... * - And now it works very well !! (the "button-release-event" is not catched by pWindow but by pLayout) * ---15/03/10--- * - Create the scan_click function.Return wich keys was clicked.Print debug infos. * - Create the debuginfos.h to group the ifdef for debugging. (different level and different type of debug msg) * ---17/03/10--- * - Create the rom_choose_popup function to replace choose_rom_type.It use GtkDialog instead of GtkWindow. * - rom_choose_popup _freeze_ the system... and get wich radio button is selected. So it will be easy to create the good emu.calc (and choose the default skin). * ---18/03/10--- * - Resize the (printed) lcd area (gsi->emu->lcdwin) to fit(perfectly) into the skin. * - Replace a lot of printf by D****_L*_A* to easily switch what debug infos were printed. * - Try to make a nice debugging output (frames in ASCII ^^) :p * - WahooOO , load a skin works perfectly.You can easily change skin _while running_, no error, no warning. * - Could load automatically the good skin and run the good core using the choose_rom_popup() function and choose_skin_filename() function. * ---30/03/10--- * - Create skin for following models : 73, 81, 82, 83+ and 84+. * - Fix bug in tool.c .Modification of tool.c to create radio button more properly. * ---31/03/10--- * - Create skin for following model : 83 . Based on my own calc (take a foto with my iphone 3GS :D) * ---01/04/10--- * - New feature : Save calc state and load state. State are stored in a separate dir called sav/ . (using benjamin 's function) * - New feature : Change view to see only the lcd. I finally choose to add it into a GtkLayout. So you can maximize it, but there was problem with add_event. * ---02/04/10--- * - Add popup function to just print error message.You must give the message and gsi as parameter, and it run a modal dialog. * - Some cleaning. * ---23/04/10--- * - Add config.c file to manage config.dat (create, read, modif etc...). * ---31/05/10--- * - Start from scratch a totally new debugger :D.Just draw button with nice GtkImages.Actually in essai2 directory. * - Get and resize pixmaps (png) to 36 * 36 pixels for the debugger. * ---01/06/10--- * - Add the debugger to tilem. Load registers values. * - Add a new feature : switch the top level window "borderless".It can be switch by clicking on right click menu entry. * ---02/06/10--- * - Create the GtkTreeView (debugger). * - Refresh register on click. * ---05/08/10--- * - More than one month without working on tilem...Only commit old modif, and skn/README file. * - Refresh stack on click (number of entry is correct but value not) * ---06/08/10--- * - Working on a new system of configuration file.The config.dat is now a binary file (as .skn but totally differennt). At start, a CONFIG_INFOS struct is filling, then when clicking on right menu, this struct is modified, then when you stop tilem, config.dat is writed on disc. * ---09/08/10--- * - Correction of the SEG_FAULT (never use sizeof(char*) inside malloc, strlen(char*) is better :P). * ---10/08/10--- * - Working on a new config file called romconfig.dat (inspired from config.dat) using to do not ask for model each time tilem is started. * - It works :D * ---12/08/10--- * - NEW feature : Can load a file using libticalcs2 (inspired from the wokr of Benjamin Moody). Basically it works, but it's not OK. (many bugs) * - Drop the deprecated GtkFileSelection.Use GtkFileChooser instead. :) * ---13/08/10--- * - NEW feature : Add the screenshot feature. * ---17/08/10--- * - Change the ti84plus.skn (old was really ugly). * - Add doc/ directory : add romconfig_file_format.txt and skinconfig_file_format.txt. * ---18/08/10--- * - Correct the bug in link.c (unlock mutex ...) * - Start working on macro handling : Always do the same things to load and launch a file into an emulator become quickly noisy for the programmer (1 time, 10 times, 30 times, 50 times...argh!). Simply record a sequence and play it to test a program, this is one solution. (feature request from Guillaume Hoffman gh@gmail.com). * ---19/08/10--- * - The macro feature works including loading file (very important). The implementation is very basic (record and read a text file) so many bug could (should?) appear. But I wait to see how it will be use. * ---20/08/10-- * - Better implementation of GtkFileChooser (to be cleaner). * - Some work on macro (no seg fault now ^^). * - Add a Save state... entry in right click menu (no need to stop tilem to save state) * - Add a Play macro with GtkFileChooser (to play another macro than play.txt). * - Fix minor bug in GtkFileChooser (forget to init a char* to NULL). * ---23/08/10--- * - Add a new args handler using getop library (add -m for macro and -k for skin). * ---06/09/10--- * - NEW feature : could print the lcd content into the terminal. So useless but so funny ;) (feature request from Guillaume Hoffman). * - The output is saved into a file called lcd_content.txt. * ---08/09/10--- * - Could choose wich char to display. This not really works as I want, but this is not a really important feature (works 1/2) * - Add an option at startup (-l). Could now start in skinless mode. * ---04/10/10--- * - Start working on animated gif. Some research on GIF file format. Oops it will be hard, file is encoded (!). * ---09/10/10--- * - Creation of 1 little static gif file seems working, but always no LZW encoding. * ---12/10/10--- * - Finally I decided to use external source to encode the pix data.I use a file called "gifencode.c" by Hans Dinsen-Hansen and Michael A. Mayer. And it works !!! * ---14/10/10--- * - It works ! It works !!! Tilem2 is now able to generate animated gif, functions are currently working (but totally buggy) and it successfully create animated gif :) * - Need to be integrated (and lot of debug).I commit it just to save it...Wait another commit to really use this feature :P * ---01/02/11--- * - Starting to work on a new config file using glibc to do not hard code keypad values. * - And it works !!!! (but only load one keypad model currently) * - Add the other models into keylist.ini (but the content is completely false). Change scan_click method (correct a bug) to use kp->nb_of_buttons. Only need to give correct value into the keylist.ini file. For the rest it's seems ok. * ---07/02/11--- * - Start to work on config.ini. A new generation config file using GKeyFile library (glib). Add some work in essai4 directory. * ---08/02/11--- * - Remove romconfig.c romconfig.h config.c config.h (handle binary config file). Remove ROM_CONFIG_INFOS and CONFIG_INFOS from gsi. * - Add a new config.c and config.h file to handle config (last rom used, default skin to load, etc...). It uses glib GKeyFile library. * - Fix the macro bug pointed by Benjamin. * ---15/02/11--- * - Replace correct copyright/licence informations into skinops.* .Sorry for the inconvenience. * ---16/02/11--- * - Fix an important mistake into the gif creator function (palette should be before gif frame information). * ---18/02/11--- * - Connect a timer to automatically add frame to a animated screenshot (using screenshot box). * ---14/03/11--- * - Improve default skin choice. * - Define the skin's basedir into the config.ini. Add a universal getter into config.c . * ---19/03/11--- * - Add a bouncy progress bar to show the link status (send file). * - Add a file saver. * - Create a new TilemCmdlineArgs structure. * ---07/04/11--- * - Drop deprecated gtkitemfactory * - Prepare GT3 migration * ---10/04/11--- * - Benjamin add a configure script and all associated things (Makefile.in, config.h etc...). * - Fix dependency and a lot of cleaning. * - Benjamin add a lot of function to handle data directory. * ---13/04/11--- * - Completely refactoring the screenshot window. New preview possibility. * - Add some cool features for screenshot menu (replay from file, preview animation, preview screenshot, 2 gtkfilechooserbutton, change default folders etc...). * - Remove old pix directory. * - Benjamin begins to work on new debugger.Add a menu, some basic actions. * ---15/04/11--- * - Benjamin add a set of function to handle user defined icons. A lot of improvement on the debugger (add step action, pause). * - Use tilem logo as default background in the screenshot menu, add some pix into the shared data directory. * - Remove old debugger pix. * - Add GtkSpinnerAnimation in the screenshot menu. Improve look and feel (fix fill/expand properties for the box, size of the widgets etc...). * ---17/04/11--- * - Benjamin add a ti83p symbol file which allow to replace flag values by theirs labels in the debugger (and more other things). Debugger looks like very good. * ---19/04/11--- * - I've added a ti83 symbol file (but it could contains some mistakes...). Flags are correctly printed for my loved ti83 regular ;) * ---27/04/11--- * - Root window size could be forced (but the ratio could be strand if you specify stanges values ... Because ration is calculated on the start width and heigth). * ---02/05/11--- * - Add the icons for the right click menu (stock icons currently). * - Export all menu related code in a separate file called menu.c. It could maybe be done by UI in the future, but it works fine as it for the moment ;) * - Add drag and drop support for loading files :) :) :) :) :) (code is currently really ugly) * ---09/05/11--- * - Create a new TilemGuiStateFlags structure ot group the running state of the gui (skinless, recording macro, etc...) and export it into TilemCalcEmu instead GLOBAL_SKIN_INFOS. * - Completely remove GLOBAL_SKIN_INFOS structure from tilem2. * ---10/05/11--- * - Change strutures to look like a object oriented model. But in some case it's not really well implemented. * ---11/05/11--- * - Refactor a lot of gif header's code. * ---12/05/11--- * - I finally found what's wrong in my gif creation. So I can do multicolor gif now. * ---14/05/11--- * - We have finally completely reorganized the code to drop GLOBAL_SKIN_INFOS, and rename a lot of stuff including files (emuwin instead screen by example). * - Benjamin have imported his nice filedlg functions (filedlg.c) from flashbook ui (see it on SF.net). Now use it for the entire code. * ---14/05/11--- * - Refactor the gif creation to separate clearly which value can be modified, which one are magic number etc... Create separate functions for each task. * - Benjamin begins to work on animation (instead of writing file while recording it). It provides a wonderful objects to handle screenshot. * ---15/05/11--- * - Add a doxyfile for generating documentation including callgraphs. * - Improvement to keybindings (Benjamin). * ---16/05/11--- * - Add some preliminary work on get var stuff. Only dirlist and allow user to retrieve a var using cmd line but it works. The list is printed in a tree view. * - Add multi drag and drop feature. * ---19/05/11--- * - Add functions for animations (Benjamin). Could now save a animation into a gif file. * - Improve screenshot menu by setting some buttons inactives depending the current state of screenshot creation. * - Add combo box for size to screenshot menu. * ---21/05/11--- * - A lot of improvement on screenshot menu (Benjamin). Settings are now independent of screenshot dialog. Default directory for output. * - Add mnemonic label to screenshot menu buttons (Benjamin). * ---22/05/11--- * - Benjamin redesign the entire menu popup to use the better GtkAction system. Now there's keybindings for menu and code is really beautiful and shorter. * - Add grayscale option to screenshot menu (Benjamin). * ---23/05/11--- * - Save the last rom opened and use it at startup if no rom is given. * - Allow user to load another rom while running. * - Refactor the entire macro creation to separate creation from writing as TilemAnimation does. Code is cleaner and simply better. * ---25/05/11--- * - Add an option to change animation speed. The current printed animation is updated on change. * ---26/05/11--- * - Add an option to change foreground and background color. No visual feedback. * ---27/05/11--- * - Correct some stuff (see mailing list to know why). And add a palette setter in animation.c and a visual feedback when foreground/background color are changed. * - Some other minor improvement. * ---19/09/11--- * - Restart working on tilem2 after holidays:) * - Add new file getvar.c to handle get var function (receiving var from calc to PC). * ---20/09/11--- * - Some improvement to the rcvmenu. * ---22/09/11--- * - Add the ti83pfr.skn file. This skin is for ti83plus.fr. The creator is Claude Clerc (aka claudiux). He donates the skin under GPL v3+ licence.Thanks to him !!! * ---11/10/11--- * - Correct the getvar.c code to work correctly. Add columns to the tree view. * - Add app receive handling. Set index column invisible. * ---12/10/11--- * - Some corrections : receive dialog is transcient. Receive dialog is not destroyed when closed just hided. New refresh button to refresh var/app list. * - Use a separate thread to receive files. * ---14/10/11--- * - Add a feature to list ti82 and ti85 entries. User must prepare manually the link. Can't save a ti82 or ti85 entry (when selected in the rcvdialog). * - Lot of bug, code is really ugly. No error handling. The prepare_for_link_receive is not working. etc... * ---11/11/11--- * - Benjamin add a totally new prefs dialog. Some unused function (print lcd in terminal by example) are deleted. * ---12/11/11--- * - Working on ns silent get var. * ---14/11/11--- * - New files : emucore.c and emucore.h . * - Benjamin adds a totally new core task manager in the gui. Begin to convert the send files function to use it. * - Use this task manager for macro. There's a little priority problem when a macro load a file. Load a file then run a macro at startup works fine. * ---15/11/11--- * - Receive non silent vars : Benjamin get it working! * - Remove unused getvar.c file. * ---16/11/11--- * - Allow multiple selection and multiple receive file. Need to fix a segfault (tomorow... xD). * ---17/11/11--- * - Repare the file loading inside a macro (it was broken by new task manager). * - Delete a lot of unused functions/printf. * - Remove debuginfo.h file. * ---22/11/11--- * - Benjamin finished the last things left to do on receive dialog. Nice! * ---25/11/11--- * - New command line parser. Now tilem2 uses g_option from the glib instead of getopt. Easy handling of long options. Do not need to take care about correct parsing. A lot of new options are provided but not implemented ! * - Delete args.c (old _but working well _ cmd line parser using getopt) and TilemCmdlineArgs structure from gui.h. * - Add the possibility to getvar a file at startup. I had to use a weird solution to do this with task manager. But it's working :) * ---12/12/11--- * - Benjamin do a lot of improvements on file chooser (filters, ...). * ---22/12/11--- * - Benjamin fix certificate patching. * ---19/03/12--- * - Icons are finally commited into the trunk. These pictures are originaly designed by Scott Zeid and modified by me. No .desktop and icons installer for the moment. * - Scott, thank you a lot for these wonderful pictures! * ---21/03/12--- * - Adding documentation (LaTeX). The documentation is not finished yet. Lot of pictures added. * ---24/04/12--- * - Benjamin added some correction to install properly the icons. * ---27/04/12--- * - Some modifications on the configure script because something was failing on my debian wheezy. It works fine yet (using squeeze and gtk/glib downgraded packages and some minor modifications on configure scripts). * ---03/05/12--- * - Reverting changes on the configure script because it was not the fault of configure script. * ---07/05/12--- * - Update doc (add "basic task" chapter). * - Update .desktop files. * ---08/05/12--- * - Benjamin added a rule to install in the $HOME directory. * - Benjamin added MIME type files. * ---09/05/12--- * - Benjamin added a piece of documentation about "getting ROM". * ---11/05/12--- * - Add an huge explanation for debugger part into the documentation. * ---13/05/12--- * - Add some screenshot documentation. * ---15/05/12--- * - Benjamin add README, THANKS and COPYING file. * - Update screenshot doc. */ tilem-2.0/COPYING000066400000000000000000001045131220200411600135100ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . tilem-2.0/INSTALL000066400000000000000000000036101220200411600135020ustar00rootroot00000000000000 Installing TilEm ------------------ To compile TilEm, you will need: * a standard C compiler * the GTK+ library, version 2.6.0 or later * the libticalcs2 library (part of the TiLP project), and its dependencies (libticables2, libtifiles2, and libticonv) Some OS distributions package the "development files" separately from the libraries themselves; you need both. If you are using Debian (or a related distribution, such as Ubuntu or Mint), install the packages 'build-essential', 'libticalcs-dev', and 'libgtk2.0-dev'. If these packages aren't available from your package manager, you'll need to compile them yourself; see the TiLP website for more information (http://lpg.ticalc.org/prj_tilp/). Mac OS X has not been tested by the TilEm team, but if TiLP works, TilEm should, too. Please let us know if you do get it to work. Once the above dependencies are installed, open a terminal and 'cd' to the directory containing this INSTALL file. Then run ./configure which will check whether you have all of the necessary software installed, and figure out how to compile TilEm for your particular system. If configure is successful, you can then run make to compile TilEm. Finally, you can run sudo make install to install it (or run 'make install' as the superuser.) The program will be installed in '/usr/local/bin/', and data files will be installed in '/usr/local/share/tilem2/'. Alternatively, you can run make install-home to install TilEm in your own home directory ('$HOME/bin/', with data files stored in '$HOME/.local/share/tilem2/'), which does not require superuser privileges. (If $HOME/bin didn't exist already, you might have to run 'export PATH=$HOME/bin:$PATH', or log out and log back in, before running TilEm.) Once TilEm is installed, start it by running 'tilem2', or through your system's applications menu. tilem-2.0/KEYS000066400000000000000000000553521220200411600131610ustar00rootroot00000000000000KEYBOARD BINDINGS This list shows the default keyboard controls for TilEm. You can modify these, if you like, by editing 'keybindings.ini'. (Place the modified version of keybindings.ini in your TilEm configuration directory - $HOME/.config/tilem2/ on Unix, or $PROFILE\Local Settings\Application Data\tilem2 on Windows.) In the following list: S = Shift C = Control ↑ = 2nd α = Alpha ² in the TI-82/83 column indicates that the key is only for the TI-82. ³ indicates that it is only for the TI-83/TI-83 Plus/TI-84 Plus. Key TI-73 TI-76.fr TI-81 TI-82/83 TI-85/86 ────────────────────────────────────────────────────────────────────────────── F12 ON ON ON ON ON S+F12 ↑ [OFF] ↑ [OFF] ↑ [OFF] ↑ [OFF] ↑ [OFF] Up Up Up Up Up Up Down Down Down Down Down Down Left Left Left Left Left Left Right Right Right Right Right Right S+Up ↑ Up ↑ Up ↑ Up ↑ Up ↑ Up S+Down ↑ Down ↑ Down ↑ Down ↑ Down ↑ Down Home ↑ Left ↑ Left ↑ Left ↑ Left End ↑ Right ↑ Right ↑ Right ↑ Right PageUp α Up ³ PageDown α Down ³ F1 Y= f(x)= Y= Y= F1 F2 WINDOW fenêtre RANGE WINDOW F2 F3 ZOOM zoom ZOOM ZOOM F3 F4 TRACE trace TRACE TRACE F4 F5 GRAPH graphe GRAPH GRAPH F5 S+F1 ↑ [PLOT] ↑ [gr stat] ↑ Y= ↑ [STAT PLT] ↑ [M1] S+F2 ↑ [TBLSET] ↑ [déf tab] ↑ RANGE ↑ [TBLSET] ↑ [M2] S+F3 ↑ [FORMAT] ↑ [format] ↑ ZOOM ↑ [FORMAT] ↑ [M3] S+F4 ↑ TRACE ↑ [calculs] ↑ TRACE ↑ [CALC] ↑ [M4] S+F5 ↑ [TABLE] ↑ [table] ↑ GRAPH ↑ [TABLE] ↑ [M5] PageDown MORE Tab 2nd 2nde 2nd 2nd 2nd ' or Menu ↑ [TEXT] texte Alpha Alpha Alpha Insert ↑ [INS] ↑ [insérer] INS ↑ [INS] ↑ [INS] Delete DEL suppr DEL DEL DEL Backspace Left, DEL Left, suppr Left, DEL Left, DEL Left, DEL C+Backspace CLEAR annul CLEAR CLEAR CLEAR or C+Delete Escape CLEAR annul CLEAR CLEAR EXIT S+Escape ↑ [QUIT] ↑ [quitter] ↑ [QUIT] ↑ [QUIT] ↑ [QUIT] F6 math MATH MATH GRAPH F7 APPS angle MATRX MATRX/APPS STAT F8 PRGM prgm PRGM PRGM PRGM F9 var VARS VARS CUSTOM F10 stats STAT F11 MODE mode MODE MODE ↑ [MODE] c CONST d DRAW l LIST m MATH p prgm PRGM PRGM C+Tab ↑ [CATALOG] ↑ [catalog] ↑ [CATALOG]³ ↑ [CATALOG] _ UNIT | or ½ a/b f F◂▸D a Ab/c◂▸d/e s SIMP % % | ↑ [ABS] ↑ [ABS] ² s sin SIN SIN c cos COS COS t tan TAN TAN o log LOG LOG l ln LN LN u ↑ [uₙ] ↑ [u] ³ v ↑ [vₙ] ↑ [v] ³ w ↑ [wₙ] ↑ [w] ³ u ↑ [Uₙ₋₁] ² v ↑ [Vₙ₋₁] ² n ↑ [n] ² C+1 or \ ↑ [x⁻¹] x⁻¹ x⁻¹ x⁻¹ ↑ [x⁻¹] C+2 or ² x² x² x² x² x² ( ( ( ( ( ( ) ) ( ) ) ) { ↑ [{] ↑ [{] } ↑ [}] ↑ [}] [ ↑ [[] ↑ [[] ] ↑ []] ↑ []] ^ ^ ^ ^ ^ ^ / ÷ ÷ ÷ ÷ ÷ * × × × × × - - - - - - + + + + + + , , , α [,] , , > STO▸ STO▸ STO▸ STO▸ STO▸ < ↑ [RCL] ↑ [rappel] ↑ STO▸ ↑ [RCL] ↑ [RCL] 0 - 9 0 - 9 0 - 9 0 - 9 0 - 9 0 - 9 . . . . . . ~ or ± (-) (-) (-) (-) (-) & or € ↑ [EE] ↑ […×10ⁿ] EE ↑ [EE] EE x X x,n X|T X,T,θ,n $ ↑ [ANS] ↑ [rép] ↑ [ANS] ↑ [ANS] ↑ [ANS] # ↑ [π] ↑ [π] ↑ [π] ↑ [π] ↑ [π] e ↑ [e] ↑ [e] ³ i ↑ [i] ³ A - Z α [A]-[Z] α [A]-[Z] α [A]-[Z] a - z ↑α [a]-[z] Space α [space] α [space] α [space] @ α [θ] α [θ] " α ["] α ["] ? α [?] α [?] : α [:] ↑ [:] = α [=] Return ENTER entrer ENTER ENTER ENTER S+Return ↑ [ENTRY] ↑ [précéd] ↑ [ENTRY] ↑ [ENTRY] ↑ [ENTRY] ────────────────────────────────────────────────────────────────────────────── For the TI-83 Plus and TI-84 Plus, in addition to the keys listed above for the TI-83, pressing Shift+letter while Caps Lock is enabled will type a lowercase letter (Alpha, Alpha, letter.) Lowercase mode will need to be enabled on the calculator for this to work; it's not enabled by default, but there are many assembly programs that can do so. KEYPAD CHARTS TI-73 TI-76.fr ╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│ │ │S+Esc │Ins ├────┤Up ├─────╮ │ │S+Esc │Ins ├────┤Up ├─────╮ │Tab │F11 │Del │Home├────┤End │ │Tab │F11 │Del │Home├────┤End │ ├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│ │' │ │ ├────┤S+Dn├─────╯ │ │ │ ├────┤S+Dn├─────╯ │m │d │l │ │Down│ │' │x │F10 │ │Down│ ├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮ │ │& │C+Tab │ │ │ │ │ │ │ │ │ │C+2 │^ │F8 │F7 │Esc │ │F6 │F7 │F8 │F9 │Esc │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │\ │# │ │ │ │ │ │ │ │# │ │_ │| │f │a │c │ │\ │s │c │t │^ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │& │{ │} │e │ │s │% │( │) │/ │ │C+2 │, │( │) │/ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │u │v │w │ │ │x │7 │8 │9 │* │ │o │7 │8 │9 │* │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │ │ │ │ │ │, │4 │5 │6 │- │ │l │4 │5 │6 │- │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │< │ │ │ │ │ │< │ │ │ │ │ │> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │S+F12 │ │ │$ │S+Ret │ │S+F12 │C+Tab │ │$ │S+Ret │ │F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │ ╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯ TI-81 TI-82 ╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│ │ │ │ ├────┤Up ├─────╮ │ │S+Esc │Ins ├────┤Up ├─────╮ │Tab │Ins │Del │ ├────┤ │ │Tab │F11 │Del │Home├────┤End │ ├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│ │ │ │ ├────┤S+Dn├─────╯ │ │ │ ├────┤S+Dn├─────╯ │' │x │F11 │ │Down│ │' │x │F10 │ │Down│ ├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮ │ │ │ │ │S+Esc │ │ │ │ │ │ │ │F6 │F7 │F8 │F9 │Esc │ │F6 │F7 │F8 │F9 │Esc │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │| │ │ │ │# │ │| │ │ │ │# │ │\ │s │c │t │^ │ │\ │s │c │t │^ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │& │{ │} │ │ │C+2 │& │( │) │/ │ │C+2 │, │( │) │/ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │u │v │n │[ │ │o │7 │8 │9 │* │ │o │7 │8 │9 │* │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │ │ │ │ │ │ │] │ │l │4 │5 │6 │- │ │l │4 │5 │6 │- │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │< │ │ │ │ │ │< │ │ │ │ │ │> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │S+F12 │ │ │$ │S+Ret │ │S+F12 │ │ │$ │S+Ret │ │F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │ ╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯ Not shown: Not shown: A-Z Alpha, [A]-[Z] A-Z Alpha, [A]-[Z] @ Alpha, 3 @ Alpha, 3 " Alpha, + " Alpha, + Space Alpha, 0 Space Alpha, 0 , Alpha, . : Alpha, . ? Alpha, (-) ? Alpha, (-) TI-83 / TI-83 Plus / TI-84 Plus TI-85 / TI-86 ╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯ ╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│ │ │S+Esc │Ins ├────┤Up ├─────╮ │ │S+Esc │F11 ├────┤Up ├─────╮ │Tab │F11 │Del │Home├────┤End │ │Tab │Esc │PgDn │Home├────┤End │ ├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│ │ │ │ ├────┤S+Dn├─────╯ │ │ │Ins ├────┤S+Dn├─────╯ │' │x │F10 │ │Down│ │' │ │Del │ │Down│ ├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮ │ │ │ │ │ │ │ │ │ │C+Tab │ │ │F6 │F7 │F8 │F9 │Esc │ │F6 │F7 │F8 │F9 │C+BkSp│ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │# │ │ │ │ │ │# │ │\ │s │c │t │^ │ │ │ │ │ │^ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │& │{ │} │e │ │ │\ │[ │] │ │ │C+2 │, │( │) │/ │ │ │& │( │) │/ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │u │v │w │[ │ │ │ │ │ │ │ │o │7 │8 │9 │* │ │C+2 │7 │8 │9 │* │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │ │ │ │ │] │ │ │ │ │ │ │ │l │4 │5 │6 │- │ │, │4 │5 │6 │- │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │< │ │ │ │ │ │< │ │ │ │ │ │> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │ ├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤ │S+F12 │C+Tab │i │$ │S+Ret │ │S+F12 │ │: │$ │S+Ret │ │F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │ ╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯ Not shown: Not shown: PageUp Alpha, Up A-Z Alpha, [A]-[Z] PageDown Alpha, Down a-z 2nd, Alpha, [a]-[z] A-Z Alpha, [A]-[Z] Space Alpha, (-) @ Alpha, 3 = Alpha, Sto▸ " Alpha, + Space Alpha, 0 : Alpha, . ? Alpha, (-) TI-83 Plus / TI-84 Plus only: CapsLock + Shift + a-z = Alpha, Alpha, [a]-[z] tilem-2.0/Makefile.in000066400000000000000000000045241220200411600145230ustar00rootroot00000000000000prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = @bindir@ datadir = @datadir@ pkgdatadir = @datadir@/tilem2 mandir = @mandir@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ SHELL = @SHELL@ INSTALL = @INSTALL@ distname = @PACKAGE_TARNAME@-@PACKAGE_VERSION@ distfiles = CHANGELOG COPYING INSTALL KEYS NEWS README THANKS TODO \ aclocal.m4 config.h.in configure configure.ac install-sh \ Makefile.in \ data/Makefile.in \ data/keybindings.ini \ data/desktop/*.desktop data/desktop/*.xml \ data/icons/hicolor/index.theme data/icons/hicolor/*/*/*.png \ data/icons-svg/*.svg \ data/skins/README data/skins/*.skn \ data/symbols/*.sym \ db/Makefile.in db/*.c db/*.h \ emu/Makefile.in emu/*.c emu/*.h emu/x*/*.c emu/x*/*.h \ gui/Makefile.in gui/*.c gui/*.h gui/*.ico gui/*.rc.in \ installer/win32/Makefile.in \ installer/win32/installer.nsi.in installer/win32/gtkrc \ installer/win32/COPYING-ZLIB installer/win32/COPYING-PIXMAN all: cd emu && $(MAKE) cd db && $(MAKE) cd gui && $(MAKE) clean: cd emu && $(MAKE) clean cd db && $(MAKE) clean cd gui && $(MAKE) clean cd installer/win32 && $(MAKE) clean install: all cd gui && $(MAKE) install cd data && $(MAKE) install uninstall: cd gui && $(MAKE) uninstall cd data && $(MAKE) uninstall install-home: all $(MAKE) install \ bindir=$(HOME)/bin \ datarootdir=$${XDG_DATA_HOME:-$(HOME)/.local/share} uninstall-home: $(MAKE) uninstall \ bindir=$(HOME)/bin \ datarootdir=$${XDG_DATA_HOME:-$(HOME)/.local/share} distclean: clean rm -f config.status config.log config.h configure.lineno rm -rf autom4te.cache rm -f installer/win32/Makefile installer/win32/installer.nsi rm -f gui/tilem2.rc rm -f Makefile emu/Makefile db/Makefile gui/Makefile data/Makefile dist: rm -rf $(distname) mkdir $(distname) set -e ; files=`cd $(srcdir) ; echo $(distfiles)` ; \ for f in $$files ; do \ dir=`echo $(distname)/$$f | sed 's,/[^/]*$$,,'` ; \ [ -d $$dir ] || $(INSTALL) -d $$dir ; \ cp -p $(srcdir)/$$f $$dir ; \ done tar cv $(distname) | bzip2 -c -9 > $(distname).tar.bz2 Makefile: Makefile.in config.status $(SHELL) ./config.status config.status: configure $(SHELL) ./config.status --recheck .PRECIOUS: Makefile config.status .PHONY: all clean dist distclean install install-home uninstall uninstall-home tilem-2.0/NEWS000066400000000000000000000052111220200411600131470ustar00rootroot00000000000000 Version History ----------------- 2012-06-07 -- version 2.0 This is the first official release of the "new" TilEm. Much of the old TilEm code has been rewritten, and there are many improvements (and probably some new bugs.) Please note, if you have used older versions of TilEm: * Your existing ROM files and settings in ~/.TilEm will not be used (in fact, you can keep TilEm 0.97x installed alongside TilEm 2.0 if you wish.) TilEm 2.0 no longer uses a "library" of ROM files; you can store ROM files anywhere you like. * TilEm 2.0 uses a new format for calculator state (SAV) files. State files created by TilEm 0.97x can be loaded by TilEm 2.0, but if you then save the state, it will be stored in the new format, which older versions of TilEm will not support. New features and bugs fixed since version 0.975 include: * All code that was covered by the Z80em license has been removed. * Support for the TI-81 (both hardware versions) and TI-76.fr, and experimental support for the TI-Nspire's TI-84 Plus emulation mode. * Many hardware emulation improvements for all calculator models. In particular, major improvements have been made concerning Z80 interrupts, timers, the LCD driver, and the link port. * The emulator window uses TiEmu-format skin files. * Greatly improved grayscale emulation. * Commands for saving still screenshots (in PNG, BMP, JPEG, or GIF format) and animations (GIF format only.) * Keypad macros can be recorded and replayed. * Programs and/or ROM files can be loaded from the command line. * Link I/O uses libticalcs2, which allows all types of variables, as well as Flash apps and OSes, to be transferred through the link port. For the TI-81, PRG files can be transferred to and from the calculator memory directly. * TilEm does not consume 100% of the host CPU when idle. * Improved disassembler (macros; distinct "labels" and "romcalls"; named IY flags.) * The debugger offers a "Finish Subroutine" command. In addition, the "Step Over" command behaves more sensibly. * Breakpoints can be set on absolute memory addresses, and on Z80 opcodes. * Many minor improvements. Features of 0.975 that are not yet supported in TilEm 2.0 include: * External link cables. * Custom symbol files in the disassembler. * Program counter history tracking. Most of the new code is due to Benjamin Moody (floppusmaximus) and Thibault Duponchelle (contra-sh). See THANKS for a full list of contributors. tilem-2.0/README000066400000000000000000000071251220200411600133360ustar00rootroot00000000000000 TilEm ------- TilEm is an emulator and debugger for Texas Instruments Z80-based graphing calculators. It can emulate any of the following calculator models: TI-73 / TI-73 Explorer TI-76.fr TI-81 TI-82 TI-82 STATS / TI-82 STATS.fr TI-83 TI-83 Plus / TI-83 Plus Silver Edition / TI-83 Plus.fr TI-84 Plus / TI-84 Plus Silver Edition / TI-84 pocket.fr TI-85 TI-86 TilEm fully supports all known versions of the above calculators (as of 2012), and attempts to reproduce the behavior of the original calculator hardware as faithfully as possible. In addition, TilEm can emulate the TI-Nspire's virtual TI-84 Plus mode. This is currently experimental, and some programs may not work correctly. TilEm runs on the X Window System on GNU/Linux and other Unix-like platforms, as well as on Microsoft Windows, and any other platform supported by the GTK+ library. Installation -------------- Packages for Microsoft Windows are available from the TilEm project website (http://lpg.ticalc.org/prj_tilem/). For other platforms, you will need to compile TilEm from source; please see the file 'INSTALL' in the source package. Using TilEm ------------- TilEm requires a copy of the operating system from the calculator model(s) you wish to emulate. This file is called a "ROM image", since the calculator OS was traditionally stored in Read-Only Memory. ROM images are copyrighted by TI and may not be distributed without permission. See the TilEm User's Manual for more information about how to create a ROM image. The main TilEm window shows an image of the calculator (if possible - we are still missing background images for a few models.) Clicking with the left mouse button presses a key; clicking with the middle button presses a key and holds it down. Clicking with the right button, or pressing Shift+F10, opens the menu. When you run TilEm for the first time, it will ask you to select a ROM image to use. The file you select will be used by default the next time you run TilEm. You can switch to a different ROM image by right-clicking and selecting "Open Calculator". The state of the emulated calculator is not saved by default; to save the state, right-click and select "Save Calculator". The state is saved to a ".sav" file, stored in the same directory as the ROM image. You can send program and variable files to the emulated calculator, either by dragging and dropping them from your file manager, or by right-clicking and selecting "Send File". To retrieve program or variable files from the calculator, select "Receive File". Other features of TilEm include: - A debugger for assembly programs - Capturing screenshots, both normal and animated - Recording and replaying keystroke macros For more information, see the TilEm User's Manual: http://lpg.ticalc.org/prj_tilem2/doc.html About this program -------------------- Many people deserve credit for helping to make this program possible. See the file 'THANKS'. This program is free software, which means that you are allowed to modify it, and to distribute it (or your modified version) to others. When you received this program, you should also have been offered a complete copy of its source code. For more information, see the file 'COPYING'. You can contact the authors at . Please let us know of any problems you encounter, or ideas for how we could make TilEm better. tilem-2.0/THANKS000066400000000000000000000034761220200411600133760ustar00rootroot00000000000000 Thanks -------- The current maintainers of TilEm are Thibault Duponchelle and Benjamin Moody, but many other people have played a part in making this program possible. The original TilEm was written in 2001 by Julien Solignac. The current version is partially based on the original, but large portions have been rewritten, starting in 2009, by Benjamin Moody and Thibault Duponchelle. Portions of the hardware emulation code are also due to Luc Bruant. The code for reading skin files is based on code from TiEmu, written by Julien Blache. The GIF compression code is based on whirlgif, written by Hans Dinsen-Hansen and Michael A. Mayer. Thanks to Claude Clerc for the photo of his TI-83 Plus, and to Danilo Šegan for the photo of his TI-86, which we have used as skins. Thanks to Scott Zeid for the design of the program icon. TilEm uses the TiLP libraries (libticalcs2, libticables2, libtifiles2, and libticonv) to send and receive variables. Thanks are due to the current maintainer of TiLP, Lionel Debroux, for his assistance, as well as to all of the past maintainers of TiLP, including Romain Liévin, Kevin Kofler, and Julien Blache. Finally, this program would never have been possible without the efforts of countless programmers and researchers over the years to discover and document the inner workings of the calculator hardware. The following people deserve special recognition for their research: Randy Compton, Tijl Coosemans, Brian Coventry, Dan Eble, Dan Englender, Dines Justesen, Julien Lasson, Mattias Lindqvist, James Montelongo, Michael Vincent, Brandon Wilson, and Joerg Woerner. (Thibault) In addition of above: Thanks to Michael Nock and Guillaume Hoffman for testing, feature request and encouragement. Thanks to Xavier Andreani for his encouragement. tilem-2.0/TODO000066400000000000000000000003141220200411600131370ustar00rootroot00000000000000- Linking between 2 tilem instances - Sound - Rewrite macro (parser and tokens). - Add scripting (lua or something else?) - Teacher mode (record keys pressed and produce a picture file with keys icons) tilem-2.0/aclocal.m4000066400000000000000000000141611220200411600143140ustar00rootroot00000000000000# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES tilem-2.0/config.h.in000066400000000000000000000054151220200411600145010ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if the system has the type `uintptr_t'. */ #undef HAVE_UINTPTR_T /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported directly. */ #undef restrict /* Work around a bug in Sun C++: it does not support _Restrict or __restrict__, even though the corresponding Sun C compiler ends up with "#define restrict _Restrict" or "#define restrict __restrict__" in the previous line. Perhaps some future version of Sun C++ will work with restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ #if defined __SUNPRO_CC && !defined __RESTRICT # define _Restrict # define __restrict__ #endif /* Define to the type of an unsigned integer type wide enough to hold a pointer, if such a type exists, and if the system does not define it. */ #undef uintptr_t tilem-2.0/configure000077500000000000000000005336141220200411600143740ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for TilEm 2.0. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: tilem-devel@lists.sourceforge.net about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='TilEm' PACKAGE_TARNAME='tilem' PACKAGE_VERSION='2.0' PACKAGE_STRING='TilEm 2.0' PACKAGE_BUGREPORT='tilem-devel@lists.sourceforge.net' PACKAGE_URL='http://tilem.sourceforge.net/' ac_unique_file="emu/tilem.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EGREP GREP DLLPATH TICALCS_BINDIR GTK_BINDIR LN_S MAKENSIS WINDRES OBJDUMP STRIP TICALCS_LIBS TICALCS_CFLAGS gui_extra_objects GUI_LDFLAGS GTK_LIBS GTK_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG UPDATE_MIME_DATABASE UPDATE_DESKTOP_DATABASE SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM RANLIB AR_FLAGS AR OPT_CFLAGS CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_gtk_deprecated ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP OPT_CFLAGS AR AR_FLAGS RANLIB PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR GTK_CFLAGS GTK_LIBS TICALCS_CFLAGS TICALCS_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures TilEm 2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/tilem] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of TilEm 2.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-gtk-deprecated Disable deprecated GTK+ API Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor OPT_CFLAGS Additional C compiler flags used for optimizing critical areas of the code (default: -O3 if using GCC) AR Static library archiver AR_FLAGS Flags to pass to ar to build a static library RANLIB Program to make a static library linkable PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path GTK_CFLAGS C compiler flags for GTK, overriding pkg-config GTK_LIBS linker flags for GTK, overriding pkg-config TICALCS_CFLAGS C compiler flags for TICALCS, overriding pkg-config TICALCS_LIBS linker flags for TICALCS, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . TilEm home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF TilEm configure 2.0 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by TilEm $as_me 2.0, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Checks for programs ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -W -Wall -Wwrite-strings" if test "x$OPT_CFLAGS" = "x" ; then OPT_CFLAGS="-O3" fi fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test "x$AR_FLAGS" = "x" ; then AR_FLAGS=cru fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi # Extract the first word of "update-desktop-database", so it can be a program name with args. set dummy update-desktop-database; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_UPDATE_DESKTOP_DATABASE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$UPDATE_DESKTOP_DATABASE"; then ac_cv_prog_UPDATE_DESKTOP_DATABASE="$UPDATE_DESKTOP_DATABASE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_UPDATE_DESKTOP_DATABASE="update-desktop-database" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_UPDATE_DESKTOP_DATABASE" && ac_cv_prog_UPDATE_DESKTOP_DATABASE=":" fi fi UPDATE_DESKTOP_DATABASE=$ac_cv_prog_UPDATE_DESKTOP_DATABASE if test -n "$UPDATE_DESKTOP_DATABASE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_DESKTOP_DATABASE" >&5 $as_echo "$UPDATE_DESKTOP_DATABASE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "update-mime-database", so it can be a program name with args. set dummy update-mime-database; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_UPDATE_MIME_DATABASE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$UPDATE_MIME_DATABASE"; then ac_cv_prog_UPDATE_MIME_DATABASE="$UPDATE_MIME_DATABASE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_UPDATE_MIME_DATABASE="update-mime-database" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_UPDATE_MIME_DATABASE" && ac_cv_prog_UPDATE_MIME_DATABASE=":" fi fi UPDATE_MIME_DATABASE=$ac_cv_prog_UPDATE_MIME_DATABASE if test -n "$UPDATE_MIME_DATABASE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_MIME_DATABASE" >&5 $as_echo "$UPDATE_MIME_DATABASE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Checks for libraries # GLib and GTK+ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK" >&5 $as_echo_n "checking for GTK... " >&6; } if test -n "$GTK_CFLAGS"; then pkg_cv_GTK_CFLAGS="$GTK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTK_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$GTK_LIBS"; then pkg_cv_GTK_LIBS="$GTK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTK_LIBS=`$PKG_CONFIG --libs "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0" 2>&1` else GTK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GTK_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0) were not met: $GTK_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTK_CFLAGS and GTK_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTK_CFLAGS and GTK_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else GTK_CFLAGS=$pkg_cv_GTK_CFLAGS GTK_LIBS=$pkg_cv_GTK_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi # Check whether --enable-gtk-deprecated was given. if test "${enable_gtk_deprecated+set}" = set; then : enableval=$enable_gtk_deprecated; enable_gtk_deprecated=$enableval else enable_gtk_deprecated=yes fi if test "x$enable_gtk_deprecated" = "xno" ; then GTK_CFLAGS="$GTK_CFLAGS -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGSEAL_ENABLE" fi # If using the native Windows version of GTK+, be sure to use # -mms-bitfields for all compilation. Also, use -mwindows for linking # GUI programs. # (If not using pkg-config, you're on your own) if test "x$PKG_CONFIG" != "x" ; then gtk_target=`$PKG_CONFIG --variable=target gtk+-2.0` fi if test "x$gtk_target" = "xwin32" && test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -mms-bitfields" GUI_LDFLAGS="-mwindows" LIBS="-lcomdlg32 -lshell32 -lole32 $LIBS" gui_extra_objects="tilem2rc.o" else GUI_LDFLAGS="" gui_extra_objects="" fi save_cflags="$CFLAGS" save_libs="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" ac_fn_c_check_func "$LINENO" "gtk_init" "ac_cv_func_gtk_init" if test "x$ac_cv_func_gtk_init" = xyes; then : have_gtk=yes else have_gtk=no fi CFLAGS="$save_cflags" LIBS="$save_libs" if test "x$have_gtk" != "xyes" ; then as_fn_error $? "GTK+ 2.x libraries not found or not usable. You must install a recent version of GTK+ 2.x, including the -dev/-devel packages if appropriate." "$LINENO" 5 fi # Libticalcs2 and related libraries pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TICALCS" >&5 $as_echo_n "checking for TICALCS... " >&6; } if test -n "$TICALCS_CFLAGS"; then pkg_cv_TICALCS_CFLAGS="$TICALCS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ticalcs2 ticables2 tifiles2 ticonv\""; } >&5 ($PKG_CONFIG --exists --print-errors "ticalcs2 ticables2 tifiles2 ticonv") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TICALCS_CFLAGS=`$PKG_CONFIG --cflags "ticalcs2 ticables2 tifiles2 ticonv" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$TICALCS_LIBS"; then pkg_cv_TICALCS_LIBS="$TICALCS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ticalcs2 ticables2 tifiles2 ticonv\""; } >&5 ($PKG_CONFIG --exists --print-errors "ticalcs2 ticables2 tifiles2 ticonv") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TICALCS_LIBS=`$PKG_CONFIG --libs "ticalcs2 ticables2 tifiles2 ticonv" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then TICALCS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ticalcs2 ticables2 tifiles2 ticonv" 2>&1` else TICALCS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ticalcs2 ticables2 tifiles2 ticonv" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$TICALCS_PKG_ERRORS" >&5 have_ticalcs=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } have_ticalcs=no else TICALCS_CFLAGS=$pkg_cv_TICALCS_CFLAGS TICALCS_LIBS=$pkg_cv_TICALCS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_ticalcs=maybe fi if test "x$have_ticalcs" = "xmaybe" ; then save_cflags="$CFLAGS" save_libs="$LIBS" CFLAGS="$CFLAGS $TICALCS_CFLAGS" LIBS="$LIBS $TICALCS_LIBS" ac_fn_c_check_func "$LINENO" "ticalcs_library_init" "ac_cv_func_ticalcs_library_init" if test "x$ac_cv_func_ticalcs_library_init" = xyes; then : have_ticalcs=yes else have_ticalcs=no fi CFLAGS="$save_cflags" LIBS="$save_libs" fi if test "x$have_ticalcs" != "xyes" ; then as_fn_error $? "libticalcs2 not found or not usable. $TICALCS_PKG_ERRORS You must install libticalcs2, libticables2, libtifiles2, and libticonv (including the -dev/-devel packages if appropriate.) These libraries are available from . If you have installed the libraries in a non-standard location (or if you're cross-compiling), you will need to add the location of ticalcs2.pc to your PKG_CONFIG_PATH environment variable, or set the TICALCS_CFLAGS and TICALCS_LIBS environment variables by hand." "$LINENO" 5 fi # Tools used for building the Windows installer if test "x$gtk_target" = "xwin32" ; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="objdump" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_WINDRES+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$WINDRES"; then ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_WINDRES="${ac_tool_prefix}windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi WINDRES=$ac_cv_prog_WINDRES if test -n "$WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WINDRES" >&5 $as_echo "$WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_WINDRES"; then ac_ct_WINDRES=$WINDRES # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_WINDRES+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_WINDRES"; then ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_WINDRES="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES if test -n "$ac_ct_WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_WINDRES" >&5 $as_echo "$ac_ct_WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_WINDRES" = x; then WINDRES="windres" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac WINDRES=$ac_ct_WINDRES fi else WINDRES="$ac_cv_prog_WINDRES" fi # Extract the first word of "makensis", so it can be a program name with args. set dummy makensis; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MAKENSIS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MAKENSIS"; then ac_cv_prog_MAKENSIS="$MAKENSIS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_MAKENSIS="makensis" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MAKENSIS=$ac_cv_prog_MAKENSIS if test -n "$MAKENSIS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKENSIS" >&5 $as_echo "$MAKENSIS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find GTK+ runtime libraries" >&5 $as_echo_n "checking where to find GTK+ runtime libraries... " >&6; } if test "x$GTK_BINDIR" = "x" ; then prefix=`$PKG_CONFIG --variable=exec_prefix gtk+-2.0` test "x$prefix" != "x" && GTK_BINDIR="$prefix/bin" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTK_BINDIR" >&5 $as_echo "$GTK_BINDIR" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find ticalcs2 runtime libraries" >&5 $as_echo_n "checking where to find ticalcs2 runtime libraries... " >&6; } if test "x$TICALCS_BINDIR" = "x" ; then prefix=`$PKG_CONFIG --variable=exec_prefix ticalcs2` test "x$prefix" != "x" && TICALCS_BINDIR="$prefix/bin" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TICALCS_BINDIR" >&5 $as_echo "$TICALCS_BINDIR" >&6; } if test "x$DLLPATH" = "x" ; then DLLPATH='${GTK_BINDIR}'$PATH_SEPARATOR'${TICALCS_BINDIR}' fi fi # Checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # Checks for system and compiler characteristics # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if ${ac_cv_c_restrict+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_restrict=no # The order here caters to the fact that C++ does not require restrict. for ac_kw in __restrict __restrict__ _Restrict restrict; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ typedef int * int_ptr; int foo (int_ptr $ac_kw ip) { return ip[0]; } int main () { int s[1]; int * $ac_kw t = s; t[0] = 0; return foo(t) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_restrict=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_restrict" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 $as_echo "$ac_cv_c_restrict" >&6; } case $ac_cv_c_restrict in restrict) ;; no) $as_echo "#define restrict /**/" >>confdefs.h ;; *) cat >>confdefs.h <<_ACEOF #define restrict $ac_cv_c_restrict _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default" if test "x$ac_cv_type_uintptr_t" = xyes; then : $as_echo "#define HAVE_UINTPTR_T 1" >>confdefs.h else for ac_type in 'unsigned int' 'unsigned long int' \ 'unsigned long long int'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(sizeof (void *) <= sizeof ($ac_type))]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define uintptr_t $ac_type _ACEOF ac_type= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test -z "$ac_type" && break done fi # Output ac_config_headers="$ac_config_headers config.h" ac_config_files="$ac_config_files Makefile emu/Makefile db/Makefile data/Makefile gui/Makefile gui/tilem2.rc installer/win32/Makefile installer/win32/installer.nsi" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by TilEm $as_me 2.0, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to . TilEm home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ TilEm config.status 2.0 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "emu/Makefile") CONFIG_FILES="$CONFIG_FILES emu/Makefile" ;; "db/Makefile") CONFIG_FILES="$CONFIG_FILES db/Makefile" ;; "data/Makefile") CONFIG_FILES="$CONFIG_FILES data/Makefile" ;; "gui/Makefile") CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;; "gui/tilem2.rc") CONFIG_FILES="$CONFIG_FILES gui/tilem2.rc" ;; "installer/win32/Makefile") CONFIG_FILES="$CONFIG_FILES installer/win32/Makefile" ;; "installer/win32/installer.nsi") CONFIG_FILES="$CONFIG_FILES installer/win32/installer.nsi" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi tilem-2.0/configure.ac000066400000000000000000000114761220200411600147500ustar00rootroot00000000000000AC_PREREQ(2.67) AC_INIT([TilEm], [2.0], [tilem-devel@lists.sourceforge.net], [tilem], [http://tilem.sourceforge.net/]) AC_CONFIG_SRCDIR([emu/tilem.h]) # Checks for programs AC_PROG_CC AC_PROG_CPP AC_ARG_VAR(OPT_CFLAGS, [Additional C compiler flags used for optimizing critical areas of the code (default: -O3 if using GCC)]) if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -W -Wall -Wwrite-strings" if test "x$OPT_CFLAGS" = "x" ; then OPT_CFLAGS="-O3" fi fi AC_CHECK_TOOL(AR, [ar], [false]) AC_ARG_VAR(AR, [Static library archiver]) AC_ARG_VAR(AR_FLAGS, [Flags to pass to ar to build a static library]) if test "x$AR_FLAGS" = "x" ; then AR_FLAGS=cru fi AC_PROG_RANLIB AC_ARG_VAR(RANLIB, [Program to make a static library linkable]) AC_PROG_INSTALL AC_PROG_MAKE_SET AC_CHECK_PROG([UPDATE_DESKTOP_DATABASE], [update-desktop-database], [update-desktop-database], [:]) AC_CHECK_PROG([UPDATE_MIME_DATABASE], [update-mime-database], [update-mime-database], [:]) # Checks for libraries m4_define(with_flags, [ save_cflags="$CFLAGS" save_libs="$LIBS" CFLAGS="$CFLAGS $$1_CFLAGS" LIBS="$LIBS $$1_LIBS" $2 CFLAGS="$save_cflags" LIBS="$save_libs" ]) # GLib and GTK+ PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6.0 glib-2.0 >= 2.12.0 gthread-2.0) AC_ARG_ENABLE([gtk-deprecated], AS_HELP_STRING([--disable-gtk-deprecated], [Disable deprecated GTK+ API]), [ enable_gtk_deprecated=$enableval ], [ enable_gtk_deprecated=yes ]) if test "x$enable_gtk_deprecated" = "xno" ; then GTK_CFLAGS="$GTK_CFLAGS -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGSEAL_ENABLE" fi # If using the native Windows version of GTK+, be sure to use # -mms-bitfields for all compilation. Also, use -mwindows for linking # GUI programs. # (If not using pkg-config, you're on your own) if test "x$PKG_CONFIG" != "x" ; then gtk_target=`$PKG_CONFIG --variable=target gtk+-2.0` fi if test "x$gtk_target" = "xwin32" && test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -mms-bitfields" GUI_LDFLAGS="-mwindows" LIBS="-lcomdlg32 -lshell32 -lole32 $LIBS" gui_extra_objects="tilem2rc.o" else GUI_LDFLAGS="" gui_extra_objects="" fi AC_SUBST(GUI_LDFLAGS) AC_SUBST(gui_extra_objects) with_flags(GTK, [ AC_CHECK_FUNC(gtk_init, [ have_gtk=yes ], [ have_gtk=no ]) ]) if test "x$have_gtk" != "xyes" ; then AC_MSG_ERROR([GTK+ 2.x libraries not found or not usable. You must install a recent version of GTK+ 2.x, including the -dev/-devel packages if appropriate.]) fi # Libticalcs2 and related libraries PKG_CHECK_MODULES(TICALCS, ticalcs2 ticables2 tifiles2 ticonv, [ have_ticalcs=maybe ], [ have_ticalcs=no ]) if test "x$have_ticalcs" = "xmaybe" ; then with_flags(TICALCS, [ AC_CHECK_FUNC(ticalcs_library_init, [ have_ticalcs=yes ], [ have_ticalcs=no ]) ]) fi if test "x$have_ticalcs" != "xyes" ; then AC_MSG_ERROR([libticalcs2 not found or not usable. $TICALCS_PKG_ERRORS You must install libticalcs2, libticables2, libtifiles2, and libticonv (including the -dev/-devel packages if appropriate.) These libraries are available from . If you have installed the libraries in a non-standard location (or if you're cross-compiling), you will need to add the location of ticalcs2.pc to your PKG_CONFIG_PATH environment variable, or set the TICALCS_CFLAGS and TICALCS_LIBS environment variables by hand.]) fi # Tools used for building the Windows installer if test "x$gtk_target" = "xwin32" ; then AC_CHECK_TOOL([STRIP], [strip], [:]) AC_CHECK_TOOL([OBJDUMP], [objdump], [objdump]) AC_CHECK_TOOL([WINDRES], [windres], [windres]) AC_CHECK_PROG([MAKENSIS], [makensis], [makensis]) AC_PROG_LN_S AC_MSG_CHECKING([where to find GTK+ runtime libraries]) if test "x$GTK_BINDIR" = "x" ; then prefix=`$PKG_CONFIG --variable=exec_prefix gtk+-2.0` test "x$prefix" != "x" && GTK_BINDIR="$prefix/bin" fi AC_MSG_RESULT([$GTK_BINDIR]) AC_MSG_CHECKING([where to find ticalcs2 runtime libraries]) if test "x$TICALCS_BINDIR" = "x" ; then prefix=`$PKG_CONFIG --variable=exec_prefix ticalcs2` test "x$prefix" != "x" && TICALCS_BINDIR="$prefix/bin" fi AC_MSG_RESULT([$TICALCS_BINDIR]) if test "x$DLLPATH" = "x" ; then DLLPATH='${GTK_BINDIR}'$PATH_SEPARATOR'${TICALCS_BINDIR}' fi AC_SUBST(GTK_BINDIR) AC_SUBST(TICALCS_BINDIR) AC_SUBST(DLLPATH) fi # Checks for header files AC_HEADER_STDC # Checks for system and compiler characteristics AC_C_BIGENDIAN AC_C_INLINE AC_C_RESTRICT AC_TYPE_UINTPTR_T # Output AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile emu/Makefile db/Makefile data/Makefile gui/Makefile gui/tilem2.rc installer/win32/Makefile installer/win32/installer.nsi]) AC_OUTPUT tilem-2.0/data/000077500000000000000000000000001220200411600133625ustar00rootroot00000000000000tilem-2.0/data/Makefile.in000066400000000000000000000077101220200411600154340ustar00rootroot00000000000000prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = @bindir@ datadir = @datadir@ pkgdatadir = @datadir@/tilem2 mandir = @mandir@ icondir = @datadir@/icons applicationsdir = @datadir@/applications mimedir = @datadir@/mime top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ SHELL = @SHELL@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ # Custom action and status icons go in these directories. These icons # are only used by TilEm, so they are installed in DATADIR/tilem2/icons. pkg_icondirs = hicolor/16x16/actions \ hicolor/16x16/status \ hicolor/24x24/actions # Application icons go in these directories; these icons will be # installed in DATADIR/icons so they are visible to other programs # (e.g. desktop application menus.) shared_icondirs = hicolor/16x16/apps \ hicolor/22x22/apps \ hicolor/24x24/apps \ hicolor/32x32/apps \ hicolor/48x48/apps all: @echo 'Nothing to do' install: $(INSTALL) -d -m 755 $(DESTDIR)$(pkgdatadir) $(INSTALL_DATA) $(srcdir)/keybindings.ini $(DESTDIR)$(pkgdatadir) $(INSTALL) -d -m 755 $(DESTDIR)$(pkgdatadir)/symbols set -e ; for i in $(srcdir)/symbols/*.sym ; do \ $(INSTALL_DATA) $$i $(DESTDIR)$(pkgdatadir)/symbols ; \ done $(INSTALL) -d -m 755 $(DESTDIR)$(pkgdatadir)/skins set -e ; for i in $(srcdir)/skins/*.skn ; do \ $(INSTALL_DATA) $$i $(DESTDIR)$(pkgdatadir)/skins ; \ done set -e ; for i in $(pkg_icondirs) ; do \ $(INSTALL) -d -m 755 $(DESTDIR)$(pkgdatadir)/icons/$$i ; \ for j in $(srcdir)/icons/$$i/*.png ; do \ $(INSTALL_DATA) $$j $(DESTDIR)$(pkgdatadir)/icons/$$i ; \ done ; \ done set -e ; for i in $(shared_icondirs) ; do \ $(INSTALL) -d -m 755 $(DESTDIR)$(icondir)/$$i ; \ for j in $(srcdir)/icons/$$i/*.png ; do \ $(INSTALL_DATA) $$j $(DESTDIR)$(icondir)/$$i ; \ done ; \ done $(INSTALL_DATA) $(srcdir)/icons/hicolor/index.theme $(DESTDIR)$(pkgdatadir)/icons/hicolor $(INSTALL) -d -m 755 $(DESTDIR)$(applicationsdir) $(INSTALL_DATA) $(srcdir)/desktop/tilem2.desktop $(DESTDIR)$(applicationsdir) $(INSTALL) -d -m 755 $(DESTDIR)$(mimedir)/packages $(INSTALL_DATA) $(srcdir)/desktop/tilem2.xml $(DESTDIR)$(mimedir)/packages [ -n "$(DESTDIR)" ] || $(UPDATE_DESKTOP_DATABASE) $(applicationsdir) [ -n "$(DESTDIR)" ] || $(UPDATE_MIME_DATABASE) $(mimedir) uninstall: rm -f $(DESTDIR)$(pkgdatadir)/keybindings.ini set -e ; for i in $(srcdir)/symbols/*.sym ; do \ rm -f $(DESTDIR)$(pkgdatadir)/symbols/`basename $$i` ; \ done set -e ; for i in $(srcdir)/skins/*.skn ; do \ rm -f $(DESTDIR)$(pkgdatadir)/skins/`basename $$i` ; \ done set -e ; for i in $(pkg_icondirs) ; do \ for j in $(srcdir)/icons/$$i/*.png ; do \ rm -f $(DESTDIR)$(pkgdatadir)/icons/$$i/`basename $$j` ; \ done ; \ done set -e ; for i in $(shared_icondirs) ; do \ for j in $(srcdir)/icons/$$i/*.png ; do \ rm -f $(DESTDIR)$(icondir)/$$i/`basename $$j` ; \ done ; \ done -for i in $(pkg_icondirs) ; do \ rmdir $(DESTDIR)$(pkgdatadir)/icons/$$i ; \ done -rmdir $(DESTDIR)$(pkgdatadir)/icons/hicolor/16x16 -rmdir $(DESTDIR)$(pkgdatadir)/icons/hicolor/24x24 rm -f $(DESTDIR)$(pkgdatadir)/icons/hicolor/index.theme -rmdir $(DESTDIR)$(pkgdatadir)/icons/hicolor -rmdir $(DESTDIR)$(pkgdatadir)/icons -rmdir $(DESTDIR)$(pkgdatadir)/symbols -rmdir $(DESTDIR)$(pkgdatadir)/skins -rmdir $(DESTDIR)$(pkgdatadir) rm -f $(DESTDIR)$(applicationsdir)/tilem2.desktop rm -f $(DESTDIR)$(mimedir)/packages/tilem2.xml [ -n "$(DESTDIR)" ] || $(UPDATE_DESKTOP_DATABASE) $(applicationsdir) [ -n "$(DESTDIR)" ] || $(UPDATE_MIME_DATABASE) $(mimedir) Makefile: Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && $(SHELL) ./config.status --recheck .PRECIOUS: Makefile $(top_builddir)/config.status .PHONY: all install uninstall tilem-2.0/data/desktop/000077500000000000000000000000001220200411600150335ustar00rootroot00000000000000tilem-2.0/data/desktop/tilem2.desktop000066400000000000000000000014601220200411600176230ustar00rootroot00000000000000[Desktop Entry] Name=TilEm Comment=Graphing calculator emulator Exec=tilem2 %F Icon=tilem MimeType=application/x-tigroup;application/x-ti73-variables;application/x-ti73-program;application/x-ti73-backup;application/x-ti73-app;application/x-ti73-os;application/x-ti81-program;application/x-ti82-variables;application/x-ti82-program;application/x-ti82-backup;application/x-ti83-variables;application/x-ti83-program;application/x-ti83-backup;application/x-ti83plus-variables;application/x-ti83plus-program;application/x-ti83plus-app;application/x-ti83plus-os;application/x-ti85-variables;application/x-ti85-program;application/x-ti85-backup;application/x-ti86-variables;application/x-ti86-program;application/x-ti86-backup; StartupNotify=true Terminal=false Type=Application Categories=Education;Science;Math;Emulator; tilem-2.0/data/desktop/tilem2.xml000066400000000000000000000247701220200411600167630ustar00rootroot00000000000000 TI calculator group file TI-73 variable TI-73 program TI-73 memory backup TI-73 Flash application TI-73 operating system TI-81 program TI-82 variable TI-82 program TI-82 memory backup TI-83 variable TI-83 program TI-83 memory backup TI-83/84 Plus variable TI-83/84 Plus program TI-83/84 Plus Flash application TI-83/84 Plus operating system TI-85 variable TI-85 program TI-85 memory backup TI-86 variable TI-86 program TI-86 memory backup tilem-2.0/data/icons-svg/000077500000000000000000000000001220200411600152725ustar00rootroot00000000000000tilem-2.0/data/icons-svg/breakpoint.svg000066400000000000000000000074001220200411600201520ustar00rootroot00000000000000 image/svg+xml tilem-2.0/data/icons-svg/pc-arrow.svg000066400000000000000000000115251220200411600175510ustar00rootroot00000000000000 image/svg+xml tilem-2.0/data/icons-svg/stepicons-16.svg000066400000000000000000000160101220200411600202440ustar00rootroot00000000000000 image/svg+xml tilem-2.0/data/icons-svg/stepicons-24.svg000066400000000000000000000322671220200411600202570ustar00rootroot00000000000000 image/svg+xml tilem-2.0/data/icons/000077500000000000000000000000001220200411600144755ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/000077500000000000000000000000001220200411600161345ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/16x16/000077500000000000000000000000001220200411600167215ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/16x16/actions/000077500000000000000000000000001220200411600203615ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/16x16/actions/tilem-db-finish.png000066400000000000000000000007301220200411600240420ustar00rootroot00000000000000PNG  IHDRaIDAT8MKQ"C ~AiVY8O3#L#st>M̨(چ E-Zm"7q;1вa{"?Xm6{_EȞV?TgDV7K(=Q,P(!! >͍%D_F;B._ȐG^7Փ,8OG`"2Y ҡā3sz@*'DgY <ž `0#! nAJz!LHlqj3hT,b<ߋ.n8bIQ{k+m#HibH+I(-77 ~́Rdo*@қ6 5HS d%Q9ס&(rSfw79!IENDB`tilem-2.0/data/icons/hicolor/16x16/actions/tilem-db-step-over.png000066400000000000000000000007521220200411600245120ustar00rootroot00000000000000PNG  IHDRaIDAT8I/a~K%> AB[H!EmѴh*Uj"4!zswфÓ$# Oq/yeל >+T@B= ~lEV A0`dM:$ZEB,ko c2yq3)8sx :5^G6 @4@؇ =f'cqMie/jDž dž ߗ)3'P- }U3VKܮt@~@L+ pXsڠk i@s-[ ԳX IsatKW^BH=H5T(;rk(G_{#.WD͠e7Ey'",׿d&^+?IENDB`tilem-2.0/data/icons/hicolor/16x16/actions/tilem-db-step.png000066400000000000000000000007621220200411600235420ustar00rootroot00000000000000PNG  IHDRaIDAT8ݒM(qwbH!W AIRfƼ䤔{Hm셅Bk5;QlR\\_߆H4ߞ~zzQ6ɼ-QM$U b2տ2]נ*fwnHGTh|94ER)zy.>Ty4zE^2dn ?1sw18>]8tyY*(UHsкNG6Ɯ吝RPc6zV׭.cɺ{M|C4Yl'őq7mkY,a`ƤնƗ*FcJ&7л[AG9_v (T2L`7uCfln_$jffáuD0 tx)vw FiD?խ<]~{{%3=5I:Ӊe'K،NoLTS;^ ;ry Moo硔{u~ԪQIENDB`tilem-2.0/data/icons/hicolor/16x16/status/000077500000000000000000000000001220200411600202445ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/16x16/status/tilem-disasm-break-pc.png000066400000000000000000000011201220200411600250160ustar00rootroot00000000000000PNG  IHDRa vpAg\ƭIDAT8c`tiod`x툙ٿ[^^v6o@C:AqO}(B؀Wٯ!t\ӆ@K?4ႽVV`Nl3?\N?26ML#SX07?<'UT58~cc ` lYL7jikAہ^٢-?@CV  ǚ`)$   >f); ?  ǟ)_BMzIENDB`tilem-2.0/data/icons/hicolor/16x16/status/tilem-disasm-break.png000066400000000000000000000010261220200411600244230ustar00rootroot00000000000000PNG  IHDRaIDAT8˵SKKBQ>=TI!EFq2JBڸdow-ڴncEdQY`6R.5sAfgy9 ğ !M/SEEIcBN  t٤)^<BKj$/`4}><⩻mkuo/·1o0X@˛ 7ttbQpg6dYC[Z"J<1)s&&}؈z$kkqhcf' РnR$L>$r ;o* OFFp`4⨮)AIUQ^]4ȗ vԤWW+PVV"^^HY6Hp({ZQp\Q"tXhZhʁ3PGn#B=XjrI V˅)+ Hp&V8*D"w~)=xD \fX쫙ďo{AT}_^+ƥ@IENDB`tilem-2.0/data/icons/hicolor/16x16/status/tilem-disasm-pc.png000066400000000000000000000004151220200411600237420ustar00rootroot00000000000000PNG  IHDRaIDAT8c?%apb #l6ǖ}e " 2d ajmVLJ?=IϚ C0 x~%RGǵ?9m4c.f׀?:O.dz)l胓 \0# .d~#X8Xae`\?IENDB`tilem-2.0/data/icons/hicolor/22x22/000077500000000000000000000000001220200411600167135ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/22x22/apps/000077500000000000000000000000001220200411600176565ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/22x22/apps/tilem.png000066400000000000000000000017511220200411600215020ustar00rootroot00000000000000PNG  IHDRĴl;sRGBbKGDC pHYs B(xtIME 33iIDAT8˝KlUsz<ر΃Tm(iXiWHt*`MUu5YT fӊ@HPD@TEH v=v2vfmJNDr6g9?g;crrRa5@ 11#P&2Tqc@45u}M.2qgEmn4m  NHF+jխz667DLq$U@LL|tK /.e9 |z⑷.5RI-ޞ㺜rSl6JTTi^$o21;1RJ/FkۛIp+Λl&3 "0|g&.]/_} 2 3}Y}k tvdZBb>@b<xٛ/]~`=~zÔdS w<BS܊,؊MM]7ǟ0 #9ǟё}3ʝFF#z/QW.gg}=#}iN B`]@BJn ;s+20U_ФsTKp6 RA dh6`f:ui4M ¶l2rV(\7h@))<E0 ЕaX~hfFR Ϗ AB!Hg`&ѕC^Cj8AiHIN Rhl'(Bm[9KI2q,"oͅW|>EDxө+W_)7qd[$LȝF3)IENDB`tilem-2.0/data/icons/hicolor/24x24/000077500000000000000000000000001220200411600167175ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/24x24/actions/000077500000000000000000000000001220200411600203575ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/24x24/actions/tilem-db-finish.png000066400000000000000000000017221220200411600240420ustar00rootroot00000000000000PNG  IHDRw=IDATHǵmOSgiݛ[L t0>ҧsJ@Omy*҂e蜾#_}Dt̒Y܋+99> ]JP9o/àJG4,@㖱l{O+mcRBac}Mq ,?\!F< 1B̋4,@[&sacp߅?+HBO:l9-4lER+)\VS Yi 燏Უ[}&I#L~]DCzY9T@꫶+U/';>'S''x0fɕsoԯRJz; %؈#""IՇ.g X^w͜wwPNla=o9g Ić"h`YQ`!/!0Y>x"Jh[hDkvm'l?ZaV: b RiiE]A# S~c0^# H"/1n2ңTKSY$C}ADIC0®v1&`lȘl9\`;=王#h?wA"{G c@%vыMI8n0=s pn;IV[LsDvMoJ3_oD 3ュkAmĺ(O頵AS8U-Lપr5imFcpu`h-+"Zkx]"MUVǁ΂妕' ܸ?򺦐+M[まϲE^_϶)Sמ{eĪ4ˏ Ok-c̶yIENDB`tilem-2.0/data/icons/hicolor/24x24/actions/tilem-db-step-over.png000066400000000000000000000016771220200411600245170ustar00rootroot00000000000000PNG  IHDRw=IDATHǵVKhQOSUvQbZmW*TI(qB(.ڽ*;7+`ЍmF)TSiI|L4cU9fdG^ϥg;ds\.F+0A fKrupNK2L@ (E (iybb3z" n_ _? gygWE@BB:ۥS/݆)WNdr葂+ &J<-=b9PR:omAOav6 R l4yD" ,̒jUBd럚6n0ŨT%oM%<+Fálf#K$0q*YPEfdp5>\HʊT*8eZN%ŀ'MNN׈qJr&$ p}4VVK[>H?K`j 'R.d {vD"?5 +#ЊWEQ RudL7QqR uœy|bS<@ h9g\.CU78A㫀(ysSmCT+0yB>uKT$ArLe cBUcedn-A] ~6^$`d|___@pUH1= *̘(Q0k@SuqP&2{\'!bl:9"_,f'w<^ckhِw|>rQhlizZn/y36S{ލVEp*XP`zp%n^ 3"8[,_c_O^J\[+o|`>i1]6J7drScLB) K7.fXf<|d\\Ɍ'nND*&3[GknoGl ]C0v8@‹~tv}qz?u5cEv]X]W3Ipbݳbo+x4UIENDB`tilem-2.0/data/icons/hicolor/24x24/apps/000077500000000000000000000000001220200411600176625ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/24x24/apps/tilem.png000066400000000000000000000017541220200411600215110ustar00rootroot00000000000000PNG  IHDRw=sRGBbKGDC pHYs B(xtIME *lIDATHǵTMhe~ofv?1 hԦ= E,EK=Sh(T< KOQAݠ658zn@ 3><ϼ/#"<#:aX(0& DbBeX@YVz#ܖ>v{%B!(zTUkZV;Դ#XʸVF3ǑBTJḊ7S/MBAEZWV+󶶸$IjRI&d69CiR,]wȏE믾H,,|q|poX쐁Lɤz`}oiy0@D{ꭹ8ʞz=X|/<0ߚ_weܶOQ C+wv__ґ2WbvMCv EVy[oN?'7aL=d29zw}>63hg+^LpE_b\?,,`xӝ; c' 88:2sXe !+ԉt7X/U* 4 @:݋f "±cGa:t](LÄmY mwHJbm6ѧQsM 4MڃMwh;kˏQ,8 KKQ(pvz)7 Ӵl~zAp+V0`|l#&aZW`Z(j'0t}&5}HqG\֚KwR|ÇE5rl^Z+mx`2t'Y?fIENDB`tilem-2.0/data/icons/hicolor/32x32/000077500000000000000000000000001220200411600167155ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/32x32/apps/000077500000000000000000000000001220200411600176605ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/32x32/apps/tilem.png000066400000000000000000000025131220200411600215010ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs B(xtIME  &IDATXKlTU޹ܙ>f)THImkBpEPFƅ 6FiYu… #P7HRQ G;й{\̃BLM]!d~۳gW "j JTMTJ3_"p|.kxo:::D5bYs;*ǰ߉._"x IENDB`tilem-2.0/data/icons/hicolor/48x48/000077500000000000000000000000001220200411600167335ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/48x48/apps/000077500000000000000000000000001220200411600176765ustar00rootroot00000000000000tilem-2.0/data/icons/hicolor/48x48/apps/tilem.png000066400000000000000000000034561220200411600215260ustar00rootroot00000000000000PNG  IHDR00WsRGBbKGDC pHYs B(xtIME !IDAThZ]lW{gwgfgw^&jLx@B UUmAH}*a}!plx~d;5Zmj1(rV##/^\ko66FzzrP9?72vVo~w]ZZ/m%6[\\>)#r:~8bxS?11P("4|eAu jYdsYnꗗ1?Tjkv 33;sLٍ?|?c'oeXd2sOA(~8Y q칦;-;5##OlĿ1;3X, I:೧Nɉ ~b`}݂ nޜ\| fׯ]1Dp0 nsRt@oW~٧111<l{mG1RRB4 Iضrq] zgݷ`s3i I# N#"i&[} 0h( ])2 `s2T(R7Pg4J۲!iAnXF&HCB A"$r0990 ! CEU!(gGaFk#Rhh}(R\FT?,__~u%0T*ᣏ01y J̹ڤX\n2uwLQ͉*u 4Ն5>s\EO}!͒0)F::@c_!O>qVg|3sUE>B 5BةyL¼]Go5 aPGqkMFbXJ % P6J-73*m/ q={W^)aX|Fq_@_5;| Xe,nî} /h8jԭ DB|d*Rl._덤l>+\ŠTF{ҕd/4"+?o쥘1!IENDB`tilem-2.0/data/icons/hicolor/index.theme000066400000000000000000000011441220200411600202670ustar00rootroot00000000000000[Icon Theme] Name=hicolor Comment=Default Theme Directories=16x16/actions,16x16/apps,16x16/status,22x22/apps,24x24/actions,24x24/apps,32x32/apps,48x48/apps [16x16/actions] Size=16 Context=Actions Type=Threshold [16x16/apps] Size=16 Context=Applications Type=Threshold [16x16/status] Size=16 Context=Status Type=Threshold [22x22/apps] Size=22 Context=Applications Type=Threshold [24x24/actions] Size=24 Context=Actions Type=Threshold [24x24/apps] Size=24 Context=Applications Type=Threshold [32x32/apps] Size=32 Context=Applications Type=Threshold [48x48/apps] Size=48 Context=Applications Type=Threshold tilem-2.0/data/keybindings.ini000066400000000000000000000341211220200411600163720ustar00rootroot00000000000000[common] Up = Up KP_Up = Up Down = Down KP_Down = Down Left = Left KP_Left = Left Right = Right KP_Right = Right Shift+Up = 2nd, Up Shift+Down = 2nd, Down Tab = 2nd KP_Tab = 2nd ISO_Left_Tab = 2nd Delete = Del KP_Delete = Del BackSpace = Left, Del Ctrl+BackSpace = Clear Ctrl+Delete = Clear Ctrl+KP_Delete = Clear 0 = 0 KP_0 = 0 1 = 1 KP_1 = 1 2 = 2 KP_2 = 2 3 = 3 KP_3 = 3 4 = 4 KP_4 = 4 5 = 5 KP_5 = 5 6 = 6 KP_6 = 6 7 = 7 KP_7 = 7 8 = 8 KP_8 = 8 9 = 9 KP_9 = 9 period = DecPnt KP_Decimal = DecPnt asciitilde = Chs dead_tilde = Chs plusminus = Chs Shift+KP_Subtract = Chs dollar = 2nd, Chs plus = Add KP_Add = Add minus = Sub KP_Subtract = Sub asterisk = Mul KP_Multiply = Mul slash = Div KP_Divide = Div asciicircum = Power dead_circumflex = Power twosuperior = Square Ctrl+2 = Square parenleft = LParen parenright = RParen greater = Store less = 2nd, Store F12 = On Shift+F12 = 2nd, On Return = Enter KP_Enter = Enter ISO_Enter = Enter Shift+Return = 2nd, Enter Shift+KP_Enter = 2nd, Enter Shift+ISO_Enter = 2nd, Enter [ti73] INHERIT = common F1 = YEqu F2 = Window F3 = Zoom F4 = Trace F5 = Graph Shift+F1 = 2nd, YEqu Shift+F2 = 2nd, Window Shift+F3 = 2nd, Zoom Shift+F4 = 2nd, Trace Shift+F5 = 2nd, Graph Home = 2nd, Left End = 2nd, Right F11 = Mode Shift+Escape = 2nd, Mode Insert = 2nd, Del KP_Insert = 2nd, Del m = Math Menu = 2nd, Math apostrophe = 2nd, Math d = Draw l = List ampersand = 2nd, Power EuroSign = 2nd, Power F8 = Prgm p = Prgm Ctrl+Tab = 2nd, Prgm Ctrl+KP_Tab = 2nd, Prgm Ctrl+ISO_Left_Tab = 2nd, Prgm F7 = Apps Escape = Clear underscore = Unit bar = FracSlash brokenbar = FracSlash onehalf = FracSlash backslash = 2nd, FracSlash onesuperior = 2nd, FracSlash Ctrl+1 = 2nd, FracSlash f = FracDec numbersign = 2nd, FracDec a = MixSimp c = Const s = Simp percent = Percent x = VarX comma = Comma [ti76] INHERIT = common F1 = YEqu F2 = Window F3 = Zoom F4 = Trace F5 = Graph Shift+F1 = 2nd, YEqu Shift+F2 = 2nd, Window Shift+F3 = 2nd, Zoom Shift+F4 = 2nd, Trace Shift+F5 = 2nd, Graph Home = 2nd, Left KP_Home = 2nd, Left End = 2nd, Right KP_End = 2nd, Right F11 = Mode Shift+Escape = 2nd, Mode Insert = 2nd, Del KP_Insert = 2nd, Del Menu = Alpha apostrophe = Alpha x = Graphvar F10 = Stat F6 = Math F7 = Matrix F8 = Prgm F9 = Vars Escape = Clear backslash = Recip onesuperior = Recip Ctrl+1 = Recip s = Sin c = Cos t = Tan numbersign = 2nd, Power comma = Comma ampersand = 2nd, Comma EuroSign = 2nd, Comma braceleft = 2nd, LParen braceright = 2nd, RParen e = 2nd, Div o = Log u = 2nd, 7 v = 2nd, 8 w = 2nd, 9 l = Ln p = Prgm Ctrl+Tab = 2nd, 0 Ctrl+KP_Tab = 2nd, 0 Ctrl+ISO_Left_Tab = 2nd, 0 [ti81] INHERIT = common F1 = YEqu F2 = Range F3 = Zoom F4 = Trace F5 = Graph Shift+F1 = 2nd, YEqu Shift+F2 = 2nd, Range Shift+F3 = 2nd, Zoom Shift+F4 = 2nd, Trace Shift+F5 = 2nd, Graph Insert = Ins KP_Insert = Ins Menu = Alpha apostrophe = Alpha x = Graphvar F11 = Mode F6 = Math F7 = Matrix F8 = Prgm F9 = Vars Escape = Clear Shift+Escape = 2nd, Clear backslash = Recip onesuperior = Recip Ctrl+1 = Recip bar = 2nd, Recip brokenbar = 2nd, Recip s = Sin c = Cos t = Tan p = Prgm numbersign = 2nd, Power ampersand = EE EuroSign = EE o = Log l = Ln A = Alpha, Math B = Alpha, Matrix C = Alpha, Prgm D = Alpha, Recip E = Alpha, Sin F = Alpha, Cos G = Alpha, Tan H = Alpha, Power I = Alpha, Square J = Alpha, EE K = Alpha, LParen L = Alpha, RParen M = Alpha, Div N = Alpha, Log O = Alpha, 7 P = Alpha, 8 Q = Alpha, 9 R = Alpha, Mul S = Alpha, Ln T = Alpha, 4 U = Alpha, 5 V = Alpha, 6 W = Alpha, Sub X = Alpha, Store Y = Alpha, 1 Z = Alpha, 2 at = Alpha, 3 quotedbl = Alpha, Add space = Alpha, 0 comma = Alpha, DecPnt question = Alpha, Chs [ti82] INHERIT = common F1 = YEqu F2 = Window F3 = Zoom F4 = Trace F5 = Graph Shift+F1 = 2nd, YEqu Shift+F2 = 2nd, Window Shift+F3 = 2nd, Zoom Shift+F4 = 2nd, Trace Shift+F5 = 2nd, Graph Home = 2nd, Left KP_Home = 2nd, Left End = 2nd, Right KP_End = 2nd, Right F11 = Mode Shift+Escape = 2nd, Mode Insert = 2nd, Del KP_Insert = 2nd, Del Menu = Alpha apostrophe = Alpha x = Graphvar F10 = Stat F6 = Math F7 = Matrix F8 = Prgm F9 = Vars Escape = Clear backslash = Recip onesuperior = Recip Ctrl+1 = Recip bar = 2nd, Recip brokenbar = 2nd, Recip s = Sin c = Cos t = Tan numbersign = 2nd, Power comma = Comma ampersand = 2nd, Comma EuroSign = 2nd, Comma braceleft = 2nd, LParen braceright = 2nd, RParen o = Log u = 2nd, 7 v = 2nd, 8 n = 2nd, 9 bracketleft = 2nd, Mul l = Ln p = Prgm bracketright = 2nd, Sub A = Alpha, Math B = Alpha, Matrix C = Alpha, Prgm D = Alpha, Recip E = Alpha, Sin F = Alpha, Cos G = Alpha, Tan H = Alpha, Power I = Alpha, Square J = Alpha, Comma K = Alpha, LParen L = Alpha, RParen M = Alpha, Div N = Alpha, Log O = Alpha, 7 P = Alpha, 8 Q = Alpha, 9 R = Alpha, Mul S = Alpha, Ln T = Alpha, 4 U = Alpha, 5 V = Alpha, 6 W = Alpha, Sub X = Alpha, Store Y = Alpha, 1 Z = Alpha, 2 at = Alpha, 3 quotedbl = Alpha, Add space = Alpha, 0 colon = Alpha, DecPnt question = Alpha, Chs [ti83] INHERIT = common F1 = YEqu F2 = Window F3 = Zoom F4 = Trace F5 = Graph Shift+F1 = 2nd, YEqu Shift+F2 = 2nd, Window Shift+F3 = 2nd, Zoom Shift+F4 = 2nd, Trace Shift+F5 = 2nd, Graph Home = 2nd, Left KP_Home = 2nd, Left End = 2nd, Right KP_End = 2nd, Right Page_Up = Alpha, Up KP_Page_Up = Alpha, Up Page_Down = Alpha, Down KP_Page_Down = Alpha, Down F11 = Mode Shift+Escape = 2nd, Mode Insert = 2nd, Del KP_Insert = 2nd, Del Menu = Alpha apostrophe = Alpha x = Graphvar F10 = Stat F6 = Math F7 = Matrix F8 = Prgm F9 = Vars Escape = Clear backslash = Recip onesuperior = Recip Ctrl+1 = Recip s = Sin c = Cos t = Tan numbersign = 2nd, Power comma = Comma ampersand = 2nd, Comma EuroSign = 2nd, Comma braceleft = 2nd, LParen braceright = 2nd, RParen e = 2nd, Div o = Log u = 2nd, 7 v = 2nd, 8 w = 2nd, 9 p = Prgm bracketleft = 2nd, Mul l = Ln bracketright = 2nd, Sub Ctrl+Tab = 2nd, 0 Ctrl+KP_Tab = 2nd, 0 Ctrl+ISO_Left_Tab = 2nd, 0 i = 2nd, DecPnt A = Alpha, Math B = Alpha, Matrix C = Alpha, Prgm D = Alpha, Recip E = Alpha, Sin F = Alpha, Cos G = Alpha, Tan H = Alpha, Power I = Alpha, Square J = Alpha, Comma K = Alpha, LParen L = Alpha, RParen M = Alpha, Div N = Alpha, Log O = Alpha, 7 P = Alpha, 8 Q = Alpha, 9 R = Alpha, Mul S = Alpha, Ln T = Alpha, 4 U = Alpha, 5 V = Alpha, 6 W = Alpha, Sub X = Alpha, Store Y = Alpha, 1 Z = Alpha, 2 at = Alpha, 3 quotedbl = Alpha, Add space = Alpha, 0 colon = Alpha, DecPnt question = Alpha, Chs [ti83p] INHERIT = ti83 CapsLock+a = Alpha, Alpha, Math CapsLock+b = Alpha, Alpha, Apps CapsLock+c = Alpha, Alpha, Prgm CapsLock+d = Alpha, Alpha, Recip CapsLock+e = Alpha, Alpha, Sin CapsLock+f = Alpha, Alpha, Cos CapsLock+g = Alpha, Alpha, Tan CapsLock+h = Alpha, Alpha, Power CapsLock+i = Alpha, Alpha, Square CapsLock+j = Alpha, Alpha, Comma CapsLock+k = Alpha, Alpha, LParen CapsLock+l = Alpha, Alpha, RParen CapsLock+m = Alpha, Alpha, Div CapsLock+n = Alpha, Alpha, Log CapsLock+o = Alpha, Alpha, 7 CapsLock+p = Alpha, Alpha, 8 CapsLock+q = Alpha, Alpha, 9 CapsLock+r = Alpha, Alpha, Mul CapsLock+s = Alpha, Alpha, Ln CapsLock+t = Alpha, Alpha, 4 CapsLock+u = Alpha, Alpha, 5 CapsLock+v = Alpha, Alpha, 6 CapsLock+w = Alpha, Alpha, Sub CapsLock+x = Alpha, Alpha, Store CapsLock+y = Alpha, Alpha, 1 CapsLock+z = Alpha, Alpha, 2 [ti83pse] INHERIT = ti83p [ti84p] INHERIT = ti83p [ti84pse] INHERIT = ti83p [ti84pns] INHERIT = ti83p [ti85] INHERIT = common F1 = F1 F2 = F2 F3 = F3 F4 = F4 F5 = F5 Shift+F1 = 2nd, F1 Shift+F2 = 2nd, F2 Shift+F3 = 2nd, F3 Shift+F4 = 2nd, F4 Shift+F5 = 2nd, F5 Home = 2nd, Left KP_Home = 2nd, Left End = 2nd, Right KP_End = 2nd, Right Escape = Exit Shift+Escape = 2nd, Exit Page_Down = More KP_Page_Down = More F11 = 2nd, More Menu = Alpha apostrophe = Alpha Insert = 2nd, Del KP_Insert = 2nd, Del F6 = Graph F7 = Stat F8 = Prgm F9 = Custom Ctrl+Tab = 2nd, Custom Ctrl+KP_Tab = 2nd, Custom Ctrl+ISO_Left_Tab = 2nd, Custom numbersign = 2nd, Power ampersand = EE EuroSign = EE backslash = 2nd, EE onesuperior = 2nd, EE Ctrl+1 = 2nd, EE bracketleft = 2nd, LParen bracketright = 2nd, RParen comma = Comma colon = 2nd, DecPnt A = Alpha, Log B = Alpha, Sin C = Alpha, Cos D = Alpha, Tan E = Alpha, Power F = Alpha, Ln G = Alpha, EE H = Alpha, LParen I = Alpha, RParen J = Alpha, Div K = Alpha, Square L = Alpha, 7 M = Alpha, 8 N = Alpha, 9 O = Alpha, Mul P = Alpha, Comma Q = Alpha, 4 R = Alpha, 5 S = Alpha, 6 T = Alpha, Sub U = Alpha, 1 V = Alpha, 2 W = Alpha, 3 X = Alpha, Add Y = Alpha, 0 Z = Alpha, DecPnt space = Alpha, Chs equal = Alpha, Store a = 2nd, Alpha, Log b = 2nd, Alpha, Sin c = 2nd, Alpha, Cos d = 2nd, Alpha, Tan e = 2nd, Alpha, Power f = 2nd, Alpha, Ln g = 2nd, Alpha, EE h = 2nd, Alpha, LParen i = 2nd, Alpha, RParen j = 2nd, Alpha, Div k = 2nd, Alpha, Square l = 2nd, Alpha, 7 m = 2nd, Alpha, 8 n = 2nd, Alpha, 9 o = 2nd, Alpha, Mul p = 2nd, Alpha, Comma q = 2nd, Alpha, 4 r = 2nd, Alpha, 5 s = 2nd, Alpha, 6 t = 2nd, Alpha, Sub u = 2nd, Alpha, 1 v = 2nd, Alpha, 2 w = 2nd, Alpha, 3 x = 2nd, Alpha, Add y = 2nd, Alpha, 0 z = 2nd, Alpha, DecPnt [ti86] INHERIT = ti85 tilem-2.0/data/skins/000077500000000000000000000000001220200411600145115ustar00rootroot00000000000000tilem-2.0/data/skins/README000066400000000000000000000032061220200411600153720ustar00rootroot00000000000000** About the format : ** When I started to work on tilem 2, I firstly decided to use the old tilem format (4 pixs around a lcd). But that's not a good idea, and the new skin creation is too hard like this ... :( Finally, we (with Benjamin) have choosen the Tiemu skin format: This format consists in a binary file containing skin information (author, name, model, size etc...) and in the second part :the image data. With this format, it becomes really simple and fun to create a skin. Tiemu Skinedit works perfectly for tilem 2 (how do you think I 've created these "officials skins :P). I hope this new format will pleased to you. Thank you Julien Blache for his help and his authorization to use Tiemu skin format and skinops.c/skinops.h files. Thank you Romain Lievin too. ** About the image source : ** To find free files to generate skins is not so easy :| A part was found on wikimedia (god bless wikimedia) Some other are created and donated by tilem2 users :) Some other are just my own calc. For the source of the pictures : ti81.skn = GFDL wikimedia.commons ti82.skn = GFDL wikimedia.commons TI82stats.skn = GFDL wikimedia.commons ti83.skn = My TI83 !!! ti83p.skn = GFDL wikimedia.commons ti83pfr.skn = GPL v3+ given by Claude Clerc (aka claudiux). It's his calc. Thanks to him !!! ti84p.skn = My TI84plus !!! ti84p2.skn = Mine. ti86.skn = LGPL v2.1. Picture given by Danilo Segan. I've resized with the gimp and I've done the skin (the skin given by Danilo was perfect but too big).Thanks to him !!! ... ... Your contribution ... Your contribution ... Your contribution ... ... ... ... Have fun with tilem 2 ;) Thibault Duponchelle (aka contra-sh) tilem-2.0/data/skins/ti76.skn000066400000000000000000012344021220200411600160250ustar00rootroot00000000000000TiEmu v2.00`TI76Duponchelle Thibault1."TI-84+UCcP7Gk[}FZEZD=[KEZ5kz$l&se,b5k{7l|<L5"lA|#C!B!;AM!C5Tkr{RsStS<tMTr5m{<L4l{;M5k |=L5l<|-Q-S*=SLEJFIFCC" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?($?ӯ^+? w mb쵎m6JKzіi9xmWoF*ե5qiУ:eB+m'򊼟S>/Cԍ,>Ua?VKv:|JGëԼkm'-n|gaRp+?~ 4q=جwEd2}ĎgӠp>f__ɿ_뺆MZRgS#*eEl]vjR(a(*`*<Ūxp^F%$^9#5f4B ׯ4ch q_x#NkfX悟rIkR=g>/g8\p,5'$׋הo$NrTi %NRS.oC 5wΕ k7.hl>3s]INmO7 w-`v>x ,OlWc\x u)pPJB #Տ pS Kk U-Sv9?mt+O/TIhГ UO :s3%<CLO)mxgs#:;fqہz_ECӥm?5_jgLmGnBc庶1F =^WLHՉ}y|A`; #Q1ۧZuZDx#.iq$^W.].>_DT=YZۋB[1 w;-u,R}SU\ qi3dk:r,րt=+KV,# 7VyuYUCfaH)>~\qt˽m/Jy%,^If~hP?zǥ` 0 ;gvqb?jZ'<53INɘc#V=̖S J`ہ`1$ELvz0Lav$rK1W n柰öOjZ2O|a^hjgӃ}[i;hitA`&bI Izs?h De ǞJy'fy A?&Rvڰ0c9q']D&C G8U YI Hd #^ۚXYB:_U+v{=kјoG.vֲ+>̵W[Е__vܪp\C `r2EdMo|7Rk?Rt]:/NZ]WNOj}F T A8AU57Sn# 4 ,I!Ab1#;#_ĵSn;}O+pͥju{~Iqxk|6<4koA_NcӃ'bseS>JŚUŒ,e##~XI>WT $|' G S;0.͖nrr[vF8鞈p[d_%]uCK;S{{:7^KKt~~ZT,J) TUnh|:MrxL iE2QoeœPs2669e%rCp+) p$ !,1#@ C2S[b M0,{[㗊U%eJVj/)|_ĝ>[cfkv]CEr@n8;wA(bל:`snc *籕e8r,NWTt85G-W?3`錑ֵ e Nˈmk~a/x _Tڶym?RXkFLW'fe+j tz08߬0A IrA22S~,K?',UVCC6Hq*O*r`$pݾRNN9!vRT9SW=@#JÙZ%GFۈS%#bz=+NHEz1]VKd|n(񟆋6*<eEܥR>W'd o 8fw!\ #'o886FU@Ab!r( ߅11O]ʶx<=&߈|VIG6O6+uK(ey 8b8-[$ 2|laL2mTU'3t~ziLml_  "u߿"}oq7&j o pUNvOq`xb$ppAt #0f(-I;0۱tlQ"eoFC  '쥤 oO׈]9m?!/9JS?G Yot+m[IY" gу<+v?[}Wbr8ȯ@dXaF ڜϫA*'taNWhrH;zἙ{*&&)۱KW}\a2I|/(W!g{)x]za%`ʑ࢞/Ve_&*EB&m&||H'rw0Bh8!EۖՃpqA 1%p; ëc88sP_${`)MV^JiM!BA/A_7L20HkH$˿-J al8Ue[i)~JNF ̀+9pHSK8xPwekG^x~u8* UNOcg^nYsxd-c9 )]g,X_ 3 d1b-rzId0c>dT1q5%W]:IgT )z% ^߱0D~L3<>9öG^af8ܸMr?LprnBP`yWa|w>J8mc z8d|Qp $d.kyTJ6 !+y~e?x-{\SQu,E;(eէ4\umR.t]z İ܌c'OۓeE,9Eum6F8᤺UˇmF?O=U}Ŕ),@봯a9 bbqR7~>v蟍YJo^FU'orvv}6?dO(kV_U8k ~XC T͵C83:#º[]mN . `Un@lggh|?;2GpQÝ dqDյKqo ! 9϶Gu>Jֺ1pչP5{Vz4ĵ~Y~p772シޥxҭl?@u_, Jxpn9P#p\W_N?>_R Mm풭"4yv*I/Qy$" wHv:Fw*A$)DPKqŻ$r3,8pxz5,>xm58-CX5;7d:[n $ Y\=oW ԭiF);ӛi6'O `N#px #j ٹ<5*u!^W+\t]{GkhZ_GZu7|H A~ WSE nϩ/ tה"_<# cmE~Bw Zq^k]mzxK{\Fʴfhv{gw¾ڞmJ Va-Qִ]OZ8"(ۍ~xR}ZF%tFʝnp$s>%S+Z7Ǔbzr]YO]K ey3T.~sD+3 FTgN *xXi]&v[-j6*z,#m;8{IsYͭO!yd Y2 HUF܂E)gyw;vd8C8R9wr6x6i9$Ps8$,Q 7"OU]{hpII$)i`s}8 H͕ar0A9$3l$S 0ݰF7lH'~z pr*z^os9]n3UF[al:Ӂޣ$ oʨ P|HHY\#pۖf]̀XN dش(K\LDtW1 I:8x٥Aa*RiJ\P%I63rja ԨT U*rFTof`<մ{|*v1,X r1 a9= !X#Ӝ#OxcJ8</ x[J/xLK ;/bӥ u}sXM27Z|youHC7y 4knf[UVFh ^Haq19єj{XAKU=5;ÖҌ$-5)'JucF5R>TT)MB.QeyE8I68AQ {dcCMYH- 7rX,c08h <*|/qX/isxVxb}FߍfMj-"f_6UnHȕ-{nj9u_þ'tF[+o%*+[Ko5{dKk*x +5TN*i%jKx^I+ƛeˊsL8`ѧQS8J|zr&VP9Y3~Si0; vH pI۹8Sҿ\Α/[]?bJEԣ-W59^ncWZH$, 7efjq?ٚO~4ams'ko'ٚD@a:qѩs$nYVj k7($cW_Uo̽Eʣnw.hG0}MJ.n<ѾSYp~Q~X7qBNFxʰ+ '; XCmO\~8neѵ)ttKwu&}9Ԯk?Tom-F[=n[Iy`x12l&fZU)u8m}gN+=I;fejʭմu.ʬW+\N^myy& b19x`mܻH$33BOl!v~ շ.,oZhޟ,>QM NfAwhc'⸸Q5vIf VR$mm5:QAVI۲I/[{kT+؝S[BRwudMm_8ǘ0~`kN26XN pFYXI f'gl^]u=??.t˫m>-EO{9--A c}6<#[[ kX}}w.xvZﲾۈncC%ďOo"HUI)SKUw8$mxiI]{j W[ѫz1^F"{69*2 %@!? @s@qes}heiuae}{e\[Y23GX 巷؟2Fd+ߺq / ;;DKjQ@׷i-ʳ]\E0GiTa~yBhC^֞"/ouET.hU)UwJMiSQ洛㿼l *= '`󜜜P瞅9aw3#8# r3KꚖ,UF~5ݐYX77Ƒ*߳Zk{yභF{QApyOT[xYYStѺNPMJ&N*UuhuTϖ|BSq%Ҕf(|S Z0 #51_0w\(ۻ ۆ ǽmK/E/3zmSJhHm[G>JI">0J O1mc`PWprsA )Y2NʮH=x'9G A >ԥ@IPI2I$䖒P Y\Fq`4DK! $8Ҝ&@ <!K;2v0V '(˴1,2XBNTA0N,F P*`$ a U Gif9鴩J 8r'+P`|Ėb3W@88r؜;bCm"5nJJR0*X9ǁH _~_<6/㎹6?ڜe;ae5εs<(K,v^I@"??@im[Oዿ;^1/[NI-k3KUY2j39bP B+}Og],,2ά*oac Q faN :Uө^<Ƣh[ F $ 2:t*5jBkY'j5Iţ ݃xPy; uK7Ec898m_<4[ӵkJēK{丿XKM<O<[~;<ğϫcoqd,EzhM m±G8'Uk}J8Ᾰp?i3UeI׍Xs:n5aJPGW^:ҩJxJU+JJKٷ#hpLR{0I=['ڽG=r?d?*i$;~¨|kߍK=K++55! ;>,WRy2m4k[_S*ο?iUuѵwOͦriU妓[t/K0es\1,4qξ &j|N:x`(¢UU1UE:tsO[Vtj* TүRkQ]IқUIMEBNQܮF6#qqM'j_Km8* 0NF2TWi՚0ۊP|czi<uO3-Gi(?>hնii 曬x'67 Ai\} Ϟ2\vo*xzUF'Ka%J#:R *UjJ*J;PVhZI9;Z2ue;ts63qD;H=1I8`~5a ˝}l%cMTzt3]Gds%WWB5#Hvʍad#p@ʑrx<ڰTգ I愽hMӦ̭iԝ8]77wn8\j..;I]]\C(%P6w/S 0~Jo 1O]*9eE XeP $=y<*d( ?wg]v6W_~Wkk-4Ӻhiivѵ9wprx'nHx9x5mDž5?;m5Yqϝuޤ7AIE\.B3H1ep';T}}E5]&Hw[IܬOK ^"f9toⰵ-}l#$)iU:8֧k+MN3n-%|wiZj~.ǟnKhf5$@.|0*pΠ1 B7QV7uÚDӻ9&gȌ[?Of=o@FD=h R3rkR"žx.\,,L $Dy(sאy=kJG G+ݒZiiև>WrRoWùkWQmSͥQE5?_۵a1 =98'$|WYJ[>'qds_IiK9Q;iJI|Sv:?|Kim F1`8sany?ty%+kz[R#d!qyۖQe36\pA.HGؙ%yb$b!QyT XdI99治wmݷgO1ߒ * ry)@yAܸ8OBH<8<#RU rsؑ'0`)bT0̸0bGB%gʖ=z[YG-]дCkq?Os sqonLrk>8Q$wtmx΅_Rh,Z)bߘ$UQss9t3ismwe-Qf .#4(jSM5MR*MjqiYAM6桥$*pܫSJ|6&P[PR"+BNsxx ԟ/*si?яvĿ|9O%γ5ן*Z4/_xOdӖ-gb+A嬓nT=/48̈́3.\-qs:[3F-0 !P:pيsG/yc$DSaYK8Vm@{`HkI^#j6>E6w>%wv؟xQu / to]qA=u vVmSDlR=ƻqicjz՞&>)P0  hI`Un.Ł7 a1S1RP6!BT*I\$T(bƗ-TpꊅH{)ӣ/vKM.0ª\uTbT+ }UiWΞ7'A1zQ%ϴlt?^u|_=. 5xwPj<]˥<XPnrxc(STIߕW*q>**ץRZ() sƓC=WZlzد*]L PW~!xnZO߇H#h>;Ӽ3 rżESҚK(u#q IomuvI/Iة+W}$ ˒b@ @%ՊNh`rF2;d1s8\knMF4&8Z2ӿ2pf*^OEJ*S R%M*.S)xeZt`?i;BxouG_kۻw;6IV-m(wFaҥvZx[K/⿇ +?OUpZ?wZdzcYiV6hY% mn>4ֹZ jIdӮ:] ^iVmm (s#߃5E[|c bO^A`-B{,fRI w,Yd5_-@À:H0 ^OR' .e(I?&J+1bTݰUQT:4*Rq!8FJu]Oݹꛨ⣢I$6#bg_NKrb|UxP:j(P*quf/i}{ &Ꮙ<7)_&[~4-m2u]ףUk fAT^T׫<0Tɂ[m`H[< KHTp2waaXN%B7m?3rS807:j$ѽ(^soU'Qӏ򤗍,<=ZSTԫ:nX˒gTь)h sSJTqmɑ 9 8f}qgp9\eFOʪ@-ܡBᰥw98_ Km|ž9$k`2&:_PqT T]0QH,cdV-xrXN3ʞ:\sޔIڥOV\s  @eW11.rG 4Anl$rH+Cĕp*€@BX 1Ps4YOGːīpafHh=Ć G m Wdc0|>enr9I1sc<$|I#vKdz t}?%a2|o KJuiLP̂Yom# UCe4?YZ*]:wş+.5SӴbT]BÚlVsa.W/y|1Ox;kij[\}kM0L꒴q,Uvt Ц*T0x~=[UA"[u<`>-3?p_X _yvs(`R\XP%j뒢NIG9xlFg+:QJ*T4W]ѣ(+6ڛįψ6Ş ]hV)"B[+VoO!\\i~mo죦XT<)o|?^ig∞Pomk+>v xN bk=A~xm)?xf;4m6Kۻ/﮵K%7w]_]M#Mrhq3g>3O$Elյ cYNŐ{f^Mw57&IE[d\ 823܋K2fv; GЧR9&SS3 qօUFJQѥ-gSR|,kk~˅U<6Z;x(TQ\*J~6qg[ǫ [L$s'-u}4@u KO.-_Qb+O~ ?dj~,zWs`&/_Ηuy4]U&%h>*k[(Ѵsúuk>kޝiQ.R |CAHuc]n݅귗pY_FEy9+m-~$y{Kzafم|fnw^_f+M3ʱJU!MДaNt*ը߂Ϊ#үVXZa% [8ԝ,6.գ#N17ď ^<khE=u&ĪuK)έIi hD!O~-֐~џ4_m|3x7vڧct~<9xX]k?<)@DY^w%ė?w? |w6ƿX~^՗QԤVŬU|.]8ԧC0:tNJхYaXu\^/bkJ*#rufՕK$(rRPQ]svedjI8KGg0p]'Ā䪟$"Rxl9-J)}3)VVf$$n%ԎpIl.pX`&T2GA}ḘYR:5Rإ 2P#ihtr{;Ii7qdvFf͂mNGB͖Fo81f]kQK_jWo=5?d؍,Xkт< !jn0@q_I|τ ?0ۥGm툵+_2O^1g_|MmBj|z"諕 _gxH)VAD cnY:By pk5'sdKx'X;{}Q_"7C?ʿ"?n#^%::zrvzsԟgFƿoyb SèW$fS&^=||ySg,;p_;toPd 1eH9 Ie ҁä>Qnsc>ݿ[G7V9%P>SAp3+lb}ܻ6/[+x|TcvA grTQQCg8=7GN;7:pǡb˸PW 9lsv*Zw.l) T!B~;OSH0G?y9 q˓q?Qu/ 7?ZW(#uk{/ٮa[a'D%Bo1|iP ͰJN;p?.|(گ7nуO+(xUB'|FvHăȎi _3920GcA_~ѿy` gQ?KTMedɳR2}z`A8RQJwoKׅukWV4]>q_Q>'=@K,|_`8k9'(~ѿA=8ɿ`r `G9~ҿ1عbqi|8#B;zи*I B/0F7d 99W>p[y7ax>6s sC%I.Fx5N08jUi$IS=D LG^v\qy_)-#`}'G>>|*r,p2@Ҵd*7>h2Ũ9|.O臜R9;|ܟ^chpJeaJ5`$*~۟ 6$Ѵa洏^"J=?? a-8?ߙG{ᴌ_V; h`1s+R/+kS ``Q9<_47 T\d ??-xr'Cjp:`9$dZ,NXh_w$ͯh.O_?&/^HMRw16[Yc2yVƵI݆>CJ$gA5[F3o`d-F<ĀG9<溻*E'%D>'`p>RyR-ʞZ{j9n//mW޿w}^6^@e8nG#j{S[ 6Jp0wwdqҿK+Ż@s w+(2M+ԞA zFaf~kcq@k\GC5RvZЫuޏ? )џeЗ%&%UrNN0[80+ð`ܤa cn]Oڪ}Tϴa>U&!W%c_ xT1Ȭx91F쑒0Jq&W;[K_9/__US_ܫs[_<#]R S<%j7oXNnҖueZ} pwvJp;W/`ozk΁`m;5apRE;׆H91$ITv8^IipdDP̅Kxv{ Ya`ra˝lJt:rCI{9ҏc2ڹv2G MR=vݒK[;fA!>`*d|:)aHE@lu,OG A IN;wUu Er`Wn#V}p'2 Y*ژ~I9Ǖ[:I $nKpukA_H8 sJ (p`0H'9SʬNq-GBx=898$т-`TrKcrGnM}} O30C+cBIpIG#eo BNdٞaP2&_'%ٛ,C +j(Tߧ5de{)J?m6Ԗ_#⇊nGU$yy\1ZfWàc 6F?kv $ @oºp!Wi\pp>dCQec,倷0ۂm_,#-8P2;ذ `RC:aNII.=^)|*a8j4Q=U%pNQ|i6쀱'$P-ʳ1,hݏ3$ FЇJqF-\1U 1O `:a-Yh}mgF߼g"0χ^8;cxZ7Rሧ:~cg9yq X s\p3UkZU=+:u#(}KO3УŜA,,LCS{* Vy#=<]ŧ˪#^*վcc/tŚKKg)6IBʷs—sVjR>^Raʥ%lgC5Յ dyRJѤsRV(*MԌ]HE4df|1 x^1ʮPm$ycg3 o3 tQ ʠ"d 8x. 5K+[c_נpܶj 25ȿ29+S Vpe)JrPnJRܢK[8nU'A7d)F1MrWz+&~< 'O20ʰ1Lp:0l㞝5Yo.|A $' }Awe=Xzt]Z>XՖKX.$V# P]gY~|@׵=׌u[_GI`qI߼k -%Y8ӭЕx U*(Ы^M3kR7R)ɻ;[_Oq.⽶U, j1XWR UQJ!o8>:LUb y`@˩;0Ow3MxPE~rpA5\?;svZ|[k?|pdH<>ř)QOH[ľ^]+–}6uΐ K9ͼ77B)ь**ZABʶJDaA:t(zZˌϸqYF;QҔ)ԬQV:sFU)ܳTmϧ;N\.r2CT&B"M鴌 ' Fx}ߴ_ oMW}O=G#pE$iCNmj:қ좳d\ܞ;1g7_Au AIb^OQվ%XSO>[[gu(Ϛ.>*T;<;j-(b4U߽9y}c!*>M<=hrNh3&^|;m4}{Z,s:Iw38m.-ѷf!VmÞ;ִu66K+mJMPKf\t.Z/$ *&Wգ::МFu"X SO4]j^Q;1AbU<,QZy}L5_JFx:^:~Z.FK1,#bFIܸ#Ag˻2B\$H$B~bu'8mآ/$[!ua-" @Yr]}x,[ z_4/u+Wwv-yt gwm ;dEXRx\&2tU)ЫpJ2q,%RdU ?5NS÷FtAjaV\ΝF}5?* -ʤ%b9#i>^NwH'u6f9_HLFz*N;|֙yqlּW'titq{xm;I[żm3K5(RVg>%j.?MuOͥjyഃS:^5YJ[]]^R8wsȹsPĥYRi<Ƴ|;\N^(Π|&XU5mO꒡ ZR*Z$Ť!K|#prxGdeQ$DF)1{>ݭ@Y[00aySRjٹYK3^*ϲe,:ѫtoF)9E4(9g-IVppq ߅;tXC,A j䁞`q_H@3l6ľ]Fq>Dtk+Y$tVX-I%h(f$aT wQ-ZIk%6+&lx\&_qnRi%̧dm4}M_qX(Ӊp.J>a d䎧 Gw;c' ͸/J_^I@<CX$Y_6Ɵ֩þeomNtZu{6};~%\gƷ?*gSs5Z1sQx+ܿޏ ɠj)bxo1|z6hG{\;tpܠP"9!f#5WZk&owGGٷO>\C|s _!JASzN2iȓ<מkѝ7(>  GVH48bF2+2|%ػFrSi?B{O95W\O>^JKG T۷%nhCz)E~8RtW'że+?JL<2xv:w~ֿlWIXK/n7G|6)WzK01JKhzF[?mLFLWٓs8976VVuF/eݯOr?C*/jR'(ٯ.Cǝ>v8S.0$|}=?0Hw%p~NX0ʂHh 0#3Þ:{Q\)-UV9< G~ 1N9J-Ҿ^Y@ A.1IqF$MRu8 A' < #XGO 6~R#ڹL29Ol:hr$KXn̎!PK^hgO >{hŌZ֙{zw/:,α%K:)\Mq.wJZ{X.V'{&ںz7d|V*VRjTOWN"r,Pr9d$*hX|eׁtM[atoV⏏hĩ6}OLX݅@xgˋ^e=OZxLIͥkr]iiK;gpPOwL \~ ?g)_ &tk<- 3}٦i K,rĞ藿O5eA|_QhIh6ZK"Sq{woou ՚:4qY]VUJ'C2TaQ9®7.F|ΆiSV5R6+5q0RN ,3,D1Y b2ԫ?``9:xZ 40(ם)~ x> _Uռkk0k~ڝ޹wsew%Χ-D.k 243]|1F|Oi'}'^y uxR绽 [IY& yg?Qq|W>*[x<-_- .ydO?c8S&xl}ҦэX¿$*~w.ǿ=oM>1?Y֓Y񍎿yu֒ Yb,ny^mu*k?<ER| >&5mcKM.[i"HʐC$QRr{,v9PqEs9xIѧK(5Rwkq ϊ)`3NUĮ V 剄1q9T\7H @d ~"_>X<Ծ xݮdn,r%zkfd {Au\n1 1Oogi玝ϱ4`1U%lDD+J_eNQKvcv-PK05,kjOMԓ_aT9N*)6֥6dR^N F0f9;޸i";Y#H pyR9di8*ܔݕ8zt_Ā-$̟H<7p{Wj/JX8'n"Iq{ec)嵰PXlU M*X]Uq*tNJ<'e Kk/5-'㮹'V=u}3jk]9᠚+٣ rZk~!ZЯ_dm5/v!x_ 9;? ֟t P.^Y'hfȐe }W/쏤DIϋ5? .dhcO-.m/F}^QwtivAoP ze\Rƶ:xi>l%_oVNt NT厉5Bn$˳jy,vO˫ehQOԌqtu1tqu<'SC ЋROWQOqEod%kٿjn;Cyn.[Q%,pєzaf#bo|b7K|Ik"^wz)՟Y}+EZj>tD5BywO q^ sR?iͨ^^Mh;im<Ь^Ls[gR실/,׎߄ |.M-4;GX;}6;8YKHa:T ٖ(bxT~]<<ӊb֍: y GҪC6F.i`s|9S+ F,^ ukS FM?˟%u?xb?7}mߋoSijRѾŗPnd B-F"! Ilbe,|yvPЊ?(%<jzi.&M? "#̆U WEm8yRhʱH;8_9p|XL_hՓjzn5ZHԌT樨RZ4π>3|YM'aoqdnni)b;F[Qz5jo^]=j/öx"nI}g ~m."is/y\ͫRk$?&?-7)\kj=~xqTNʈN@ڸq_VZ᧎|Omy; {X4O pi7<ډ/G .Uc)U̚wGxCz5 Z{Om*VJEy=Q2jMZ) O%oCx>(SU©\xli6mAsi ڔܭm F'1\ng<Zʤg0HNtz QM\5*8$gdymn&*o( ԫB/2:U3Xx\]\L<=NiTാ _Nφ:<~,/+g>u:ikB^c],HpcMEwt"Eڤ>Կ/$^{yddDۙ3|pEip>'lk>:$:imE1mwI %7MW*WR_a7Gk+)4[=xc<%V[Q**ܳ-i~fu# j2y|ᤧ9^#J3QS/5޿<9̥fbS6pL'J&6\ъ84OV{jb+tWeeo FTF Xz?Y !x]m|y{>uZ=*Cntg{y~^'h-sIbp~ ɿgo)]7ÿ'zq..F}=Ye%мiE0%,i? &5?0φJsh:+kPj '&Xcl'ڌ #*Axl F_[քFWNlP̴Ҝnx˸/8fؾ'<&3d2P}xxloWJz)?&5_xr?_ÿ|-Qƍsz^+ZK>WLZة#ZF!2k v\~\iq! >TNr 0#v>~3hL.X*hg-f@5㍤BIKYR(c0ܻC q s Bf'%ܳnnׁoZ5q4KkNz( 1ZeYo4|C6|ևiƬ*Qj۬ *4a($!x[,x;skĶshz./4mZ!L]ipŒI,ȻWs/UiOg|<\0^Aֱu>OKk+8mRUO%DG2 d`/5QM(Zk|nXKےRi5L^"|/΋/ 1'ZjpVӏ.o5.E濳i/ 6B|%@?ܱ|.YB -L _.x !O]O|lc!,WWIYQPӓe<XS`pWb ( 0 yjt}FsTFQJUg^:mrVQmne [8'fa*ScqX b3aa3|N# a5|5:k$דHf .'s$(waNv;x¥'WdeT;#*!\eHPH; r1%dO ʂZ 523 ?ҭUd۷v22ubJeN1_Tz+qkobow6 l-8_]nGZO8&ߴ:1Vt|l>aԁ粁`n+|WN<KVko}Z6vg[sӧ~rOl%g?=0sUP1s 7`2Ӛp\$۸g9ۅ=FH  ke$ii~`FHV O`-)wNy +"l*5񾜌P(@BɁԒ;dg}Ȱ~- D" '@w+]MMۻӢsd}Ef.t/l3,v֦ -C_֗UpdeD@^j Ōd{TΛh?nPJMTnKjq ceie_Oux]e `=x3EmtRl XޗeF}w>q,#> 'm}6H7u={ʽҊg8랜Q_k~՛__lqa]Ŗn@OڌÂ9' k %ϯ^3_> Q;b%=p s/pO0R?(}9_͙E_Xc?~769#-xFl ΀(3nA0/*ʈI)9_9`{'^ $($s1qRoĈ@pr6?gz*Y||kp˓_E]rw mWj9Q d8I 1jB0X&v) \yzqP(2@RO݌1諞-KGki+u] 2:9֧PX3H= yʖ኎2pWߌCOxI`F¤#%vVG3,3@;cn~VB"2mz*E-01 FC+ynPZ.R"#vrs2e͆}8Bo򆍈dc`BI;UYohMЙ]|&o?1ĩ_<aqluo:MLIcn-u$O8A+m]Xx$S xE)rT]儭(K{!8?_~a9h㰟WPF*~GF9ǖ)+KZJ-~c7%Y?h.O 1s%W:H;" .ID`09ḯiainP0@=u'##'5Z|f+/_~7UUk۽#H/l/m-,yId=+e{UNLu:0NIז QBRW$0Ӝ!yif0˼Bnc aө xQn6>r_UgVW?h4m5>OM{Tr+z~RB^]DXx\s |Q xEUާe/!x_ߌ.5/^5ƕk5FT'P:|;E$1ĵY|T mC[Q?gwz"_KmOCMƺ^<Z x5=Fܶ_>JQ.zZ*w'R*j{)KĊ G?}Rt0#513 rFYֲ|m|  tSbhLMỎy~UK>rI`5r6M16Lh`2*InB6_RKIM|Ck?쩦xUS}?w(։m3Xeͯ4BhG ant'|=_k#/hZ>YZxG>Gy=>T:+[u"L=8adH}bOӧ.S^912VU#GњuV)`"Wi}|egGO;[1VKN,¬a+ѣV sx+'F$IG'hf 䏗# ]DI㏿nd3^7]xoZNxW8]O汨{]N_5Ȇ&2*#K"!,;#oSzf :`p 9v;70XNxsxzX$oy'm&z?qd9kxFuy!UКijMNN.^vo%A_ۣrfN|mُ"4iGZ۟ojS޵Zn{IcpVoqBdM|w?J# *)º2I'ZTr9Nms%u "j^sۈǙP>[G=&Afo G*tWb_3-Uϐ%_ KzK̡d2ILo̟8@RK!dX+<A5ݤ*vKm ޥs!hb{wF A__Q/+x/Rߨ|b ]Z ԡ#o;m=5{d=Xq>zjW^X<kGQ\"Ki6y=x~?8j,ml]1rG,*Z ]ҕۿ< x ܌!1 NAR2) @6 &EP#?n01T$"r|mu[ώ/>+|ҼP_|7 [kweJ,;?f..&[h.f bOZW~8|OW$ZZUDŽty-{:2[uEnu'hrYLt1byJ xaA7̪ΛXoXyEF$SZ9\꧜\ K?V2fq4)fӨc ' cUm6|r>2 Ì?&NJxR~n72]1YiW i6|fqN ~/ڦgZLxj^"ռy*UΩqx$O l\|Ŋ{<2|⬅ln'@Լ_Jzdr6W&/4ͰX2Uzn.8\e*ntsaiO 6R񷍙w2oqO#ȨԞ^"8W_')EΔ~"W/ou4vM%ҥә4XGj$+ G ,/e£_FK`x` e@;?$ ?x|a9$sלk?oQv>x0ut'LbO6]Xw fPՏf㇠!>M4Σ敔T9O,ˡbpKx~jqJ9E|v)AťZi)'9Wć %pQV"I.Òłe_av Fb?MO؁+/A9W~;??gM?>ִkćT ߋ/ a5޹IFs*UMK5j)rn cW<Ҟ>[*PyΞ*T");#\VªRyv3a+8^:YK a΅8Ԟ::t5:є:7|_ rWRI ~ClvŃ$9%\8VgDOڟw]Xм#x{ֺ/4ܬU[O[AOqqpxȴcJ%hzOڅE-cwww+42fqm/FsmGb(PhU <z2Sq{:0G#E&j:G <,1yOeؼvgYm^0umV|r Bᵥ)zIoT9=ıP x$k>o'oBGLpd8' rx9=NWczI<`|FۮK-uiZZlS3RhiFgf2+%G&B\"UNѐHM:qc9 ~-Ne0ҼT9rϖw娭(?|YƜ?,o [xCVRe`,8%.^Zsiw\ kߍ7~#&k%͖;#,~V$9S' @ʀ ˁ3_gxv]/L .1pL{T9`yS˰-xyJTP}C_XE3WP/v5e ѦC˓ ?6cv~k Lvۭ d,z=_$*?_ <)(6X9a\zY|*:\#hu4^rqZJ?$>:r39%#_w߱ `0ix۰? |x W2dM*bsybv#/o ;qj*I: wҧo_.8lƖ)_Cd$n`@-ʁg?ZvBP##X;ءbNi ˑz@vnybpXuvc{;@r0sOr@HA C y9U`yfW,X);CqwG ĀP@ႆ<Q%umW3U#͎C† !H}+ٯSvN? HY7^MT;rzVΌ;D8"I$E, YU:>`Eo1e1[:<-y( VnY_;VU??732;}܈m~(xD&07ZX}۱%QcDA`cw~R| kuTFa'uRs;msc9\(‘@ێ!Aˈs]+ۦ sϱhszD2PP\`\1GL,sBDYr]xkg'Ư =u|?\΍iSS._OQ*NC caexa%ja Ru)խN<ݜQj| rvk \2'ժhӡ^Ҧ7Ѝj,)UEag K6R_7گI?eτGk#1h5mBFQf->nϴ?&iEi?O/ #ҭ%|oN?汳T졼7F VwğgS ?~7WI;{OskwtMwPt +Q=[{3|GQ>H~({> Ir5[ߎ=/O؛mt4~/{:Ʊ_i mum3wo:&: }ϑx' d-r/5i^]g |}}}OVž+tM` JoɾkgKHo#Gα({|J>!k߳-փokXI|?:tY;R6gs.4IwzuiAl)T2-6_S*TnZMЩNUi}btESjn%W53TXjRVcpdrڴY G+Ɲ*yLmj9y&j>>0O|9,S7ǷWLBO&X$e;A"Ckyr[  H FA'2`~WR><~˚UxSDoxyt9\hsyi֔:T_Vu+kJzOHE!ʽ^,q6]qUFYW1X?幞.c2EYb*TRUUUUuQ@9uw1~#|tԒš rTaúw^L>W:Ye*TU>NYZ2G_'|V~~6_>I6N+xrOk7]{},mhK[/O+~Ο|X|)BC魮׶VV@>"m:%uXMpSi̳C(zxwCko x^杯xf7ҵmR{-/Kv)pƐ2O#/ګ↓O @$mFg>j# <9e6KD]:Hh]Rfud(f\!Fz88Gxc[>1U%:|BJ?:ҩGo3)V]G)% R%gᆩ|n]q _&#W >o]\,{Ŀ5\_"2}-%/9u~}F짎M8 ix~xgOOX|UI g@Dž5Rt>B*arClN4o x\H`}# *Oqi:Zh`y1ІeBdPU[ſ'ǟ'u]fH?tZτl<<Vg}ovl0{]|*$^vG]zQCh⾷cG/g٥24rT.+Srx< XJ^X~~0U⯈ |]98{-s9 {^a,֐j!Ӿ1xR׭}cZYYA{/T7fM7jn3|-lƟ7Ŗ~_{i%ּ[i+JԵ/Ѯ.66:o+6 Jx?$ YUs7猳)rFvlWԿ{ώct dxľ kYK!ӮQ˻}BU.=r-`j%Tf۫JuayӃS}u%fغyY:axVx *U!*ҥnBUr5_W~"x/Ǘ,q_+{ۗ2jZ~uvO-QX:<\`S&QPUhTX`y$p09]#0IgI:A!rxty|"m~_鮧<.ZlB1!:Ee | sG`kɼPs3 N68~n$ &^1 ,aXH:( ⿪RIX.mGY6ُڻ/_`ߕ;]9/$Q[,s2]"0U!Dm-ĖS$N'c8$cz83'D27)mBYK4Br8aiʊw&&VE  7ǵYUON/ME>"ZUkU_-4%rI]lq`?'e i{,xFX9KK*'" l7  #빏?5JNY[p-y:n9d+Aӳ(L5*G,(0=A᜽ejbqMԪwף~4Pt~}sԞOU^@N:}Eql`0 s):HrAEی2I8Q~v,\OvА>}RF瑎D.wmǨ@O(#18, Hy*~Ma0oߓwZ]~ Ia{͉@gfVo\?+H;NH ~eCml 2;ylI ;0*-/+חP (``I=XsH !v-$l4܍oFhs'<㑙c:  ( I\$cԓQ|ob~ocv*6A ܙALmR}Vŕn2*6f8::mʢʲ9ME9 vEl!!w)Eg,#F :]nTV)Ǚm|Ex߻$9~k}NYbgKg,77U"%C JdtD* f˿vsr3yq/^F?6:1cߎ@cs a $˸|J/rxo|w5Zw=*ye@C(8hܒ8[N&8h ~音vO}SZ͞TSѮ峂gxME0*l0FY!ᐧh"W>|zkg_|j8[K{ntm;EK-F=WHPEq" ș0X0؊N0rjSJ\\oR)Fu.y'W !q6OWJbJنJx|Uc^*Xэ:Z**S߲Pxo?i8}/s9÷%6v6]sطm=<u|< ?t>9Ҭ}Cz7ZeZ67 w|e\U<kծ;gP [pHuɮηrecյ<)f8xhpʌhš.|ƭ,EL=EMIpʸeS*J':wZ)EMUpӣѭpyL73`~O:<.7f8)%}L~?<Ɵ?_ |bƯ WR~8USH/xk ͢k][71q0R[^ŷQGm SjHpI/%zq>L²tT䣅oyN+Rխ^ڔ'Vu"[GꇲLl>aKQubTF'1jx6#YR,$nG ^0B6rW>K\7D6/ÿpFJ.77A$ ?|Il|8vyϗoO߂3#ָ(4RkYsI>tgek0]?VIxn\#[I5 <@89<ip?lo~|!6Xֆ[Qk{X|1yjk_%52\ [gxn*?4#Z1xqXg UoA=T#!HP~?'D GmZj^+h:ZNhY]]KL>\jNS٩6lΗό:J:iޚjp*uqV8ͽ~<$!\_[OSſe6 |7oz|A##,73zKx}m:k6?Ï q|Q k\uL66Q-^uRiq,s-[/_{h5o m𗅼y 6:ǚ^7ҵFO,[ֲ#+?⎍M "=OS+MMl&oim=FMy$Ԯ İh?^/1ToQR3x|zhbd,gK,OhT3>&5xα_M,>ko/~7<=~q%dώKs~ <#P#'.~.EkG <楩ToΗ1@50\4xtnd{)~'{WhZo88Ia$F#H,&jO<]oY|Zw2 \HOzH|T}\C JDicN n"gՖiK eYTƆ`&Z)NQteE;3a3.OXlFO <*<=q̪}K3JgKX]Xd3~ڟ<'K |7f_<)\iFyXǭ\q5΢0y.^/m߂?N |AO3όurRtMSB]R;~ZP}:ḐĈGS+ʢ`q1\c'O,5U䤦r;ӋnVGgخZ19pi`jax @Bɠjۓ3^_>?h=u Lw_[~[>SA $wK0.w~x ^7V!p߻V,p3Ul\P*Vtg5OEԔ)bUr_$\}EˍyУF"]:9fkFxؔVX\*~)J6 *Jd R ~[x[GS`qC |5||UF:gS^]xb\Q_X˽> GI''E$pI f]C?RprWύ?"{W.|Ms6.:wz}63Xe:2e,RUU&U0f*V,m:t99(rZ#4RX̱*W^Vpі"%:%85()GğW_~K_]ihll`ӡԮlƶd9eamtR7Vk6]|.oL<[7b勻'#wzՂ&8J$mEZ3i|=x#_7~Κg!z7A)5'^:mNquVK[=YSr b$\}SVđ? e|b,, ćRqv7@"5%Bu0hbjׇ\-IG<5iEc C2⅀HG)F/?>(|hxK}w7tE_#Fi%uE~|E[ikOm\lʹF=G-{d:MwVQl?Kh5qK]W^!_ɧˢl5yY"f}.ٍuOkuAVkޯ~ma] noo*7Y& 8X)eR_aRZFJty%f8,"G+UXL9,+7uZXUܫJr¹F5 |j~-u>xROW~_7iZIqy(^Y[9c;<dnYppi*:^uS2UȀ+NN03֨"R8/ @'5s,Dkԧ Jiфi(J0i:&6䭱q ~'0l8| SZ0YSn.|EY7V\U$㵢Xp̑!NFHz~X¤+Hې#e2kк6!_ zTW]3|R`d `ʹx9! 2UFPߍaHG3b$ _<}AcU*IH+c`i$m݆Sa 5~W ـ fpPp4)dd< _ZKA؀@Y0\œryldKxp;m?ܿ?L n|e}q]1}fͽc3 KzY˸w d2pL2 3ɮČeflRUV2 R"a*]x%I$*͒Ub H,0OP( 'cZU{7йI8WW`d_YP6dʆ`F_9*?(#x09IFvJkdჸ]1qЁ35y%%G#8#|7:Qۅ,c^]d;PxT'5rj{m# 9:N"Yd`e%ʒh-?6km۷y%g8?ؿ>iMw`7ÿ @8=BGbFz08q.90E0٩Ͱ1N20pkDjQg "yNy2OP#83;.l"9?)u b^2{n(ʹ^a(JץK~KoXoKeu~|B?En6g c&mk^b=9dN3+\IRg}^=kVtӵ'+&+. %Ӹx$C&ea*~eR>߁yUJ7pʲ+0kKZq+[^GL-߅_nh\ݕ II\g/WCwfbP-N@'8-?s??%BI'?q7'?3`ڼbt:hX,$|1 W-~i֥}QK^EkgxI:,$*I%⟚Z.w<^@@B##`~gr s ]w0x-u8Y`P>^>l6M e$yO~ *FwTrN=*XAW817mlJaz0brpA(A $dDdp׌@"D_.T[+ Us7K_$OoOe \yUprRIw_NȂ`td J23#eá%P>`J<JL\ j"yGt8bbρjjgtolB_}JɗX*$k-MRv8j|0`$N14365 #n^5i 5%ӡ-|܋&99{f\_#8_<ƫimXw*acKH 9 m֙7~'&6 [Z'5I\h3k_3Est֖Y4١hRH|e(C<)6M־X|ygmj^:U'7>=Zw&ikȭ~$h:WeVx_ӼEVZCCuNOѵ)5}_1;8>G>*{ /><|@}w'~_uoG/~ж< }G^wn|[CiZ}}sx|۫Fap?j/s'Ǖ֭>\}ún${iC2Di2\@%'ϑhs],h*S[TJs^Y\k{ u(ƕJ* a2™v=X5|fT' wC3ʟ?Oz?/tKπw$O /to!EMj"M.P̀˷qp(m>b `pCEzpw`II53 ;~7} .0\'9dWGua鵧^^/CEQ~p$dT|6YI,S_ό8x;viO5;m-/sM} pnvC4B`)"e_?)'1 ~ Cd}O=FFz`p;_K~?n>49E'> 'uOLuOx+Z^{er-]|LMnyHE}bGn*UJZw%*E>?G:yeĺQpQSԕ54j)F/|2~?şq_im ڕ}^5SWo-r{%ܬR$M/ Ku{ONJO?h$5xzO=꺍WPFמ~%Ues:ľws~пt#_%ɵ7\wx-twZo ,?RMY%k.1o #Wa7oKuV:C[ŧjtWzP2oJ~UaHVΪ,F 0a#OߌSC ԓBxxUFJXN5rv.(xKӡ| FЫMl. ^o/."9񵰕1Ykoş_#o5jRwhMF1>.$;kM_Yh?Ɨ] <{} nR]md,x%^ ,nf~% pĺ&k[!&m#K-hвE;۬s̊X+)#Wx3BMď"ԕJt#Vc8iem ,*ȩPS3e:t<JUHV_~O>ѓ_>,x'Z~$Լ}ir}T ɣefR<ѓC2~/_[?Oi <;2VzŤ跶CM5ϩa&UiY *ſ?Oo'|j:)tm K.f֬H}H@/fV;iY_fUqx\)Vx(XiCJ'/okNS95x8%SfW piep1|-9O/'SX 91 b0QʩaN)Y?:f}yP/SM:xr{{X5[Y]:DS ?x > 69;] T;K2w wM|sV|ޔ*1T5AQ(.kJUdQJ)G'(_1x.¬m<2&8G&oY'`)U՞'Mjtb~|'O͂3o\ m%H<NGAB<1cG^u]*?*—1,5k.6 8K_kk׵?࿈P3ķ=úu^[bo^DXw?ͩZce?-~$j~,>+\]&𩵟oHS]l0`q没 eJ9YSZy*؊K3)TtԠڌZO,&OW-M)gS8Z|f]Ԇ;y"xL\J0Gl~ڒtT8_|oG| «O|;j [hAɭS[8-UMN[XiYdi_WHM> &.%$f,|0DKQХtNub2Zh[~n q1EQ2~>Wǿt ՟!ҕlWk/W˥thPj#BuHR]cGx-xv1iN}IK'ď _SkC,1i1{)d Ï,AO+/Ɵ~躭 #/V=qk;8=ZX%DtT"|W į|Bwh9L׉ uu)1 KUoF3,NF\PAIs_tcbG {|)+}g> }bK]*[sk7%D Zha_* %6,$8pN6w1eQTƼdT)IZT78(զ~[ż5SsJ9t\3xJ)ž&.zu):mUZI>$]bFUɑYFJ(q8|W7'p~RF8wqCo W8v n2"˵\ 9=0>Vw(C@(K?>i9^ 8Up.H1Ggxf@VaXoχ̡_xň' _''9c#d FPFH (px`#_kU^k B=Uן^--}V[P2(HyةG2( #Xܴ%hC;9`6`ܒGދa@"H-NqG̫.L8NRrI,TBF ۓfZ߲WU5gf ~_WE ۰| Hpc8G-Q܆ }qF3Q@@Ŕ} $6)H5R CdH޹ٸ6ͭ7w"Nc|v?0 2v!H4t}-23sϰVw2'e1_mNLeE}GhjuY$C6IST{J oudVo7鯙~{'Zʯ C>ۜ ͫ|``Nkd8Rk*~$ XWSei'XF[&dvu_MѸE-_S)qWkgJpGo '¾|udb9&9'2j##A RX9~ljz'^oFn8`0y0+uyyo) P:d(# fsP~!I9,0: YIVv'k)9U<X <sԳ$PIB.yjS9i5~I~E/ G;dR sGp8"D*Z6S2c'$xx Fv$uH8 1׬96%C`A<]5O]HP$bRl A x`W*73K "O2"҃0. @H WhWinYI4WH.0@B,\>Rȉ$q xIq?,CJvs ZIJkESs鲷e 7tkncen+?6^BFc9n2r2+&uD)!\h;た?2n/AMR(Է az}2]~ qaYkrIsǡȯ"nI3ƑαnT=u" xnqHW_9?g #6V> ]w|&t=J 5/tk&XF ?HV/߈p6Y1=O t|s&W=ؗ7RO1Ov^αi6I%#?|T1m>t }:p|0/??9?h-b>"BM~'?ߍ5ş.K鍥o4H__QK0Ӧc zH_x"2_ ;z~sذ$)OjZhcNºT_M6WIJA3Rm'QJxr{* MX88R+T2_Ͻ^(O0Xw\G1X~W(*r1nϝ&GG·ľ #G(#zl>6:t?,.muOio7N/n,?(V_هVtj>mZ8]?OoɫAx<@/)p <Ҩ/ث?l|Qχ?oh>1Kx[|N'QSKYTWMuſǿP߈/ 5D"s&MgTƒCje֫}kΡgpړF5̒!O5{KtԫG+ES3ThbiJzMRUVU0ؾ<Ⱌ) ÑU!J hsx3L3 JgZU1t~?4g> Ҿ|4JFY^he=ٶCi.GlW3r?=K-k:w/h6?i:_~aM5Wu{ -ೆ馊{mng T0 (SJTևJ =XPU':UT_5ٞ*֎O[-1T0XZ|X1Y $5jx2êHpо΍ehW"|Uw챧~ / d+ӯ4+-PgKtS].&ݤ"١jÿgtÊ-u zl.FI/[]l!7!#as;A$䜜!ld |*2rA8SO3Bx'*8jc;@ |l]\f6zQtiSTNi҃m*etV|0α9sׅ:،j1姇Gaܤ[* +Tqt?8s>D֟v#,7˧TxYO1|U}tZ$--nk\m,2L4!EIKc'&&$ᇽ[ Wgw&/5x6Nd<5-+U[ZZ4z6חJ!If 76__V/#_O4{|O{M&Zu ̶n,u}=%&LSS, 7~o 7C1i#w{ӣh0ggԒSl5]~_n~/]|DMPVڧ1$%_l%[d .Hʟw W =i0*s 5Nx|q.r ӓD&K^&'ɱ\]'V[f#YZn*:u:RB2NN_l:ƿx5<; _<[o\᫛EhFn4m [4iڗ1[|V#'yikWn.m/Ӽ]'`@Kv*o[xWJf])!Ю[?F]&ʔ!1~[ :ϋ6Zί}M_jMNen5]2StnN0KP،rFxlv-C x8a}j8lV.)8N 4YߚԠӚTF]9:YVS[(˪f#T)K O 8M}L˹JQ5?X/ۚ޵_xs᎗c #L햞T^MLIyYO[`|5\xPtwW/+[kWm[ane*rTK ,ia' DI֥8u)޼iʝIJV~\^?ʵscy=,Y^}Bx,olFlUX}~O: g+GۿeYsLoh V6a Bj5\Mug%k?@&2(W GeF\vѸ 2q|ҠO >$tτ[ jGe-܏m7Ku,BM.ٕHՉ 00dQ# (rR?Փ#2r+)c佲tW<)J4# KuNmߙ6\sꪸ厖 k˨ZQ˽o* :"jbԝJS\t\}2*K+o*rpų+1g' T}zT)GU$TJq6`\F00O'GÞVhۿ;9~߿R/ Ͱy %m9 0AT;K1 c* /Q'>h|!Ylt|zN@Ƿ c{ma ;6c`C oqɯO W>A)'RW xaaL$*7;@.|*H,W$ ؃ )>Te}n]gߺ0`h'dmIl۱?d+3*vp+g<};_/J%R s/<ޡq:8ud0rW ¨ e79A,` 7Af *|s FHmYbI -8Ze[M'(^]|nTG ܹ;Jv[60Sn W,*EuFݷqQB *j+3YGV{-/QI-,n#wfPo8<ֿ[bu.vեHP7 1*#e- Ev,N=\IPK,̩ hJ@Dg-*\PI uH{i4n[>KT1@w<mTUUWgY+8'r]/םN7dV=*ta[Sl*$ "QoUcI,ddk4Iʡ pJIY &մ2DbyZ$!O12hMi@uilJx?S>|7g ^&2-[Zu4O XŨo[Y]I40S5>ds"c8݁|]|N㟀v ]ĹN.L58JVayjCGL3XG(ԍe(FU:X=iKkGQxE4cԮ[mJP퐉fU͚gFoؗXtٳ%b-ŵxQjܾ&m6 _ZݤH.Hn=g1).C~?m_ګSO<}'N/6iF!3ON*wڼ'?yx/> m臎+Ow'DM!m-u}FvKqt+,-<JTb/ P,=iCVzEYQJr'R895-9^!q-l&dwq.6%UV[ a*P7,Ǎj~>4w_fѵ_YkXղXG-^M-q¸-|Q(ʞ5{wmZψ.o^-4K]rAe&sn\Go+ީiex,<'. 4WCV\T7P$9ʕ TS_ yNXz)_6SX*?V:׷5R./& ، Trs9Wʵ*ү 0St5,Rb1jKF'~_>%i&տhSs]S_ FУo{m*StgR%K;eyv $| Nc~344ө"OE'5;WӜiNZ]cw|$mQ/㒼g5gpk5VNmҤ/VªTܧºYYiΤjJ +Q9}W 1cySڔp 7#F*N8M\]\\)TՌi~G`IR V  {4HX@2šUzף1%H׆cǩ5|KtĵTuyȈ:z'2Tk}JS>K}^n~s!{8[F9\_V~~5omoVG߄ozN%$pًHyXfW3G^~ y<M AmT )u:%Ư |k-r/t]V}v΋;YC,Ri@k~Ɓu?xBzZ`XM||@oV";9{TIg{1[~ž=kmx[g27iO>%eM /[MΙ CU&"x. K )㏇)uM#j]ΣiƩk!en3 ®}RN\ۍIJFaV86YSTEYOSO4b_>^֝y(aAPp: ZQKPap19i}.|LvbGo[gMZH cǷa-WTFEqv'*b/a:-W]/_]j_|i}MkOA56OZK$FQKtu!'k{?xxn"i#; 01#a(z_wt7[ߩa֬u TM\AMfkh +MnUJ\b1XjG9F6Nq97.[=< edY<ʝLVI5a*^YTf3 XZaWXg,;_>#xw>&t Wſm߇v_t wz/g 5nK2-W`XQG#P(]W$0_^>tQ~"Z/?vxWPnkyj-.me=Q{(>gH+W~џ2~ >9C, ^/x^"D4nC=O01Mse! k#)̱'%BV4ը+8ڥd8VJ N;x? ¬0<p[W,N?.1*ԗn652w f3 ʧRxUZs>e,fy9#)k>Fbx`ndpPS8*@# w?j cÈ/|1ҾS|DYl!Դ3WSoq̶1L''z1g 1ԪO|dѣԒYFI^0U*jqזrTܜ.T~yeAe,.*th*5R: xZ5)C@|(?|b װNOr{o(9߆4zZKukO>ywxEyoM^s^\i\I+h0"C>]](@GM|Ǻep95/A_P/|ZcOStV;}SHз)};Gp̓Yڟ&RU+V$UncnN9դW5:~cyz3e.fxڳӧDLVή 'ʤEܓ칗߳Giy?e_ :/iZZ4ItY|NwgMge?*X~_if?d~ѮGR v^Mb]7[K 3-Ο\/ʾ:ͧs?kZM-FA?t|=au{5}J{KO)&[QșQ?->'Þ/szHЯ>mc0k4ܤ6MXêF@ .S΂aA"Sk^"yYṢB:QعRedy6a8WO)jtpج.u3pu3j˱kha:UêRoJ'7 KZoy/?S??V4<%uhӼ m}>pYXrwτ~ |oo xjbm:Ŧ'-L^&զ`wrYVDվon16d\*I~Mi.=]Yɩ/ Bݿ-d,d[v2F{.bs$lĸb;|J+/j>9iz'|E*t'N#UʴjF/ާJm*c㌩T(/a?ЯĹf41JեʾiF񘪵%=S>Vx*B;A5\ޯXV*7JHRy\zUF1J2 p0~Q"䏘ucmpw7ds ?6V=O GR<x͂bo2'8{(^! 1ܫ6S9%IRvh-?:4TãPBTgwzBC(ȊYsKn@S0r#WT I(SPn1,˰_zo Jc*`PRĺʲ*pIrp2 o,]ɗ<fx=w>#lHnfxB(ݖr|mfPɱPr`]V >b~EN6sk)k׫&PJa|d4ICr\0mJ @'8*1<8ۓWpH[Fw*@73u=shiy8RI 2rɸǕM}Fex]#vƈH;1a-1A@ 0ڃ*B'-}LJl Sc 6db lJe6[G,_?͟·?݇'|fm.` '$ԯB)+OK }2^GT4wy<)t "iM~T|5s&*Cqh~*YvuLu+!8 _J}Ni=ynt46IB8i,l;L>9$y˰*JvjҷmNrƫTi[Tn׺}(?ߊ(a{{ޔWeCۛ6HV A!Lм{@Qֿ_MCUPҭfoⷑ%o-#b m{(o5NhӴMRܺyYO<[5#\;jjWxW%M Ӫ'繑TVFxBS1e_ N$A>Lx5tx_T+c_Ɵ |sw3wu8`){\ 6[ f:vSnT@પĒ 6;Ae877?`'ժ 瀡9=y=z2isc&܀Xd_)'$! +m*\[c990>k*I+_Fݱr)y+zks79z`0V\FNpz =z¤\` `9'+()A8`xžOT{mmwE4A peW,@Z-b{eFXw6;N@rf agɔ#'( Q,cnXݕ)fdKnVD$,1ѧ&7V]N< ڋ>-Xg ,Če, TH'+ۮTi2 N9vb:IF鿶wec&_«'\NVRH$>2%Ie'= 濎-|>&(MJ\^Xk-.y"?hI2NTX|$)n|O?l/~i?wx /tR7ڴ:n\>c|\O/,ÖbaC0U*pQ_SF<-Mfi9s4k,}<e8B bVaqa0XkbqFJx>x5~˚'OdCU>!--1YI=:` M2' ;XMŬ|kZO R}?L\l)fEf8c/t xÞhٟ~^0Ne_xHյ;:GV[i_8"O ⾁Eemb_>{tOCYIoj\ˮ^5֚Aqje #iQ̡#X:1ƓTLT)NQT&6%Ҽh>frjY`':O[U˱0b8Y*Oi瀾>x+I>qZ|fEwe[k7)وۛmaWkhoڗ4A V~Z~>uE]K'u}'Qy21. :_ve?i߉_>9ӿdm:#}$=7tbOIv6 Ƹ7w6b`^?ޅ+R?v:񾹬 n5eмiy wˬizb7>DjC4r8 K,VTUJ jfz)(UƎmC O-S*Y:t+/ |}m|s+鿳G~-4]xF&o7Uw.~bk۷VmoݪNpp*1 ~ <<6<1 )OVѼ#kݦ.|+qiC oo5-um>9x7!\#8 uGFۆ;y yN\*0cr1UV[l*ԗU+`jʖIarX:QCXJԳ$\u\-SVv `h ޏ#F pÖ"|E^>ۧ1p9j/m7l/|MW\M [ĖZHdԧڙ{ce쳨TV@.b os4Is޾ omkƿ/73m}'G5U|v3^Cڢ%Xwĸ]S/*q MHwxTqvE,W:y,UQKJC$0kل/ ȥ}+R˪Ž^R2uU^<4pp{N^Z%FʝjRp>┳:=bp\-Q!Z8*N>]S(תҞ2n9_ѥTQ96Axឹ<>zL[ \i Si#jV9eOq>&b#_[f1xφ j_SBuo [izd c6dʱ8BUK6(Eƅkz!H^*;1<4AWkGكzg_i?ռ)MRUMJ+5ffUTE<쒞&g'8V XE*F`aJU'*Q9^ʇ-NM/*9+S2Pp9 ,};Ͱe,.eOeؙc0^SBj:Tԩ?p+~?!h(k~/߃K+=kX𮍩kj6ZŮկai x#,akCm}M ;O|Q}z6 +m3VSB#/nҴoǟxs&oSNgӴx_G`6_dIsy{u52\˰߶49O٢E|=^VO<=y$"j-ݼp5̍귛7XZTrz8bX)a1Uexx⒵5 jΓ`9$< r?WgyW5[2-L2QSX|kPYq9bXl Wn"1^}pEm | JͷOfjw>{-,XH7wtw2[x 1x%r4-OB 'oRٯ^+d#^񇉵vښw^MɶuOh[cC@ko TAԁ (}q.c:18ԩG?kwMIJrۻm\]K-jb8vUß[8R5UxQռISd>? +rp #ӜrN 㠯$,gMKIx¾!Y|CM ksyvuޛ{%#إ𼐝/%!ZN~&cʸo,~\)6 cq-_m3$>wAO6O}%mC5;cg{y] *]ϕ'm{L%&x~?߃gMK/𞒗xX ZF`kh-R&Ӿnʰ" U [(Όj _7t#goǃzt\)Ͱ8Z!J8 NXeF?<ԬJl=RבjS7[ _}7*gɡ"i~eİ%|A$Q|TE_2~#:?7!N{B9r44˯ŤjSi-n1!ankgB74hYH C4Ddr I?o|R񏃧Z|>j Ѿ.'-ލڲCiyn;EtRYfnYQRj(p8N/u7F/%5Y5$02`䥵č_J=8+GX!^^7#08aX*aZ^קYҕwWu#Uɷ.nf&|f} f5ify3JFtܳls0QNXۡ%Ȝ\(,[8 vn?@lr73=r;WHXN_i($ddlSHUGx^B #x $cgx1:6ѐK m/C/UM罝#f? W*gKx^He aq֢@іqr`B8ʌj14߶ | ׎ Gzoacr!]mU SLLxs^Jؚ6/]}wW9~Izvpz&Yeް&V`0fUW;Ca%L1В[ؒ;]n  *DJJBF&>X*UJ*e$a\sRq_31N󓵯-nMc$2I{ 8'b_n qӭ r1pŀ%r.FGأnܨB\HIݑ*I' ZgIVg$*YN$Tp@љU0 22 Hب&F%qiNGM Y'pHl* @`zg8V5TYJYH,FeacJtWik#o]'dԜ4VESP%IkJ nmms'GFf=PC4K嶏gFpmr/mo ߳űVUʭ9# þ ۻG Wtmyg,q5wuYR -8{\`c*S/t+ﮛʕ>4}g:N9J0^Gk4ZG}]LE":v +_o݅^GiesqI2,B|bzpswĒiq4kiesP,d7̮$oGzj~p^2_tN8Jt82v[uпE*1Owm ?%oevV`OʼnnS_0&~e㓓~+ru p X$1 )*yr_,QSOe\ ZyА8g|/Hg N  -)( e+gq^20VJIz~= I]y,V#iٴ ٜ C[ppW؀p9 PY8VЂ`ӭ79,, |gYEsASQ[z.琶^DČ3vȸ zfP SV q I9<$N*tL$tAnq3Ꞻ@:] enT.ٕN#WP3E1d7PnBs$@Bύiyp$RGg>mUďcظg}6bKF!U QnLoWm>mgh('|Q>?|@\ o @_'dc As"A'9rz'O?(wk?5KPӴ%كT@$׷d>;xź~>[t ɤZեW4IehvjO'-D|38#*ZV&4(A]l$Z|`f\YCBl]$)K`pJU񘺔h7NεY5׹7(WAhFqH9 B@o)?h|'yZ7 H<#'|"<X5f_ҦΧqi$21G3WNGO#Xß.~?|['vk^8ixYF6VjŽ{t.h'A'-I#KO}xNNN2F30~SvT0>? '^`g%v$/.əҫZdu]Ƥ 8ԄqjUqU*rM,6kB'G8<~uļa7b8IC9K )WN~Ͽ>|{W/—|g7?.,/X͞xY\om?~cun Y5 ^Ib1xOO+?ٟ_Hwj;Wښ~ׇṒk륛̖KEm^l)뜿M`T7~Ct9.*䧇f|Bq_-zre;߱> XoYA— ?ὶ [;-6MZbA[[k>*ZK|GqOxn9#5Wo?ڒ|c 3u#Ѵ6ڵNuA*$p?9~_Ě`I',@*gWyH;|G"oɭA`Wi<zk j:_`uN8i8ԜNF┪I^qVu<89,pMeq\6o^.Tp*bqڵ0%SQR>9k*/?8~k>o~" +߲A_jJԢX 纄-?dx?)m5MZVJxRg2|3dGQ fmb[?j)C3nګ!_kHO0րpN0/]&\;(2q`U[ C G"%97:ns,D$ڏdV@W<6-D<};uCE6zΕk6ocjl"[9x/1$kvy}FX|7 R{u鮤BOo'*Rt4O۵Lm=T@7)3dPYk(?1MMcu¼zhbO <4hUybj¤ue8>+KYTT1_%|εGZ)iUP>X$m:~Xn0Lscdcڱً^GhJ(~K߈N>"><%tCo_^h6].]x<ο-a 5&f+r~QCa+`;U~cn\A#5_ - Z:.H5]}gwyNO8ƒgiaW!C5qUFN2T\(Qb')64y?<6gV+>%fL=ZXJңZQW  /k) އ9}mK79]Ro8c# v:~?gYM< !nx̾ѮmlhI ͺi(`9?Uf5\wF fK!fG˒yGBXnquy+WER'9:2岌7M<γptNnrݙwm*+'O[W8f,NʞUgx> STja1lTlMF~ߴo~? | & Ai꺧#c|6XgTB0LV[~5~+Av>ojҴR ?[b>fRH5[-OP,C$2ί^ڏ HlPTO=2piNA\ŠP_jN ?Xm I$uIʼ2ZXaoJUJjXcETnRIR"Wc^YG$ XQ\%L¦iqOxWSOJԪ%mjk>'Y RR44h#XHQ|y~>|ſk~MB]0 Fm"2891_2Rp x;C# _ j(u, NcbI (I$υ>4xè-SS>K\Y=\Hw$0$O8F6j u|=%VL$v׫y]S:Ǧw?'SF8N+$iJa 3RJ:X׍;;J~_|E-i=I/%Ia;sҿeQ?%g{.Cg`w__6~4WFq.u&۱e;[a̘_0!Ǚ0ςQwnCw6p/Fkķ/dϪiS pzgz_t8=rK l( 2 gIYw _#9l8ݮ_,^R;U{削D%0u"&XT͸$B2X96I0p&9#%;q$Ȳ[&k S&[ UDK~*0`?l]Ԁ 2xsc7]A>o՟$aF<[f2#3$\IRU UQqg/c"˔ݺ|Rk=lO^Ui/uT[k3lOOFE89?>_mӡ~e}e/TԴO0yD:NcEs R}7a^2F*߶> s4 =IJ1%2²ǫ<#3A p#þu}tk )e<Țt{w-Uo=XAyiR ~ܷPGIn R K8Vn\dzW_IoUҎZ߮j~ㅽN#I:xevR"ZۖR\I;K"ir:dE*wnOWP0>픰Rr#rXlJLßLcj߱MN? a]E~NUAYdw,~ھmE U'B~bTg?[ŧI7mJK.c,3ek?M"y<|<W3(\6#׾\Ql_8`w>v g@"w`X( %vF*ʝx'm*NIQ^K[[/&r~n3~f?# Pp&J*۶vpI*JɓbF 7NCrXv@}2ۼ|ʞO<20@63gKDnfHH B >˥F{ Bʹd %VUUj;x@!҂jaJ<G"%;s^f-|@ <"ڿ;(t]:K]f1cn"孢*82(??OwGoc7νm$։ơeo{gc[nA#ƫ~ǿY-xQ|SG>/r;÷=3xu;&hʷNdd7Ə > Olg○ ~jn xǂƕ}hr^8HViU`ԩe4hUPUhr45Μ5qNM>0"gasF֧Ǝuc-S *渴Xy*u*ʍK{M!/>*=CƝsᶳD>\I[M>-E$18G;b_^e'7g f X|1/i4iCO]>7?itb4+o,HVc ﱔ~ճ j'٫CӼ|g-7_5-f?EbԭK餵`gղ\pP'8Ubp*jMIfc8'hfyD1|kG1ta噾KxU%Kb 5GZHP__e|>)~֞  1w5H5Ecuu>-Nf$ 2۪*;X?mk/;.75/΢h^dXkXcԏnf[?J )`,~{sZb*ғsq r)terܿ*Ufypz , fL8qy.PaZ\'X܂A* 6B0NxWg~Շ/xuh+ McQ/HP֖7SD3*)2NCqu>9 WƟ+?~^fڼ ;dӴ[/W>&ܛnU4&;kvӝXmη HaX%o._!?}JTFhQ_>?G i!Y#.akYhvhz4/k14vm!hem ]n .J|Aiu_hVv^!W躆s vgxw2}Sww3:q4>q4Q:ݬ~-t-j]*x~ջ2Vq)>NaӃaeԪ{:4IK 8Ѩ(G RfR?>C3֖e̞ *d4aW(吭+k</ K&5hЭO͍g gVnxoG|J\Dض:ҝώf1 hFwr45kE? ?⯈|;x^_2iME83o%؞z U0੼S7 Euۙ|7C⋛M{:Ou}Eiq Vd{C}ssZѼajZ~tzk4K{;9Ty 'LQeSKWxTӥX5NܕhS|xg/cfzr㯊pU|ξ<~'ypjK3UR"xVIb# tĥ/$Eف@9c eq} ??F8*Eh:nV_|=krcOMt YJ. $H_]|M?>|HovM* v a,ݵ֫ڲp9L̮ƮG|I{ϊߍ5~sWA5|?G{g{=g_ӵ=e⫹oyⲍVIfEO_|@?]/ZÞ,nu{m S&1X. WХc'G1u3J4`'Xw μyoGBޢ(E͵Q'keQWyv.r G :x9sJx|)V>v:R^1=8&\* ٛFɼ-o=w{*6ƽFռ'6~3:Pk ğjA}4)4iG#U W%TK0H1be US[%'úi7ܔjJr$DkĘY{<Ҧ0pO/pF Id`p9iqTL5zSFoR>Y`X~H/¶y22033 hB@ 䃃#$e,A i66O?[>6~з/ 68kn#&8@sRYaXg-.N3 me-zH ='~6* @VhCJ(aكUfc%6)%cu A~81\$アyU+MB R#F !K`b1cfPF؀=x8tǮ;,)$o(Ppb\+ 3-‘`7bXY''dp<u(ϖwٸ)؜ nP[~q N ÏP`H {N)ќ)DR9?sv:'wـJ嶾qʀJpdX49斜f%eQӠ9n{pOSk?/4#|Yg(qm$]4`Q'Q1 %NH H'LJٛú1i \(,{r |uZ/KILݿ)_ K)̿>2[,6_% 2`_J#zϣp#g~[$0-7NW bgeUi~*!vN#)+oסүgF{T,# 䙤: ە$gp9=x7¸9o˅t^\?ߣKtK,PYYTxMI9h6kO?sE Mn-p|-?| ֯46̆Hch{xB>eFf_ۖrc͆iᑕYXcc`2ndpp;W4/0մ[5;K skyMoj6vKt ycq#Q$m%xu%d|/ho 7/|GдMwC .>Ke7 k0WOJ+Z=י˹.XAPQ?wef LJ\30 ? ]mf\duA\4̹T>MKJssJrz<6lEUMή>NJ:\2R9濴8N|dg/CV=m /ni$T}$5}vl3r8oml KY! [J涹Y S#ǰrO>h xS mno +ZhT\Caa =a2Hd'`ϡM5~)Ɲ$v0RDhWY|-Ԗ𿄮chMkV.ќsWᜎgYʚkQۋqu$ڕvwg 1:*5' ͈3MMS*J.59M炜e)sf6Aߌ.UbfKr0I-ϴj1Tk0WM+3鑌l?.[FrqfaSDR :̓#.g0Hʶvs>{>2M5 zYWm^:VޭHw)g`]a8r~j~?o7?ş^:k:q->A SG7tHimͷv+ߵ;t:pH q~m7*x'/;Y.nN׆洡<] ԲdgJjq&ϕɫgn]fV? ai𕣈9FhMFR^EZqR_MZLZm^⹸FՕމsvW cXPȱ+\sIП?߃?|m3Tr//;xk(m#{OS,&MV 6$*d~< K)Vcxqz@Oc0;u'# 4{H\KKx0v0he@]]bƲbME] T3n ^qq}K* O:=E\M JTʶ-Խ.Co qů2|7 V>;^M;Ķ&_u[YEm4h!ծ즒./w[$)YΎ#[eSKL}GM,!- ֳ-ݳinw.iGڧZ$78T!N *8 H9F~l#DvH2+#\5BrUlB!)(8ƛyiIvޭyn"ϳyu;N 4SXW)Q\2WjPo?%|T'Ax CM}gZn$gZAx[Uh-.ae[Ȗd#o<?׌<7kzhִ-^X{; sNʃRVYseY@M}>~Ҳ U ۨjAUAЇݹ+ ,/4ZTpY$ix*FBYJd[Vzv+RҧME+BpeJ9/WecXiG <2Qmލ 5V8Z^1juoUo|EDr~ڟ]c4ݤ"{Yao:f1NehC4>ǃ?x;7;NkGHcuhogO)b;BF)+@Xxz 2&ŷ>\ DeCȌ߆؎p(W/ կ-.aF o6`=XpwrkuF[M̠ܲf^Hdpb!r-"r`A[LM#0?4r2Fy'dNܒ=*]uga02U\p(uϪqI{Cg80r7 d Aܼ̓Q{S ,Hvch9bFўAf2pHP3AP qFx&{|C)m]կm5s2W Xr]{'Uʆ5MTiv !6ܝWX"h@wpYVÕ8+G4RUeð8 V0>k9}'lD&ֿoG!_y>9m:~@O _I 6YҼ*wT&!嶎h`f,A)6ҿUW-lK㸆S* n}>[vn0gm<F<,?A>$T0-?Wױ`g4Su!*ޜ-(my4?23$)"ϖpP}*+׻?֩;5tho[?4Ox{"AZi"tgLp۬[kU+2($%_$|J;A!J6JUڡT(_7? OOxVjVQi qeym@&+$n&5rm?ɇ+_GVgP̌v0U_xtږo)PV+%st<+)EU{—sug}l? \o>:9,?h/HNw7B9S)EF!\>|#q#*s^O%O/q ?1?7f=s_w0s]IA ߴq͒8 }Ns.lݬin]%hF=Vn +YW l `gqǝ0z09\ @ݐ:+-<:s܀9@ܥJqbJqɥu6-#˲_0p8\n#$ |qA㚐>7 C`d0u$|f3 19s OBX0`!z⭤՘X> segSٶ|(2A=9# mV真-;dd֕Ns\69c~W\Cp嗞z38GxrtUV a{.qzOL8LǠ2~Vz$,*M*˕cT8~А-웇.ps8'o''!F1T@xP 9l8%-;{0ܤuۢpT_~'_"d$}1Xn l ss3(v  Tiqc9dt9Um͂9b0 yn|9b9'_5Vs#TjM˙ F;,<'lGm>tc2dnGn98$;YH9(#R\w2aTnP02R{ӏv+5Sk3h7JCcIv²܀ 8$]^!̲p ;Xc67GBF1bVp͸=A p9F6#,%Yp89ǚ?K&旒Չ֪su"Tv:NԮ+ p8n@@gBA (\a UrX~R'%ICw6N1sK²Fā@l l0%*K_i;<{CWZIJ6̟9,| Ҥmf?5v Jt$ \3 \TWuA9'P9-cJB6vfWksN6 n2G"s/q \c$3j?9 %KRw - 6 $ 7 n*8.8vR2N[ I!B[0:Bъ426X^J30϶ br^.Ӹ0"!u-v0Xź=H @?N8rOk*z/ymkp~ Olǧ g EyF u Ē2UJPNH*xϧB,9!Iaruj5g9[W%)?W&ər]YfOȤT0 A qX0?*s9)db m8 0:ؒJ78; ڠ`ӏ{m4N+pT8v'!yhd)b )6W9+סe}ݕČ% =H1^Oql8(8TY$6LdhO>RIgq<:j%mZ47`lHN96G^ewe܌ w'8HT' jFJ`ppņN@8MY&ȉONv#! îy#CkA1`nSwI$ M܅UH;~# ʍ $ KЂ@lc +EJDdWa$˨nOR1W?H" {ūNv[Ohf1LHO:X1FpIyy0~; ,t+ыB־Fx!WQb{%+8Mʥ$u|ͻ+',,4q2 pGbsLD@@Q@E~nt鯡zenk.kjg.߬-jVvquKtl,nb3 z)Ae6,be ͕mn7H]u~Bnt]=Xo%W]]A @UrĀ~wAP0 UQ=MJUAc<9mb5OiSkM^tӛmO!zx\28 @P2e.3ұuKš C9P@i,6̎?@P!4@*99e죚zn((S/#|>V''vB# MWn V`A jkU +$ q*,`H * i6זS#"*UA!9㎣)^n6j; tU *p ` ^yaT6Ha9$uPM]ky#-FI;UR`w}ɪU(BÒ G= QI7N ?6H*01as/8URF#$g QHp!Tp[Tgt}仰#'XXT G$$z;f-ciڿ0a9rN eh4vN/[bu< MY%9!Ww`gzkMOM]N[Ȅ-WO 葼ΦX̊$0q/֭.r]cKOw-A4{_No%ܕr\c1p@H8].d8$#dxY:t .wژ.%[㶷"VIG 7.u~$w3HKTu6<ҭ UH y bP(,1ȕ+kMP3*}JP `F Amc9a@LPJn ddw`+OVm;~V8|n'1-FTѠq!6W"Fo|M~u`2"Hm8&ahhϙ#<fl]VrFnVNôm-+V S֟e+)he| rNrwdtR2LK) 0z;@ d[Υj$}gR?Ehau{uو`-%~{wOiƞZMʛ4".{-"9i.Iм\#Gtһ彴뮖%A:qm~'eiCl[RAL+liM#GFbU6J`<ۘ k8[,[A)dXw?ʲ>Bd|,%-iuj"cip ̆AsPT~S٨i)>Nۥk}^Er[I(9wV4N0V$6@ A~c1!1 8̉`pPs׏LWG7._Jb񲴗<+E{]r  ܢ@Jڭ֨c|,еMi!2?>>f;Wmʧ$1q9ZKm2~]k^ˬl:lnD_͌6͞rXv 3J#m #*r0pT q[ ]dö!mLؤx| b"c2Q#c wTmv/58o$KBV<" |T/zhsVŷhJmI}Y2u9+l~׷@Y@mn17 :Vm d@tVs $Q5էtM$t d!Ih-rThTz&uOi[7|E)b ItX@P¢fa3etYJU"ⒷV}FNTyFn>% 9+C:|pw q ,/=AE,Jd=.ʕ #<s ݝ嵐Ӆ<̲Q{9"ܡb8g^20]e5jyNͮ[ < Th++fUuJ:JU?>MBQWSOvuy *AR1#M S/7`r9<[KYoy'h.g(+)I"RM7dl! Qpw+(8esn<sGMURO{2,DCJ ie9L*< b3A'!e;1ٸWiZe+ x>c 6F@iQpS)W,`9!=At zͰn;b\L~y,H d n$OX%lS0vIimXX3[Re*qm!̜g8Oeѕ A%ϖ,Y(A=Moz| Cp2풣 ԑNh6~rj>_*w$U,ٻ q'- w.@'! pNz S%d]~Vג(4],쯮*#IcV,c1'JMBO_S_v◕fpT(;|vqn~\dA^I$m-= !A*9͞{#+i+^Þ t=K_W\ 3(A#=ڊ^sISr*~_U?)=[#sS1RvMc͐8$r9xVƒr iF9!`$'dQ{i 6 2-޳w槢kDm[vvsH\e*0@tJ "(NK!ă fY&gW3&nt"DlH8 Knaۋd8~kt3*&uaRUiOϚ;}/Ao9j|+qyQG?'7O̣v›J含k?%]ni K+HեvaD#LJđ.9݊GKƗ_-KMF%էӞPh~ipEowk+[&_A0{H,$i7gˢ]MmX2`fIQ`Y6lQn{9R ЦӓRg5u%k_aږoÕ%)RJ䦷gZ.VnWx_- e PJHSؐx$qEWo#4+Aun"YSv8ݵsE~wVww]ztm}MS-KggRx׊tn["3,i.{kF D,AD+-{88*( ,W ݌ n Z?uGJG*k;ҡKs {JUlkda2%++1V3^F HKI$\1av9gyZ=%G9T}pNxSΛI=^ӭt+QFWqlw&3'g 8cE 9&*:udG.Tʨ_%J>Ȭ&0L|q7rѶD %uO޻xORBFAF331 zd19_u^ .}/s+/ꞪQջA+쒽K=~b's@ lgۀwcf@nPH|߮#W} `@r#f h|`` @r@*#@^$}I;AUܸV,8!8?6xt'7]me+X[Bۺs]>Tm>aVQu#q`0ԷzI&*q (Õ*8[ Vœk' 7(X1$?wFVZnʘū,mk$TL1AsVԧsST\Ri+="E"TBϢx=txuezt$;VdbȉفP*nXjcR1+(]]Iu&YEvJ~vk7);k$8фc&a F@O\kj/yRB^ ďiD3IrAK:.WWUy%n-俍Twoh2|7?>"ym5EEƕx,p={ /ok1  U+FxGA&.~M%nȄiShTi$ۂilgmDcmv l$?n'pNH$w1|9NWa_hr2!IdPʼnH>mGŨizpѓU⿱N$iK_H"J| 264mKzyዽ+KpHSlaD ڪSᘡxJ_ Û RSdMkKW{hgp-RARKT6jϮz^!o!JLI7:g F3 p,` +z^Menp\Fڟ# T@|.f݅Z݇|i?Mڡ+yd sw<d ATIkr{>v~6FI/`78ό]WgxNWźc3ao\A{>2~sd,TT m!v tYft$ !Ť߹Cq\B5RX5W(QN3J k8;ݻ]+ؙI:Ufjqk[.zrhZί. Uy65#'cīj0vCT &xN7oᯍ"h.M<.FNюcR:Sھj[6닻:;I-mn&Vbw`Z$ZCOS[iKkqf-a/強 ʲ2urKU"\KǕ6njm׶.۵ӊo}moG'&MՔF6<1 `wP9s,Wn'Y#GJ kUfqUpLh:<6뺅vG-b2I+EwƬhTΙ:2Mq\H,qK$yٲw3;9v9v<ݥ*ꑜ{$n*-M&۳M[EwlIƕ(*smuY^'Ӳ -?joa$Nk=Rkguw]KL?;~5}I&&u,4fkSzֲYʧɋ"suw3IUyoH.s 2R M&ѼtPĀLѼɺ2r*QVrxX{4UR5թKo]$9~IU[F$Uum=vKx8#YGj>T"b3mmvߟWblR B 崇p'\ x6byT(11c H0V< #4ҪY݁8%u q8ܟ3O6E($JKt/#fy 8HKv #v97`tUA+:`ppH'4nA-m_A鎜Rostݐ8'k6' SrܣpǐOC;wH;X09 +suZcX$swݜ$T ge{[^bTu]Y] =K K9(#jWZe~9d.Hʄ!KtS_ic 1`2r22?9Wۚ!$! f oUO[' ( |t: [E?<<vOyksYG 7 m&eǨr}c1DžP>HiVz.exa,XXgnY*˽BdpDk_L75÷98o 11dRH0}icF=C-32HZu2 SC6$9F%˚hvDVKEcTlSN5񷤷c悾Yݽu|ضk,\mE,Ė;rĒNI$IU<>nC{,Z]dL.'%T' I:\*xkP,w97PUL0ȣ,9"{*zZNb~zyWc o߀YCtnWy8,XTnJRzف:b 0,xH]@=1\nYT}G\LOoE#4+۽!r# Hɨa(đI@< d &ȞU\3+(F.\+C?_~3j>~i~b/:N7kak_iQhzBDBxnK;hKo1+s9㰹0\~Dai?i*BtTJh{5J>߭Fe>{jdn&$B#r[FA*rq`P;v J&R8O-_|Kᇁ?!.u][ğ!p%J9-Y^,r5*):+}?>|-7?Z>!^\\~#O&Ś8cjq}Ex.56M8F?? sECjJ ;M5sN:oeiڍ%?l_ jO t C cDҼ?_ /}jw;m'A>xAռ 4}M4m^S+:i5'|<` .?(Ob3b牝 Tje 4h80iԜq+SIT dy'js)ά:{ЍH-֩x1$H0w2c9Ap*NA9 9xw|F)ڎ|[}oF'ƅoxMؖRuYb[裰y_M=i'$dn1̃7r\ ܯ[QSnrJT8ԇ:yI>dy'nuu؂Go* # r[)9,w*PִWmEum:K)j@l**Ĭ&; /7[>>_>"OVq_x_N> ,Gq^KL-b[y~x7ɣ| ~GFe֑ZoExW?6ƾ ӭ4 KthԵf[K[]0ep"R*ЧzF Dy|ʬBTpG^tXpJWj?ݺu$qj|W۲Zdh_1u;D&s]S"ķFYV HжغbTl|+pF $p=⿟ÿI >%Ũ;v'm=oι3:j)-#?qZۛMP:!I~9?'¿khOω>*ľnt__+Dڔ6nwKM׼=ok6f&/3\fc<,1y\l>g" 8+ zuҌ(V.4N(Zjaiehƴ+Rٵ\O=_N I<,ޟi81'$&Rd>Y7m:᳝.O]E:eG+'+4.hމi߶|U?h?sxLkwq &tQSKDWex_Rb~кΩXxv'TtO]Zx,'IO Z_ݼzީ%VS./WTrꘉaׇZ҅lڎ3!5a厡vӡRHӺД(Ie.X+E;6\ђ_֨# PK dd'aq@TMVr 8,9*0rkٓ'| c㯉Z.ºf=3BԴcD[C0 .QӦh_L[kȭum~?ل s냕pOJwp5~7._`{Ƶ'S VTg*ub$wݦqpvm{=V5t՚ܕ^DG&$ji5彍1K5Ա[octM$FE*ZV;UI$*m*s I$(1+$f'<7E7~3;u j>(M.y9&/gO3RH[{=^ pxr\)`kQKR :z*\J-SSQ8:8ɗJsUJM)7y;'/y'e{~XjW}1KoyiuݝR9mm 2ѹThc$'OJះh^0ռ1iMa/ W]Fne:vem?H4YlR2to^;׬|IKKx7cϵ_kkײoujw5n-K8T爄c:T>*&VXz=ӧB3tv/,gRI5Nmrz/U[vߕsHy99 TfQP~l HKj ^O_ >?;x?L $rkZ6r_h5btkGqտoY隯- x7#iq A|.=C{Y4ƻ[fԵz}۴T#xbOp~; Spt&կSC,iO-iSY]|e *ǪiQ(ʦiA*bʝ)mEܬڍӗ,-&ì7e]w+r7#:Jn-tg(`d"{od\%y?.idO㜾 x~x 76ux]Ԡz PC Vl*jI4{Ȱh?(>8ΚgT|H7-]i6:ƃhֶڤ֋jpJTqmo~o4RO_woC]__1xn_MNO֡ug,v7RKqbQUX_qU%lEzJWuC+-g(a*b*^*L;q֥9RBPE)N#)s>hsJ 5VTu$ AB'q(C P1^O_o.N}XiexV-^o~":yttYl|?c*.3rqAsH+-s >W8j8lf'iѣq5ʗ4)բڌtܭ*Ӕ&U(ԦҒwIvx[;Jͦ,~VmC$Gq)F HWh *Y2 8''v$ #:ȯ9RH rכ_)Ƿ.]jwA,7!+7pw .~"Ib` Nv3 g5!>*ec6T3)~k9vGK_Jxloyۏ? x /N>ChqO[4^C5(ʡXc<fE$C7 zlpVd7&ohNlT ry\ZH8teQKǕ2*?)YZ2G>3T4YV]{7tlK= Uƨ)|.(8^Mjc:}W6w0^[Au uUK4{[cdd⊯خizjg]>faGW'Mʎ8(%e)%3ݿꓓM%7Nj? |KǛ|w5M?[-B4㺇l0]])dP iYvĥ, 3tWaWp qnl&[~(kg<_XMa%ȞmNH(L'u&݅Ur@\N!7cN3;LxsQeXq$N%_ <o9wǬbzg}Ӵ;AX c^pCiZ߆x{⥯NJ]I FFo|vݜq`?/#if%bb M%*.XA>ke6* 9Q y8IT"_[?vݛז+~kCMZ)&0Y"Oݻ+$n*(y3?d=7C%/a~05ZO<1b :F{ *gx6sGa ݟe| }>Ej2~٠jt{GC5MvêJJ7~ci h>us{iKZx"U.^Y.5=Vey滚w8so b5O.U)NWTkץzMrmևq7q^'8?kQʮ]74̳ L+Mх:iPhP)U59NU"ҿ?i[Xgk^qg@*w" mGOn<}޳}efI$ pۭP*b1i%ֱKVv 7miX5vjmM{{"l#Qa:2/_?W/?__mxTRKM]X|SoY[%ŦB`{|^ώ>l9+p}k3J-bM'S竉Tt9/K?7x_2VSz[tglWWxN7-`0S[*PRSԗf:ɟqwM>!˾ xtۍ Ϧ!>m]`(5?iMŪx!}KN%4ietSXjKj0^w8# tq R՛p˱nc=Gw_J5|SZ:牵sşE}G-VÚ\ UfEK4j>焿d_<7<K G[҇K}Oacq ^n4pGaum$RY=E iIxE\SGɴh ߀{<>ӣxUR V_.U0k(]F]+IWw= }ř<0pRya7u}3MS%J,^YNJ?/~cS3!Õ?>"Y~.ì^_ו #VJV\_gxW.xKEѼ9i4mOs4,aprrM3_| º"xF4%}b!9 Z[B7פsw:V*4$,obv_@XFI%Il[ A;Őh~%h>__7?~4VjZd\˫S>,'ek[ NX3SRjի_'7*TRR9ͽO_goS)Big=\v'X vkUhBlv2X<O7R jv~_aQG?z%wz|"[a>(xú֝"}i ;AV~:ޝhڿum#@PtFZn/Mu#ĐC OsWw MX𿃼_o3VZW~ ~>4o]?4?']C֗e aNյ=nX ׿#w|9-q0׵m/ |wi-"MxR.<Z U? 6KV_ٔg7,ӊ: 8*V=Jt(K@_/e(2.&n3Iͳ*+4 QRʸJclf[0am,f3 R(ҿ? 9.h|O\xhou~mγ{meou\A'{,ֱAi1Y-jD^6_:wmw:(xfeG_,?kT0|O_H?_J_|-( ֯/|kO > "߇nX}n4?nw\?爼= 3RYax?<)Ꮑ^ ?H5ߊd֖S֬k?z|vZt#l4J4R˱:Xr1P/ex5j <өN<ڪtkcp\\+dY3 c~J& -f%F>4OfJSLSM?Pӿ-4>,5/YY|vbWҼ1W_oQǧNgP5+w-0X",xH¿Zg=֙?|SwxZ5lBRHߍx9C ʪա]ZtGEch5 p9$;ʓU%)^#%;%Tϰq:48-Q3l*Z;S+~klt?K,> {;+{eXbXⶂ$X"UتJr&D]eFӐ}y$u d!,x֭WZjO{+_Ӵ)Ko[oEywu,Ow%NY>őxWg 7д/{ĊF$.q4LK5<{SҖ.r*r[r5W+5W?n51=r."QmQ[WgZ MB_W{7~JUR߷7Z՟SU_;#uL&\yG-'6K6#մ.#$((Ïn43wc}czLK>k [ⴱ kky\[C4LcuxS5|v]꺷5KՇOi4[bXHF]4g_i)?mqi mozK i?\ |s9Kt8O(c23=a~]RX 3U O5~҆Wq挓_o RyIlAصMCHm^8nVk:}!a+g5_'MK~omt\h+/ھ{YZ0ahs/tVOm^#xV4iJXENQ*AZ<<3kߏ?ǂ~#~5Y|DYcs"🇭UE51[Ҧseo/} 14_'?~=hO񯃬|-go Z;_-uOzֻ6ezs،'`1X*.ZUupsF88SuЕJN\\ڋ\/s~Nj8+L5x5 ts<Qy]<,fYA~!B(6I ~_*鋧x'P=efkkFd๸Үk?6 Qyj6Y^[M$ӚmuYA A xT𕎯'F~Y~:hYt|;M8|9{ bτַ}x?m~Q.ID8@A>0R[iNULxQ]T4]NN漝&_OQRC+bLqGڹe70{NO +J\Δg~xH/uBKkK;dygXYEм2>|[N-ej|!Wau5NJ _\]JmGW Yv4E$Wo?|O+_}nF?H]CywkМϦsl"9&S;y52پcik[ d ookh7{ch>[. U"Og 9Mru%NpB{/ x_ZVu.4imZn=HӬnuU+F'O';ox|:߀ ^F@]^j_ VƑ56|ir38ѪSLʝZjR(Tj\z4*wR3+}?g/m_|]Q̱n8a3qNYY /U\qȬ_߱Wuqm;j7Zj4+#h9x偗`m#JDUCw)^(4^ZyV22CE$72-767Q[[oڗWx?W*5 k8́u-L$X/0cj>/־x^۟xᾟ 2 zw\8{3:S'qF},_ >a|UKӮHW6I%Ht/5Ve+#sxȚۤoP}&ݡ0x3ݐ?7O#|cl~#Y>K-ݷý= IzmVᶚ}RH.o~?uOxKJO~(xK-1DQCh,E7Q]˩Zlg)?coZ;wχ + <;Yxb}㘼1}up>%Ca\ڥx^/̾<^0Z5優(0ԪSETJ\s/B_D919v_ep5 - \1=jyQZ_x8V5 ~oǿ'Z|]k}Ykş~ٛ/A=Gg:(PY$U&eBjh_OD|C/?~xG׬m#Pu7Fĉ.5++I"7 "?Luo"' r|l犬=oSMS|`%4GsIӟPCHb?aOwzoO|G/~cV;Zu96OKGjhϧ[_[izmfSԼP&1\GUVJYa}ZxjTYPWTMTQEEx9я=1E^/縪8:J\VU4q2Y瘌CaJja"2NG䗃?l?.~/DoMx+"V욕C&P^^H%Yc -gX~׵}W+;YxOυU-vv{^cGm?G/uH,PSmljem{r|x=_Şl|ZGH[z6[+R ^_K?p~xŸ<{(? h| .3Vw\iiW7:{kH}26mcK`K;o٦dO.0ZTT+իg*+\O"J'R':ܾ@Syd(g~qSr*<+Ԍr(_Pqu'49՜! t%~2E~!t>'׼%=&Uƞ fz 4u jđEmƁ#X<3rVtu\2d6zq}*ahb%zJ(oirԅ_yY4tx"u80eGx_Fg #X[7voޮu9*,V;Xk=F -|JpE}a Si9rn6Rζe)8sz]>vY6_ ~Գm>[V2lK+|;t ѯM'NԬmoO![v8b7mA'+c?OZ$ޕ4Kŝk^(!h{ ]/u:W?z03^88’O`:cb*EG^e'|ݒJSt,fN ,BçR%Iђ孒v5OǑa!$7_8'}9𶦤)"xFɴ$njN[ zz~Xxw[ <;?3+vφ5vyFK PFj5|f1&+tπZbCR&BI $2q|ZlT$3o\ NC`W^@0g+t{$5>IUf![KlvbF)Qv~<&ڳ|W֍;?T/)ΉEŵZ| sⷉR8e{sS'x-[QeMf}vbwCxRmL"ִ{\ӂL?hn[[n!Ь3O]x>j>ZjNiy:UvjV_X_5݅YA<I17/:YO`Uм-ưxrG<[ovf [yZ6Z~6>#x>Ӝ50UєV& UiESuZRI]5ߦ}0<['<ÜA[eO\4cQ4)QI;(hİU!D Pn pb۵\WQ(qAo u+߱?ŏB-4k'n5!k{Y_z/3,xo gJ|GʰxZԡBY.]+P:ʫ? ?g߱m^;-X?kiG㏊>2t*_^qiW~i7nj:OxTS'?dOO\KO|6~,^m~25ϲI.e/ hms.Nӵ[h,;Up?;|e>`f]p`d߂v^O$ 9_^>` V(RX.k;8omn*x-o>b9deN+eyP2' 0.ӧ<5a`+R0j~K[Z C2C/<whS$/5<?|]Z]x+;TФǦj?Vi4MQf6/ _wc IY?7j~P0>O>=EMwƋxoOO]7d̜jZ05D$>_D7& vG Q[ZZQ῅g+Tc8jNua(ʝ䢔""=^ xwᧅ_۹wŊNSe88U'U El]_c EԄZQFj܇i"6HJlI8 8'߉Zo)fiɧXWωP]7KֵZx k߳M j/ ލx\XdkxR_dm(hu,mdd߅G#ĝQ[5m>"!|-nJ,m̆L-gX_ؖ3?'AT ԫBSN +9J*M8L ^3w"-X2bl 3H`*#_3 ONN䞧XmWFNx߅s>6x珼?мtJ}Vq]ltM.4!=S3Q,#|hku;G~"~~9?V4-SkZo5'J.5{kms#y9gtŦqkq>V]&Ttm/\k!5s~ ~IRI?''9~G+:Y -Z*9IF?,]Iǝ򶝾uf_Ɔ+.p5L xS&5Vgzf0 d8bQC 7*sO}Ꮅ;7fG{|;Լa{Gď _K]Z[ﴻKI&yKԬm];u٣^^2/?;]D|gyqN /_񶷤YeT-uŞ 1?h^%1|- :(II$SXEEkk!#x_G Ӝ31'N|HpyZ0 >IӔeI;JZWΪRź5V?.bqM)WGKGO7QJuCfXhQNZܔxoQ)XMec~$iDbĚJ AuXcBȿu|YCw9:eOH\9d[Y|Ejz2I#g#$G( ;XdXH d(a=O?z/k4LĿ*$W䃆yI8J8\6 -:th8֒9Svnxo8qg\GWsBXuLlhkU:I^dfoϩwis妥75%Sе_ 7$2@fWQSOCsΘFhgeog`>6/fmS>xBW/o5 =OYԓB}=,$FO_N?|Q}ԗ !ꖐk>/}{YhEa 5#]׉%cUK٤YvEi|h#`jnv,ghґ"'b3?x/0Mbӡ^x9M%lE9ZUx&/Ǎa!ԣȿ[rY1,y:4k_'B'9I߱x =7Ǘ_K=' ?ڪĚg“AKQtmLu[_k}C.9Y> _uÍSg¯WŒkþ4ҢW|GcK5].T{NY4'4%?cA!F'%’In5N?ip '%ߖq6($#!AS5jOߤ鸽&xƕLs1Lׇo#)#?,e' ܥ0VJ,m?Н/.qئF/ÿ1tJutF:)bhƅjr>ӌg}?>9eͰ T1yfcͰ rЦ߫S:\OZ4FT)P𽥾O᎟O_5/ |6tc)[/ G|Sy$YHm4-ßh3 u X#|7Ew7G8.Cx`Ohg-ޭ5V;Mc5H|E9&Iѭ.`/A̶7 h]v_o͗,Gs8(0rvFy^ |#C]Щ碜9)s4^IiZQ4ow-pJeX̟8{,Cg f81f@sx?Wj:.YjNgqj:f7v:b;;ynb,s)FH5˯XCduHlԭVaĮ\N:Xj<ЯSǞ 8w;bLϧG6?S+؜)<+xKi?i^(ԼGY#KkNJ颼SxEZmՄw-EkoI e9#o"c%|>K H f$/}d)oݫ`~lB)P|e>nx8ra#B1偏\m'+$ϦGPp~'U n7[)YQ^!x,'U0ϳ0 ЧS2ѢF8?~9gl)wǏxW?ɬ_h~|kҥޡ*j uKmF7Lfz4* oj~) ¯𞿨^_ëDn WbF֟w+Eu}qgoydIX|ucF B;ANV&]W^ .slS.2\g77ɀRxyJap|QFAe~ xw T&Tj[N?4_O>[$QȖU Qb:ů/$^< [0-V]U6sc|Awm"G2x{J<;c:8;+UFgonRu+/=[RԵ漽Ws}7,FgcpMiҬ焜'%1"NRV?4t~ Q\Q9]\38N%ap\V.Fq5t0UZ5f,."h(_獭U6||O++_ _> Xx/[oI[W:/ &?Ziwi$w?$mR#7[7YOc¶kWQTk^+!63#sR.c/4;ψ>,W@CxKԗj76D~Rᶉ_ H 1U Bsڨ~E̯Ͼ@[$ ;r'!UT(89<|&PJ\,5T)BzJQI__zJ]ROTg}TXһFc189*V7Q% ݳ:}1 `gM}=f>EL啔nEsvn'si#\e㓌yq==3_mxxmb+rB:|m\7dF@\* >w?LPIRWrqTf][T? -/FҴ\iiEHȠ/@'QX~Py$Dy%VY\UVT`FmʬI$E~4曻w/?%BT(0{2NQi?4ZΝ>ffLֆ# KszeF5 Jyk9bV2*a}3o|G,!FX_T#p0nſ S%^4^06e) ~nBBnؼ+^?) רFSh9,@ʟ 2N9_iP7%4D}od_WSej4[яj˝v]sqx!FrGL ;OQmycgpRņ2ppGXOR2H+xyQsM^m߈fHڠ~UdÌumY[*T.JdW,İp<5crUA K=:{q[6$x d989do/{G&e[UkJ ~sRYZ6H®Ѱg1lq51cxawP=\G0e[kN@h>ax21SigTLubTmm V՛vI7^?G9[QX]s_p(`%8{Ri;mqz~9$0^A'w8in8'(@ǂ[I?멛n^׳jW5aWv$aA91WjRRXWt$p0j8Ԁ^Fc7y n8QN P0{A#C~yw@߼ OX3+jP ]p@IAUif]OkNQwMշmoe䬌nbr(Vf1y n#ss?y{r04 1lp*t~JA# 3}\vjP֩r'ɣЯk$׾2Ud;@RFA(SAHN3r00;?R@8%J0 #Fy㓑=)a8 XvК׍06&,A>Q8X8X FHg2N[3dFP 9vqȨޟd6ݯYy+;=HPq F=YۄU9E!a9'!Olt#n8ۅgϮ@f̙`7 c#sXO=2{Muޫ5)EVчsЍ! ; Z599P,T*Ŕx#Wwy=Glg n`1fn[ s#=1b]-VMWmB'9' [p884ԑ\PpHPFU#q$u9'0>m,C5jK[ݺS@!O *er|9y*^DPgn⡎s0^Wp1Ik Oq A}=rm켯`tJҕE)k},rIL`PH '#R>{å1S0v$e_NO-55C9~asP껁qNFrrH8YvI,$bwd79`@8 iͨD"d8l]r:sUa N]pϾsջfn%v[(˝iS_jV€YG%72+^prAT1P (0] m@p* -p@3ѰNyB 0>88r]~j}u$nͿ.yHdQNg#X ʕ~? IW8qԻ@T9 q,A\wv2zgmzaRhݵ]ݛmB  ӡ68D(9p1Gwv{qm_ ? GsqHn! K=9>w9lnVC\ݥmm"2Y[L’ ŒIQ_HO-p,I}β&i ]aS unnW~Ok`Y|ovH~iv('8L|OOO&k9M_s|Ru:IғQ|=k:&X6;('FA#'kDuF<)h$rM"d&H@4HQҊ6v睝4ggxiz%WUJ4%$Ֆp}KBQKI6hBiZ]_1]HTˉ S씍\i|֗U]VI>[QU';h qҿW XKKcq7GeDb yu+Hb+$R&5P 5" an8y~A&㈪7kD'e w?xښuۏզ~חkFw۹~.|A+8`1r>V:|B m2w,>Yk=\BR9ۇ:96>Ln 27`eP)/ lr4ڍ5 d'.I 7g#,O;|܌q`0H$fF$X;sA@^RISX1]8@8< dpqOU|F $'iЂNp:( 2r t|rG,RFFHgs(zQnr.x>Q~^fdcrNr=ےvTl'dobp;*\qw6ssiY_4OEnERbXs/rNǽFQXn^Q_\vݬC# G'8P8f7e q# "['yveȨ"n[h8$70@<9$m@wq6dqcu 0[k @һ*qNTv$l[=C:8x%Պ.alHh+k\Ӗ^ϛ\O>VԬӵm6i;^ͫ۽{yvT9q9#99@Am͌%Q<wv=52 Rv;n2į\dppFUo㌝H gw]WģQQ$fҲm kNj޷Mz4#(gq;`sGLA+y'N8np02pxɧsBI6O^1iaTn `aY`nq`FX1 l$189 N:ٲAgneg Tn-Uxy/15y;bB칙B( @*1B2B2ҔaMFJ.ьh}=tEx<˄ `>F7dPGc>'p#!{ Wvhp]2F0nے* kXh";ʋ1FI+(WU1=EL}('+rI˛ەF2rk'wR y$ {Sn+$[z蔚M^y@uR9<7gNXnquo Ŵ4Ē<,$hc$C\e' Nl۷ sX|rv 8-FQiM4ծi4I$ӵwӽݕEn \ʸߌ8* 2B:z`rw)@qA'$sO8 C3>AL rNP qG32P봐F02F}௹YYCN;8! ! NHҴ|Ba @'<3  p`֔J<6=2 ܀By\wd0f QwtĞQT*pJd~\+ Oėvno&⋫s_*siVy9$uWu־|=W(G> ǩź1;ٍgUL٩wV'wCTԵxkw?2yRƚrTH-<=*0-:OXGqa#-# /gNYԥNU:SW2\ʮ@ϠOvmgʫuo1!Vv\YDF<% @#Tbo̠mS|֬Žj1*K*@ʳmazd`?-坅_\[COswsu,v[ZwbV{՝ß]xS'V#/ өVXGC0JkUN{ l燵Fsua]_U៍"Ǯc÷R&%Rਁ]i}]Ik6~;@v.{oMb*x,4^w ./.w;G$;a\)?6TjR'ڲ6`7el.pJls݀2ꐕ|E,~2Z6Nꟼic,D>jyo ĮjqJ ͹Bps hTa:`㣯/F6zO,%-Vi%kX쵽+]kEa9dEYY!uæVe ˎrN'-&/O! iaޟmh|8 RS 6VbM7ZMԴ97+/)Ѽs 2ܶۘNR _X,6mso*? ߭ӣ 8A{ZT\EJ):.SS4$݄jӓK?D^4˰Ϳ^ w q,>.,66!G=@PpG$|lgS[-o Wv&EU$C`ϧNyh N2r ztq0y$2/9e - =s01ŧi~Zb6x qs%Fs>r(c@qux294URܐhy8\ oBdo i  4X;7ᶝ$_9Tkd#-?OwO-ÝI:3^+&" dN1Hoܳ",Ⱦ\V>bD^sFx/j?ڷO2-If (~\%V%grcLQS p2K ǹ> $l-v:*,+ԱxmwNXwe xrk$mLie,I$pHřij1,q4VXOnCA52`ExE~!7yIyIkjyE(ѣ7QF$T8 Uwv׉s2DGlfyȯ4,.Դ[鶉1HMoL,!]؉*+0QΓy8P)|]6 ?)x'Ӽ7ӧ휣JRk6Ϟ7:+ZU~mW:sF^P={ d?U1;~:|PR 0I:.wicl)-;3#tdU;@Qhfd;Oc}07Ed~l}B ! XqBQ+7~&*T@P `nGAKFqv rɭ@L:w"Fϓ@.pbG|T|?"g ?#6)yx`MRRt`jFd9> .U/ TX| z7d-vb2K3 YOF3`4ȤX62ĕAnI;8 y"7 Kka+6-۹ J [O~K AcIJmh<v8@t H@e |b[Evi{[hXܧ?>vݾvQ93WÁ{W|Xc'/Nvr\x8: "TO;BX~jSrQbWi $> ԮgI,5m.l=KhI}_T~$2 plRlqI!JǞ+Oi;i??xWփCxzE Ԓsxrjzߋ|$!%$Aia ~E_ [5_?o漺;kVuK˻㴹mVi7JZ3I{;ٿc-{w ܞ :z~pEapk]m簎O\Cm_\\UzBiWRxJqX|VQL$g(}b8tJjI'JN8('3JU\KݻQ(G큧x~;mO A.Z|2ݷƛF :\ mkzOƟit_ u{^/ƿ +ÖVw|Y|Ci(:\[-Ŧ겆gF% H<3Wm-!M&̗aI.t3n?6۟'58|%Q YѦd=ΨkCd1_n<,9vE!̱:{iteԣJZ1)bJ^ʛꪕ:s9Nj1SSih7KpT20qೱ HܑApXS2989WaKwAŸ9;] jlJi@!@ pm5:wF76 s 3>4/Z7P|?Aد5K7ڜ3ƖZr]ىJ|__|[ | ѭu>;Ѽ'k> ΥS@ xgFQIf #Kшo~^eKsjfL)ԯө9TI<1.9֯%(TMEΤ#87Rnַ=˫{~^+w<{^ŝc_6tm_ExPztYk.k?߃VJ^-<_֫_.lΈ,림uz-B/[ͽSh=:|oE%R1O%3k"wu'0v-t۰:|$O/*O}=I|0OގN4ҾUfkg@^VS}xC0oCOA(`pSOVJ87*TOGؗ9A䰘(D0)Ci-F;T-:*SRq(URZ|A4_h lt/dž*xz5|ͩV 3Eִ]rm6W*K4[Heq#gswk{#_GQy[iZciϡi(KړdaڏEM& Q~F$-$K?*ˤ7&0"3:@Khb>mu/neOҵk^0R\Դ'b,$ Y75O<; 2sN_Q`pU'EC ί֝J*sJN-Ӎ9aqT*'J5sI~A5_ h&-[:|:ާgbt-CWKDV|ioy-+L7F%s8A?|d1;@=7IFn,ZPuf5QZiՍ aL޵o$ȭR cT6 _5JjU# ՜Ntr):(EQRJ0"5P5N..1I)nՖOK4j龝Wa#aXYX* n,.s[;B3E#)p7c'.6,a8ӎZ3O*xjaZ 9Ls` `` @- 9w`V SyR9Zo9Xؤ|2Y>!1riEYl~5&!Ok8$p8e*Q8 d8pTKؑ-A.|`"P,q74|JLJ&άW JmNrThIB ݭ3J]JB]L^2V/^MN*JPNiU|l'Ҿ&x+Z/4}ĺWuFKkQYV`u+4%Vi0/߂XY+e1Mi- KffhΙkM|4!??~ xU+YjOËz̞}t: Wʹ]Xh}_җs[RK[G_T|7P-o⎗o"Iyޤ"֭K]3Ɨp-޶H{ 9fx:(p8U~UKwR|J0ms'$2NZWWGȸnx8 uxFЫKR)e25:SRN~ RPF e<8=)9zTܬyO]a9T}A5Os%s%ww7|=vk+AW]qw|$UUԴR̽5۵ITgNR&+Щ jNH;Qi4GH/@tб ەf\0@nF+=:.DB29 nASNXgޕhRGNA-%4~x"I $nQ ebrR2NϠ-ſ/b."A+ٷ?gvDto%&1&qq_]_`HR.$QGUҝCwb}].b ikyB"(3Xb&7/ ѿU񹺕T׵r8-XJ8ckQ^#xuz.OmϑŜzƊF{#Lq=ӂq4)~vl E~/^g'JqO2ѨC5ѥdF IG.ujdz=-+ۻk+y.8=هG;qIN?NssrWp0NMY|7?0Oyg\hQMSlY E:(+ '"=_T j.W>`%I5_6KJI6쓢jܹ-'Ne]ƵQV(InEZƋ|H7۩|pv~;pYAerjN6T8*+(钤 WVV0/@wvᏼw.[=}`^XU,2n#@pq^ncn8!M7o]4k{E޼_xwqWUF. ;~Lfp X&Y Pn N[8c5 fg U`^:yÆԁ`0ŏb& pXdz*qj<];EKGLӛ\9l5>M='›sL>>3ǂ5V&o jFx!+*O7zGIcO'潷՜ȿO]Vr o-ơkF}SWsy{;suq%}L.^fCRnnl> ^u+!P} R@ Þ'Ɲo D5+pN=FR tx9.u;{{tx[MI}[Sl~]Ƽy'Cp(aQg_Vxь'(NjcGB4g+4jճOJ񍛊mFE/߉?~1xN&Ï x? >#}/Wk^gk[&}2yonmdI ߲w[|N_xi?3aWq ohpZxN F!FXe_Qvv梑#휱UH2J;.͌FmbfG-GxESoo:i.u/jW!g##{ii:qc<شZAik?_ BO^34]oĞѼOoҵG—=/PKk}:ij*+Gh7i;.UIo;r~;Gŋ )s< ٻFkCuRG)WXStcZ/O m: 4\:M(UY£RGψ2hrC| |BWoIwT>^7\J>'R*]7уQVt/&"qkU)ajҧR! W3E 1|@Phw#pFU!f}MNK\%6rr2r@O@|J7=~7xv!Y>4r']gPVQPkk%"oῆ?h_υ?o?f[6ŏ㛉.-5BJ֚{ɧKV6?alZfeoPX'=jp5*W#/9CpʤYJZNKݲǕsW5`3)g)b3:41Tpf¦:Yp%^y+*O&JqQvGlb+]0v$*Y\ P r#Nxƞ>Y16Q;(oFN{-#H?Ÿ |'?g? Vڽ7oumC䃦K=̱]\]>ul<,x~m;|8?xv?:aMJ4oumwkwcz,u(RZjk_?#Fp]H׫ QZPsb,5b\xjKMSuda<$*^+7,,*SXtcYIeQAb#,f4*ꋥR^UM9~7I~(s}֯-J+P'KimI 2@ssm$Ӽ(o햗WچY07rswmhO?`_x[Xໍ[ҭn5[(|+i5ʚ6ԽدnG\2ՍZ9lq5#JuN )T&G'Ns$yO# Y2^iV#IufJ4۩r4|'~ '>xX:xRsk"ٺn[Q^%'|# zZocg_Ŀl<5oxV)szlCCoH5)hd_ύ_KY}|Ue~$XO2H㍝T 6mh;ۘdڎyI!>92`|1gȒV ʂ9kPZ*5*Ũ(JN餝ou˦wQc0'ɉ)mbj`UiEvY/O h?whFDњ >6(6~k $i{&m/\E{9lcQ k\6sO3~Ψ,v!8]6M`TWFFBљpd@_׾|6G/ol|A]wtSSWCuψ.xWu Ũ麆mvPldߺYZxZ~•:rB_~xx]Ӕ)ue\=qucY+N*XJ </|n OwĶ&xW@ŞOZ)-}WQ?5x1+RcH*_q y޳ǛW]|4fH#Iۑ|b9!v/Q_̦ſޭ3M|%k,m<9r犬![֞l#K$[V?o:ٗ3xpx7Fh c2Րŵԭ(isT|blG&z֧tHK{[Ҍ,Y;gxYVKK-TpuSRѮzsBI7jةAN]~#q'972UJeUƍdx sCk+\O+,:/z\He焦=/~8h~=;r-n-|c[3?m 0 P]O],xA=r'(YVVn9 Y;c}q1IξQ;QUb Y9^j4vTd:~Хd<rl'/~i~| Eu5O 'Y5Xj:架UU֗,o-ƣvA_aY8+bS("0pTiaG_ʔEk_ՀSI(6i :kV jנ]lNIcYYmemښQU.F e 3V-#rA^9մOem㏔wztu𾛬j嶓h:]ޭ^ܷoav-IJ |yqyj+{%ggߋ*Yn"T?B|_iYԣR*QڔhF+8G;/|}|1XVG+MUaCg猣_ӆ_,,c|K936r`vTVUPDxw91+r^^O 09g d`p0Nxȭ:GI cw^ .I#:9Nnܹ%w(j۔ܚINӗ,n>e̡QE*1mY^T[Zn1JXI^\O?U/^VO#i 2%ե̆e_ʶNŊFCvn#+ pÂ6r0icC>3ynǬڵDžnጼw<7%m$S.’@ZVyJݍZ ~|M.#^ֿa^8ׯ,"O[V^'UO(mJO WHRkP:Uh8NH+8I;)· *|Ď`r2cBҧȹua(SQ.UI/OyCoT 7(,mysrFv7Aт'<I#ߏw+Zd| V$*ITAtGV|!ᶉkA*C V<,?QEF[uh(,_S~zs !ĬO>XrbO؃#v(.UO%Ž,&ܠ{i˽6s,?&B6ޝnBI-_ <@~2z } iiI7Nͽ$jUS#IAsVycwI??J0r\8UXڮҟ+]>k"讬9XRpAEC[K ;BV٤#id nj+woK~?%i8Cv,y|<ͮ_xsᏋu}7lVc2KR&o,2ndV- V!*ہX%R;f y[ƗEAq5wfYdhF A4h/TMF&*ɨL G+<;k-W ѿl?NWʧӽ '[zhn+T 42#qo呱X x<;BHTy($x$q [~ÞG]W'i7rP/# AbmbF$e Bw0\\L0]'}aj5(VIoN4k3`@ ` `j)GWɧqoFs' eܶ5x0P|W5ACe 5 2Q G9z+D +8/> Oύt GthRznEZ%隂Yjd/saOip _>=.W:Gl;C{\ּ=VS[gsd[Fm>ei/\MLNoWx5ixVu-jVLJ42Xx[ ѫ2lx03`<|2e< CqXptp/ƹ{Z_Vqa__ Iag(Bc MlFF3qXryӯIJ3'$]gğ.o⯂|o4K<5I=oNҵx. N^E+3nm 9/3[CdxU<:ɮG:Vc]}|ś[`7Ŕ 1%voIT/rٔM~bnB>*0 :p%T:ooT2&h>Ч^#V4epZ҆*Qƅ%V F3Pӗw=9K9Aźt)ӷ֔)8&+Y ?_Q |%s,|I- x6euŷb/ [R#k Ṽ$}*QLÏ-gZi>/ϋ?5+_g-'}c_sڷVҾ[$N\ߪ?*  68?,Q25~6OZ/_dl:sfi⯉tLUeqU R7eGyK^z#)cbE(O٫UT,y[kKŏ|v㯋'nk#ķ+EΏi>$յ9ghZYTX?AY.%폅 d MuX;^K>xUg@:UB_Q̐jV14o7^@,\_]s\kssmo7Լ>+s8z*Y%Jx[eQ>xIUnTpu*ҡի(r\]|%jDy&T18r1ŒNYYBT|}džt91nyIWk7<Ē9cb{?x=o]A(о=oKLYPIwkl/W63+U $ A%% |@Sz??fj7?? tSv_~ Uc5ȧt?fII?[w^$y^m]Ig_9ŵyҫIҗi;Y6Wk3lHSYӯ&:X8J-ƝJ*NIR5Zx[U4^$ n:ׅb.5=ZZJܶ]$;5%~],RKsT"W&Վ{]?j3a#o̞Q7oi^W~w|L6v+c#2|Z->&o: ?o2,Ðe/N U2jYkKʤprhҔHWS泚{ъW|3ThG3* 4 a*pQ]ՎӚؚ_ď7.|@ n-ŏuMn=& ⴹ:\ZCpғM_D<3xcÞ:9rw]gLnJB}Ɵaymi$[Zf?5UT| b/Oi?W;m  3;>$ơ?g`dž*1pшeiԚIʞQ9TiR:t(ɪwmSG=N)У81QTj.ZbSJ2)F2IE_dLQnǶ^'֣-c.oq[SRPKK P EPư.447eoj:AY泭]jz}w$4$CFGF>'&tX?fھb=|No#^ɯhNJh/ xR]RǢvD_" ./SyL_iGwK_W*ӫ<;c^TR0%%{7R`vRq&*TccէRxU*Jo6RjKg7>|&FCbGs%|go-ͯu| M KukGhQ.0$/,B̛\gvկ~kboFiSYvMk֧5jTկ5 E̯^{"C RA vVGr#m(#[I*R6\d)4Bס^.TtpQwN$5Z_ |-9%3麇? KLޟ 2]\GdʬEb=ƿw_V?*֬-R\aMYk:l˦jqYOwiIJWg2ŹK//Ś_W=WQ)ү#_QOxoz֓x֯bvMJU妽\i87&9Gro&h"Dy,wm'|Df)$BKgbORV`*tb!R\y$)8iSN$c`y=|rf^"<-ZSS,DhU0&6ӊK-Ŧ}e~ӟ<[O)x:ENZX:VA smi—2\D]b6SyKy}$`zgxϊ<]e5oVqO:lV:wy lỵU~i0>~rp|G ? WFY\tz[hP?(9v-FN V%hb/ʴ(҃ӣq5W:5N)7Ԯ9.+,Nc5 խ^&X *וWR4*Fe8?r^R'%G? A>(/Ӽh*橧V3#7[X݋kL.84/o"WFS5}:4+'zڬځٺ^'{JMq\LLqc S68I\/⬷ ~г6Z(_Gk47zt6ܶayIG ChqI.hN{mVx[rϊ-IAϨjڎ*qa1_<|Eg |ci *𥗓eϳ~&dCΌ~hz37&񏉴E<|tkNѼ)k:'5 z]C_M/\?Z:_ &n_NN2@+Rqj:˒)]Y+$M{h"9U ,uV"BrTia$oWz M%~I~-5'4E1$uajTIG#ߌ"F*^f o[ƪ˕}ےR8;o,ix#ɶtOhK!(hĒ0EŸme4nĺ0YծDX7F"u3 (ߑ)}硛RrnDE->̺C~a!O:xk5|'sMժ|JN=7~ K/|O#h/-<5cGo^H-+O.PW72heR] P@ŋ('z 9_ٻLC| 4 !hMsn!VUҼUN#X-cr< X.QR>MkU.|ۭ,Gߵ;Oqux~"w^$<')5-hJ]tvQ{2e_sϾ5;=>ſ__ٿWkC _<\e{:֒5)xcV]X{;z~-ܿ|7< g|w?ß>/|[xuǂ]OH9l㎠I]ۘ%M($(9 Ŝ?7|Pr1,0rܟq9+/PUvJOVmm9MK^菏tr\z|ώחǿ;O~v:{/u=E`vʬo٩8!k$.3#&5u)V2nT1$,p,5NX>/|D AЗ%4^{["QSڼ2m+QMLOW!U3rs$LAƪw)>jrsiE*X.H{[8’r*y|>}EQWo,UL7rRU}nq7D b r888UH<8Lk_ؒOeKOW0ye{ŝKzm5,/۵}]ypYj6zщ V,/˜(rGlrq=?o> f_|{'JGm|%{|B6Ik6[MW7.{$˦Vu<eFC#ae:|E6)riƬ-?Kgx˄Xpi%'ÜCSKu1ʵa 9dtppeuN8z> x/PVm>,Lְ+)*F++B2H}ܾFVke$zg/xYE+k/±B2H?Zdگ®Qa ,##ee;R \?&ŧjwZkmB|=$`> P8+򂭕-J[ 1,C'6xRv]T Cpv &]jj0O$Ag`eC:mi'`׎ep:A%*\  r3gkx$AI"H[v&W@2e+9༟K`]ZK0tٿs %qN>ٵKےNK;;?}>Wg Jt-$j@ $th B|q+׫nֻnݵz|?a~kB b/W?-/|<.u `Ű[Ѝ &\UU-HR6YL.\r < ]s?4ufJ|IśH> ^gm4ZU[[[[=չ"Org7IB0tJ-Bqw^y27ė[/OKox3\*66ڭ1BմOhί+oum\_+]AaŐUؼA ݯx[/N9)5 ź<_kM6M>kخ4[;hth.b>%x /ƞ,~>[Bֱ:ZmƝZ[MZ$<b9) G_x:tYa. ossIl._g^9OKtz k/KZZnHwuHWVWF;{U~wC_|&εuxs <=ύ|?w]v[fOkZZXZX@D%=]?W+9g,vXaaa\'MRs*uѥ!taԥQ֘)F4JU|5jU#Q4Oi|RwD -CᎏEn{vL -o./ +m`eDY7  v0ٜdbx'_<%QZxWzh0]ͨŤ [5g(Q4KWnGD,^3H!X0  x n+>]s6 21.9W'ƵZSaUP *29xG:E[^ҡ5Msi:u[WTFjFF$a';SQdȣ͗kP,oo9o[Xsm7_ χ4 xG^5 Z呺խm:ܐ}X ,*|ޙu^;9/<]km>H!jGa77bnkۻ+&ψZGM_?xky,G$_ ,5='’YCk +Zɞef6LƺO'Ś^0FKUGK l|@),زe9$2}E?-[θw19^[10[Z a9j J ]KjNSIuM)^t\({MSHNn+O=& 8>-OP5v^>4j~)ͩZWl,"[햻#v+Yԕ."ңf>jO$b7M,zFD xNf>Hs/4-#GexGm7 k;-M >"xvZ7H//DYgcgB+΢Ӥ2u-2'yQsj;,xS>\i[Yc:8dKwntI)I؟oQ<9҆['{ [ɺe.H TFSnQV.fRg{-c{H.+`0P9 !Ir65) )c'$d q犯x~(t{Z= V/4gCl5Tg1OԴۋ - ܲGuA3߷ 8c_FMJ/U&}T߲IY-xKi;t~E@~_wM'4/fcfmgg-"6y&ԗ@J"Vz &!ZEĽ6H~ xAQѴ4 JU 1 Wbε-|Cכ`%ѕXIb]BHkSi?|O&-4NYBx*$Vqm(0%'>$x]OaѦ:$'VvaenO3̰8]eKZ 94g/ukZR=xvypWT6? eQR|ٖ. 즮ቫ;NǮ۟kj~| B|/[:Q5gV6nG' 'o'84'֬ X rZK47m|T+i"=;|2<'Z!\'<fg,瑵Ym#ȱщQo=c {M_?:n陣xC&Q.n$Faҁ7ol>eI]ʷ|Cׄ*|w .cg\S(SSN 4*& ,}FӣAZ(REk},Z Z|IK0Q< qڗD׮!Q …RFpp;ǎah`2'ON?~:/vklMŚm"T^Aߗpis$ba6>|uIm< 6\Kg𮰗}XT&彆,S c%ࢉ&,2s|.rNJ1!r)7S/S 8p1YF*W)%hfL>//M/zܷ#犾SO[+Dյ~1 aSYZ5bv ҴM2&-mF0xv~!4H T lfLAsӸ4dM~|_zo >N";T,Wq*ūmn#exe9o:8%|mmgR<'b1q<.aQk;EC$AY<9{*fu FU*zucK:qFt$pܡMǬ6l&ⳮ^QSeXƶ3\2b).G>gWㅔgѰpw lXǼaMz>x|'[\^4}1mp^^nd>Юd.AkL4 E!$1b!ڴk֭{_뙇]fەhE7i-/ rlu N쪞15KYj.μ=TqRnuO1+9M8`x{ktcfw|l8|`Olc+,* idz=z9!Ѵ%`d8,$v 澋=ihٽUITXVG>iGęܠX% ¸,_ w;`}.. EY~|.|S'd6K4_1HeYDV3Chm4頿_:_h9Q&%oYq?)'g$7F{*oxiW9dkv+Uԕ7'E1m{Қ^U,z?*aFWJ8s+$IE kRJj*ן7tlj 2X>(Cjv #-m-3R/On\:m,s .IAr<} |o(; 94Lp[xZy$,?ᤰU*u)`eB(ⱴh{J)`kBJr6)+TV.[ Teƕ\E,u*pU~Z4Tu=TU*R)S#Ş5O|Gw{x]sOyw9ZZyI Wf#*U֛# )QԮu+++֗RGs f94'FW@W쾥ெ?wƟ>9kI_1]Y-mumW֣ jcͣ]]$to"8YZx~;(_ wV|i խ&ˏ^7[pOecmo!y!."`V50n XüUjQ%IJrsHrI҄#VKզ/ хL;* 4Bc eq&άiӄMשRTRDu]B6HҼesxx1kAc0JB Դ_;V/Zֺw6IXDtB"?1XĺryՇͲ8T*x7 TgR?)%/y%$ZoهgX/W*:S?u˒jhTeg??%5[#|iO_~,' cSs⷏-+PkO=&ҥ}n=4(څ`G 9E"ƑI s?1߅e0ɖPp4|X`B+V@)A%UMGxĚ? WHH)4|7xB$Eoj>-[9-%.bos NE*xB5RŨI(J47FGcVI%EF5I}Ô `A#W拤|/[kı5ùa_WxBa/t4_&:Fo[Z76bڲjVvZ{|_;wg/Xwɴ'Win+'CKb)mS^Iv+mG*euaእ:rW5W9ƕLXB6%MQ? 󺒡 >qZxJjRTO*5%GTu!8)rFu2O{J1@Y\2PA0+oUoj7bk[!y ǵ]XrPݵ7[Ŀa;|-ݗl$e1G=׋kmqMI<95S~/ƨZ<3A,<$ byp8a!p۷`|j> ѥ]*gmsx_نÎJ!pH uhԮdi']B>vlfcҎY3i⫪pyTf-ԩS{4VKʩV7V]l'NVޯ٦cSR},cz:7v{O$qXiҴ}gڥ>( Yy%MKÞ"K-cVzof$`QXF<ಜ`zIsf][KĮQ]vsNk]Xա[ jtӛjVwR^h?D3<[2Gfa:5p=juΠkQ5iTN5iN9{./ >-xOX?/焯.|?/ 5Nxh CI?egs_ڭ9o=sA)ebukoie}^9fX-Bx-ј!]~9$03sϕ-ⷚd $8;C202GO)xE3Ʈ99Woc/]sINьUůK0<"Rq\Y{ St^?T/R*)W -OҢյmFmoŞ*՜.}˭Ϻ[h8vŧZ+ =N-P?;5~=s{|*%>C,֧ƺψ9Wg\A_)$hK6S]}_Z¿i]-' /`y#0>8$rEڬ).HX0_/ҵ{*ҮӬ,Ko1$j#ػj*>bP7'r<Lm*I9iΒVjU"zY|\ϐ's:xڞM:8|3TO:\^igtl NZxЌNF՞ sͬO'/&^(ݷ={ d=dyN[e:j`,.4c L6JIrՒI95&`LIs g{?N F8d88c߭} bp.7oxZw "i/tMrJ:յK-FՔz- oi5}. ;Xk||pTIj)קԲ¤*F2HSWUZI[mYocg>ef?fxlCbrI) S WN*Js sEY;_FT,G\-><Ns杤F̭匢K즹I&QҮ"ObB9(:=LJu[BJ52Ats%i:w}k:tVo,/#3B-%ЀARϡFGxFaVj8\F#PU{򔜕-V #fVWypL/a1Qij)]BڔZQN2P|4 |6jǟ aa~,,-Si_xuxωkl${辜~[^跇N&knZaFYqn(EP9Aym{wx^0Ԭ|!ۭ˛o j6DZɧJNʋ" Jߢƥ| p5{^6_w9~6',oZrnӴ ӗpr>0x$C?c^ʫ JJ$J8MVR\jAjo1}~ .u#<+DN_/K{Y%Z_5D=^#GGoԮVՠI߉-n^̎KKZޕ (mbk[K Zv4p+7*1SC9)HvͿ6W;ls/ cC0E¤f?giJSny%9*{O&ʙ& /OƝ:pfteJt!)s<W՝jP q)F0J)#;K1 ^&m`R`o`AS*ȷUgb9>^T2@I#?@R0qʹ!F>_XR37}>?&㏘=a5YGAZX;9/? "~W /|@v8BG gտJ+{}&&CV"F k rYzQ<kO-0 E~X:lfHT&rTK&Ӄ"5TZ';NEerF-nV,iveCg?CwNbPOE `8 x?aF_]^׌ڴ]wZNT%9JST+J>*GTēwa@(0rݸx^IYT8`Y7nC '<'Gne.Pvwg*NMKE6}ﹸUF^ r5# je\_Nvދ}:uw1ԉk O٫"%9bTF6DŽ<~'x<9 ON|A{ԴK2{ j-uSMScB/k[Su ߌ)Ò]OGoWӦL$tiYVY"1yu~~Ujp>Kz:1|o!_ %|_8 Nd`6yE}ZrIR˚G+*Ҽt6F]^9 Ì B+\(5U 5YTiƂUkR劋I$͇KMV=~Ӽ^[?^i޹7^tm#EPX:׍S TMN4N!M9(F[$ۗ*wop3*iKKUƬkb55ң^*IF>MU1{xoI74dZ̲!yFT%hI d*aFf"Oڇ *&w~> 'VE> 2]ErVT쫔tDߢ:?è48X(Q~q# ~0|!h~_Vc|o2|=y4|M\yA'ysAuY麿1*yVR$+j#jV,!mIFlBU&XT}NFeZT#xJ=t<ᱜl@a3mŏx[ .t? x;><43Ol|]_j֭s/+mrQcic4Vq?qrfAk`|=gy~37ӧc F۵,c7#S$xcpg`~'8z?YYRWZj(IBf8{Y-I)I.[9⌞E8\BRx\:(NQSATJPQ(%G~^2>8WV;  Y4M+–Ь:x{ES VvD[ٛK.c0`ŷ(Tx_|Ct4M$w;믰5lq(̼N"ad m%_Q`@NJx@P &CAR')H`o񷇗KO52(IԯC|4\-J]w 0*TiF49j*rUlwTRxM(`R3X]/5jDiկRr*tG'a|I4R-_iX:J(aD$Xy$Y~yc|f4ut+Sr\UB3P攥VSn {$p.XdDu_ Hg[gǺIV?,?w@ݘQ;OԵ?Ь-561=I%hBfVomCzljYjڷ_kh<]{_]ԭ};J:h;ܮ]+I+Hn>@TKxTY`V 2ʺye|-|\'IѫGl5aowIYRa)WRjV >tlk|m|A#Ǿ!Key6|(#QuRPXGqk-'-7}ˉ=t5/ih4Z&^^jo|db+/IGCG~{Om/+pWylcI/ߧ9Vsu{p>$x򁌷-mh$tr:Rkț;~_3}{/mV *$*z y`1>%ʹK21 0Ĝ;ic# h˯$ I G23X:rNW(pGp8^q0$@U=ۺӣIg&_u=f쟓gXWi,%M?\f0dNe[";YϻOY'o^/`̛0 p@pF2TWĿa߇?f)cYI߱=p+-:֗}iyKb)]n xVk5Ǽ'㼪U U9F%)Ɯ.IJJҧV_Ń0f qY͸4xR\&)Щ:8ef2F N22DUpX+_ٗe(jciF|*9 I'S?Nt}x*w=T kχ(naCAIb!)FIpiS k^wD{[Ĭ,֢:'l6 e,eqe0I EPvv~?Ïv7@k&U5/I-Zޕ4/MuttY^ٳiSw!FVܧS>O$w4v`m&IgT@wJc@ήE> S.s8ZFt׵p/h!5u8ť+{x=$|G׌<.WNQq+6Fe2?kR<jxny{ v,[;(g$vc2 @UAСJwN}CJ㓝(z` u<W:OBWo2Zo4Iq'mqpjWe# 5߱x >4x>+x-L|7w|MLb2˼+}ΫiJiG|c:v5}Vѿ/H ) )"xk[xCRBiSxIƋruzժOYW4Fac(o*N J.hpYɸd3cVg{=(G#RNQc 4ZĈ h1U*qhc<}"-V2AUpd@(zU-,@aCp>VpG*0:BTȤeyPr Xg9<#g9s=^攪IvJzvspA`1Hrp'hE߸z㑕 NX2*sh2Ur|è!@7(z~WoODfg{jh }HD(T!'p z_v̸6l%K c䑜wE|+}HC.]9~v\0. EY @$2eqTs <KkcR}~W6]IV?lx%E#09\8\dyJb+Zi)Qq4HxH #FF?>[ aUG;q :O!s\Upt3Ex`QM'fP@Td.3*ˏodIe/N[Ty|Ŗ㎖5͎4(i/yPO^s)Shƞ$qĭ?֟ k_ٷ8six#8f-ϳIg Ua$bGLm04#Z݅ZtiC %F ܜ`:8ib{k[uMDC-m%]h5i97DD>lW~?ܔ*?iP!$o1X;W3pC+[\D?-aֿ:N*=ӭ%&fIVO ;wAf.nn˅nnnY-%!mb1W8Td#q$}{z%uNi..SlQ)Wnvzwzx_Q.%!$ͷr9WGˑs_Sgv# x]cCۨrWQKJbAo=1遀n]e;V $ ga[T܋_d^e=oenk_`* 0_;B6a:Oj}]ΝZX\W1Kkpc miavb,k7ۑFPR$UbBⳍ2rFv( 83]Vv|}{_ÚNQJ2ڵԴM]Ŧcǯ_`srs}.w3 x`h~'|mi{^ ~ʣzψ>bAԅZ~.FIo /+.X#^ԝOI4+X ~{vv΍፮XujmgK]jk]^E$}"/Ҽ;˸;3f^9r#Җ_(Rtqp<^y|1eMڣUr)Kb1N3=%^j'.kQ䗻ks](4o/ [ŲH񆯨@X~$ڽֵftA)m/SRkFoe"/ |_u߈'[Լ#kiIyica)BsV~ˆ??&/o?gxWuį yY4Kk_Z|k}u}gsiz bu ld?x GY_^j cLCŖ=ӼwRhTN;V5+ Ri50@זo}Gueg 2iT)~*j(*)Q }C#:XIIBI}b6穋lڌyVrJ~'=R͸u43xΏh^*Ѭu]UѼ=ڦAլcƗVowJBHD="GI>X@\$Y[t}Iŧe-,rZ߄7h-[.c4=F2$oQ@ݘju/>@<z7"@fRjA``W^_etdy: )e/A$o,+?-sRxDrjV++2T #$mT*rJЋzqͽ̽Y.XΫו:]lF_3hQU| "pA62UT?~4 b-NX26rqF ?i ` dNUr=JB@tnjtB:]Emr778FI$`d _k/ Y}վr;B9^U7Ef$X(`Aa] k{+;{;;PR\S-"UBĝJsl }m(cɡlnH 9f!IudA*r$s'B8crT4]4.񵟚QO\qIGu*JoIJN՚|ֵ浵mccr2x,p P+9'V##۔cs AR ۆG?t0plu8d s@]ArJ,gvUxݷoN312mn=ioV^˯B2FY&w,7CxJ2ddp &v |7~3Ҵ-YE[Yvvi5-R$) k$SJ]|}>ipRA` miPN,]7|b|-h? ]xFh_v%N{iyk=ům$ֲi֚8/a=^[KAl/3p٦&.cptse$[ MjkJSAԝ5(Ԕydz^ssIF-I+%tg~d|b{C­n-.g׵O xb{-[@̬eЗLO[/S奿o/g_ o?񦫨OZ-#-%m|?>.n5}6K]F+Y&koW_i:=RF>"[a[Ju;:/ mVO'Ǎ<' gß6<[|Uώ~4~:e>s\W{m"욃Ke,W05ơ_TtʮtUГ_5*ή.pn(}N]78A{ ZOIKtMBc> }0~ewSÞӧF[ Kմx5NӛR-Fh-ZWOSj/ WZŧ|M]ɥCck~[Q],^Kʟ=>#oU?~ D!xxcľ0⹾ xÚXh%N#_X^]M4v4+-`ݜ'd.o7=#6#cla _NxQw6p3GӞ]^mnlӔlzfܿum G~O)p[x1y$q;R6)) m?)##Ӟ:cg]s[4"Ѷhձ#GL J\@J?F _ 9sR]'+{4ՒJIOعe*=al#pFFH`}INA\UX#Avq1ҼI~91nW>)rxI5~ Y=i%K&( d͜RZhrk5֕e}֍{jNF* d/RCr{K o=0L1pۿXS FPv$%cux'MkqsG4r9"9 =_3UN=G ;yy!O`Egvwܦ3 S~2z/aO%o)c8nWaH2fED [jy6gkSO )|/ Ca[ ?/h@!rraf` S=y XG7 ot*yn$5 㺪Lxur?1*!2B'eԜcm*TA deOf8/a~僚?˴ڷqnxjАn*TRas^akBܹ* AB0^  n˒ qgdTa62׾"Z^7Ι{):BTaZQ]M mpc(j_MUֿk_I񖲰|!߈5|h*1WA^G&)$>ƚƿ'uDk owW,~6y KkYcsqOd)>=ηx>KyV[]bזMJk-ӭt"M9o.Ro۴VV20UN$m Z~2~_'JUB ȴuV=> FKm G!H/߳_Oh|DԬ~'\F>񿄾,;^6n&K=),[fXkZs/C< Z;UQռ5B:7]i:φuxwAl:e:e!㱴nmg✪J4:ӥGJ%U))rTxzMF^.Z38XjcGK2V˩fkB0iՔ?oJR7(GJgK ~0ox!K_y\mQ/m7@zk>?Eu|V;>$ai?|7gwi"ݚv]$:,Zch6}ML(j~|-rV6mIӯ(yn/mh+.~s@~ $m[H߬w[v%NjymHSamq@{ky$YM˱e*xld)0IVTjCH5"ҝd>C+\SV:::*jJRӴc⢯(V6 M•@ci>@+;~:|v?>jV> O56_Ҿ|"QJV x5K+߇5|隟u$,T{ZG<ےFpїvDlJĜ  = cVo~͞Ss|1|trol.|Wݛc}o,+ūL:aܛv!9%ʭ\dR[-XxUNtSӕX]*SδiM2neO{>վ?wOc⿈'.wki01l|;h|HqK& /|_ệ:WySi?Exx>ê7|M.x7Z~%pZ4}iYCqwoGsNJ$?9W/}xKP}3G]cU录͞pioi)$q_ItGm5iO_w:.q^^zai^An~wb#bfx"43L>S BRQPTiU SҩV-{8ƪ\I MXʾ7+e<*XbNׯO -w^& N3%)Jx/.:>_ig?C[<? j~wSH/|3-;Q:kK}1 %KiўU ct7UqS` ~QtŸ onsZmcWVR|{Z^_]U/'swq,?7;m.t?m:7xԴx ee$J?'μN(VjQkE.Tۧ7Vh$ a5M6WxNh]7fc}bYYX\WΥ=/|4׮<öwiq7~>X|Y+hn|'wjz߅^%f.o_gK#y?o5Y['čkQ#jW6IIwg<{v) znFYGce QAo yq@#o.zmXY=^m/KNe\:um my}-wyr&|8]XjKOpvRʡ+# ?0ciex}˩Y-u5++(Z.p*-:sFYBk԰^3 FjᴏGUR%z3)*ibХR/j`)? *1|7.[+]%8*@"?Kx|=xWIgG}ch͍Yjzg/LIc8`CRl#| _O|B]}'HӴ)/*xXPծtIӦ{yꖶI_?f~+ >#xt^#=&P_F7,+oeg6+i%_*0 in'b\MJxz5+*ѡ*׭=jƦ# Z6Q\X㧜Tj[PCZ0BSO qQ}mY |O|E[WO.|K?Y~uOE)|]!O>k]1gdHA6u_A 2I ,6gE(h!eKnҬϵdl<(ffrr9<8:y+Jʵ(wޜ\mM--ٞAͫ(XZ C~„+֌RO'Neg]*rT?>6~&o_^ͼaܛO݈f6:E/ ĺ஖6?xc.Rjӟ >"/૙_͹~PVVωluuMgZ:oh/q⿍>,Ɍj:{Ed]eƚpa*=$O+n cם1 z6Ub*ԣB%ލՓ+.[fx9k˰:x[+10rXJz(aUthSIFSR督UgL /|.Gq 18$drIfY?>e'ᇄWIR{}!Zo~##Ljc=7ÏI,.uYEbM3@G;ܱBa5|}7{]\XZ]-cxn,}Dj6O#%?Vi 4$hv#+bV}E Ζ1ajR T9|qqpIW/^ɲ,vc^`UʭX/iuN3\~gOÞ=ӯMxKY2Gx#/x[8|1=6L41Gk}*^q}[jmrS^8#=rr:nx{N[=.ڲʆ(/_|w9"$(P>jsM쒻yw5ŽG8b6n/qc'9غvUJ2N2NKe9QJR|i7zXPqq*t*\܊]SQ mΕ*|>OͭiHQHTG<][=$E}xD9RT)8!HN9E}[M 6} zg@Ŕ'|l?fKmn\d0 ku8dFr}_"?O+gK#FLj~b]#mϋ>"6ɐIm lJu4n5e * ѕUôr+_ k|JTp|b>PF8}JĜPBsut}FO.|ڻ$-o˰۶IdDfEBWhVLJUxf`e^Wo+#J\Wx/%o?pBQ֊eUL[M]XkzHGq*$ @=Yڢšx#񇈣Q伟8 $. v]_ƼdnR!ya~ſL_0o3ĒD(TW?GŹw_?BW (wFJ9IU`6KK| ~|5`X~|u;OqSS-/ FHnn'-B;UJ1 ź>ۜSq'a0ݧo&7/v`ow. u_3y ~aveC1xr@*e;G)Rp,PaGPHx}M?T TiUkC9# J疯 tC1bn<,8 [R1䬼3k}?O_QѿNAeoJJiy:0T]6)wI~t@B%02%Q{Mڶo)*>u PJ0nB3+Np~ x/|9>/8ׂ6Ե[giwwsoZڭ T7ji*VKcO~:J}<^▁ cPNJ#2ӵvL/rY?Ia%S[\p b)RUY:jѡJ댩BS .3G8LF3(3<]JY}:~.4ӗUkʥ*KPsF]H8oũ~0. Q}z K}p^2`^Ge~՟ 7/7ZgMKƗ麄ǂQhūE({Wm[;k#F6em6!㊰3.mo<F{ӌJ d'F iV??5٣]HMG^XtmZ4tIf +n3c :M6#*[@V++ ^%OվVԾ>k > DuEzw*^>|r,m.5 KCŇKKV/eyoF槉,~ztkTӵ{ARRnJ}, XWWUc)Ӿ(Ssj3TԔ )ogN|)Cnmx^:ҧ=RjKjE嬓Diucpݙ;{c*^xPž^aZYr a4HDXq[[ƯbYDmg"ӭ7 żOa3\v O :?ҥv9NR^wIG_Ø|]௄G{ѧ@4][W&Msam* J;k"xtm?3j72iQV+ !aumHX혮U$KO >q}I?e*ZJ~2d됻sW'sf'4 GJyu 5֝<&+G7Z})Ԗ St4isB z?Y[_JY&<~"TtSZuqfڴ]zR>?k?i~I Jf}?_98W0@ЮRᴳH'sϹIm '9qDW 4|/>"^Ω.{j֕͡vM]"x%tX`D6~mL͍Ă03|y'74n%#C.¶BXY@nu$B.O% +0F>W'IgZMJ)%dq_cZ53QiQs ${lqSb㮯~d#_wtO#6ћ N4#eʠfmKඅsmU=ىe,a(%X)V88? ?Zǿ·]{'kJE|9gUׯ .OMBK"MAs_Sw^־?~ᝦ*!$ps9obcʵiMŽb踩ljMIu/R8:U9z xarZN4\~nUԮ8%~[jP@(Я\UEhQCT\^\p!`C rs8$d MWᯋ<zwOqk_k:e OJMFX`Ѯi6לĿ5 A)7&S/*]eO:O<4]?V>,J_xT7_W`\WnK_< O|we{{lt.iW%K;dP6/&]0<-28N Qsk:ޥii/Rח[ba$)m֙OwޏV?.)6M+Z]KM־"f =/ #A<f+-r/:2`W,iӒ^rД:F$fN8zѸR/WP n/1 6 9{|FF,?5^R!s{7(ӌe*+÷q-ܑn *3lV?1錑7>mTOgDY~˪|asʘը.S!~ 4mHpB`b@/t,+ƥ~;-V׾|J4hwoIiῈɥ=ׇ$2Зþ֒m|YsyqtjNCBJN[:u4VnS# í%VIjBʭh> ~|$x;_?Gyi^/ү-6hܝb SM,m{/"%Y_k9 Zzτ4hEeo5VI-ܶ#+o6y.jr $qM *ʩ>jؘ*xG5J׋y='u#V(Q2>QQRXm55IM|+ l.x{os6iZž&fR|GKb[N|B^Lz%Ǎ52K{nkܖ+'6yX4JxDpU~l8Xr ܑy4ˇGPoK†xWWf`әh0]xZȴ.KSQ]rTɲG ZBxժ ZTu牜Ƥ#9ԗ=Gr͸K37СRQٸ:jrɤZr,Ѱ4'!aS 4Ė#r 8k-M|p\3 -w`i |W״%FS*O+ؒ7csXRnyQ*Xz=4QKOȬOjq?+t7.'~+ےƣiAg,$FWNԯ|5H-M,#g"R:d-u q ^M/yb?C],l@W>!6A!"neqEbWpRaXpE[?켿u%uѯ}omn *vS]}t*)#E~(I'Vgȯ“z}Eg,yd$2}3Tq[cۘ>&F ~7ђ2?^F~])˺O_yQrȰM;[O->u[>R?f\6^rGv5ed}bp9;n tl73llWבzV2T>Acf-m`MdwO +Ų@Ü[D[iT]5M齣Tugeu~JI}Ҿ %t GOlx^}GJ\k>0OCz uY##,,3$(E#̗aK2$ . ݵA/ hog%`K{㒤 H {:jSݝZoRSeڊu%VK|7ݍKM.0"`ħ A*NKpvr^~ :)ehB"ʙ Ʉ6@9cV>`ۖ׉"䓀T,b!s 'I>W;p \$a=sX'4nVM~_u:[[ַ[=URVR_)xAW^k¯ AjR,Y+Z<)s6s#9/q@%^w|P|%e<2G8& {UO{%ե)ZK=˟:h|,IEzݭ+EQc{4ڇct`ez-> 5kN/fmsjSĶś.F6zv  l+JUD<~ k >`? |F[.-:ƾ9O⸗RѮ5ho$F,:pWs)У:UM^x%thED!g٫W/KIK@-t/w&ܱZ}%C‘ /xNM_8q.# UIS8xoԩVxuqF0RPJMJKAœ!JQInKEf禭[+@G?)ʖEsy*|V%퍽q9zk{f G9t ي2 TҖ®ÂR:dM~/)Kɽuo_Ĥ\xoVW^~ы+[5M>vY]%42Yh<[TQ$(cOICQt}nцp#P\2)* rG-&nm)k_ך=hh^ԵHv.=޹-ය"Gno=:(y&--`BOF'0[KVpHթP PU*J )ϑS,]D Κi%(E)(TڳIg߱o>ZxkQ"uo> t=nC}S_iK7omyi-8.A& ZÞA[߬+]Om}2X\yޑnFK>z?#DŽxZ񖭤xSݏMziVB5]6++=CS.-֩XWF-o>1N7 4?񎻪EaS|7i#k(mwLҵuxn/'լ:MG/5_ 5W(0aeaL4plTe0eW j1ҝ 4MlGa%1Td%OS<|ԓNujq$Z2A'&V4>{לxf(I%ݴpk ?oÿNeeM޳yǰx]ƅ 2[׋t_OHx.!ko?LĬM/gxK&,YP{[m6@D3dtPrI`Iʌ~FP$vCc"0nXĝ),>csor*rIBI:IrǠ“(zW󄜤nܛm97-mQ'y^/4adcIZM, WI$u8ǯɾ GRGÏx%"_x[H4$ge[ {GI\, ;770Hedw`qXSO)'k}WjR򒏼&ݜ4ލ'oO13ᯍ>.xূ,9}]ZnVmֿon/K׃M8强"ʯ>|8m[?״j~֭i)^Zfu{K^]CT}Y%}2y);~ :,G.G~ߋ<'yj櫯k?'յ -5 .o2Mf͡H?yxٕzt1.dLi*8ʶaOĸu0ysWX9O(W8ҊsNQS_-~%?\|𽽬օxUlF[;{x𮗯\姼Zl[.&(cXF/O2)ZSŶ} |{{-XDt ɼX%iM1n#3JV6ҵ8/n~j߉~ѭ|c<6^jnṦ5}.0L P5 `1p3o@wd+9NE49,iia%VS SO :4j8qGjqUT|}/R-8֜yZ\! Ii9]+6LJ0TmHq2jW2 ާj8$   lH?( .8991`cRv\>猒A_RrHt۾۾ĥ$nݬk~ƿG=BZW?z|^ҵBlu.qq)`I~N<_'W욒+'o {"#HÌ _su [*2nԞAP tŗ^Fy.~ q@ q[B.IrʳJܮ>WΓIݞyA ܪfIMV><e4C+4-xRH߄_4TmcX f84m:; ޣ{umm\[>B)uFze{n؇K{=vVz_/=9HYm*H+(~@x`ᏄoC~cŢjkY-ֱ<-ng9 0p|AWJt)Urax#b9Ҭ (iJ^Yb#V$V%B**tF|r3GںG2ZGmm@FtIPZ95hJ\3 ;jEWލkr6wce γ%OvrGZ6cbUAF1:SPX0TecFW̟֩|3gQ9&ҲjN^ݬgvRi˗vntWtQH9mI+0Ҥz3ˌz wPWeHR0F~gqêJuׂ@̣;~nA>=᭪ir{.Uw{"oDvI-bI{[ݥQ^IEzÐ:Z\ Qvݴ?Wu;bA'H JLs_|9S'3u0!sgH}m(ِ,s`0W8ksF5qlK26&*ڿg-~} u;}vpQi2 $}~_< 8mbؐ>ϡ\a@(KJbno2m`02r[BN? |?PkG>7(}}?#N|R鈥~gܸfJ50X[dd_ÆU( i؉֭%s>0 1`t-< '!ⶸ-2%N8$P03[2 #ϴdwny.W,Z-=LxX sYswSM<ѣ;!N G.Kʠǂ0 3#>5}Xl#~Kp&p>Vu*p0k׾,?ܺ)gd\pp 9|KyA2B )@NA)Ѥ5Ѭk:n ܡg>,A*@7Mv;#8}3DMŭsF '!ei̿edb%m3@IBPr,?ui")<tJTCU)b%*P??to3Йf}VӵUv0_PgoeIX5mW-$v|+m壎Wt>/MďZXjp֣xSTJuFu?uuiwj6s#IԚNuuJжCQSԏ\FzMy$R4?<_|+_ ؖ\ј'(acF%JU9ɨI{KQoVJ+s̱/5VYaƕ U(V5M=:1:Iߙl~hm/l9$IԜ ~b`~ Y_hOKjޙ__k>,|UմK῅R fLT׼U bR=@i6~9>J)Т,[Nt>iUs|'.FROQ!ʶDeoʁg a/"! v'we8qVRH'?>s qoDkp!?RgwuUӴSLզ;]^е;x{O]"J:d퉣¾# {@j~aٮ~il<9ѪgZbҮ{>owwJU zԫxδ7RT~(ʭxl+*uaORR2#ZsS ^' ƌhBiVX'W_ (TJTeoɸ?glr0cKxUG>3KN1ixWmhu|]/:ǻ jz߉-b}|e4?~Kuug _܋kMBm'VLóle]2iS)fG epXJ1澇%Z*g b'-Ғv[O5b&r[Vq7E(I5% v}7¯/t-#Ě,"h$ԭN]WNҵkdoXмEO$:~cټ+ \ ԸHL C-,#vտm $Ӵmc#[QW!k8TAIAtP*ͨkW.h[߈Gψ~2YG5e6G|#k%JŒ@ڧ%ɼ %U.'}Z)baJQ Rwj/ I$J[M%^ҾLj6|jxI'{O<Ki>)h7-M1]WOdžu(o4 k⟈tv-K67W7$:-׈ogfio]i_DywM?~ѴXݷvAl"D>|'+{`~IH\I휷Z o59kFvfv|y֐#P'9AyVE|LS^.ЍIJ.IF5'y.U&ܥgy'q}OӕjpSMOVZUjJu9FiI9;Myq}In@pmmU]tI=|6CO?jIp ~qۯ+0w>'۠|30i͠|O4 /$%P)tg8I'u4PY؂=n_ x3_4Om xK=߄{Mqf,gW6JKm{%ٝeZ^ ٗ 8կ_5gJRkSb*Tԡ ezJp?eiVqaԥ&3#.V 9ƭ'F5(S RjiXI~Ҡ݁}y%Vŗ?,>%Z4E{=Q$\񾭤ܼx!ns<2Ʀ?@!x{:]Q<1O4 Z_Y4J47 ^tf Dms*ThaFdr >?hv~5lꑋg_K,M'HiVոhnoE-#ZǖmWSWt<=dGh06#%ן`aml"qIգ6SQgվ+&M, >Hbc9#FaWPTRqxJ0Nn |_z|Z|5{|IyhH[REj'0v75Χ "d &\4.5{+I-ڄچ}q42OI%zݹ^c]w9E^*T)sT*SY9s'R+BN^W.f<6`SqiV.P9PGPZu)ӝO]RVV#RTuJϻsp$b~ ?2q@,~8O^_?ClQe,%OD X ,9K~#Z忆aM?۷6I$Q0vQH~{ t/Ph> xs_~xP\3Vck:|_x-Dm&BYfI1rB\39R` Tg(Tslee:ti6$H78=11Zx|e,\-*%*2֭Na(%SVSN'YJp`ٓęoY?Ooi2%`!mCܠ1̟#Q fOڋXm' XŒ~[Z??l|3C o X_ږ%Y-Dl|*?i?!65o6[k qt|0mX5? h|iIԵ}Kpoy-xK[otK|KcwjXZmYZc BYvW F2ʲ܏`N2~ɮw}O+6^ȊKx`YDQkIV6YUF"=;5ʹۊMʢ狋wR19vc7b1,ThPbI׌!RxzjFPjk}k:m03T9a Ҽgzf{o/ .">(FC^vN#~itim'7sih.|VM@ a1eb]Oʍoz^n&k_ _|+K]:W%඗^=Nu-RWj#YB1Waud J)r%ujUayIaI\qN{Z2ThҡG NSӥJJZZQrݹfB_s®8?Gq`r HOk©9>;Jv30G Y0FW%kov8_ onWË߉QsAEoGӮn,Q 2H΋iڔ%<'?O|#U׃~!vի7ٖtzyBMSJ gpRhͬ^~ATP֋IFKUT1,S>\Ǯ4ࡏżm<=HIC)R^"pSn/XX-8BqjOoٻF[ПӑoO m|F@yO :?ߴ+7G~u-+~2Nn[zn>3m>2]&KW;hqp@}BwxH࿷uۀAIU^V*C.F̛fy68it%S25Y7g^VZy(ͨhʦ!bJ5W jR\dB2wVMs'{u ~9x_灼)'wsxSzj:s]Fֺ7Fd,֋Z,KwVH+q۔\78y >|7m߇ͧ<=MxFbFK-2_>YEjxĞ#S1ڝدjROgnV<NrT6ߘ'<JBQ+JSmh+׫zwIͦ_{K N(QԵh)Sӄ!QZYg|*_7Ě6Yn#6coqЌ} 뢘!c@rp Nц*Ufa9oOJFI6n=o\b[:H$|W=wq_-?4[oF_8_cX࠰?|$|}4UBw$Q?'堃?A/|G8 ;ZzzsynYO#|Iu hȚʹ ;m +}jvs緍jt ~T m>6ʡ7m*KiO9oJ:j^*t՞-G}t*)#Zb+c_ݞ# X#1"b@N~!Lቌ_9`x@BFlj4ihorUW#HM8c">5#%o{C DK-OI+ljxs>T U;99}VxŸh׺ٯ⧅?OV6|oh&JJ~x_]߈]O|ۨt|;Ox6՜n君Uʹ%cy_jy[8V5_G*ʿ#vq^ԕNS$T:P|c[*16B]ZI*xXSjPPJt:htbMݸFmQ44_oN[k#~m17slPmT<;r|Ϳ3W4ٌ-!hx~oj'. &S:ڭγMA[T ÂxS$1}1$:lSYk? /t?Z{v5 [ s$qfIYW˺&qZqipѮa̅LrWR$: jn03?WKBug x3)Jhӭ:U}DGgJiMӏ8,]\ӥJuuWTq4j.)UI1Tڰqm?/?Zh]'ޓMjp&-/Kdג3Y ~k}b1db[cԳ1;iL3nzPWi n8F:8j a8S2BxicjJxJU,E*𱌮ǖ1GU^9xShRJxԥ>IԪܡhre9RA )$QeQv+bA CckKRpId}@A'9<j9#8=ϊe>СmGX/$ C€,q<E%UNzn҃WII^5w6=jR}ci9JJRv~iMÿ,2cf00g8É#OP% ʄ06AOi9~,h^/(ı%I>qB@A c㿍w\|GUl+!+wBwk,xSZViieZ&n>ھuإwFJK`{ Jع ]XO4T vʅ%_Bte(6߻$~:U0M+ j;R&)¿ ı_|,}v$W Om3,AWdl7)zk#pH==99<_>SH1дQj;C/⿇f)i) mad4o;P6M6,O"(BCme*8c #$#+FX*鸪{YŸrI)>UxZY4<)<)5% /DgYj7VM^u /|-n_Z'>)gi5Kamˮ=7$ѦmWG)-%OL?n˩AO3uoO/᭧.73 ?  nele+\jfZ꣮\F<1 J[nG-KQ,>*T]|V!QXs/𘊉TATI*>"q-SQJx\&K.^CǗT?ukc0iwDž jZ ֑_O>=mtQEm^cAgk$VYha%5 İlfumry5ʄ.ewxBt$#YE9axW Ftcs 4fV)Ek)(*Х:}cdo/.Fe 5Cল*!IH6V7d'²|wrKcTGL<|Sw6o?z7mv4|ISFV7׵_vM 77Ӽ-msumnL[o}2}{N|GKi76/JŨiƝzZz]ռץWzTwnok;ҝ\Y^\ᅍl-y+%NsVIFQe)4KF7՗ kn`wrv#'N+*?h_ iwmzG1xZxsC]*~ R := 8uͣ\L4dԸ(קRt=IxQ[nƤfSWF20J1Vq*{oU5kqf~\`UJb_x@ᶴ@r+:m'QԠaXn l,vtKKP! Vf)~eG6%n9RNr (RNWk 985GEƤyURR7h>Ugn3jn*nj#8E¥)|8jŏ>=ˏHZa5FA֔nht_iAM߆@nk_~"FŚx~u jZf7Q%ty$ntieka-nu ]$w!$v xfK  H f㜕IOϯ#L,>F5,RxgS;ni56)Iڹ5}ZcNQvN,\N*1QU>C02#=sA `gs 5xN6mgK% Hr@n21ְSFljQC( I둁>;|X O x+I4]h,4MLiouW&; @}SZ *QZXJօ*4)cz!v9իB IF,b1XzT)u(BR8(Z+V얬m~Eoi`_-[`+ૻc8@ RU ØdKX 0$. "+Q?~٣Qm^%Obg"\HUpg[ / #Ԅ @\nkXMcl1~!,eTpHؾЦ6 _LyFyy5z[&o;O]OQu8RQilkb[y71QBp=N^Gkװs\*GĖwiqm8P;E$d~WÿMx2i ;Hl+ 99k$aK^OhxZv&1vUK7(.{߇SGhFNWI#b;/ߒR 9:2avW?g{~Pgύ 6Ҁe,WڠIu gAz !DfX_ݼRDmQYH`w_?SsW xo] ]jQe]м]\֝[>׵;mKWGAfQ9el0ld(yar3I|aO dX|jTXW:MSBVQX58GݔSJrҭV+Fua8ҫ(Ƶ *rh>V?*:m?iϳv+99 |B\GD_,(m?c $g +ڮIqS )ؠ; 껣%09 r٧G?oZM⿆֮ou- Ez6qk5a3\^9ԥl,*C :YSѨ! ^\viUiSenYJ]KJ-A;'%g(ω#{//W X>!-}WojZVs]xš4]G]BU5;|߰ZpC?9q>cfT}KQ2MdqQaiWuZHNU/UeRx,u#:U=\ڴj^["]$:-|m.q_%'Om:an-wye4M}/߄xoAҴ-K6fXZvlYkk+;(!,Lj3~iz6Wyq#gxdB  gnAOF#X>^#Dq]9o\19qڒwN-[guxJJ^jKA5&;Mg{\T>~3a1[W~ mD^þ Ѿ%OSv0Y\Gh5MKkm$Ubkʈi&EɨK Q덹• @k M`]SZIFhmxF} V-VZ~Kg$Kz߈lm;Þ6|~}Կ(Gt~$Iyk|Wj6/uԀ>i( %7:=~<>SxcM_5¦2 8X8et_T~)Vs:)ʕ57hѝOk^)TYjJ^iI{.w-%)9]vvO;e_d2hO 'i| B/Ů|V(Q6W^0-oKkq~\\۬gG(%B6kdZk>~!6ƺxo֭lb"QmCw[ -\v-s7+O [mv{'@-o-M&:Z:jR}c 6pG4Vp¿a /j4$ =OS.~xCZ>=w@]:]_Ú6#Y7_bׇv:fuu(vz]V}*;8y C}iOWz?SYo~obW[X>Q27],rg~2ʥs9n#<͆ x:Ɓ+N4][O`7VjV7dGFet2F7a[Kŕ \T%Cn8(ۙrrĿM /]?boO"G.44zF5ޥDJh7Zy[-8nIR>P۴d73}Yf} K㰔Ԕ]YC(9mӼ/uzeZMBeiJQ]}tv #g`gҥAՠtohWqG|O]#QCVho K{>GG Zk4_.9qxz&PmC uj'.TE%g ri=WV=I\G 4g:džm!>x_M[(#"Mt}S Qj.._um4b2w A|gw;1:瑊9m'4fX*5uW,Z.桢Khگح֗7V:| ,V7laWqrUGes_QД2yuJ%+XTV*]ZnH8.Q(:kRQ匣'F-'vVm`1%QK xuu%xK>ѼI_dӵ 9O4c&giaU}";N"O,Ej=hNa*)s"r 7AnIps!'=jغ\Ejrr*jԫ/gfTQVRMٺ5N0! ENhѧ Z垯Ek#: ڈ|W>&B0FyXZxMtsEӵ/UT[K;Q˻K[kKC$3a&eJw$H='!Fp:l@"`[062N7YNH$qV-reI%$蒶$9tp~ꍓ*啝Jekh|-~ pդ3;[D]. 6" ':E!b8bW5qj#I\d`[_r @Pl¤oˋKTU@e1ٗ#AY\7d7Ȑ98{ҥ有S9VCQ%nƽח2dppj6,sMW5Zؑ1ET(tFc@@B1Fu$Pιa09tF#/X‹+x-p|HEhk4^l Ŷ-Cg 9Ὴ'o$ ?>?to_6[Ns Ƒ>=K' ,%nNiԫWƦׄhPTz74\sPj1S|K}މ]\W?bk2_\K/>!`wWqGMxP_|Hq%dž/1Hti̴$hn0q`WǾ!ԝYQ]4r7l <܅rw94JJ654C8.R[$$J붧A?tM_ľ%tk]ڽi>-ާjMI^dX9LMB|ii!>|$|kmk_h=]x7B [.:7qx@h\|sҬ"A k^\ƔV?'^o!cFZ-M#͜.9 M:޹q#;/%6%"D@z$|e.D6Y ujm[jꖷ9K(aJ*cHF7.XMMZhqk^MSk1x uziMR^Ѵ4īI|/s .ٳWRcqШX2tmSY-٬^bD#|\=w_ .5߈#AcۋgǞB&ndK}6E4 gP.Mිm7 5|+|N?kYҵGÏI.JRVjF79_Ж3)eͪ`cuj`SO*^0_:v^xhRiEp(K;ǿ~+vïu( YZKwX펩K'D.ﴸ^/CkNi4:x/?񿀼Q |I].gsy:~c,zO_j^6,z\.ͭ/%dWVesI'qv<٫VcӵA>4"}~,szT%׆nS:3Ekz1m ' s:1TeN)Ӽdx&ܭn6WѡRZ:sB8RO,G"փ]M 2h$'NIcʾ-/«&xu M`G2eYq$> soqg~/j վ~̿%Uy<1{/^t_!a㏈R nUHbvجe*Z1n:(v꒻mf{ʼp1raO4׽N/i֢~0>!^i!~? %5q{Zk6MF k+x> O^ZxI]nn#ont^푥$јf?Q_҂ʌ$*|z399';$׌8'Hž F3I#r*ξ/)ƝXF?i(j9cx]$ݹ)Ke4:XŶ8i]uサqRmܼ!O(wBX*R@qpÑx`TxK{Z7XK;9ͥխx8exW}#h^=n_Pf% 3 3qLF%W =bs J :>!$S]C"v+0ra (!W;#:51|F!b(S?BQ=')R C)6pajparFU!N#*SiNt^i7̗2e_Z5MK,ri7JsE%DVFQhϋ T &P y,Q9 @NxS__h>";\xNbBşxOqTt_ĶE1Yiioo|LÙČUY|1W]6+$r˧([G pTU,Ss竈Mj4ܓFۓ}"ZXw-99V,%^_uiIG~%xǾ(1(x~7 Ӿ,^kW6myocڟEF;b{Ko =Yc=O^.XKOUiq;yao|@yrc"tI| D_f~ ]j!oQ$?Dxƾ'owFUp{daif #ߑrYvp1 t:2bpVz* 8nZQ]IԄR+g3 G_RJ"PէRxl= 4G *nJ$߷8!+_'3qPO37rtG\#/+@;pmYlp#SI<i |S'vKAFYNv]i^a]rnkh~7n#)pW)εKiNJUKܥNU&҅?q[8l1cq'e(QnqsNOJpI?byomVA?e2̟ $ǫ$J۷ HI|ճijZK_ۗ ֚[}:D8ϣx-M-|5\"$oo@$pppzp MF@t23+YN*roYJ'&պwwrmܛ?Xy]2ק._c??x_ ?jxkd[ykⶳgm!f߈LZxSW&R4q[E}k+0pӰn!G͟8߳_SHu=?Ꮙ ^0|#᎟'|&t"x/kATWkEqg|p-W" jQx>>jG__8xF,^'lCf$2To(BH-T_/ϮhxYHWw8zqwU2#Xc$ HrpI}y> hNmL,!PVW 5^*jt'p8%;:ϲ]\>#2$*YvW8T*8jj5un2vl[|[GgZ+ &,%KJ躽x>+kxKXnܥgsjܰ:9F 6 N[kK[}ş,&ۘHeW[~v# 1?\rȆKv׵h,orx/cۣy{zrJl$犒ڊz[S|֮})a|3AJՅ%5VF5'8Ε} B#]`;&}fh?hnms_ZUH彼dN4xUkC{Zaw_=BVV:Do*dX0Sq|Y~!Wm¿ hk qk7PJUgi),2iV(plvbФBGhJRjNJj\}2ϤG)18.nuSԧOrtqr%J_VFL]K:Рw;*67@}7^ͤ*rgMOŐxS CZ|M*Lij6TcÞ*BB㩯$i3;2R^@ĩv͒FqЅ!N6|tYR08Cj<]Y$~ww-Hr'| _q9d6'f_Y~һJ*{WN_Y7PIfO#}2Ho {eB r)ֿ1fO׆BZEe𿁣!&DJۀ6`ʷ_ OڎU>p)uA2m'PK'dlDMλ*hpQi5o%w'*j^îIJӣԚɵ_\D4(5}nCex|La䘬q,6* r'*UR23NSGslCS\iFjO.:d37,)rN%8ԩ)(? e&\0Iu 9 S}O 3Z?Xi>5 &eo(F[/ȒÚ0gs0j&Ԃc <8 c 8*F0zo'Ȳ]gܭkʼmfiYpJ5ⰘiBtc4,*JJN:JGu?g<Ӈ> pKW2֣xj+$βDiqtNNkB/U}jN5/_4zO-FKD,u b ^)9Kk> mCOP<3U}ņ9R[CL~A N qIFc 7_?mpp(Lt (GP2] *m=UmOU?kgxm.e杵=8EW@g5\mȯ˒26bpH*>&Y6ƶcDž5T`?|20 'pYrbpӻJ8MnqIW*^w#~i4χv>Wψs<w9v9TczUն} TvGlq%k$Yp>ρ?08Pgc#qq$8x$am`htWI?_+Tixɯ{G0m{47-t.i,xȕ٣'#ɜ2EU̼IШ#`|}b6KLaoUiLkngvJT'9o|' ԍn?{OTyye,DKޥ_Nj1j->RWå$1jHʹ*| $jN7fE9"} s(FT1=Nk7פ[~>l.;_kZqGw)a{aC]ڍqg{c>ehYtB6V`FVj>eJxoh}j+nbO5%qJAUmK,;1=)ʜgH6Ѵ prx##rxAۿ7U֛g<)ᯆ>E2[E:̰Ep|=^V7 ,6髮~Cȥ\1y9TQsd^ANGxk##HVŐGHbkrygkcj^X7Rԍ~IEE)FQ\9uqzcxjN" eJE,N*e?h?j.Akxg²xu~xr{ۭOXŨ[Mg@}Hwp]-ι|BluONڥޗ˩Oaku,Guk^Swqswy4uw8WHR5NVK{溸 [散@#S$*R*9S`O|N81Y`rF(Ҏ6>zBPN20VRy{*t9Jsv.wptg,s*XZVTםGM=PO5ĉ2! !7chel`_DY:%A#2YA@7e |8ߺ~A</g+F|#4Gx#?{s[#7</_|/MkZ$oNiR1%qoԫByJӵIdC򌲧%r 'B^s=q_k-4ӎ]4OWYr8%fIm.ɤ}]|i$g?kY^[K}R)G#Oӕmh! md,)tX$] 1d |HwA<wm>0.?Bԥ{ήtyxbPRZA, ۂH<*mTQ@`OqǙfץJhNx!Q ZU̞/gF 3<-|y6eRӕKRT(µJQVX Œ#ᱟˊ|,N1]\`ks(݀Xg R=Sdסx I85 ZxtK'Pյ+ɒN(mk%b%$qT*s*ݺi_;5[x!*SR)/7(/ _/ڞXmYf7"X?Nxb(I %r#ȧpLB7᷉bވH 5F?eaui_o|YH.mo>SkH.exLL5қ h#%X33<=e?gZ*5-6G0$[+,QL"!Oʬ#toڴl^'yNg¤ٕ*x5Y;JrUbWۖR~|2>|*Ug:0A\ A'#9cKc dg/\Cc~h?3]{3MK<ѼWAw1kJxZH$G+nԩo~9[o|Yо-:~n7x ? ċ>/_K=6Խ֢<)%WrTzߋ-,/, 5 L}zF wW6WO<6d:XS(nު.㫿Eemx'JP5ITjw]./;8bpy?6qF<Kr ~fh'=s<|◐<S#-T2H88'S6N-Lif+iYݤm˻h?$xkQ-sPo?+5:x5gu@evC㟇¯ 61OxiSχWS)gY+*Ӗ{ʬ\+S֮YӖWQTs*כaMpOR($vGE')"ƷY[bXR|! ErRG>W̏IF'W̉d&L[m-KH9*]@PB(?_ -9B|;о&g>(|5EfO*öUG ֺjM5Ě38;1KBRۅ:,}k4!Rͫڝh{7O' Wql Ic+… cl l=r\WW nUyl%r;q˓֢/#5; "kih.pҫc1.9"vV6fy.V*p &v !w9iw JJĠCmmIU*u(ZYu[)nڹSY:8ԋJ9ArV:+BJp *ҩFIѷ^mt? xj?z޷I[]>?w3A:7NM!:uHXWzsguAXhVBY-4Lt$ifȲ.evk ]o*%V9՟?S"?0mex~ɩ(~tv'i N~ZEiPLVP'S轀/B>!/}{Lǯn:Gwmǃ~.weJxЬVNRT~x+C6!F6+.Ƞdq-9=-O!Wk2$ҧQI[ڪ.m$L^)ybih3Zh?ώ4]˅p 6km$IN6#8`FsDUxcMk:˩ P\VPZ'%ot]I袊#1Yz֬[K= #l1֡~ȹR1~py8qރOάyԃNHΝTꦽu["^Gfm諂 +4Y[`5$=s q:~vlbAI@F{]UnP("NN6pk# ?m`A6N9#~O =_4?qtcKG3 6H]&ݶmNc"4'A6vG͉`(;[%.7o]7`zPq=:|t˔Lwhդ|Rx(p 7NcvV2K+~88y;WtSOtJLt;{ KO9o,o-fmhxۿدW›['U٥?o_4 k < D˥7΁;Dž?ºxI]Uŕ9 ,I\[q`醈0 R`ry$`ӊb1z[ _BU(ji֣R5؈ENjF %:ܴ >+VpS+Jάh£RqJ\TTTP_W6lsȐd@YImL0| 1\gYS~iG-0 9~o RWn [p`g#ɿ*?]O<~.9/ ;KOZsuQi61OZN4!\)>!L.a5\¯VuH}bqW]>yEӊWsGVK&)nQti0ntᥕI6)5lNY}">(M6=fY\ZER.vGʞ>;|l5OS~Ρb|iE˧AP +\obTԼ[ y'3M$"Yb jѿ,~ߧō =q\$r\i 6xNLOxcMOS{Eg~ETiG_< [ЫJ'.p0 Up<zx?5zhM8xjM9œʲV4eI՞gZܹʥ B-BrHM+z5w=&EcgOIAk|G}:Xii dN. ?f?|'|3aw$s^\jjW"GE|c $%$眜B8rT2?;pݑn"N'4Ѣrz^Z9ig S `hNJu`p¬g[&v4iv<'F$0\r8\Ă^Ek}x_Z}ǧj/ @.9O9J|QPl\ZZ<֝i3\i?PR 9NNs m=>&$HO0V *sZtNJ*Bn8++ZͻS֌燨ғk=lifm4M6i,mg/W=&'Hu?u?1ƪ#[~Izn/<9̿cJDbVY|%KI zt1RJ 4M ۶rmv lY:2ug'*'9IJMajW/')j'ۖuJ ^8TI_ѳoFʏ ObV??me/\]|X*NBcDPY+i5/ ~̋B?$3]očhגYG鑏2-EHoo,(t5^GL>|W~"~ߵlj |2'Gmn>*[#s{E2=lmKkkX,y]8ؼ6jե_eJ O/b3/W:1Iaܒne`FXy4nHQFjJ~Jh(U\/Uƿ D\`K/$,%RԖ^{__Y k߄|<M_ƚjO<;淊wú݊Gh=D|7Z&nk’Z]n[[:0Z29-! btIpPK!PQ܅|@/͎I :y^;gQ`TMөMѩ8˙J.iQ )RSmKR5(&"R^?ūSiԴLO<#XmbQ58PGXVV* 8cCq; "kcv22:WU I!G,pUٷ:'ϱ~C0erOptWκG{4{w>n{ms_7/Ŀ ~(>k^G_ؼaψ>Ǐ+)[,2H\窌9lzpk c<>.I{8J$Sr5Ԛ(+ :qPt}^ғI$G(8.9`*7O?{ p* bi|ߊ߳r!VEov% [gƆp%f;\`429id$_O):o?-xACg?^gh>s׹״7]9tDiۋ5tաRH}qV33\Y Y͝|MQԌq8jQEF(u*GNhYuW(gdU:s:TMBSQ!9)nW_|__&HDb2|nC@*H0Xo7~X#<;(.h>ƛ?ق/AqOJ4h!o'Hf si_K-Mhpk*n y Ì܀O8kr3Y#KeO"v՜ppCkQUkQh*ً˲dR#Z䔩1dMvVC_#B/ I(VQx^Kx-RE(AN\<~U%`ˁw@2d`\ iT7Qx؜rrr9:*U'9ΥK9ԫ?i97|QT#}eQEI% PPTR c 4#QM%:96soYJ!Ls!U }?gTA^ 5  Gww7<6|?:ϣ3Zg#-ui{_6 H2 MGG5)RU$TW,X Ν5 Uj(\b?dmYlV*v8G$P`P H'f}E^H߳.$h4n~ ?>/5i<7%ÏxEtjYѵ[;끭>G[AyOT>(|8b>O-sWt ++5ΧMa=Ai]Eij[Wt#R2[9uVʴx8СZХRV8W)R#MQUK N:r\PRrtYCNRj<=VhKSc_C훆[Cc__>-iQe3໻CﵹP+>~U5*S(6S~.&=γOjjƥu-Ɋm{H1 wHg0B}1ChI9!y$`q+F7qxUlCܩ)*&)SFjPIҭ9*Mn FO APSwQNukpVrEZBF . Cp[rA\ďſ~m7~%ٵ}RN#fX/Jpn]jZmPYAq> 062AÁq VJasfv ?0+~pv `JQdR.i9Sd(;2Z5mm^]kXZ:V8ΝZU)THp )BJi??I{othncxXNucl$5[MSP6/U)B?ᬼ6y,ebH LdP%B8$1a[# zqJIR*1 $ x7VuX:*IrnR|Ҳpo[mc+h}&%R :c*8Q Trqm-O?? ~KfDx`8q3@.?|87 |CA }9lco@A$6︬B'v a 9` +?En}',^[/{v@Epϖ?g}"}K)P3 :} GtsQhזo ']ouC7#lL/~ѬN\n NI #L9AFV;Km#yϧ#'j ¸:ѭɰS*߰KW/9>+"μX^S*x 1$R/ӌ'Ťk|%gah- x-b x"PV8aD$` &ahf#ӥ5flc ۂC#'nZ,nݒ?0pI$?OVMB09#r)i4ӢV]?+֫ZINNrIʤ'6.isI7gԋ70ir6ǜ>w4LRqj)OɐF>ebFߐJ}X5ye̺q6U ~1-dW8y#r98$drkqZq^NIJ2|սrtӚk~+~:g&tY*ıţh> 2^cĩ,Fn%(c9_=1zv~?=\Xk_J*wO- Tmqݍ"Gz||Hn lZ ëhAq$g{uԼy 綺Լf+Ȯ,?$lKi' WwƗN[K +qxm.ae?/&o x۬\.kӴkm+CL2;NӬc[K+;;;T {[x {hc-a$E[e+ZP+u"N*qNV>'s(exl5YAWQ+…:sVq9JHQU9ےþZ\\:1݇ "Wؿ'IPn>E?OM@Z5xZo?4G%^rH@J{'[~"|59T&xM=[i^aUkqu夒$c/Zt=gVRi}SJt ދ{}J.Pa'# ~_Oaa7C1TkcZ4p!Z5TF a)sj3qhYL \ƞMuq0WSBKJsFDӚ\qe߉?:ih~,]=̗>5MFKBɬo$˧wK[FOQIR᜚:?Ԍ_St"L,m/˜U@^V>[#sF Hܕ,$8 `0PFI*Η׳JJ(TtʾΔ,)S !&%.+JӖWȕ.omE]C\ iG<*ڟcEhɩ%x;~ /xP\xkH veM}I{OZ/3aSLSH. B\Xqk[u)$xFX\yd:C!! :sc >Bmf;BGYx6@Ziwom =]$j/-}ٮg4ʣuyjR^+ӥ 2V9Q9¤*;'S2䙬3b0GFx*jpبR\ըTw:zZZU%zRQmKnDLry`$ qK=M2-_7P{Xh6iZGjZ<%_Yj$5-Þӵ-^Hh+_Bt7gXX'aFL'sC(*IoNL`2dhhco_ |c-[x⟃>& qZg$V>6qhypQs\ >~|MRWPum8P%Q_Zc{F ~ٶ/_NJ/~ և}/],<׆`yo?~3iQ0\ m~Č^_ݐiH1 'nK6H ~דT26 $$ēW^5 j1xKAVv֭$P֩j6~jf1"/$K'LV TViѣC+^J'N(SZtRI)j/uz~\jy='MJ 3(zA9A}xsNZ_<+}*@u8u]5[iluM'VӧXo+eFIepf8ٞqb5[_1XNSFj%MF+ӄROZ\+:4pج%ySR֩:S'OiW4%)FRn'EdpOX/F!96]f*]{NqB !ؖwմff8uO[gSچ=)_|!{ֳy|F KE<-ٸ<; iZ4]H|C2M;EӮu[ϞYTD?hc/4}GArѭEWۊTynJJ:?yve؜7djc3VRFZ5{{=S;x}KJMr/t|3{=Վψ*63nYjnzu߈BZO5M6KoPHy~eIt5}4LyZjWKVZ G{nyw ;9~-|`м?㯈Au|;k9GÿeӾ|>%o+þC;{8G/sraphP*Z8MnYI)x٪45t(AR~d\ fSJS !'J ȹiJN1RUIJPK? ~0 }0RYakvܒ ={ f6ߴOXٴ>+l`*sOEo{-i7W@8Fydb@ 䀑`~F`8\A?}oт)PdW!m݅ϞMܣĞUu 'ʱ90sK-9f>œ,N26j(7*rIx 1j8y>ZuZuNx')IG_V_+O?P 7ۋx\f7M>%,*$5X[ΛnA֑|k xTM= |_w1@T%ۀ@-ƿ1}˿5z&ywaqW]f֥OoyY:itB SQu jVxc/=W~:WNL~7|J'.&}#>7GG |*2*N1V׋Sa)4(SK79N5q(oJ &Lg*," C$'o &i<&GS.>S8o,.ӿF p{qO|AGo_|7o Jj~%nxoAӣv_ݖf%|G#&Wa18X|%JUU(a\|MZj**YeRv zRB#y֯-RQrNN}f/۲X}A$/G_i  $ If'?h&?M &׌} C~Ѿ.16qVϮuKOrevB?/]o !~ |K",W x\4+X$ݠ0H#u Crcϯrcq_H x̪+4c3'a N2WIa25h*S8>,b`Ӣe1!d_/w_ |AѮ\j1IkW?Ac> ~ k~ 5 xF2/mN)fk>;.ᑓFFe8aUW[߄g?c‘Ϣ^w>-6i>1"~џWY񯏼Me h-zgm,⺾յ]Ry!4}.SK ;u=\*a\#vry/0i\x{'g o:P ;xsCѬm$>c&9c62|vq a)AUR58ՔTESu*>HA9~_G cc᳼E|FmJyvIPxҍLdiSX|$d%[K/gџ~2[ ?gK{ bM;UN>&c4W> ƓixUT l&xV~av5ۖ_[^4V-0cV``vWx#[Y..&#PB(@GU$ ;kmnjwlQՎpN? ųԆW|,*:t鼶Y(SkZZyMʴUi'tC=Jɰ0XU P|v/kbjƝ8ԫ*8,%<5 NwRNf5EAg ԕ-Gy~:++H~Hq)J8"ko*})GO,`d-pN] |-O~:o~]>VdѼSkJR᭮T1HZ}ϪGw̷+ğ2= _J|E EizGc wM ̖=sz֟{h6ڮ<X*+bҌ!Exw:J [Z_ǧ7rO&:XJٛ)b_aj S/yMҐ}vZZ'5CJ `/I2+).N< x.1Fy!ڬdP# HѶ2TKMI,*0Y4EV˩ќέ(IÖ՚dϤ~نYυNs/h`qСW1Y^mn=Z.USN?#Ƕv6,76QZ\[Mk[%d y!&de5:8Cy8C _>Ŀ `ǃe>Iw#5ƛK_q=|UxM0Z +hPiVi_5z#n N㴦F6'1"09Y̨ӆ&;98Ÿ]7U ֯I-n33xaA?xw֥p}ɫb8aq!KO)rעմ4\ZJO) m8EUJ1R0 pQ!UrF3Ǯ2FwĜQ?aZ\Vcc匇mt$ AFӻm\`L/3`dg5S+59dI?&xXOw-zUZJR_sk|o'nZmin0 HLZÐM|lJ)\u 26?A?j-4?jꠝ/ڻŪ[seNxPc, #s!hv۹viRpd3%s׹kIJ daR=߂+k7xs-j-?=ST!-tSolu܃ mmn6ȳxZ,*^iiڝݥd㐩 n .I'hmQqݥFԋIid۲Ũ<4ԭ{E[NiܱJJnM5'_I)#GVUI3+hդPSw7O/+Tfajp} 8H%^HQFvcW"쾣įᏂ>+?iv7:,!›($4ʚTSi6m Flf9u-2o-K(#x~Լ7@-)障>l4}GZ-/Ks}{ )-5*եZm"-| n~ǩQ57SUw4#𽦫mH,-n jkInZ#|z7s֫{ #M33XZt6e! zL㱖/F7P:\8sI)>Cn33N2a!f86/`dJxEz\pb*ӮκԛR\,`08Ppp:c;~L~1*kmRV0 ͍Fَߗ0P'9)P'.~ 4G[k~-H񍽱 FP* qm"-m;kdC~S'+ ӭ> kyKA/:l $w:Kl(&^oMݴZU,%e~m`%B>Pc3+~-izßz\:7M[PЮ5 u]R8aմu==O{;8' AlU`%Bi(Kvp?.bq89M~7=B#7RUK㏊7kzf{OWg$F,eՓLOӛ_wG<t_okJnp^~ͧw@T]ȻKǦqީ3Op>;zN:jv:Ì gc9P&<.k;'))(?ա):v+iwe^[wTnf?5oѝ9!$~0r ,gTŒG"1V$_PMt_tG&Y#7&e*-ڄ.rAcڗ- K Y# "xji< 202"],`!rd a!kK[ӥUc(YU\O^m_ߒr?4^.c>2]PP D8'83Ϸr5'?&Xt|&s-6)5Z#H]G %tuq"VV#=ӌzW㍸jZJg;9-җ.ܭQMRʹRU(ӳvyLj k_9v(ב\[|55ZWV,6 𼫨YB_koI>*~ʿ H.LG M_ +O[_߇MfP#OMb:E{;]JV!\k7Z=51)qoq/aoُ:j3kթq:O N8ui3,*2RqU?$ԱoS3,Y#JIQ,4J.GE6uN>O6~G a'G')~/M{nτϋg:Q7s_̿ct|t~YMP-#oQ. { km^͖tN.3^Iam%ӑ_~q_9$j}ē? dX?$>bIo<6lmyvݐ 1<׃{v:9ॿDڟ<;P˯_߆`_hc_#FҵAo-൲N#w>qpg |_#ia[ʆiN,e:ᾳQFZnahT<=iBU77W;IGڹB*9# ?boxr|◄K۟N͎>c6 jdٍGNWSMO'7տ_%<i7(VywjS]CPYm[dU->64>| nӾ!񆌞m4 xCK^' J^5;3þ Ӵ\kWMBho; <S8| ֢[xᶓo g|cMu$sGg]sUICJdH!ds { %,'Qq>+82ɳ+qXzrÈb:rTwѕ?ZgU Ὅzua'N%R9Z5&U4M{p :zvة?cKW̵CbPyW>:XN]B]81a_v=:瑎s_Y'cxUۗ,^+z!q&׍>ҁoRZy"rR{C uBRJN-36vѽ5?oK,^3~b6,C6ryȯ!%_eVk?dH[)A呵}.UC_9_jom,5y}&(]zhWs7__S>16Ki{ M?iIj_RѢ[=Y;ٯ&;h$څw|hO߱>8[k[/1=io$t+ drk: gu8t8zYO;<b08yKrS5 %e W%]>|Q1/\%6QӋTqTftJ3RզNRjiI?u$P~.Co `0+7\/'>{sBq8qx$3 E}dYXY=aAT6v<%95N7H$c m9c1wk}TNt 7GDMk]7}VSOJO=cu auY2 u#f 9w h?T'Oǟ??Ÿ2h6ȣfKr&nOs$8Wc{\v615ewqVZ;9>O-s+5iJ2[ՖuQ\gQEx_ 6_h&qkQI_FYq{A#;'l+>mWg<7 .LԴ}FȮyŬd9Ƣ5qg~?[ Xx[|⏇>5Ӧ<-W= !_|!;^)׭#1Z^-Ѣ=߃4?WF;P =1& aѰs2za fNVs[Ki9QcbZ&?X,~aVQ(K<ӨO&0Hø]~~H_"]T[̷?t0r6X&r'ԁxJرu>Q1 Λf 3@p@O?GZ-忇|7<m]ꚦ\ehMn:}4PCBogO3#L˱ujx\QN5JX>g{ sk QKZSm(Fq);6Mt?=#D\WRN29FFW#m=BN UObxe+x7[C|^}Dxž =X1:ռ/r5OZNmmjPt*-R [a/'v_7M{:x(֛ TS^ԐB^+}AM[n>H@θ{xo'`sL>T F[֞":J ,t"rMKȿIsK)!qNt}i^jt.NO?jI +1⯍?~ @/ÿ|M#+&e徣"RJ5 Ko6⏍mw7mj >ĺŜciNng5d_N,o-tK9on&ԵmOUoڃ c9#6zܵd(USK0JgA,vmrKViP=.m}ꐌ:ZrumBO K V OG8ΥzJPR!ʢv=/gZէ)*':D8u $ 6 8o~?5όzCxW¿7ÿ cw~7VáߌuoZoQuNT|Ekj@F U@as7$x=*++F A=W  !Lׇ uѮ;sFQRi=RR?zQIY>irU'&~~ߊ^e,xwSmWB?4x~|E^noZFi(h-M⽂./,nc.ᶽqgy$kKc-H )*Ea(&)hSJS$Rvu}{Ú?&XY.au&5`>7‰IUVE|l3ь%85)SJU97'/p>)+Q̰BQ)BQmyuE'ca#Txh?m5h&o G^+e-:&K%|Sv,lxfgqFv{ Ǫ9asW)kxSSWl`EiKi$(@7 ׿nuMQ6Ֆ_~MJ0-{|JV+O!C,77,0Qb)V4Xz8|> F,=1B*)8F0\w¹u SS(IBҗ4r+޲{IH;H .@NK%0X|+ ܚϦrBjIsZ4i_ c;%Ϋ^,{O^!O_"e?kӮ7 x_wǁ>i M^Վc.5vRerW34^/;EӃHy-[hm<$l9 \' aΦ%-F75jլrMsx:0ZiVZ&~Cizi-wĿ5[]7sjf)m7AMz\<'?I1Dcy4ἳɳ)"`2+D.TrH#BG閖 Ш$ķAҴ$)#$A>z-*q(C٨'h-ƱbW)+Uio_i)H^r^.~(xJ?ǃ'>I! ]=֟K\iq/?4~]CZX><=z34;j<%mK/KÚդ7G<9&k8 敬iCCygs4slj`Fǹҫ0nݒЩ(ᑰhÝ3_m|CkZ[ jÜ7_,;$ydO'ZPl;:nu.:J7QNIERȼNpbcJUp&;V7wʶ?K?n"|(_:^!R'/crl<1Y{</q3bVQsG Sc TmW̗ 9:j;i$vO?ef/mGYYmh" k74uoqgj~jW'=KUϑ|GР}^xǢ(+[C4Q*/ȑC"!!6lkm,*E q1+G1*R(cHPV"K?&€8'c{v_C,ᠩ?y]SҵIkV)妽AR#ʸ1K|]J\0#ҋm鯀>oX ѵ*ǁ;ž.U4isA7rjWwI9z-qx7֑;㦣/<] 3B~n_oEh T <=-pPexny%H=98ɮc\w|Kh>%дOhz,v:ޑ}(J-l.V0r5µeX\1xөN6jrTvg]Ύ˅V5:ZǟgR euma%LCeܐ7cfN*x }m=G60~Z7lSJP䪪UN$msGxycV1S2i' 35 :<-tpݝ:Q:heK/Μb-8AF7{JRtT&nR}9i?>)WWɠWf^&\ 'KKT`bMH.?>>@? k |+|8+L0[x9rmFj xDl</ EͬoP7o 5+g^z 2j?MMH9fh5ƈHp?r;1; @$t;6|Aox~XAOoiiR][Y~qsVkw5jNOiiGqFm]I,O8` I-4y B`e ;u]JrR0N*朡:r[o FRm鮶ks Nob1W`qxIsѯFpgNjt+i0ޕ\O4首h|Kx<jFaxCxvkxĶm#7Hb߶N hbdž԰$r1 ݊d=UX2v/$Í`'*Ն^ ` #RAqn? baqTZr8ѭJ0nM)ҕ&ݕM?,K ŹfiapxDhӧJ1UʚYœ8E "B2@*O50ASl!?OK*HT s c͝d#0K8'x*FX %w*V~S9"?J8ؘ+ͪIկ_S^޹ /kv+ONI@ސYy~*|83$퉘gr0}>[Aik~=SKQ Vl,<KPQԼiId(#!k@<ۃ3 0\!#i+7m9  dF+ `C ..r(x9BJIIrjևwYAKp9.5Y.C?WJѡR|4NqOJ2~ xSφ7D<1>L4"I ]#_jz̗ڎ_ƥkWuss'~"*) Ѵcn:$Ywn xbr#wrUFs#v'ihR7=~TcJ# Tph*I[_e؜~acq1XV*q8'Vj*jNRIIiI9 [(|"ï< uXΈe PFF GxjWhkc T7 p~h$Ьquir$`%Y[*a-?r[HҤ:ӯ~xgOg+A4B6A |y[XoN@ ȩ+)>CJ *T֊:pKQH(9Q svxƯ5c]\\F0, pseN~Ϊ0pQb؞r3_~;[s\VbzdO-n݂`HY{lrZNK~I%,Y$oocCH<%('Is}%p+{ŅT % #86#?B>nNS99|Si@ Ƙ ٕP~c=$y _NRZ6Z5{/Gi+P­tO~}V;5Ug]Bֻu?x\][,. uۋ{WKR(XJnrvIrZjVKk^lv?aFZ8ᰔi{JTZ^Ӝ)75jU*Jۗ$m-Wr'evM%@lX3.Z#iGʧZ|^AU7x/loXz񱯴McEN᷻DVڄ1wL}kEybN.*k ՗7!= oxÚ&xoIx^v;Uhxb!"YRxJ' krVLm'O(ЊnU'Z(Eg8^}<'jX,R\E8P9QҞ"Xa 4Uim]?[j^_Z}).5_ ¾=dc45~ w&ui.ฺ*PpW, iB?fHO3on3)v9b9=1^޼t>#|3f?}^O ,)-t{D_ՂF|<(eЫj~xŹB,DJsXW5&* Ss⾧G(,5jҭԧUSR53$eRySǰ;QeRNP{然)RUݑ#A5moWeddBϸ1p:5xg< xSOR4M7Lյĺe|% h:X`w\17VwJә8aP0zl 7 2+ @qa<ĀE"Oٻ~8(8_ m 79~߷jbYo6FQX%Gy y5ue}_vה%MҊMshyRW;[KnVEf&G"08cIHRF0vxȦ0,p{'9X_C'q*c I0:FI`x dl:'ZO"2|8?>xvOӓqKR|E⟇x /.m-Oiwjf>":4slj *RƗa9Z:$I>.PFy4ӆbkqVn4RrM]!峕;W@##w;Kra@i,0q=1+ͭlnu[O0;9$}z>f5$qH'Hr(gHsxG/iG_Ѿ(lAᴺ}=cWYԴO9?Kcq R@Zԭ簏3Xi. 0JwCj4&P^{Ny2Yld +܎:,/_᫋r<w +w]i[Nv c@f݂pF1>aV=pQugoP);~ ?ڹaw`r+QMӬxf/:~Y*i:ja/b|#+5 ;(휽JME9O}%e:Ibr49\`Ar99vtV9nCdH%vw[ÿϟltWw O V |k^>V; 7yZUVs\?f?: ëpcRx'VjЫKJZJu!v5VINxjp-bMLaQiT^wX:r ɩ+.n#'kwiduyv;K-Y$JHnFX) y`@ ]e ԅ*UE^cnq)fH.TS~r5nrFFw3li 2 8 2 9'2k nPr~ Q7O_POzcmwsw7٠sÏi:gigZ[_][Z-n$~%Ot\𯍼P>MHxGVU׉hh^HoIcX1. IZU[FUӶ9Gk<ۅqYwZ'{4ZdޖM$y x, x Pēr㕾+]G rMq4A0%O+\I! K#97oM]>R  ($`FppF1/V|C{?lڌx:ڏV4kèњEf}hzi.E=moM6KQ׆ -1ye9 rSP)FSsTsiyJ0}?\+ ס:***ar̿ Ib Ƭ(Τ08VțgP)/яJ?g>"=گ|95φr -=|5.zƹd͕[-@ u_Hq0RᨐPW Cu F?~ /2OD6(Ƒ9L1U s9yI)'qvr1C_y"1U)<K Ԅ'*(NQNjӒ|H~pg<{^kB%1Yt:xu#Bb*{>WZIK\P }iˀF[Bȧ͈`W|2D)0R@r9$dWNUC|e^/0jD*2~f$\epX['a;<]}^fHj7xkWݗGO: j.<Z;7^ `6!` 2 pXHg??珵mG:2Z4{ Rwq8Zl;j7Ȗ>`o"9]X0rѳ>dԎy@a%:6Wq_[Y$Ih  I Elf ؊TW FUJJ .dQI$k< 0plj>"C,.!8ҦEeK',,3r!eV! SJMΚ82iH(VQnN#M=5{wcJӎ{1oAuuQfy:{˕}e]=-l (Q@%q~0GNnmuj OQS.Kk~'kxLmZAJ5/mN2+~\9眐N}3|@x_>KoGR;C[kRHMJwM؈Us@=:ɮs +b[ mtC9Ւu7Nь]G3L+Ӎ(ʶ?SNa;lBn ˕Nxa18.(ըIK4)(E^m}3 ~~'t'{1յm'|),ZE4߇$`u97u=^}}X1;r?Yp璠 pAee GboD(ĝ_WZ펅zuCv=լqO_?>/ߊ+|CďG@|FcMx[M6?aԵ߱Zy,Z$E I,ji Kx[^WVϱQ4hݭEXދFj֓XjznE=_Kgcu wk4L'e1999?Yb.aېC` QG4mjKI[3NtvRmZMFrq嗺Z5f/7l?f[ۯ~ο?.5.Kx+GkA<#&֗M-K˫.L~CݴZUޣ!Wkk+^eI!kkxn$R.Tbe?߷F> R doG ğXG(6{WVd14tUap]UU$JXI`p~ے֝Nbg7:+9PSg6$y_V8 ~4x*t*fq\Q_:*VVeʭcizCٟto|p`mKRt+]b^F >x HG[]3Þ7ikz^tZO^8=1{=/_x$!A@ۇ'_G?N:TZ+UII)Nu')Iv+ɨnU*PC BU:ThR*qcMB(B0QkдmE%x_ MkIsXҴ&wjWCgeg\\Q,_#'a>3끁9`!s_x!%Qr&^ydIowh:qد r(ftve#R_h_IcjKˆŇoӡI[M1$Ei?>3qwĘBbL6 O !Kaجvaը \U1Hjy?eh<*:֒I͵ե82PVZMX|AO2|?F Kvuybr Iݣb@eqs|bOV>x|I\xSmKij]jRZIH[Ī"I)y>vuG(4rJNQKZn#7PuppTjc0z>}Nzg$G*jʋ:ixiMoMʬM4ounӿhl߀~:?+]O:=߉ J񽆗?xSY<1 8!f33Ocl4$* qUy7Qһud)ӒQRi+?+ N $Ƹ*x7Is(Ӕ(Ŧ(kT~xC O_ 4vkomZƟEu|RB;3$𧏬<-Ə++T=MC;~/x#z?|! Lׅ|/YChtkTӴG8,>%I?c#*)*ZㆷMQJX)r߶/.O;D`z+z'Py{>:N"S樣ETQs pԨZcSV"UW,:5iIPU**QrJ32o~t+?_5~gaOkhsfec{/V=fmMFwk[O3ox xx(,=|5̱(eF1,&KʜCéW1|6RRpj*ժJ4Qu*TTڅ RQWt馪ʓ_O_ۗp}k S"moO>D;)լk; ˦8$ [T,RqIJQR斮I:pvo4=K+AT $fҝi]py㛉/ΜҀRA *8doWɁR_!b qOʼn v0c|.;7'/IRH8!rqÚSwv(֭" -ݺ6 $:*M2 k9ʯf4/{`oqvZg(%d kc\b2_jj4e_.|>UgNuQ:1s5T N*RGz&WFwbz՟ xľƥm[:.~PiJkK=b.qIAuC9ef?}1b[YWh\[m)SۃեN,q]H+s*uiB29˟/K/tR. hTkrJ)&*{ ֧xթK8QS>gi Ӵ+1+]]OP?CCCf!Y˒<)hq] E9]/2+FS_U)&G{ZnT'ZP(sQSTh+N(X`H# #pH`@kЈ3ە8OGkV q%Ndc884%&Qx'rB|حii" y)di$d@`F O?U)' -ﬓXl{ZJ2./oNhINIJ¸det/Ub:cs1}2%[ob8i:',մx2GXZ εIKhoӵt}Ml7?nQ_2bƾJ b]jpSx xʑTa>g)B+%Y=8WoRPvSʕ6\U$ Tr +xєHpI=g"yoDo+ߌdlÌʖ  U~ʶZFj+Ò3xPx'YGi^8i׉4TvN5Kf.qK)bvg_ދ;+(o2xJ[2[^iZmS]A ZK[xjpqaJq:'I5rNShVPi.uM y\TSE1vcZ#3IϊdCOʷ3O!_xE|%^"hra ws:|Ow~*xMۗԼ%֑t׺jrCZZ!^-gǤWWމS_4sණ92K*Z luioNOo6-]-RJRVY?IWBvB+*@'$d[nAr~ pC)^WRb1¶7^8zqC Fsԭ^1JxR? 𞈚\jc%(xDWq1$8;?NZ ~[u}m:7+mPƍe\#m T0wda@ pIY+W>1i}o3#> Wޟs{ϏL67$E?x"Zuoc(Bqb\:(I5J/Y)SOݒn~Ü KAi)JIik}ya \`!zg|'|I|~*4?v`MuxKZăDKOpΝ.1ɘiE#_ W^otk3"ыCcVs%ΏM7G-$Em-ʬCFG9e]']N$c1q+3fN2aկ_pW:𫅯jpsHIu dHUx,RjaMS:ϷW|r QE >)xS+o/}#z׉KṴ/7=cwoq=^? TAGoof>PtOC Zj2B~lcWl>#?tk۝:{xH(uaL+)༴wZ5/kgx֣?Sƙx]UWҴռI}j z&XpI ">g33 8<qeXy+$غ|jg<;a&:s_akah`i8rK Tq JK1e(fϨ8c[ Fh.qm鴃U)$ITPv ,rW :=h)GoWzÿ~][omHj6U#վ0JZ¯i3[MOZcX&jq~VSrV1PJ2Z<<+WmN4ن |f*(BU"uVWUVm>_ A?nt{u=zI#dxC ULgSb-g8Т}2j[eC;<QF\Q~xP~!xLߌ[Sύ6V*^mki$wXg:ki4+'FR[JʺH58 ( xt{/]n&ŞP'XgEe'erzn=1X<)#Wm:m?_~|A _|KqxO~ 'miWWw661G=յS[ʡAqn@ i#7-jIVUSu$xn?ye()%YO9[&J9 uV*e 7+N+s;|/Ix%y{ᯉVu|%IyM!]2[h͖ILof]߰ or+, P,"iei]5 [V.5mwW$Pkdkb#/ot[J nggfK{{xYd5bBk.?,qUT3`9cN b2UU*QbjRs*ʲ>X[ )Nu#t:իr.gv{gNwCYPcᏅ|MMumeCXY7/q[JR0 ٳgZ~ϟ(+A D9 $W\xwmWa W~$C?h/Òᤓ|m?ψ}eςGxWׅ]cUCm|=sV$?fOV+{->; xc&4(!6qhJF<%eBTWjJӌRʥU-)Ҥ: KOa,ԍyaeZjTN<]oae@`gi__="Xm]>ӣRwMq{o fToP1P| n](=_aƣoa{kj:joxg״#v֓ ߄]h$ӮXjLZf͝Ԑw᷏۫d/_8,D&W~ kPA }[ோ5K΅4WvP?|.tx^m>-1X\1js RTN%R ݭgwԲ&/O˒H#N. Z{pS菴خ A%œ9= _O v&*7 <9m_4(tspې;q$d׍~_=ş 7-WzLj>xI?S-/ 0/<H+iZNwiXxil ygbY5 [ ,*:5.lb,N0~VqPR".ZMl%.x%~\c_e|MY3)L} -0uR]6ʛg -I6W7!X1]Z_d|m,71X궺Fi/,mY >0񀐫|$>&BTnI0z}&ֶO)K2J(AʐA x~̾{*|ҹ 0X\$B<5\}\O,kT1m{ZIՔ)✝.ۑGɅ?)T8$28$sU|ZJ3@ܿ'?'-ek_RWt i>%ywumkEuF.X>{,䊉%Fauq<9S_=#/ OO}(+SK15͕q*8:)OWV7<5CRjbN\]:7?C+9<'&tZM>WnWi.Uk |΁>sl9<?LĖ}3cP+Ǎ~0kZcA^]jRz5Fv; yWOϋ7m3V񞋯iOĺ )'<7=J>BSLf:yޱ{icB%mՔa*-B;?E|G0_V/GGδ(օ)ʜ9*1H˗F/%euL0dy7 p7oq8%Z*1U/ /Fi7 ~οQ^#/.\]`g]>#tj8/ zdpbL GךOY7)94%|3ˈx1ysbqxeYWRrRZQI/< ߇@ UZ:I;yEʩ5#ĭ J8t˕ }A*%pK3J7' ੯nNnIhLzwҿ?7Lt%[U}O{:a؜Z_Rml}_u)L@G ( (!r$rr2z0}ߏW?Q5VҁCkgio\6d W bg0s'~ DZAC.;9#veՏ~t;c]u)PWG%'{muky~qlj!hGM#CQeҮJLQ0 2l7P~qծ/L>dEݏb# H8>>tGdB #ǎύ5_7JF6G7#W88שjv6uكůwߝDp k'AAg`Hͻ쬭;[;l}T32c04F 6>D^[h1? xBY5kv{Cz6jQMyk^bROu_~i߉h6V "ޕᄲ]=&q W|O5ƫ?`2ՍEV(Þ( ^֭^Zk޿,c;R+WMj8<$1ʕ 90ӍlU~nQthAg nwoB>8wZ6f jMu<2˩֙6m~[瑞&H3O>|7<2>] еz^6ҼC$ekC ƣvq%٪PG3B7AqtJUw#wGNsQ߳9u(S vÏ `-` 5' <* 68 XypF?UR(t|^):ھir'Ç⬫ .hbs$4^ %8\܎o]%I̯?Ǎ3Ɲ_P+ %Ӡ"Xd9/c9XC-?_/k xg|}3s[Z,>Y5ӥj:j(hf$QBZDZٽ!dS€)J#6By++ ʣ2b| ԅ_i<Ꮔ8 Px1^#Q<偫bQs 5jP8Ύ9D(RaQ GW aXYҭ9TTpӥJJs~4)S[wm as8b*`1uqӦ4iR,***cZ:'/hԡy/ԘbY|Q\6\uma\VuXk(F $Eu`x!=ܑ w*pq swBF3׏\e%%f_qxŮNJxok>f+wu=g3./>v^el<z,)Ś6 ~2{ƻ8bU;-[|;F~{K۵Cnd́<ʹ88b3s1vXΪwņGONF,N.J3*9o^zIۡ2w|)98̰qG{fiiJ[E3./?K7j,Gڵ/~>|dҾ6R@|V^Sסh.?iC@̥m'Ķ.ݻ$MWn,Ctl d9`UHye 䁀| 7=r,+"צW:k>YZK^}GA((hWQ]ju⽛:vk|_~"Ϗߴg{|D .;gyav0ꭩJLeF{|37ý?W>btYvlYN \ߥԊH5e9أV8AQxh A5Ys'<F8'`Ppsr{GS.1vi+E4y815j&i.Pӡڣsܻ#`#vN8B!: nn8'*670sO880ya9=c w]s%AF>QVd+#\8xBD`mbA+OzZ'yP:a}m`Qf5NDi.5/|7oeWk%wgxqˠQ 8<=vQt*F6v%Fn$'s+NVn}qi78W|=jexUW~,Db]g'5!o_ 1HWA#2\G'qCلOk^?.Yy1ұn>H@S,y`)cp1\/PIy5.( t FpY~w9XJ҆zpzJn{"xuZ7/+~#_+yDY> ~Ϻ'A=G'h7,6>FTfUP>)|涽oߴmyh>m:Zi·DWԴ^Nsk4lp: ;,/N@ A'`Oά@ `tm)&M=W[NϥWfԢiMlMc[|~aͯ]_|?tߊ t[R:xw,|xYퟤE:G-~(f_?hOuO)if@ 7<9R9Xs `F6qR:|9P9ƮoѥU%gQ]*VTcQNmqsIPqPKd-44Opd:i>3xTYjFn$A{y-Τ5hǟϡ|'~.C jF fNi*h_r&Ha gqF0{E`Y~e YPOU'g &N4-x\,g/JnoEn*q䫙WqݧRӺ."b<__~x32)kwF3mFVxnpVOuO< }%PY|J/jDefPNHrp>s5\HY2I S)psBr22XawpON*rR$VRն9Izɶw~-lE|LjVڍJ6kdKQFJ @YI 6g .gdHVđ,A0N ڤ+aѭ$2fnAScgΎ4S:G|k˯2(𿂼/oj w1=ծ.?M> $Gqzzxzm[ZPEӏ;iӫRW!N-sԫ/}? 0|: qGٍ]JX9sWb3ᰘ,5<|'fE7彏uxhfnr4'0|Txl|%ߋ/V]txEaUvGRiRC{2nbLG/./7Lww^b^.es,/^\fb51"5kNS31 ҝC@ WK8Xf+tv ):qXJe:P[2/gc~XP˰,t)a> yjS1&!# 0~=G5ڟk/k6k?w [\/f]2m ceGėRZ$XL-4nӼ!xAjپm#4d6Mn4K)b׆LV7hiZKI~8[6ۋV a#~cMmJq48,#vXn'h pI9YT|M*aOhS0֍:󜪸<8խP T#xEITcӓGl*Q ? *rn%9^)NP'o&=]]{HlέjhmWRO&-hwA(a#ᇌ_!Goh$H/$W쩓 RK]T3Wew~c&ŀ^]qotk/]/i[Glt]l+hn'u?)YgCfiTaO<$qS:^eW8U*u씢߽^+&G3ɱ˅|plP4h?`8utFua{E9SXPp$Lg0%wlaTӎA ;vΊX' q->\.3+hũ3_x^-eXyCAa֧h!|W}nIEӭa.mۛ61EÂv]Å 9~Rx\V;U(Z5Zq(ɩI5dԺ᷉?mE¹/&0Чם*iOU)4FMOxuvd|J>pB*}|P|H <u{n/xi ;uQUG**͸*h ʀU]@7~,q>٦*r^b1fu8m9qGL7A՟ocZu5~GM:<[^aEPEPцHnrI=;n#xo%K+clp@ gG1dbLw'Ӄ}~u~S?LdMekyWڢi3Bxf\ӌFqJ6n֨Ĩ)p3Ɍ/g(y5v쭵GJ$$/ l/7;ͻ|%rn@=x7goPiv0~3$1A6X-J,Jv _@~+D#>&s+ P[9 erKgm(E/wދv]s8j:n^Q~>s&v|[1$QʞOff2C֟? hiSC!Ϫ^D8n:{St)pn'kK,Q$ G@U~34?n-68d۴-+Ɨ$ Go<gƲ+!ybTY+K8GxhOqpvpm G[g_ SMeT\RQbg'OI5xǙo>+k>~k>+xw᷇u!g 6yt k6n/#yz_?<3~;wo i?H \ˬzŤ龚kK4KuRoK{? +ᖻ?I}w⟈>$6Ek=k0E 5O"Zi%i&^o?$j -ur|05Vcpiq]>󢶹Yo{?ifaE:YS6x^z/ aMC[ J<4NJ_c,ïr<[,<唾xڏRXLt1βaP+[XP>48F/E xux㶵q/N|YxBhZߑ Ҷ\pٖ^]j-n=sxm~(iÙ5}]ZٛKNuzouV-#+/~Їg?8iI׺;_kz>%Ԯb.#}I|6Bi,w2]M%E?[¶爦5MbRﵽcQcweg`څ叇gLs_=WY% rlZXG1aaCO !FXJX8NOÖ?Øy&+B[Jyuj7.2 uqxJuqխZ<4i}Zjp(͝Զܶ͝wqKĶvҘ`= 3#->5H',=S(AQZm"O)Y1ɍ_:l!vSdPTd`UQUFOďى$7RkF4;/BO-dbmGxNxc!i%m%+>g&e'%F29pyRf'-y>^tIǞTJ!ʿJo|9L3kq7Fvs>(o_k &Lv~ ֧'-o:<[~A4K_֧g}m;G7ݨ] iH"b`H\38>ihefwo?4Ͳ'-ŏx|/4/ ?ӭ Px^o͸G'[*^z*jTKMFgV,RmN/.hWF~5‹['4w r7T1P~r7`6?1{x-"Ҝg&Tc2'"Tld *FR]lȮmq@JO↏ۣ^jSxOwĽ'Lo6s-&x _xoϞI.%{u߅Zxc%jlOObU%qh}֯/*Dj % 'XIes*nPV(jC;zk4NQN/?|X̚bEeԥ짫VRhJW$iGm$>xs>1l> *ѭAv7/u- ^MIi'~!K3Iյc'/(vN>hVF V^.=bHb>xGmK-@d3{+i?O?|OgC_hzïsΫuk࿄?o5_ h!O5n5sSܞs~qsU_GK 1/~"%sUiQRIaFणRi'Ç7#4*ӅLCX<%:pµ^NV5RԡJT?ࢬSgxrc_ڛIJy\`я7 2[0|?М)S89$ ` P*faYFI ;Omç<"<<5vN߳ !uG7;_ #tjۑv"cP|HXt ?ƚ:ǃk4~iky9K),AR6dg :_6[?|GѴ_}ocZ_zÿw&3-kvOGx:J+3Vodz? ~"}i o."tZJba}uc3aY^&:X;4% =xM]U\E|qt/J迲]k#?oiWzׄ%jv#s- ,~x:&5#_`ӼIZ .u[`&,ju.>%kݲK%j}VgTvO௅Ï~<ozg|#} ;]gi _twrOy4E &F6)֝Le7[ (R'^jWS[SB %|8Vx*u&T%V|M8N*XzmSB= |ݴrOK\h=:XrOٖ`_Xa*Xg(sX1eO02v;Frv|BpQi]:奍4\Ekoi,pĈ9/"Hk)qWרxJ'$JKӒvBu(d&칦K*ҧHΜS¹Nii-uI4!:@;J__ԝ CvRdЉ7nIG0ο.2`+ B߃+^ǺB.Þ3뼺}ܶ麍u5|5kVWnH&sܬee$W7 c^?v0|]{ -¿W7l}|3/u^\$}cM$iߓq^:?i`ѭR4 ,puN\Z ;SNRg~d18̒LWqIzy-rJYBMKZ<^qKRF\A8vp`7L#NJohYc/kmA>I/"H$G97+zo$m`ec~pXl(mi 3_"|Wc7?/D̒xkǟuAЃ-G5ҡvd iz>IJQ8x:ߩE&ߖ[ѡ[xzΔ\P*1ՂPriɪ1MM5$/3ڋ$ %<2v; =CX4JԵ]cPt>)..=F;K KhX,a6KEWgԢ"RYI ;:i:ΧwH{6YRgm&CLxdEB쮫4H̤+JYΔ%^R *p)uӃUjJiҪwr)U|OTjcja}\Lb%%F!ц"ZWS*tjJ/mV[qk_O]dE?n/w%Ÿg ž ;Þ//AWi:L1ˣ1gȊ\0?|yWysW Si4kĿ-ۆG)&Ѻ8'8oobdV1$;@h$?NI`pRRx ;sFŴ)+.o4tqkK74~€~[f `?qeNN>9RFqڥa9xk; x2HSJ ec?k20)+_C͑HK <RNI cc]זtO~7eQIK^oOcOONϻ3N{&OF (Š(XFH Q_+^V6Vz80+|Hw`:'T:`?$qWW)y}w항t3KMEffR3?cw4ŘXcQ⾃E%e*UN)E웵_*~~-X~jYFՔV|bKs3s 8e]M=Dvm8a2I-cPHMF}eKKzݧfkMLzRܸmGݦgxğ~cGf<=Ÿ~Z\Kocosk^ټy Z^Ca=ܑk-:W2Zkm/~VI#<+}o~ ҮaJ֬HsP,rNP7~d H9#> WO6j+_ 3!?Zu5"oxF,R KbkX#EHE}W+Q.eN&F(bkЯrJj3UY{\=J)7Pbpaԩ ]|4?9Qqo sx#&ѯY>*p[(hoȳIX sn&4^p+aN|N; q4UJ8{J)x,O=i5' R\WtyTnnۦU`7bFA襎sgoNIU+ޤtjo'_|LӠUo#w:jZl/,l Pcr~iO_[G?eB7}O⟌?"[giO<K`Ng?:ni= fZE%|;tyKAq_קS   F%ÿ.7> Tvf%5TKWDD(҂Sy ʠUb Ď$!@*0WP?bV ~W!\@*OOUÜ>\MOaL\.p8|= tEwRI'Y8G F4U.wIɩNJSyͷ3VK*9(aHȕ:c8<W*y9$ O<{q1Ki63 =p2:y9:K][+v^gvf{]ު]J5?k#'}'OY !FoZMyi0 'vRUڰ(+ |$2'CcT*GЙp uK=}`A6H͜i3.EE-B.pZ)օ8Xw`6^W-=]!۶?fȽSh77{hd߿|hFM4Vo޺imVNF*R*UgpTc7(H uq^_xb*&'>pqWy#®2X7j0רVT?p*R*|]GGR\RS6n^^ST6QdI[e׿?:u|3%sd/M<2omn|:k2i'ڼG\V. 8Ϛ rq׹hV,S]c.F99f$ gŵUVjT(! mg3ȸ߄հfts,.eV:s9ף*zܔgFH_Ů Դ+MVnu='XNԬPBKi}gsͬf_2)Pb 曩XԵ_Ūj:ķww=̷W31/qq4M#29bsC`/?t]3=^6\-Yiz^b[PuJ K8XD]kis~t7QYK TWM=%d W̎ɽPBX Sn\aG, Wxcx*b+u~SO ,N":*B*EDlE* BpG7_XxxKŒq13m_ZjYAn_i9ynR4i_V؊zz>7v{Ul >YzWZG/onnvCn&{a"D f'%OMxz? J!W v4~??| >?jtУ]G q|vPյ7Sn%XggV w4L \`lgiW¦9V8f2 +Su`r22r˺֘4J qn`%02HzfjWJ~4)M:f') :Z4e~ >({S7=|޾kyQQJ*1c)r1Q_OhhNZL` B6<_GPWT ӣ=y|u[G=> /,1  Οszt; ^ cU9;|}g>_Zݖ_]k?d\VЍ:z~--|](( >ھ:,6it_Uh>ƺZܰ8/o8V7g_Mg7^HDv&yk.yZfg5*(JITQv+[k38T|7PfYI]ӧ^;MK)R}ϋmtg,>$p0ЬHu`{k>!ĺEm䑐ź$N=15_&; 33 #<8|-i'@de|a4j8뎧;7֩C6Ϳ-ݰu鋂tI;y(ݾ&FXFЄcl6FFpyj2(?ӟ+?zG}m摡hzhڏaC +X\RN e\]oўmR0u9RJt8dS?Vu\ xFO KUucCTwv YǼGP|{%qu!33U ` q9?ZOO0KߵĭS_L|9Egįk 9k tSƺp #Q<[kwj8ZoZ5Hk^%C/1xLF!ա@ϳ?ú]Cyb<;{,ߋ2FnN5%Ya4e:j5*ЅZը# {Jx\KAIJ4NqTWbp8~H%uo{"Y&:cU e NŽwgnaQo?/!Ğ tI;.tc ~J=흵ŴNޮGI1N+'Ğ-F ~+]mw_|SW~T * $ ޝ6 {W'hbWu-*D?}Q\vٔԭ)GVO QK ፤ rSkÖIO~__VyVoң8rl<ޓZ^콍NOટN*߃%O➕$ 2`|) %t/ vRm7Ih-$Of//s≾|,OÙFu! `i^obJ[I^IqpOkow ?cmmo nBc[ 8,DJpJKT~0\iV:ſeֿǣwįjz,\ DUyʭfխON(J:?׮gbgMQUS*TlC+'q5H s$I q~Gm?|ۋR_~ϟ/u_+WZ|?3MgE}{Mgu+9F˿ |>tOvYi~G~$j\DUȘ 3n􏇾 ߂tRֱ~Kz7._peV' ˜jsغBWeRjs:4(aԥVU"yyT VkTrN]m҄m7N*hWY7ýsW?$$o<}<7kV4ЯGOm-KKyh,wT!1ʌ2UUYeHn)c[kiі{kYwCuo23ֳ,NF"wBf__E習&🁮ogr5/ Y3..n2ϘRUi?m{Sm3Vmo[ctmKJ}2[5;&*;k[Id~ Ge?৺+Ok_|3kwz|sAcq&O74p,ui /w?hlTE_ X/ti&pYH<f;ʯXճ];Ew#j޶1m$k3 Ɍj೑.1Ǟ'nEK8krLKF',&'R'*Wn*b/j TӢG(B)Kܯ<ζ#1RE?eZjPTrVW;&aW~TS[I|%'r7WBMy5H~(uim;ZA61$ibY pƠg8S+3;`f/Jy~|>| w:^&pR\^_R{jQ;ى ^߁ ` Hw?e~ϴ?ooŵqÞ'e&[H/:fW⸃:8C<$)BN_/1aӜK'%0pOQpR|:tXū(b6M/g=d}ga^_+H񖟪|;Q^[ͧx[<9|q<9qxᶑk:{hthNh LO-/L4 .ޑNJ,YZnbR%,It? h~t xwD<=,t}@,t=HHK=3H-v"y2ыi## ]B0'8<2̺YMC NTrZ')sT^aN27ʩœ)ьhӧ9{J?3)q6&ha4\{4iݭ6x;xZ#/-y'Uߋ4TW<i7sO5+ SGΘ733࢞?~ U=ZmC#_5;-ǎ?g?/kx$ZNG\3gŞLQ>i6P61M7cb|619/><е񿄵BR𿋴-3z7uk|@ '6xX0 9Wy%,*FR Q+J[j/Ipc^uaE*JSBJqWD*q{m,sã`ņv0b}0 G>.c?؋;jOj:֣cZNjenjX7,}3o4o@-'No#Sd<__7N Fc/Uv%#ưLc4_~' Ҙ<3a J [Cpnn#جhQUcU)b0ج}F*!ZrTr5^= >gqC*RXݟ# [%wM?ϭSex< _)˥Hoo$½;RIgquo6kxַm[j>#𾯮-G K9-χ~GׂtOx;)iZaXrpJ,k>o2\E3⶧_f!wzU- $)$'$FzΣ`xia.Z}3I>@ xŖ|qO,h^(棢~&,~+|d/~1LBw%k%4@|,V&(B4+3ɐYn-&~W',I' W=Ԕ}b j՝VӊS&G9ũ#!|<ˎxj0lOK.||wEO&zþ.=Ǎt˄:".Om:xt"mm@-O6~'ċ=Z⎕GV ~ּ.9]񗏴mf^Hf6˦i}Ҭ#%Jhޅe>M8xP]",K#V7Y&o 㳜~u+f4XjX\3<8E*Fl,ғX-*xRd8J8z~. UXPQePZU] DVY]~|!dW xľ N|M UKkk˟oS6IɥYg5=cRsqq+;(&uwcxV& nZ[9nWI5 T~ҟa;Q y^ ݍx<I܏xU?jF@_ m/uOC@X#9@Ϯz*ck8>e,[ZuV 'Rx|ǒ3̰؊dҏ/*q i/q*!&V4_ fk }Xe7o٧Z[H>|36/3mj^N6Zi7Vs鷖L/?_W[yOjho//m//N8N/&nිFjՑ?o!P,K?2/8@X3^<z^T,ڟï:'ٵ@  Z.ͩéiBPo,"ś.[LYhSf\T'0ZUqUiQZy&*18`++Bxbq^;䙮mS[-x qPb _<XcP*4㉭N0'ʧML# gж9D<]gOE*\I`ΪE"M,Tt]#ZW,akCA_kf[UN *iڀ0~%:[}ոVS.p3I z0ww%{/TJ:jQգRjU"ESJR՞wqgdYEsl|0cjLM*aXjz5)Յ9tRJq#(TRZ?HP%;х, w~gLMItI%3VʡTFK6-O8W"#F+m4Ly+LV˧ۇOWbe:Vn>FH:~--|QEQEW_Nw/M!DTF j6b۽0Y~?j[/tbjfgL$Gމn^ݗ'p4E򦱌 ˳! aʅR 1~j8,iޜuzGZ"2QN*\ӵtO߳vbN}?gͶuOes Xc{Z3M#AZF8n!eֵ+Ffwy$bw;H186EuKi,'ƂO~_]U4|D\c t\=YNwqNxk~LRS[F*iY%tסJNy];!kF->em%vmIǿ<=LJ|_~]RYa[QHE:|W"ggƿ?k/>5u ᗊ<#|y|?<:}jJjsXI$vf)ҵH {|_?<=+qZj:>zΖƓ[]Anuh.#G{]BVA7)\ws~_u|hŝ65SaR)| ̰|hOXg ,: = X?Sq,L*7:48҄iw[쌒D URGuNÿaZH[?G_>4Mi |0*gF-H$Gdi;a {;O=q;_PX5'%%&/hk t=T!%(ipIJ8jҴR6).wvvp+u3\e 6[&Rkb!߶ɦ~ :.mԮԥV1mجQGW/S~[x'Cnпmoz?_<{~}oQG +Cׇ5ok(ѬtxHtk= ķ$u%E[m7Kmko|FL =.gIk9^]iE۬>=W\-tA 2[eѭ_.pTN(wV+HitW#O &3ewonvX>͚m+-K^BO?>C _S.pX|& S  w׼[w⧏]Hv~Z׃ ѢEs57W>#s KY?uо7'Hψ6Z'†ZE-i4[i/$΄.P#\C$z-+JMCZVj^(_ i~+KB[UᾺD\M'l5Cq\C9> ~S~ϊqƿ ?>ƭ&>d|/'>\&Ik˳a՗b3ӫWXOPfK 3 w3|JU8\%Mz-SF*νa/R㱸pQjŒԒi~DH囡COs5v"̀ym@NH8ם[%6?*#^7\b26퀩V==k 'i@ -Cc8$ϒ~hfms$O]gyl۾wIOu͗`u䒧wz}8"a oa;+p0Tr{2+ϼ[ |5yb\v^M<xio;t6o{Lu[|;_=x_wZѼI}& P%rEwSԡRz3JTF mΕzNtBN2q(ΝHR чX̳Sq,U+st$q9֧:j/eZ,{P'-qGb}I| 0b6$|Qݑk> ;H]̪NzK(0-xZe?S/_}u"_(xU|kFz=|]I5} %jlx8L%i(AWbgJ:&)Rzj4T{<_q-<|eiRYXa:u!M2WUOk=ܶV1`>7 h2-|#$CcI9lmGKϫ~~.cgh^ɦߦ$yloQ^HIl88cx8s=g fŧhV_zuJj>.*u#5tU5<>J'Y#R-Y#9FQt֋j;)r54~ߵ~_|T~.uM7:x|?4mUkK H`Wߊ_~xCt/'_Z׌<h |9}_czꇊn%K-̵W}xž|3'iT|9ln G&ԼGi o%՗o߉c<@Q9|i^sĸqeY#[ >]yn,neYlk`pgVhNhԡK.퐡ݏ ˃aU$lX8# Iܧ$$JJA*k5|`+O~-x/O~ px{"J&jik{_hxk²=ajS|xIڷ'[׈ixcds7*m׃|muwt[ðƚf#j7V~UJ+G.u:oOPᡌ.Xqμe*pWR!W0?KoxU<)ey#r3p[Cary̨aㆎY֟E/;i8f,^9A|9y,w1v0*NA[nrw -W㯉5_d7xH x)uSuAa+>ּEkiVmu H?l߱?Oj/׆<7׿,l@BkTC)еYC*Ǥ\[P\^1VqYN# ˨D'O Fz91Ue^(*0:Д#VhS qNM\+şYq!Jkeh->}:)r2zӷs((i"[ iH\iZKpQ0b8P8rFA+GE1qqd vrC}lYcS[5ohɨ2w#^qTrkV;%ݣ^џ$ 9OϦy]06jh > xɡ|*ӧxbWsL'|7=skx,~/ĚWLcx@n-. {kgr$l;?u奮6;6 Ͱ. #9T ȞLRA,K?MK(7tǿ xw~2|o$$h׼;hhWg8:1ᇌ 5OVNJx-j5:QyQ,! f/ UVjqNTab'FyJ9qyR0_)ň6眀sQC {䎭&9]'.K*٫Ï!9-,#`@PON5<63?f)yJ!Wx澽q 6u2ә$m|Vmnxsw{FVW^_ن F Fw,@qKd8ctt?) ;buvc'O8di=95c C1O8i/SmcܥqM_Ij/og+&W0һݎ k>Ѵ˨H\<79*0@o2<xվ~w|_e"~ 6JoZQ4;-nFK?tXM`ql_ψo+r-G_ 1?v$is^+mX";Afo{Ѽ:G èf ;S-Zii縚Kۉn/.yfw9Z|>qRIVKߍ<6XؙE*ձBm5 :N\1i.3؏ᅏ?/_ O4_'n9_~)|Q͕_xO +\x[J+AIxSo<yp@V ے˼u< 8k n_ۯYg$32i_읥ۏblUpobkjS^"(VjNT[R98Fm%5E7 ~.^#:L%Jy:u*>G8&SQQv[m$VDNF ]Q qy|Ǟ>PI< N@8 1gqcÁ_,~F(_hmF kֽm/L|H"6.f@G#IGGxc{ie832| [X EK٪f*:juVeR4n67x\F"S U+{JSGݢ쓼Vl?Vmڧ x'^K(U^bNԂ WAzƛjzFg鷰ŕs ݼ4S]$E",NѿDw&_NM ῎'?~'j~4xvw5'tKZw6by}]ׂ|1UE/#|Gq\,,'x#VYiǂ/4o[i֖Vc@Gx8hAÜug xux,k3 :3(5sF,:X*Np>gt*a1.XCa?JXSTT.U>Nyh/,z2xIurmͯ_\+!~7.r+@5NI^u{ZV Ue&*<Ӗi'vl?fJ =LF4F8ԌTme9Ԩh6I~,~X6mN]r.u/?o"C^/Ω MGLy8q;gfTG߳p*1aq?9:W8qMzҔ+իZm9NSNMF)S)Q)R*Q5IF:l P:Xl-aN1t MF*%6I^U%6qns `pp9!&DQ*mFixf뒖K f: LX ȸO?gLJ\vnk8]uUy_BkkQ(Teu'DNU6pNKK+zhRٛg'ձׯ pFI'Ǯi႑0$~l 3AQm]4$ JhoZII)Z8Kٮx/I6h?4 }ύ>C]YVq] k]f8yԼC]Z++X?ͧx_~l?`x3FZeAj:O&h.4ő3?36]Bw+)J6U\GaE "]miPN:|!PJF݂2[fkr7M^^ʻwYԄoNSb:q9`sFKpdA+DIgMƹR|WZkwĺ4uys,K$756R\c`0?OWsdD,MUz&v9FpCy<8jsk Bz#Z)WM)xZp MMӤFj^Pv"#F/3qWjQƒќѩVXӌORQۗ+, \fI,: F_qNA1~:'[+ Wƚ4L4S?|Gx =ƝGvKm,r}Fէ 5_o-2-wZ|^&M6>aj$d/y-l#Kxe_5<+TȲWeL%ʰ8je _T!e,jGf99mڇ?N=e׆uǯ >5 A? h:nj/}|^BX/"OfS\C V+/oK/YV>#LpUЃ".nƯ֩rb8(bpacN&[q4+S+x[Y6 ;/ _v`vuwiQ7x;͑KOJC P!C2 #*ˇ}mV[X]ݵ T9HPWpur;sM|s&,SZQkbZyP.{-2ųz%؎1^ӌqy/N;3L=(*lvU9jbwQ^Ctq_pҋlfyLn#4#N4hjpqIN:^0Ҥcpma:{\]\K7f$oBboV(V v#JY7,Umpd}x?8!ʡø:H0Uӊ2,M9/k)RMT=˒ ?Qqa[3lNWc70X̨`'K/' JFj4iCTef?7&k?5 i6"x׋/xznkמּOΰ5+ү/,Vh"oR]K_}#Eoط_~"|0XOOþ4o Z[xvwԯ-kLIZPI?6䍻drp28sJxm* Jgw,IbxMEoxZ7 *bHC-OUT=ܟ cZ5=r%:;}|$3, *x4yaCc9Yg>#03o qHY-<|u:Ok-n~ n/8YFI67ɭZM=66`u5A''zӫv?\|QL(ɒJnI铂s÷ XTt~k~ڧ ۺiV٦~?9h?Ms}me= An+|UB$mdG[C*M21byG$p@8 φn%CzTΣWу-+L>B35KL{ym$heBC$LUt`XGb@5fKXyORNWZ.<^XlTV2Riug Ǔs%bu0TuPng,8Pr# _ā-x0#eݣn 7 -0}7 Lb*&CbF`{?; 3oUk+3ڸ˖T;p3>N5ƬfQOnf/ )-ۻ>8TMReJ΢թ[}nWBa N[+>W<2@\| rnBqN:u"2WJRマdʊyI%(Y$k׹ɹ*B˒m x92k; o[m{hnm[T[/~߲[{0˃29Ee]H >’>\gd>=j?/ox}{Ǐ kH~uuC't{WZ{wyŋoiږ[b\n[|-LT佯UZXRufJ*e^3>|guNtUKVd a#q}ccq__\k>[7xHme}'6BHbaDo‘8hn_>+|5#ǿ ׭bѼUi>)ȮghWz}]&q,R!TYCt!дoz%x o_~Ng9_W-v7<@[LjD !woJ_H??5?|ZM_5Rƿ59[ /Sbu#7+x\|C]oS5ntKi?39#v :]*"9FIR%~2w]'2zq<~nwg<Űw :=; C 2%[]1"9ffqaA|eZE,a{ *HIΑ"dڨYIxz>&V̼{It'^,C^xa s4]NX}bw!.5I_`<5.yk{m-XraH6̒1H( Ӗ'jJ6pR06iC2|~iK)֌NTmUI>mtGSֿ߰^e!O{G̷ l^9c27)<u|~~o?bm<ƺka-C7nO ݥ u_TE֙g'ך=umI kb)c5&G$2JHWI΍t(A ~`?,`18*J3g?e]BN{TaZnhb+KS+ΰ9S^*>.Pwt:7fT^5@ێr+st0pG2{QOK$!]nj~8𢰷 Qo#..m.ڪoR*p3s۶c$0q{z27ɞ*Y>keraƼ.x: ]QQu(r<')WIF V髇]EWN+}TNj:6s2IG ` c?ӧz*'89UXH`)a8 Y eRm$m+޳thڏ48E(JU%PJ*͹܎+=s-br{*.XԒݯŸ:3j2fY^|U)QXSU:uGGBj.)G*hVBAPe^kNZN2ER'OHH觃D_R!j7RH|Xh_a^W;i$,l^_H $:u ! !տ_8kwn?i؞(ӑRt gNwmd7{h>M1ʍpIbI<=JY}ow [o>vw?~ ^D]_<:<-m?@XvaTeN%R+uoRJ4=U>βӓ:<.02NUNu^.օ8k)IY]^Tp?W>/|]yx3~l??hzfljWJ[PY[FΨ{ Go?luK-S[K6kzgIbc ,h"4唗In FA`FVcTmw,N<-$nO6s|!ɲ|3)}N{vg8, Zq0e+{XTYӟL <ڶf &IQ:11RI9AԜyb+DsA/%02)ieFWY>%f$Pv ?vфu`YX9&੟.~woޏ?GzNkjo>6Wo$|5_ x9`[2suβ)F", j4pYʥ?giI?iJԗQs|#ۙ-Ѯ.06+)6S8I9 uGmC¾#/]wAW]+RNԴvK{if^6R(F DGd 1%sz6AWڧ8PI3޿Ut9( 3qvN-(;̘|NԣUU8tFjqNpJtJH8JJI3_o+Υ⧊Ծ#&Ѣب9xt xv5xtwPx|GDMm^F K9q_м@;'rx2*J>[%8A0H<|&3b*b9֭': JR|җ*ok/S't)\ iѧTt,N7P)ӃZ)2S2_: :sӊ~p kV=x?~[Ʈ(ӼrǷW|]? gO S~$yR=ݽ׎~$xvʞvv˫[j7LjH,وD7vc u߯ik H 6d$c7HqfG07d#'{`⮟1r,<*SjpnsחlβfKÍf4jt0X6_*+ҭFuYvVNjzMs2Rw=Þ -4mD=cmNbuXl-Goo 11*|ӐeaYɑ`C3l 1f P)Q BA#{Pv3_C|:oO#-$3+4V&k<|ݖ!%JKB PbG16޺,;7Sq.RIάխ9TVr'R4_L> 7x,ibjR(/:0RSΒ2>hW٪0{JޅeOtmaBnEsy@Q#$ 9lp;kqDXi I-`0T?);A#8H|>*#mbˆ\` U'o~[BiOU18WɤӲvխ:/ %azh$9q0_0$yYٳG#I"mx!#yye q5B9* !A^z=Owwbw Ip&N *` \ኞ`` ##B>C s1Q hdWGUr$ޥI#ʆm+&`2y s=sq% A + t898#*F3%BQqc58+ ȨiSgʺQǿVoj>s {x큞3H\͓1IROAœjQhc-BcƬ57k81D^k0|IaRD_-|>+ ZI$5eʠXm)mWc?HҾ5a71O>$tԥ'8 5ORচOk#nRO/Œ|~[UY2`Y14뀼nV\ 02#inH(X2{sO<2 ɬ&K+{2M4UgOM&nN/ӟg%^ֳֿ&=^1K[妜Y~_;EjOEg`/n^&8oxz2('Ui;(Gsj~}?>%xPuTp#[d vFrT1aJarORpzbv28UawrFr:خOT9Ua[˖һ7ePmSu+qSLVwc5[5 T;ά&2Җ"I|mt!c8+$Q9;[1G8P62Qr8W8y#d{p:nQqn[$y |Ǡ8m49kNwGVi&3QP2Fcz'|.dca'VgQc_"$dgK߁|?o,2[U"xaO|.HAR r2b@46:~Cu @8j8U%RF0J1хDCwOFݜr}8\X|EJpRTV֋҃֜8ao_˷ş ~&|, %|qm |d, O|?lk|$jxŘbĮzx@3r@ 9`yIJe)66mNX<1䁍$m[#])X,=Fl&S])sb2?-CCm1]<}[p -ef qtL~DQ/{i~^NmWVo(۶'zf*dKd$(sQ H32H= j!Sq<YFpo2I)+5)J87-5m]x>FX궖8lT]^k i;jWKgxf(u <++6g}m#ž="G1E$}Yoz(X4U80"P( -Z2Pc20l񂀌A8#QU瓁@#廄9Ԕ#QJ,•R)ѥJ6I#IZudmɹ]vܥ)ͻSYIVnB,W'yx9+HrGn8t8&P@+`t3g!4߂2Wlʬ˞88y'pЁNT(#hp@ }|X0ۀ!z|׌Vڹ.IJFF1;ڳQA=VՓZ+fl `Hev!;OBHaZV q!Wp3q'X*$>Tr 00,峎ۼ szi_\B#6&+Zۄ NS8N)+WۧerF6iQ*j4"wwI-5Kv ֣ukaao,wR!i& f,7;qn?_>[?˔Oj)j3acnɊ&pB62h|$1;[˯/Q$n`V5ė.<9D).q'?*5^14_ZQ-wc;8JIJ8LyVWN1ۙӵ՞(S((((@ d %N? <%kE/#BzŠX2~ m##<=jթFqJrR/2O=M>5hQJtkRZU#:u<$JjVG7_ƞ75%:@8" dtzV%ڌgrgjMey $"#P]w y8~ z'8q\~x1zm쬢 dkIT1a%d\<+mQ?42˳ T'y:U#)):^?ԬݧM|s;s`8EuKee@olXyDZTjt|S=v2<1%)7% BX psCJdѦ;%SyamVM^=~sS$9T63#PqB#1B_8f 섞:5ޫj\YI1@zxGIqH$h$ѦKg*)|tk5# s|h `Gzi&H݅`@?73jex!+xbY I9=20}x1F`!sŒm-3@_?9m$w)rϽ*Hf#~ /Fprڽ!$[hq ;@Er1fC1h y<8R\;UX2#!ǰrX 䓻gۡC \v䃎6zTHN9''$#`H4*!2I]gs${&{srOc9Ē,2rnq=BAH9{'srŌ3$1;m;瓅AӱG*=;`` 8(cBs ʹp{g9쓎v)U<Nr w_J(\)[rC$0p 9od88 r3!AGI$t<F kn9W.~Pviߗ' p ق#;w˜#ҮI ݀Ԟ3 jho-L~6'c'a#m-[Iy~fь2ZYE9m`E93t'9\ಱ-l⡄+Z[U5|gap@wr7B07 r@zkwXz]C%Sv#FgǕ'?a#ɸny(V ^$̍:-lQsI?XsѴ@ve=K&s >_T2Bu%fq)7i/&'aB*PUbou&2rzr_ 5YGwKڿ`j]%povc *J33N人uԤgI2[ u}L{>r . 9|+ƻ*7a{[~9VCdPaYFu5:I3n_[$(P?_֖+Q@Q@Q@Q@Q@Q@Q@Q@ F2zzs,}E4mҥ??V^kWL g6/RNx_.TgkI-|$NjC|EArvU/WV8.Uխ9%_ӿ[Xޗ6XUYUOZRL4Upa8I;]}x;+^2OtM&O믝־!O6[ 0}Qˑ" t ѰxӐ:u=OtῳUZUlpCd.A_0Cy^f|c\hoḽl wBIFpsO2/g%R:$o<*pjOxԣRpIh[35w\:8P#rxn:$}G6SZprnB qc#. xMx[R%6j2m^/ty< f;د╨ 6Qu="`FT^F@ﴌd8* [I)A/"EIakhߧϏWbs4{08w=2 <ƫfvL:O8!IGWw;r'í|ĖKŒ06%x|zh2K`1,pӜ]12;*]{^>)6Bmi;fV #i f5 a a${8ӯn7wQ3[)m#9 Cž"`Wݎ[ dNAyp_痲goSNl&E'pzg80@i~+GzȿgɅ_B[86N3[CpF8h5xp/'b"Y ʷ90$%`:ׇ<ϧygbDf9zQ rЏcv_S,e?L_u.1!Mdq O-71tTf2G9x[8• 8 gen餖m~mk ]_߮_=-[OHlpC69\9~G :єy@ 1\ bN}2I'Z+3'#!J '*x-o UX@1zn='!g :>RpsWN(*}~~ 3ΛI8Rﻫ)8*ߕ)sɏ*f@#%ARU\{c9Anf`\I3&O,}Nx*;Rsic'SV?nϩr8烎 P3ؓ ~.fueҺ a<<7*xze7KwhK ?lg\V4m><b[onXdWhEmtj~{=$raVdPpBن6q5d)r|kn}.#pj|joM5$ROҼ=hqtm'Nb)M>r03cIZ4|=sO4+nRmܜ b*1Kӕ/08ESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERt>Q@qG=)@=zǹTo ._9T;?iry㷶6*#{]C OcuϠA%ONy>:E.i-Z.e}  ;RcQ[-QE9 GuQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@tilem-2.0/data/skins/ti81.skn000066400000000000000000002271521220200411600160240ustar00rootroot00000000000000TilEm v2.00``TI81Duponchelle Thibault1."TI-82[Yi P;OqbMcLb KDbRKa=s ,w6|l7j<q;t FR<.sM.K.J .DHU.L<`s}b|a} ]F}V^{>qDW<sGX>uGV>'uD+E&C(FCU&NJFIFHHExifMM*C    C  M!1AQaq"2#3BRr$4b%5CS&DEcsTU6-!1AQ"2aq#3BR ?-$@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ 2IgRTbt;[8?x1ODo b k9!FlqL7'\c ,??  pqOHH?H?8$/)+?o?z@Pz{"C@)}oOHqOA/qMH@ Nؽ? 8oo[@4@8$i$N q{~$^ ;c "n޸$P8S)zE֜E 'pK4(҇Ѐa]:`5ޖ8L(^1VtOLi@O@}6p\C7IŠMMŊȝ׀Hnu5> Lxo'DO?u -}{`:X?x9edŽl | '!Nz!_hahZ}<pZo g!crA3,08LΧ$#ÂG7gv)iCbQ6z*Ma]@ $@ h' nd *FaU98qv8].#n׳cE-2Sͻ8TVI#Wcv_M:i#ڵfuqS-&9&ͼ_•'9Tp;FoCm#MTy saڿ+kBT"p=:m }з; 0s o Wbp{HJ¤ ZI/Q ЌfrZk\~l 4.io\xm p=9]Jo{yMni= nOmcNm|ЛU~*-V E^Ax[\\b$tIAYװ&Ԑ}uK*&a6D}+&?`wߒ$!a۱D4B֊ǨElEtl޳> jVW FnW"\qZ&HBEo qJ b ʇ[qz+VSMDG~!IJn1웛N_p}lrP(3Kl.[F'>H\EGx8 'PV%li( MpC&LBnӊAt|[ svz#u:rb6JZrƺ@B>Yh4uq3 v ^\M䘔b&An-cKv|a$!훪L\inY54 ^vv9$;)@|/৒t4Y>hWަd&h*.Г y*a=Is@ʼ&8atiG4&IʖA + R GF<;7;m^TZw >,oihob0A}7/#vvxM<N]yXy=X|%/A)yjfSbdbȧdWg7m+~1eJJLnY%e+*/q> !p/2cq+1ZHAfj.H 9cWqĴqtTk[-1v)QlJPnc c|ٜ"go-;b&2>"Z& DA=΃HЕlﱣ5xMCF5_4Ul1h5M0X=u$! gvTl _'Iu9 xa$֣zK@"GX*Rov% će7e'b؎m&Ӛ\C~lH{}ދƬgqI)Mb#݃Ī؎)8ۼ)d8&6>i+qzן~8W~&X%ZݱBV. t;U򥦘bXb~R&iΈ'ą 3tО5`؁+IUa÷:!M1w)RmƯ@5nG*JڞJ-A0wӯx*6W]!uؼi5Uw+]Ր/P|q_ Meʹ@5U}P]SX@=Ӳ_5>T bzC`iPnEqK؏Vnܢdx،Nrhj Ѣ@kf$Q&g(`8 )&F-ʌsBt' R=.L5#Y[5=]fyOx͍9ֿ$fHOdiB$Z1ЃEJ_7CkƎ؎ܵZfYSI =BkG"g2ޖ.v<FK;)vz&=o $>: uHKq,o|M"Qˊ(.g.E8&ns(:Alɀ4U3v׹g97ƒw'LIUXeu<̙a_m밊l +@hNQ6Une?TSc8*&cA6Zurn8W ~#6馆`4%R^ފX Q􍊩8-0UrO])3T3(g&)ԇEp>GCI=Du.=Yq5?d5 m.#$q3  mPÊCue͆x[ꎌG"bYNpXG;9ئ}Q -MVds{(>Aϊ%cVxv|`a HZ9K^m<-U<@#;d!;tG1Lt>)B lۢ9MM;_K dzE-u|-fFi*&W+)q). m!p^ي$rIܤ-:ILvAEx-n5$EhKQPb5M X'g"CC^l+:]KTSɊ>;Ȏ9KiĔQOO-4E(d̠q-=S8l㘥Uakj%ni 5mٶIhtE+r=)QŇHvFoyn"=a XE#ځlТF0[0ps[e$d1=D-|vc(Vꐕ 5V8=?ØqYFs`@INћtz3K4#s'x*RDEYj?i OkԐH"؅re&I6Y%cMi٬W}G>dM\Lqwѥ,!SwlNewt2ֹؖItMc~X}.͇t H> ~bhLacK {B4cHFlsmfd:wcIM[6<e`BTm;*`ouu [l6S#Z]%7މT8Xb*"tч Mis75> ,8LMHwbպ:7aWb#V: -I.iIF||w~>zjQQ09Xv|s*-Ivrh ki'-s=ڒyݱ&4DtEnmjC_SڊYLS7g7E:3m3и+! \K{IKಈѺߕ֚p}J<ܸܓ" ܏{VYڠ6]!R⻳ lP}ˢv˖}QD8K}d^K+h'rұEe @ 5㼐=5+liQ 7`sl~IK[TX<췌]tAIJFޙʩV̨ |+z:6>٭ F5kI&c$[hBM4u­$?dioQD?h=eqV䉊m 5Q/`N = r4ٮ ϒm)M0,@iӚQJ-c1H]wj,N} F$Х)!f h;AI׫rlMXjJ\u:Q!Gv4LRhʭti75,E(24hx[7*V.і6T晣Z\Ӧ`$ev6V5BLR;R䄕l9 Ocqc欖Fo#^5Ha E t;]%MoC[G<Y0*MF%~]lvXY͢#tu5LMrnR_%wV}ft_&$@zZ+Ӵ]ȝ &,Z|j+bzzOeќݫ+1o\, 2F\ΕͽbnM4@$dk}a'F& ]%'aE/O )>9$MͱRnGVU1]tsMMBTK#`(жn/%=mD܇Eyq5-Y;4#`[2q+l_܁I=lE$Auct!F-l+AuQBm#u[[ YM w. 5&ƀ(FMqc?gU *h{@t)aeJn-\eTqH]0.Rɤ;4ʕP]5G/(}Ll+= 簜iU X4*DDpQm4^hХmj,;FOh+L'oO5o&QՇ={`&IQ0zqyGz (PO#W BY3G$EjCk9xM6&f쥷0eRmlXߚ O&9:vt0RN Yv58/ TqAlTʔ$ zr7Kh~yW:__ձ~tw|i[b虴`13MFK\ LQ'ԭ#:iVg.fu!ߙY[lӒsͬ4YKH?Kz(?._CԸЄ즴KI`uoJTs~<z}FNU$:;}̵U'H\Sc_(ͷ D̶ۨkMeUFi葤uLD"89TLCU XNВl"D71oB`ԛ*Ra_t1Au[J݀oo憄4!+An_B`P$|6`li!juE +iI76rMtP 쇡':u)YZ䝢R zbDF K`nJrWC8\elhM ]I xsIڢ[5us5uG2(a,fg:Mq')ZۮcC͋נt=.8buӍ~'>GrfR٬ɨ$5䶊9RHYf_Nh[{htl6SR4D1^k3GNBOgen̈́#4ɛeMP]mKئ--t$]G@S+$A1 o!4U[!A$h7+&1I-uJ.^(E7MiialDtv5T~[!$+`)ݔ5czATM6z +N)4'OЍdؖ}4OT5γO5R <ۊ5EkLn-i[c qwȭ8Ve5vJ8Ԏnjqg5GDvӍ,Z/pG637b!l@@ \+otabw۵⬹')_E##\NVN{xٮi6\,]6:J%ѣZo5*EU[6<-G]ŵg[5Zf2'oK& [*I lu?DkKAhsUeqplvCHv;}Se klt!U؋cK[CduUckC&t|6捱'B- l7KCw>Abk[Hz:麫& u,> 2Wt+`Dh%w|PrGqPh"\RkF`YIkH^.BkHvI[b1גѰ?DWr#2Gk)i\]Qg2 vHtƶ. tn?i\D}ٱ~4P^G>^ /I:I@RcM).\4]1H\PY~eazh̐˟WCClCAap q)1B%7E[WDt4%6 M:-dX@)V0:[CL(LMA6%m dXi+ߚI$ |C]+eHeЍ@MrĀnEf-Dծц_ BowiÎYe';Y+5at2k51{f6]B}d;͋o@@ zZ8ͨϷa=etiXWTiG?FWݙF/?LRk 4ij ͏"`vCcF&'jP9D2fTՍ0F&J%; $VG1CxeLKcMBזɎKénSat:"U@`N؀萖ŔmHa:ca6K@$'a@"!`C@}D\Aqd+{+}eCXH$_DhHI6H[XR`&(-sQL[- #[]: h%I0XD5%hDekiTk)t ڱ7H/WAB{$غmt85HN`v&3xiXF[ϒh*CN'ɕ gX$-ܿ2Uÿ%ϑ|yߚwLj; )d:͋#7 t=*x:юGGp .$6(z2Cbu]Pz9P]KFc 3ks\OcI-PvpD)؁Hٹ b]#f0rrSz1Kܘǡ{BC^ @%/c>x%tXH}\ !B*6 T:6Hhj,-llFG5 XD+/ -ho`LN/6;AROZm @%bΟPcߒ :5EH"h=d .J [#T"ld1xikR2+imHR[ ,/5xDW6wW9-0U9ysdReh(]EsË{2СatQWAߚ'ce>v.VJ 1PqP&6([ $1! _]C I؉#}HmE!sdc4,W%.%=5;! 1M Bd ?`&Hd :`'Bt;▃Th+2i4@.JMFPU,MUBUkEƚK'DK7\ZE&h0PEE#ѱ%Jo~qkŤa#FO,cVZH -qnrHY=5( q;{qg,| YlwU ./nS~],F9om~ s}UG[|E{ =<ojT5)_AJir@rEiڱ{ֺ- [i]* B@ۋL5I,[P;: m}I#khCMv:čB40B-_Aށ m,X@tC` ܦе[n#∃E*6e]${pi!nmϒ$OU(9gܝ,7G"(a5aneylӋ W`QyLѩ =$祒ouՉh+14z|N6Oo=٦r_MFI@,l$h &&]4 'El@O NÊӽH-? -kY&v lZ9l>@)~JCHtXtA#@XjS&4 ۚh Ц버,n7c]m /[ T]k /sNUatШXu+%l\K"i Rܧ$ =X+XZi[[+hVT? m7PmW~O2[LՂ`P(ʑs0fug͡/'O0:GJAd}E>b!IGҀ>m]xU# ;pO%6Vi测3ڤmΠ 2Ѯ 9D6Ul9Xoh4=oE*78ۚŠMktB@/6u"^jߖv[s oRƄ7HCMCwRӱk} v-RlR%k,+An .ƻhD/bjĤ @䀰n㱡_$ h<Hmb:*D7t;3w{T4BAMwM<8T\ kS5Mi_ak@i!Lt5T1ن-p$ZUdtojю9Z4iYfgDZަ1Mشw@mu>>c FzjH?(KGbՋhȶb(4cp*Z+[0<ְZ2GZ{7zefVI4t}I%^Lp, U"5dڒ-tt1e6C)- DY+7HRbnG.,z+&ЭPE48 PDtHZ"-K`NkBz`̩鍱ְT[[mKRw; @t<d#T$l P;B}"6ѲvRGk?MIrvkgEḄ@@zY|Zڜd1o F% ˘_O5fRDFw\Jͽ;Vcc'(6\-v>I]JJ;Dw"Xc$Fص׺盢'$j ZF\D=&F*t ; (q 4 z (+B)4A]PEJHD_Pomy(cLn 䘞imT-ym6"h-E"ܐ4 kú v/cNȰV#X z%b]Lmlr=1؇;! h;afufZ2GUV74aՉX6DݎGnൊkf Ӂ%4n XmsbT>vvz\cxbz0΋G Ҁ>bN.rvbhvXi*'H_)-IؚNQ¿#r}Wں;ik>^u<␥H}jHN&߇l,ג_$(BHnN/{qkP `8ۤ+$m102E0 h!pb"3jd+] 740f^I_#tk$>!ךi RZcm엹UN-IB$0Fض!M1y$0w!VG;i.0odc&4/"BN.*ookVt+^uF9(N*^aQe%f#u1tyT~ #YGL)T۾OoT\~g.Nͱa0΋J{bc4b(U>]S,?'L&뮫E`t[3y$W0!Idje9S5gT%Fi3\6LHD 22B-SZ@,40N ԕC&$0Tl|s \ $44O GT dZ}@"Mb. EHa:*oC[avCӭ vJBAPEu V0P B:ZF3ӤtbVdTYuCNBVQjs !7fZ6^7M3Teپ5@6q1g#\˃}:/zzH;c>)]X\يւ`eǢ涃a6kw ~ēz1i3Э\\,"%!\;O海C;:7lh4YX !aAaMq&@T+;M+cI7oCt>'u%X@i-HV'H@5^/^LkJim7m2 B[cN![Muls4A6ʰ$&mBvuHlV+؄uEb}R; {"Ɛl7E &^'8vZ7^5vSHЮv*9v>֫-`s}q1N<H(a1Ѧ1 RKCuϬ?vmHt_,=A$@]+ubVlf#O5a!䅤U"$q=Iˤkl{9.7HkdNk'lah"TS$k[6 U`G9WiX1 Y5BC}cC~i„G ߼4|RT#G!4c}e^¥4QN5]d} +VAL hKFRmq0E{6qko `FdY4UdNk+L+e $װ{S}QZ{Br@ӱ盈\~ i4벴Msm:!6IˡJ squ} !Q'% b"SʺE=3>IoxNDnU5Ҡ~Q#4{47nS-L%M%d8Vܘl IQ2LByz j L%fڼdۡiF:#QػY>RU RVj+}%'i@3,{?s~j(- i;ĄQBob/6Q[ 9Rm8N["&>^-"fn]ۗ5hފTW4yNwWh=Ws/\?cht}{WBS@ l|Ğ8Յ$<]Y^EbR!lF 9Of6-mun AiN.kFe['őv4Da/ D5WcZrB\/`5r!S-5DaiďivPtSE26.a 6L`7||(+^TDlYno4p|6H,omʮ&1PP45B[" @#6KTC"0} wRMo}|斂Nd\[䟉AR@L9oV7v7$ܤs~6Tg@d,l| x*rHioi6G@m؇ok0Ħ8n?d$̣E]8$" ^S7C+d{(L4R\_kgḄ@$/n95ܮ]t6pDT4w:f H$9iy57 TA= $w)OIM _tq+$;T. b ,q%dᔷq@WR&)qBy5􉩬j}_J)qHI͠D`|qA? aEIon;&ɸ!yan|Hq $9X ~IҢW/8o ${l͹^؅^#M $IrhBd" mQE:l5D[hHn6<4E*)oF&$$ɠxC&R$!m aѓPIwh0whmς|SDǒw|Ɛbm`u,_p|C:VN$DFRDicy!$S`|FȪ&wXo%Z u`(Ul3C*cy,F4r؃{'7DIN,iF6)h!dse#^מ|_,=Y$@z`%qyG.W4ނNbT$"U19IcHNEbe|6*:V&Ciz!B) $!`SI=SN[?15PES)܂hCY" M4&݇P$ƣ6Ke)P M`:lB \ ܽ2=iA-ӢHhP[˒4h lI)A62fz!Ǯ$"hM;h@l :f|Ї7d&Ju6@'8T дb8,v hUcru*U-vO/\DU9Ls;wjCZE !jd=Q M#^{%͗h;rƐZ>RP,=i$@za%mMram\(}{-Qxy≌ :4^F0:V7A:&}?`'#W ,7G;#2N633MBtPHF>cIRFt[jM3)<x E{cJE&i"OC)B :}*Qca($1^"PeIlݍ0 jrGU=ڜ%ӭ`5JLvƔiMǂ6Kw$&B x9HtDr D͂o!"KcL4E]1Ӵ:x%t5鱲|،pl8LȩΙϕck9{) wgGm\AK Lm;Nj LogJM][! ߙJ%GLHbܔi D$S;0ˋvTK!0c{]I.UD:Kj\la똢ʊlwcFq>Rc9wwK>4s:H 8s 7NL1ƙ.٣hRs ANm#h Rg.ΆSE˓7G^" =e$@ax#]xVl|6´n5WQz <fS+7pg M8b4Nw:+ؙ &;(D{6ةI6 Seqt!{_1؛^!isEӱm+CIحX.HRs jz$ ;ck%+;k}MZ^37k]ֲcVG^jzQhU7o.i':d + ;Ā>)\[ht H plD lE!h#DwE b_$hM 8!! R>ׂ`CoA6"ɠ8\܄r'lv*V:=Id"mM{_TVZmNy(Js??59]#ll8LZ˲9/fOG>HL ~bC.]3(sP %E,h!'QaLZdZLx(n݊ӘVܐ6IfԳJB 0m" 2Z@ lP>Ÿ>!uv2-l2һ[ʧE|Sr9JhX6? Dgz.Q4Cs8 jjdž,o #ܿ[,*85m\z)I ݟ4y'!X~$hap]N^pxFnWFr<'{4[[#3Bc ^u`Sehty?Fi,Bequ<hoaQS} wG6KSm^J,rnѺ_pKES#.qr{c%$gCEP:V㢿+2X+j?+)I.F>™_S'4r84mH܅Ў(ƙFx槁 ]g<>]q4IhD>JvZp4y'Ŷ畑cxb;Ձ&}#!G%7Eَ۱4Íأ iNT*l%Ԓt&ӻFyң'9/z8qW_!Ż ޛ:Z5M?.+ |!$sk鲞VZ_=k;WbqrWG)*d%G0Y@*GMNɸ '"f~*Md~FF9#|1yr1v4h$=WU0U55<1P;8]4iR\]C#Kh=~mI6G>ȳjkpr;Oeê6`LŰX_POI+ݧinMmtW;|A|mbDxG23 r8ynZ -_- 8~ppUa5Tb5mq\O 3Gp-6-8c6/o^b5ScveVBLӼ>6yBG.9)e]1+GWvqFN<*zj32踢k`8."q)(@Hߢ`GRql8{ jfkM=l#mV1GSSD8bx}$.c{޲jў"X qMR։;1M9| E:d4u԰@--TI ~0U<4yfavx \Ī'TT`8E4]VJ^`3RÃ[ _>7q<[|1R 74WKd㴵VԚZ2B8 8ɩS)h8tѺ(V:bmHj<]M+~k}G<l H̷e0bIiTi&/'._w>/,>n}w襠P&Ǯ ؠ=27I>ɲϒa:6 -2R ЋqH2>в݌mhϞn0e%.`OɣD=!؃pBj{&yFel /9-dݒ^hT9XpFSu$9Be;_^h:,]5]599[8\?p|p$|Bͥם9=(E4]Z*wygmA8Ŧ [*Q-Ss8TR ;7I9 >qj\{״c$, sF565v/IOcP\js.9܁蚚,K8Gn+c 쌻YO4i$dž5)R468EMևWΟ"|yax }5Odc~CvyvqZcz:I;PV4 -ЦB8)cL}dm-V=%cq>)LUqP*[<ԩ!;Pd2Ϙ+f2i˜ 4f҈} zN"vYa'`t+?Q՝>|jmu : pElTKMdavz{ꛘU\zd5Nm#Xckp9#0Qվ8ą'J6i=#qF j᱀\9n^q%qJY(*ĐH,񕠑3xc~֤l}29ejWub#Ⓒ\[Go !iMkNvfWrQhq6-{;Oⵔ|DNl]bb keۢ"R+T8'1qVУA/ŪM0I0Q6LmעN|gz~_^pel=ZMOlj&]r k#,{M6ފzijP@Pž7F^L,\@!Tʑ{+bI!ٮJJ#ƞ3 ɌQ,&Y*}:<ݣ Ui)5.hM8P,SWM;l|I_B]$qC=x)x$k~M%ĺI ܽ,ҹ&I8q&*f|LVzuL˙GKqh&o\vܟ"(+rlŰYph SM<=d B#آ8-JhTͤd P(F=.VSC%b}[[ɌlL> cW|^K٣z|Q "A}m'_G4[w(90o>iDΖK$t.h7bmٔ7Fְ=л,Y0렳{ui sCᛋ1auLq y^s%Y"F0ڿlw52QȓF(9kK:Z$ fy?36h`Wf(G6Y92k)&y4jFUN:vbfN96?, 1dA*4}f?ssf'֞1yG @Pžq,WfڑpsbVW]Ć2VooU$P$Q}Y\ۋ_ҴgJ;_s_ғy~k7~h;3Ct1$Xv:Q~J|lXp.FDDMbԐ\Np>B2&1-JN-(p&w(Qk,Z"wU:%,lXčZy"^d?r%\yE,ѮҶ?~6gp"~ TXn 14ÜoMlL42Z)Jl8QU;\y1O)u_n)"uVmeGEŷ2^ -Rq;#ucEg"-yB ԴiX~,mTM*e[l2Q~–ha8Ŵ&O7 $'e/Q@N$|=("שT!b쿅'$ bB7"^}TDXkOky$2R9Y%y>%!,*zB -ajLQ,Mb ؠ4 !Eׇ308YpY"CM{&PՒCE责JcঊT[&dwmtl\$%ߣo梐7HW-h-e;#c4e-:mn~ ŸNn$PBhaVe -@6y;A)Q}+aO.jl-`mpC/c읹&I69iK)Fߧ%I螅biaS` oeWbaifxcuтO,87#a.K+h4}l p'ٔ#/x}́- /rx"9'x|i<ď M{wi ~oӢתɑtlu+%_'9Fp5+ <{ |!`/ - R+A&r3:717jF.h=>K^Abh{ $|_nKF q, 2tWьO{+p:QCCIגiQ6̩HSevRHhrtv+e m$PЯ~zzd(hWcˀךtCF;~zrJl@[ThjS,h$ju }cb4BՃ{vNf>[mmʝ!B*&CNAm,ih$.Oi{ }H$UI_`R!0k-ssDDvp l:n)E EE!3u]9Dr5侅GG󠚒 O::x# ,bCѣu견pcy'FpfѶFe:s^W&O^*ΜSi)ЙH5rA'Mלv8p#Q]h.S s  R#'ep&&9MoL)i&:vmQq/# iϝS/}e(PGb>/y@]_r[4ëOEHM {%H|Q$7J4y|QE_ $+CΛr Cͺ}XÙȤؚ^Z4}PNEƻ+ +hihy  SCR9i8뽓'l%ke-u@y *+ШT4!ucɵEℇ%cCζߢm ;{{Q7L3@8mvV`h\+l{GaO\8CV": miЛ@kKoxJGtoetHn9DzHX;tcE/4XMb{T+&*Ssso"@1v)K*~&oz)E_i!XC9tGȏULķViϖ.7kQY0O=tK %f,30fp׼t>y}% /#/%|v~ k}'3CMu~ 2ЏaE)}%)}+Dml0ZB|%Q^wWUZ֖}WYe(q}G7hBɊPtIZ#f65J9;T2S2 yBNF,i0Q˴ ?eb>HGs,Mg ؠ=6_ִ /$~^y:+5+NTfӱ:Wd7mI\mN_8t+|1M*=tp 7)+8/CXm$m&ςn1eÔPam{" (+'Cayc0p,&Wɧ)Y]t!Lv 8xچmV<<7b'e4m7 1}#EZH]z8/ȷH{%C3uEGLkCZ7>%y1*L:5FZ, 敓TzWX~URJLm6MSz%i0h%jK2_JI+jxbԉL" G|;M0ivTdFY4M64n/"7G$ڮH#եgk.(h͎5mA#DrVJE'E6hKr~HI[:Mv6Ά#n9;e+IcT̽5yz\Xv;AW; 5;D/1GTz69ةnw^Z=ݜm ™z:8E9bX*5i#Yz I\緷` Gd8ڳQuׇ*< a_sD-2GH̑*b,F.oKDtlc bЮ=}a]q$d4S薘q@1[dQ>ugD̼Ò*M@EpIlD mYqX{n>4 .Zb/ԲfWB-%;vt 1:)˗wMJNь#:mXKiYiQ)j5Kv&&şBaMVA-$XѯmfWH"w?+Ew4rzXV&)RH\9i/˗>[ʓ^è;9?Zkc_ZZ>3uŌdx[#hc֍^ǢmVxRCh@Ϫ~~ ],Ӯؚ|}6rLb!rHi sLs|v;}#d1m$;.=b&ӿ̮ GY}>NgV+JT L|WOG}.?C >$z };u/[zŗUPfƍ\TGupcdh-6yM{ӷL5Z:8鴴1eGMnɟ9Xϩ# S@#xGOp]tszmrV+tVmN'ny%VBgGk# r{-aaѤ0@WB#4iG5~+}>C]鮀fbQQز#鮚t#>t$Z2#gv]Lb)z{35AUؓ LV3fr4xpe,i|VInxon4vzfg{?5fWMefݑBnޫv/Xyl*5b\c>WTZf{talp:WCJ_^-#&:v Z(c`t> ̜dNL5Rz-vZ;)/p\I_lBL@^_Rl*2PM.&, ЉJCs[G״]~hO7r:2lFTqfW kc_כ鰖֙z_+8X"Rz1oEP-{ƴVrO9h&4`N0wCKA•U)cB`/]W"k RVӑ+5x::J-dm~ql FQ⫂]"DY͘NKNt;<МD&*S AJPhL:2]f8a7z%(o.6IXmCYhQ &\MrA ; ЅBi0nla@sFÊEWnܭq] P݀ߚ: iME9[o/},95'c')Y:tA-[1h/~!t77)Ž;a]a 4doƋݚc>A,_C` GdߦִqS G6n;]zzmV& 2R{'qͱ;-LY CE*(%!N i!;Y;J,c8/O$ok9deoL8MŰi)i lR;fBFښZ LFdLZIWwcQ,OQUG6[YT"k Q6.WAE=>mkj"q0]WTk j `֖4w;tAnRI$ t!ɕ^seE)hmHb/e AGvXX~ "cs4E+,nd;Z+C%W0ͩӚv ,L>iY-?a2X>*QVfm$ 2FaJOkwpVcXG C'EkxNLX[ y}4YXrHz΄{v?4Z9zLB ?G俳]T9Mc#^%tc3jq`p|Zᱲ~E,>c1$%.GR# j N#Em'hꟍP\C.Hh| 3GCƆ. 0}z}?4]ð5 eL`ϏPKS%8a;ꨪlg,8+NRPmͣFU䗉2*bL,])75aꥁqj0O26kTrXca+.Ztvƨ"l6W)ij9pU0=#Z8Ƌ 4a}|ȔE.멙YK%;kňOÊ8Φ̞3g)y\ WP2 4pw5^W9F-QA-#+_"8Zud6v>!QOE3+^t=*]gqa!7%Y%6bgXpV&J\%Ym\,\1;fq%~Xj8v^jy&hA[˯4X VӚM+`9i&ځ746Z*gTPlghq-JrI}Ӵ1qXrpuZA(6R:ZXwsA>v]ѕ̒ވk#PP)?r+9NitBp7WJ\weQZ^лnzԲ?rICK+ۗEps,GNȉ$hyˣ nG.I4Gan,n -`ȹ:/z4|̽fFlPvW+]a+dx1'+>GNo,?q.y27P|:WřM.]EOn~OGPc 8 0tm QG394 /.s-S8Ņ[Vm:c(5[@Uxh{ @zsI]xlsW~Ǘl662KVeCA 9+v6lvTvznQG?f#1|R*ZVN6;NWX({mYwYØ&t"/?_䒏i2pGOWwC)[l#=]n#K$1TߴqT[L ҇"cin9$ߤTMU[*fz`r(+MZ9W1ѧ$}6cY8y٣#GS/ QU4*Ib.7q~Hvٚ1ÐT=sղ/y7 Rg;z3Dz f#QԘɥWI+#q'Ĩ-J$NcK^5"4.[]]#2MJ/af]hx wE{z>DZ=3q\!蓼slǎS[z*ðF(q;ݟ'h:*vZ nj*ICܮ풛 )u)bIKX5,Rv{ SV7@ت榤im[lf9 s.'Xt;I^yy]HEW[3b@+e)#\B13R;tB09o#=Cݢ/>JOo=f5SAj$U/Ϩ㓍clL>"04Yr2xҹul,g2=v$*T|WM*2ja_=NH|[Y&|ɛYIs c@>V8 *H'!U:FϬj&i,x4@eZ+[O L v12!hMG@r]qv5O@ ytC%j^ڮI#5R2S?d`8DNc[%Mrvn̰Hë (pz[]W{2:F!vh7 #f2i/;3zxPi,'}uS\\F,INk# 54pj5xS~4cZ;VM!4s(Cn.NÚn{:|>ћu+͟oGbSI~nю6lȋWz5^n쪤Tipw'AIH.:GI'ct+sII)uGXn9 }8F.oIi$IFӊTyY-ȿ#dn :Lm+['跡"f-QxH_Kvn |cQ[qC.rL|5HsuP>Jpi>$q)!ձ>K96z^ 3]m?3-ݹZQDɺc1W^GsxU>mme5I9 t]WdʬWpN6 5;% gI!8j-cctn?ᅌqՕr`/CG\ǻ7` HN20tsfV8? cEFOw2-cdqTeeLSK-bG%+!y.H`5`' MlC\  `6r\p؎%)L7'OZ7UՁ͞K]MiU&{r;ͧg_k"&谌*k"::ch= 4?v(+WU͙wX-T4XG#K@7SlJ&:kju`4ޝ rvyXCMShD^ie3Jmb ]ᢧ;DRěG_LX%am{I\Bn^hMI%sl&*Rd0]8\p'䴲c9O,Ty%sd™s(A M46ӽ5!2I8UG4&7rkMa@;Uiݘ EFo{#q[BR~ DO kBkaj.db:rZu,xjˬepЎkG3$̛sYٻ3km@H,sAt֞IZB_۪ ʜ2)$\RhZ*ZP𖲃̷q"|X`I&w>#JG6;^IDy*7BCՍ#S䟍ڤȩݘkmE$g)Z" u\F tu' [Bd:{*? E"]X%g&psĢ]A{,j֌eټHMzs ~s>G8ݐ͕L#X+ADF=Z ZdtJʅ@η$YCc 8J z7OLc1a!+5u3%|D%1;)iVإDRLjSflݟF aR#}n-&hFh#]H=BLjy*MMC)9_XN{!1Tc'&May]imݣ lMwb g&έuEe%n3'EDQ]4WVb5آcF%.8ɧ"AWZihNg \d۳%GM;RF,4 !hR_0ʆs#!kfIs/r29;G |QOzMA1r{;TRRSM5K:Kl%IMYIOU@h$X;ꅶK-U\ijH{ !t 8jEkc1k*9j,;,hT_ܖj!lT`Va՜ )q;N 8"sc&IH IŰ'6ϤtN{rULSPY(i);ZQѣ3gVyI2+Vjg='(=+/S{*EWML{p݉<+,Fi[ 渚wX' )} b_a2y^k{:@ S6e?BZWm] 6i#ʗ%Ж5ˡCV? cqGRodՕ9xpJ}]4]YkYu{ie5CCg 7U vgKF:j8\Z8eLuزSw7,sKMzW;@^y>>g7 W>Lfß-2 ;:q'thg"c98:X=ڇnm/8npg4ƏํO$P@%y qg5]~Z9:<:u%&*Fm2CsXZQqr8=.t\>G+`@٠ď@b(> }WMڎA17-AQ5œE ,x<_&GC\r> خG9n8é_ 8臹'U0, ¸ ga|!Td=&PaC[L),,oqT~ A؅]3n&5۶4vMOb'd4sqn{. Є#a`~$xd c6 Psi;4e $ı*i`|Q߳^-bS nʘT cx ̓ e$xs4;PA=_6(p:e_űTRwkn[eJgK\_bf%U;SQ+L} 9EXJl37p95,gwƿ<^M#v]';\}F{+z;mGa1JZEƝW-ӌ_. I_8QP!ֶfhJ|4ȮݏMɲIHfaha=5:єpvpbW!+&oplDI Z:l'CPʜ4:W.h\[ȡGBH)S[R8C]gZ6;Y5V|dGYTeaNGdYwd_W 4H, sO^ktxwPsV\βkVG=PbQޡŸ{<c1 h:lB7մYA `rk0~/ weX)Muʔ[ grI'hOaYmvQy8`THetG9$#W4< s}3 V,sz*۾Rζ\ޥ4uG0e EBh3[v\8䭶% 1Kn7I$Ýw]\9BiH3+p+}}5M,720f NS:<'לWE={ꛄ&X7P W4HIOuE=QU kM T 9a8~?6>g<@ |KOX1xHӳ:-Š(Jț#$y- ВSh.,&wrL;iji)eX s lRѻ[;%cm·q>1VG_SR< q` |z&8i*)*͒cm\ +)!~hhZvѺ%1Uߺ݂Rbv8>vetzj0ͳXvurџ},7vI]+bxd=g;fR^.Vl2nu+\mr0̵f Hn 6hS 0:k08՛29"?P,nϪMϡY79$ÊYm"˧ӿ;<ޮ̭E|g0,S;y-_!ތ8Du1./Q9VqešݻIYػhLj#uD9I1:hͬࡡ;/bv8 ˩]~md`ncsʁE}૒qauty>aŗLV@nVc`F^kؤ:mt%eg&Jև?PllfF vf)ϪMϡY79$(Ӂe<u_;t[Uy4܀EA4N@ds:6gkXfaі3r\+=Uf6R>y!f  QSʨahYEivU,Ra $MMvhpz.rw]˒NQrlO%Z9^ c ݡo} Ömuysxt/ f~v˝nO5KߨUے^: m<6?:蒟Z׌bTl6&-킣RY|e)id*LV0! N. gV<ԊMٿ74B<2`7m?۳O:#hڣue,{etxQ9rE<]V':b/} 8;/ l`, x |N/:CGE spk"8(k?ٷ#d##A;"~*4>G]AvY 0xQ-診ٛX7C.WcM__8}R48Y/7w6 _/P*^@å,a jl6 }vaf0{_Ђ͑lyt[aTE%*aTsjs Du~Bo손z(SbFo!/OG\[ l?]8^|\"}̭tL:*ų_I!٭џ&Eg|E-'h浭%6 XԨpu,X#%lg]y)p,8c!-iR_KƬlOami#y50w, &aicV5^@i[N1EQ},IJ46^2]eQvY m{)O(! 8$Ohۢ;;\5AAY4xcy O$5dNIxiG5٘nuRbsIcH҅p{9F~CG; [KӤD66םqlսmLC.KBnlZ 35\=KL00emr2ȊsZX$YVTK!a.:i)nie+m۶Cdk ߽nvE t.h㒕>HV)8hOQKTC Me |Jj41ٳu56L3)#X] Ah3UNA=N+IkTSZfΆ^ۏx/暊3΄7J1,3kKx<}2)0\>c_$gNѷEPN! G]8sj#ePl2:\K50cc1fd(ip8idcY$ls2 jUn` mbգv̄h9i%坝M7t}|}=)9eé۞FlQD3̪$#YĖaKTWvSҡ74X *%rUԴ^cmI?5t|}3Dڇi,qjNrFrOdO͵̨8iT:x>7kE(x@YgnV}ll}qH =?MN5Cݑ[z"@K\[2u=Z}ky$ fW ptqrAl\я1~4dq}VKGOb60fA=`<%F5k]&*?, O[YU,dēqPE3Gv| &>(qlJ}==gARAW;&Ow:Z,q}2] CĒu2G7zmyRF+e,2} xvpD, kSqi&@DK)`9h)sC"T};c_]\{]vG#~Cs~Z= }iye p',2^qc.ʟFS鏑Ń}J2Qv,'x;QAYݭfYKE8_pVh!tX<*XC7\>Z*l&=,9-UF\!2NeEˆD.*Ά.I\n)= yEwsE79$@$ܮ9YA=VȲ'FqtC׆M.".+ lm}+^{㭁qz4($+s3W] IL\tn|;!mKAq%;9X&񚶜M|JF nkN2ɪhJjRC^ɏ~$>Z H涌eL ݈=nl)X!qqsHZAH<l.rYQRuͨ'6*h u: Wa mV$~(r&(pn*2޴h+HUsfվȱ]p"TmڋN[P: [.h'gOT$ s>6|1_V$˟aalu1֬4}-aͺy47T۳=ޡ'#l9乣*gW4[zb.o4s|%= lQ[Ю, 2d8o&ܮNQgGEڛ8Vbٚw'@m4Teo`!EGtzGٛbo]5ҶȌoF{-N)&/-q&*lX`͉ʱUM-F4 mLTmHi{ 6[|Wm_Th,4K;g>.CsxH  ~am[ddQgGH=Q2hia =Ln11%f˞7taN \|NcAС^`\Q*SM3*Cmoe,S'Fw )٤v :4ѫ.u94dq)9ׇ& $:yňSZ芗\BZzݫC{YK)(N\=%RFG]#fە\dМ٭hE X7vGÌO/4g]ᥥ{-$1 qhyjm;dKG<`w,eHۜG Bd7[e ,omZ]&{n6 tWCQ8iHiRq((+܈1UU4p]]K@/┚#IꚒ*1v+ic Dr}ue8>)~79qVWCO dZn["OiP, i &i֥qep[N52 u>IKҴhMIWcpl#G\ Ĺ?85t ^3[4r =5-YQN[NJ*ֶ Ӡ8AE+b2ꪌeg>LB,/J+Nc=eL ǁSK 3f7?$,rqZ`}y JqK4ⴀܗ_)N}^4?%G/0@(/aT ǚ`od9ԕoEAc4х 6Xso3N!B'B8>$'R$)$p~x]Q [~"Xd"9:d$H7/c).#,yb&ʺ1l\IZrO1{TX-#']c+=΃MVa;bdPO…Om&,0%&^ v8a+gD}>KG1FGE3Xgoѱ]V14Hs_FLdN9TbBzZ vh^MqSQ##kwg(EYӊ2)M[Oؙod8;e]Qsg3T {B)q$uə'.{ϵ^odvS7+=F,$Q'H>QtM'\/KE8>Ku[1 leB󗱔-A/R&LCiў5>! UgqLi}W7I~՜ѯÚuBi`%t]1;=z~8`c5&fs[uW(:H2R4q~R$O(r`脇aٟK-6Oʈʗf֒~k;UVLӿ9͍ߣ|~jefHHVu. Yu$ěGPB<,5C]dW3OZqڹQwGDekKبH@EqDF9;4QmnlLb{uщLW9\G]e%FǴhlCa &TβQ~m¤ r,l >쟦L]^ƗF<9GGM7Ct[IX̣ 伉=ZFR|ex&mw `9Uy_ඇtbrP r_$5:d5D`NF֒(zXq<Ƥ˴7>nB#5DkcAi5qpKc:f<*G^)o?A2C}~RL\c1콓l-n+2P>󾣼gMA/ XMӚLVp25Rt*,) u*:! `Ln< XIEm@@ |MC0XpFEhpEwzkdc.w۩Z#Eൊ0hg\~g(^rF{ wBG*y6&tPҠa:ւaw-EԌ ܗTU73\AlW=,=E[q䝡v`O_Zc{-ŤFTt %>]^4Vi %܉;CL]k (#hmuWD=t5NbX_tv:D[&&gQGm컰捻-:KV'ْmtyo@dx˹(mKcsnbaMYZPTnhCE ? pN"MHV9} 3C  <_ oq4إ<hat⚕C' mhDô$VҼWg FWLb& ά&͌QZI޴nJ\tlRKU30L2M[fyrE#uFC-$y릞2zk c7m+_9Y#X $e9?,`kc%/+<}p ?GV/bK3żAk?Y+2}حnM҇y/b0EYrjY1x|޶Y/G _׍D\$ *[j>'F"3@2HǤU-)ͨ2̬Sl/Cԏl16LYG( aåii_`8抟$3rQLb9jG/fNc;r䭱!]؆{[E)47ךid3f<FqDM|e.7e]?ՕnQ#Ge^kdz^8lf6(X>TΆ²bbSEnb?$cHk%˰`SҾ9Zc֌elwVfohS%mrfm#5x W]Υ, _a8\m(OY23E&W6fDh y,Sjwj ~#Y>)hn.r}M{ٵג0we:.YTW :)x9G~k%4'_2 >l»4yu'ahЫĨ^cG4T1cV1\F֚e}#wf}1M+I`]dd.sBBͱWvYK5yoc9[ 9)I 9BsG!t+Dx'z4gAbIi# > kG\7 8ŭ&>'25a-?9&6f,:9ѵνx#O&(c5͡B6 p'.d'ή_YPa)#Xg[J\?Ex~@ǛD9hXrWMQv oi$V)P)44Ԭ$1epe Ī#xf|þ9  #&lBI\!ciu!<혮q)Hc.94 `EUa;3M6pN(rVm1Z*᧞6I(g%9E*TWaԔpedRC_kx9bwKX_>QE )PGEMR%BÑX,CY9X٫Ȓ8.q XjTsDz&R e"R 4Ԇǵ׶rW2x*L;8mm4>#٭YJbUv`;sSG*YRFi;jzBt &ۀ mLICo-l%(+5Z9&W#ٞrJ"M2PofhƎs~aMlH 6ӕ9"eAlw7ō2}۟D5zZIQ{Kn5tV\EC$ r`nvqdKbIzTe9nҼi)V`Q6]Vߖ[Ģ{*),4]ڄqh;HߚN]X,KɎDžSPyiG:K<WpVS u5du3Lc\n^D+ᴮ{&Gשd 0i-@S׹KzEZ_F>ی0stcKw|Mk8 ñΦh.̮\FЌ{7 oxe%ӌoEH%$~_!|,) trW%WpJ &Bpq$y/Q_K{C<élr{L:<%ъm1Ѥ:pgb;q,\K5L$5%76?9M)>nOU7^`<(ӕp6H\F6e#6J?|`p7ذ[rx\=~iew6<"#]i6UHt)éK@!&6*\yq82RA >CًjхR=#gf(T;y'{rNOmud8@YiqU$5o24]=kj܋\rѧT]6dQECBƴN`X5̞%e]P^lѰ e-b o$2+k35ՉȎ[BF:MQgbv]UBAhHC{c%MكmaƙiG?/tC!k9P&xe=B 25=?{] d|Csl)S;|3%lx7lv^ {/\vwz%RѸ-qkIb[7x^r.w^zQxSr&|k[c_ɠ&K"kJ.Wgw |͟HLqnQWNq\9{:1}i>/fH  52*e}s{!'qdet8XSV*87K\Alaq&v]\F%TFwlo-䶎Fqۊr,eY]_Q,K槛b|k`ds= sEȏrɾnɨ.k1ѵ<נ8\lz2<˝7=ܶYY@ 'jp ;A a891l$z# [bo;G2d; \R{;F B}<]3˝%eG9yt7.<ӡ~I7y ?YYb:{qfa[IDmoo"waGٍ2_D"!Б=O[iɮGScCd^4vQKH#\?6N_J>9p6I'zY;Jy{t*%3TqLQհt_U>|tZY Z8k6g:(+O4sFQ}Ϩ:*I TV1л׏OE/f H w4&|38j`7[+dvo]Fq7B,{\ٖΌJN?l4io4X05ၾ' Ġ8߅YG?~\N/80ӎFʱV'X1FY+qN A6K_\r41k|N,G8d J+wSŊ<,N%pbHaРA@!ŋ!q#\$pi5&)Ty#&mUD,l:F٩J?guVz6ih)%t51"Ge;w_wj/N>xL*zY5L*šJ|(;w'J'o'>7a &SQIKT`mL3DuN0[ Ü.Q$\,l/)i:!{_Hai+Ac*Gʆ2 '_!#55ia!J~ e# e Kܵl;+y#?uC0" wֻ3'?%ƖI|Qeyvwd-jO`lQ$踲vAR>ZOpg H Z9*[W9;?N8V`i/Z.ծccDSvg'[$ !ߣv;\)XnF h?'a(/fd#`>^N8-|gz `;eM&`]?ru;gik%g8430X.wf+J0$&R}SCh#94ꆛܴOl +ZኊDq+9šoGu=F2v962 $qlGtك8nplN'5`icfJ5 RJ·z2-(␼eO$x[>fMbcn``Ru/glJűK-λ(pvv]8y=lkۗEmǪd 3gD3QXaV~T^"|pmK<a ,FrOt`ڦU nӑp q'}o˴]jwA=dTk\'΅h[avꗍ{p_dxܕ=Yܺ~"|8[-WΔ|!Q,԰FMKs0`DiEC[J=O+fsL imFˡ*9SV!LMUgBff; \9{;!t}iWB̳Ԑ@ $k?BZ{M]z8m]rIZًMEW+b(9]5'U1V6 S Q~xISfsPa=DnZk@P_ɖ2(Nd` v7#J|iz:c1(^ ZA:eIH1(%㰘vF?eͲI4`Aߒެs2| [hi;#ylm܏iq܌ԁrBE :w6N:fԇRvk9IaiVʮ5HewpK`b4G{&W脨|20n4hY*tKv0F5QS8e,8}6ӨXSO>5tZB-)&ɚ ֑ c%Uc#`ȄɊXȣ6tHiЋ B'Fpg-fſ᧓Fgwԟf$9IguUEv#&QIvpOD8&_|IlcI߿0ewX5ZX =\ UǦm<腁FFCOߍAqˁZG*3.;G^b]u8{+JJ61 s,%\=Cf+YbL |^1kst/Q?DpYZ}įQ=Wֺ S?W]>u2_s?xc94'_s?(}^͆CbK Á1䌲bqin4+k0;'\Ut?far7\3J2bM_ a§ϓ D=BJ=ot-d-?G !KV·]-ܦdExgiX^cu$s]Q%f9#D5-A6W"jٺ}iHA-CsemF—}A s&B8}#jFEt.y2∿-H15 DGMe\9ϣ1M[Iont'pi6OG$ʕ}8i'x<5ц<ȣ;k˃56x7C\fŤ>A?fDTXy }VT0pEwgRB^gT}%}`bx3ណ=ddrH=C\Y\yWg wŐOZnmkC-Y=gBȳ@ $*ؿBj{E2;]ʭpr Tgcv:!īGun3ʑ'ldpLJQP3,Fm. T)4)ƶ1 .ďFƸC%¢al$PK[KDhl?l۝l9cqbc͒"F^Ū*SP8s*e+MS'Kq(/m˸rޞn*+aĒ=Eh`_ū(C#@f1T쎺\BR 4rVA"~Icfۭ\N-.EۗS3%Sc[,rQѤŝK a4s1>EJj}D<ے?d_:<.3k膑gh0M(՞vAqEtu,SBbzꆳmAvK*I%ĸ)^I10.y`9~+=rtꅪ:FG_6>A Qss[e.6k .ւ%dqRo9V9r4A-QFH'-e.dM9Z v[i=wGE/eH 9|@/ցb|)ʪ#2qpTFوTeco}- Hc~,$u]=x$*"irlo\;~JbbJ5&e3ȕrl<ލ\39̬2:0ƙY1s& Y0xP, ۪ L3j';0ugz9D6bKIq6v i7{m,?}? 14!+nіCS&g%Ұ.Ip4>/\\6[csdu祬kF urYj#G-JIT*b"o[ 5mTqaLcxEauL^NI>ģgѳcuG^մvw]~Զq(:5D%aPsК^ ZAH_ NA hr>QNo4sDcEe?9 rEO]*%(k^ o\^*3N3>A|gнA(fUH7:.1eC}2Z>[ 2T@ $@p_ |%_֕`%}ewc-Ku:omYmZ(bT̪"k)Ѿ7).RHq 7tCʟ{3^JAlL*^9 eB8TU5؜> qꔠYbNH쇎I f;X^I<y.r34n붎 UM5m3RaYdч'T !1eOMq/ b6sL?Qď<DĜR=a/]R?J8GI|cqSv$%͍CiU3Eϕړ[btsfGg#z9=_K,f.~N WeAU孨2SWd29Xۊxn?񔜦G8ŶD%6S6,*)J$̋a=Cw KܷIZGY4pw]Qi4euЭFKQMX_c %_ȝǖ>, OYRC#晧sr0ֻ^-T`E[3sT\,L'䱼\:r_ycuvpDe$g<ۉhtiUD׷`ɳ4 a/V`StcafseՒ^'R:@8McZ(a5>'?a˙̗.9F[qB8nRsFO}"XUL҆G>A+7$vۢ쎝T183ivW-cƻ.^ce \ЖՕȵN[a,=Y$@ Pu?@b՜j]ՔI7'lΨD%CȜ9nU /"4}Oy]L+ (HK Mi4/,L4`Tt7xE#-1)s,wDช-f0(m i(ԇ çi_Qt[9;; R7XõC+\+O[A-]lmsYq '+Qf $!̒W7fh4j$}D(λF;ab +;?OI4ê 3=Ьbֻ4K{>7Tv00G=`s>*A$@mVHaBp9d0>!ۢ8&Ȍ2GTѱ]fdB2puَic8V'fJ渁kX↲3D59@ cZ06n#wl`4np/e4aVqudgg+61^2ʺ[5L{74OOYؾF0gJ6Q'h=s--Si#hkogT\oQ;(k #E[G(asweiG<&(IŠB.йjJ*bf&d6>+tM=0<.ts֚f Ng6zLmMMmel&ҖEr' K#Aw(x*2m'v;Ek@岏^8tPD,9q3ڷ<͖\[Ѯ7 |VY, N,㸕 :ﮦ~- C3PŴʖMߐ+B[b'Th[)-p׏Ec/ 4=Y$@ RŅIWqYُ"[#[?.rNWѺINVӵ*6mZ"!Vh_e,Nߞoh%*^h| d^k(YGoM7Sy $e IxTɞ&dpio Ci F9?g&F]HJ*ˁuCb>&ʩ ¡t#`wfTq3.qkiIz%&gx)56K~ QGpɇ%/c qdx)~~MlGx0ɇ/U8RDae<-)}"MJ9{2InBE*+sar9 K*qgU)^/9pw2|?Y^T>!a'AaӲ6ZOC8gQ-S;NYȮMIZ$FKZ v\MVw+1JH*p9ea;oX?]핝I{^^ږG?^ ;Z" l~? 3;CFd|2raHu ?uO. l:J[!w[-#-5Wٕ]M3ەKch1k&RI3 Va0|L|WM'<}E7}lY-l'ҮawqT_ c}֙4O/59Rb \?o>TqQNZtf%dOSk,qg> pk rC!˚3{oM(:0zetNQnap*;456d5G0X;%n\;`}cYzH Tnx7Sn='g0浴f f`AGNkuYge|&1*\;6#ckA\W~lHl_& FFzos* tO+$R4#uCEq4g') z-к杊ʘ; mɼ/!v8?+H?y:jze5vzdRͫ}D#v4L1WICWY(WlJ&em6ǂSGf0z:)5RԴ/+z=Ik d|n-s-6#{%g<||w3J8K+k \>_QkG49ǪNAYZ[^I^pe" #C@ $jz97~H^#kp[91-ɶ"[QT_'h@湽Gu`> YGC E{fℽ^0HB Yqv}ޭ/m ;1af GNOelgn(eWpmUt\EUq#kh7 L]Q=%b(q2 `<){X78?7oUW(>ɐK)EˀLy+=q7Qm5FC@~W6nΌKMbjjY^Y;'LP$򽚇WdNl{jnVM/F侞7HN:,RTQKٯn)STe9ZѥQSwy}r95cK?8ܓrzZ*I;iwdwg '@oliȈ6 Z>p-q*h-E)&HVٍ߱MWFH +f¼PoGN.k-dl&i?JOgn;;\.Q.wcI(9RqqGBNklsU m{@ m;3?ãEZ<7ތ+qs7Ghl͒caodPA l)5sײ-0,g6:.FDz5?$C$1]E5@ö:G,GF^l-RЭƯlpdpF.h6G"ʡ__4XUq =_Usdj캂~ev&ret)õmWc WEGƸh@[qF?"uƶH7-Ve84*1u?,~6pQ31gqzWxg* 2Y|>{&X̞AT3X!҈7g^4}a討XH !֞Q@ cr>&:vCr>UZ9c6qNoe JTӺ=zu\h?s!,5m̯?ޙFie@M:)B1Ԗ n;Zh6!'tšDi!UxhGG t/oYy4l6~kҒ9o*TMkŞlB5{LM>+u:2E!7(!6;:tm6Xi[@?7\4_\/cFG6)[Wɉb@SϚm@oȮ8wb3ڶ+to_\WՉr`K.p7Q֚4&k^TkM!J,tkO'5ޖt#uU%LNVִr敲ۇtŖh]7S:7S x[\(zQ⃥5%8t1ޒٕj~EZh1zBeh 7USh_H\A#]l`6Y,>t檽ܷcᅱ9Je mZLrRe >q{;q*G>`,MOY@ $@ X< wF^.휻1-Y4guL筌'}KuJֶ'<79ɈӴ\[dIL%1<5*q#< )Y0!ͣ9S)citgN!H=[5-(( *wٵ<)y5OXqJQ`kXZt ^lkDjI qPu 1K1?Pr=)w~$,l )'f9d:)|I#$O]VjD. e4)3ObP2d7]:čԬЃe6A?3]W9v~CrjaױOpX.'X闉\.vw&5&N|Ũpf{;}]EF H Kn(.?mJɑ[26q[Y_h4F6X\ VyNN#1Dƚ7J,9۟3sj0G7&Y<[Rp-]]$u-7+(4#~=O@"_%| ]l洃&>}0k@h2f  tt|]i?tZݳܽ>(Y \IW&z N+56[TMLZ?$EI ]4l1B(@GߏeO~xDu8mT21>(B7IdfkvpWti#""vZ[E?s=Kmn-V)#C쓙p >kaittI5\Tt&B[`,_n:;?Taf9X Wd/A;vsc)b|dv {v%V*%J) k3AP*N5S⍖ -2I dF5`mּrCIhReHu-(̚쫤?@FROx 1ʞE,-.4H'F'Ǝ@nD>fͽ}1.|ɛbhձHHӳY{CkQ- [ =B ;<>CL]Xdu-8ht]I{gz-i!P2~uTOD$ I<' ٣Pae^$kr8ށRTFK  ⛎'/',l|nb-돉]Qe- PgM=.0'4s׫`G9vvPZꪫ^)\1QkܑvZ*gbzY"ԙzN >{{L ۶V ?G$GGkl}T6@6e+)%\]sEhgiE4.lSy6zk_ OxBZ9ވ,,S_ddzt|r-{u枢Ti):/sEly+YT%3;ɂmsNv{1:2Dka]k~DM雘ٷM6Fȶ=)!awhò@IsiƐ$/yԔ 6DE I+Lv-_fT{.C^Èremnbd  qEmFFfʑpnHZ3;g[K8jІv5H_k%6:${iпB ت??M|syW\z9r~ÚjHc6ͯ;쾕t|{ S:Z {v".Cv!-Pj:9AtEYsvTq\c}[AYH |#gӅyWM9x?16ȋT+tl{N;͸clIMͦzqaxo+>4^Cy?K<@xknWNʂxk?NW TZ]C^@S~̧!؜S'ƛpƥ)R3ɑqѨ lz]ѣ흾i{'3#eDӉ6_ҧ_^||ЕUm/'|^+|A+2ߥD_y[r6I|K=Y| &'YNGO ;8÷>*gjXj-5еrvt+w PNg j| 1ʏ/uZ9$=yC6) >f:\4D%m,-Dǚu5gikOV}GRJ\~&.7M`Sb:lױAN>הCA87.)sA,:m샮Jh0;RjG$yR:E0Q6gˇX%aM-]X e}Z/V5P[@4S~l{6vZtF)HTՙ]>*"2]|rj#*eV|kZ4{aMala fYfT lѰD=5="^g|U( YYhDK!j[3MYJJ/mze 4Sl0EeHs@Dq*?p>ẪX msw1xSGBsi0)*^YpOa>}V4v=ZڪIYN|S:=V. CkG:hѝ#â$[@ $@=鳇]`&jmIt/lA];&jң7vqq #5<HXG'<TٳPkn_kX`&ݍ]ĝbY}(H]%H,<gEQdJB,+: 4-  .R,WahLAT8nFO܃SmcM؀UhtM:I!- j\6ʺ&{Z "ke,w{QݳYΣE EzFvt;已PoSL$q)Ka!e* l,$ PX^*CKY~E VX$>yh9&ICk9a{ufV8fh k 5d<{=\/K"3=\:y%Ez:oKEj^@6TqyYgou% 6uw ThnΑ~,3aOģ{{(?hmod H H4XȽEƾ8ZlhXCtő^sMacK3LT5fjkk(Xrzi.o|)؍#GÝS-mQnM wFVZq3RN'"X JlMaMopZA-ҠuaOڥj}a}$1#AT | w4МXuKl*s; 7Rl)@.-Qɿ _$DBI o} Rۤ^['E ^(8nRżӢXK+} [$O@4M{f,EF- Yt654kENP;%Hqah˚m"NMM+9N<[Țj*+&VGoIV5f)HMO,#:Bb>CX92H Hh{KH(ɽ"p{q$6]'d9AR=2 RqAHasKe-:4a8L9) eOʬSV?cKyJY{Z,5KȆ1;&xwJ]prl~*zR$Ym&Op$%~Y?NhqkbC-E䨧 +Ty/ ]3^D570lS]~o"LO>[adX&TO?*pmmG5!x|SWؼ?ͨg(yv!yȼ,]4 ^U? +^!團*-bRdȾI0sdyWxA/⅙|"{4d cL*cXZnMQEl3US!2G./V? wou)IYJN,nV9֙$߸rvivxrkXR ON?rB"[K8f>[4zKIp>E}b~Ǫ807e( ZAR71xuJ;DYHE"`' a8F!S$q0Fq(^19XXU\S,!'@0WW\x'!+ s/`}uk ='C[\gSM| ˄@l91Ƴ?܏KB#YGb/CƉqWsdpBZM1 bnl%p9vB cDx˜\3 7Ū퇒|ӡ/q:0={=>9'{td-kXЀ,6@$@ $@ 5@#$r;_@C[M9 ǡ-1އ! GvJCoN=zՏRf>Hz51@7-| _O:6 薈$z$N=>Hh4P /L:"d<@2<vH`1YNH H H ivG?p|a$_p|@ B~ )` EG${@ @C#evL.ɟt|͟t t ٳ@ #>@ #zr@ #z@ (:,@ (Q+Xt@+: `H H E4bbbbbbby@9@ 9@((v,РBrrrrd(v!@ 9@P 9YYYYYYYYYYYYYYY!,,,,,,,,tilem-2.0/data/skins/ti82.skn000066400000000000000000007033721220200411600160300ustar00rootroot00000000000000TilEm v2.00`TI82Duponchelle Thibault̰TI-82aIoP45kK}4J4H5PG^4K0l}6?b{B{-lz1m ~  Pc /$jC|$E%E%SFe&G-[g~z^y\|ZT|e]{-h{Wf+fzVb+g$v&$U&f (-;k]x;a<_;Uad?gJFIFHHExifMM*Created with GIMPCC"   c!!1AQaq" 2#B$R%3b &CSr45cs'7DTdEU6FWu O!1A"Qaq2#B$R3%b45Sr&DT'C6 ?%5PTe̮NS2Z *̍ߴ\oPхP?L} HOoUK ?=c@LpIPA?0lF5UYp?SP*FRRBN*3=?ŭ|mqڽ In ^ Mn걂ANt( MJ@f4/jmۙxHygytDڜ+2 $TV7ۯlT׊T\9ϨHm4` 1_ 85&::Q4}kj\G1B JTb&ݯK]Oփ=YYfY 3@ ?)Fqx^ץt;{uSesLB68TZx]8$Wx~X}$nF` }~x>5#im!5HPXA 8#B]%HŠvhbw&cdCԸK7/Z JȷneeЬӺQgr`@`ܒ>@j6u <;Lv;n*{Hg]pIH<Amn} h/TeE}w[8cê*:M_ukCƥH@<:s~/gKPjMڝJm(Mo, PU, f8ޣdvЏuW+34}>? ii7Xt%CDA F^mbu !v~s33YA:BKcTedRT+Wb䩍F `L~>%C#`g3Qx`AN!՞ 0VSS"HjI= 1kl7V\r|pnd@ gXRsIi'χTHB&'#}_-pO;pc j>ؾ4ʏˀ69T;vA8N}<@A˪d}*L/O׬c< j&HOq&>V0NNUea#ka~< {V~Ĉf$hxnej&$-1ɘ0OgZ3`>]6c&x2AI{~7,pUׇJ9*kTv)ko\T%A-A72#קӿ '^J4wm}=d dYs;w:y϶!oOJJp'_031_6UO9 'L8PoF't_3IJu/-&`D>ǎS,f9~Bl/PB /ty^?tf #rg:ej)<-ϑ'׺^8YƃA0h hN9S{ #rV#^{3m_[6JO']*ze*HQyf׿5?2RQ®,DǷ~,mxd3q}`N;m^A HI#8dL%S'HTl+~TE:pHUŦ)37B"At/>TV&?O x}ee*1m[D;I`IH<򲧉ka \R9@$DDڏk*- 쐡o){$VR6 A=76 ZSJ7pǦ{P6QnRc}Ϡo n`^pĘc53эo@JRrLO˞fxQҶTJBDt[u3l PQ"RnxOo8>:0PR2H?ƥxժ+ZKb&xY邎{Lz5w jʖ`*3Dא׊2)0'xg倊Cm yzׁ0_b& c3& 4+i ϻPQ c8j):ΰL虴 >Ծ{ub|wFRJ=T#;y\_#$W#鿗Lj|qH$82@mA1W&"6y 묇6g5bI6nAN0WG`s#v:yĈ8( 'mn P#a!oD ď͉}uy\N֟gr k`Ts6#6;*8u!}OH:c9Dmn0؃"s=NLN"As0"A鿴3ӥjz)ɼ-(TjJR%j-E" M#o\h>%l*EIag|-xjG QP<$::BwckngU `6#?zbT>=ʁmoN](վq 7wŗp7T=+QWN9slVMH=;[\kZ[PU02 &DI tΧH~r9,#d FgWϴ;˳ZMjuY{!**PC _+s=3Ak5!mĬTRWA1t&uM\82L Fzظ?cg?G*:A%[ ot>gZJ.,RI_1R}-M0L h>Vzmwk[TSҤ*ĂAĩ5RJT{MjluwN~r7TM%$@Ccq}?1R}Ry>[$&q3BxA'GR?(ũb+$7ĶUD˶-*v9k1z*-"02Sdr=>a.:RJaF9 [u?eOy=/a#j;}έ& r=139;qRL8RI3Yh 8fTu’$muP4A֛*3^J|qcUڥNm d$tf;4Zk4u Q0u<'OFVҚ ޢHX9Hnǧ!)4! $qtZmFVXIy!R5/z^eن2ejT?3Ӿ NJ=R%=:|Ao u.*1! Y A<;!LIx#yU/>gϤ[? nUO'ǂ,wZ v~H0F g'&.,IS=`Q#833sRO*%ʬcZ$PM'=1;TLl 7|dGSuoө=㠎qហv__ H0yϪDDMՖ)+$0 =s<:9D-ꀾ&63~`0q ̅(bDX^8p_zM>|>pѥ nu2d$^tx&Hc Π=7ğyoI!V~< FIfmKR&, z:L0dhKf@RDBFR$6:>Y? 'uG>stʠ#|d2,A}G]m!N7e@ s8tSwhd b~F?ykB-bn3o!J }/ؙM{TS63x2nMm|xxNRg2 Bp#to Th6 9xHo5Gi(M4v'))m snH8mmA۱Ӏ8HH=u@T"s`1vh8'8>8烔ܰZh 0>pvJBY&m[\/N#L*Ѵ)HI A9$ə=)L0q GuG 2ʖEȹOcR8S}s[]Y30$tᓴ'I=s}po(]HF8}8䄦 N 1gy9d&63k3aE(j rFiȨ_eL%*RAi8+II33'c}Kc$y19& k0ʂCMID19=@!=aLm й22Sΐ^yEzT;U!KiF6z[/5W).X2V2$rIh Px;ca^`rqx rdm\vc'mG2{;Hȷ\-Rgq%*Lwo| T`K|2ez>yJH>rD|ӌ.Xu JXڝx[tZ+MXA H׾K) Nܘ 2uPTE3 {ޮd3XI{zYt)&,@;vTd uhm<WS䚐02>'q$0 A1:}AKw #Ǧ o-HrpMrӹJ)@!+Mę8 \8U2Zw+u T_f#iz24CZ:y3&uDd!Ʃ:?A v-<87֗SuDS6f;'wV{UaW"JdL`9ci(ЀVyxsĎ+utc@Q拧 gKnf${o|6J=39M0&uԡG8HRL8 8P0wvܣ]RJDL?]46 BI1L iTeʡ^}-{|7=cFԺo%iTcԣHu{LשyQ-] 1Ƞ3؆bH5]YQU0FcN e2zL_bqXĚ5@ 4Ώ8_|4?w#U5YC6tTIH$ňu]ZN?P6"ID7O7#"v۩"VcK"kyb1aJrd?Oj+"]BiT;weKd!)uc.*9b5Md# @~: ʴNmE%Ma-V`y~U5{]:T 59{d@?sox^\)Z @IrbLHNLB*A#-kK٪]L,V [pNRmpB ,9l,A7.]}9۩zO/ds/I'Y0ը >)AW'yIqG5g1gv"cłdPJRzLuu)-J1h "LgV* I!B}B@3mV+5V֝:9Y^OIQRQ^nAKT+{Ǖ%G"ƋxIft9ɝϵ[UTm~ $jU%Oxun[si̳rѡ-$r-  `G"ju˭-e3Zr"H%Sʓ,珼c5ej[KI%Mw!(q+p@S5mUDSf(2îTS}lafa$tx<;7m`#zeL8׾ՀT* b,!Ϊ PQi̷63 ƹN2TIRjBpL#¶:>MdaV'Z P$[e\?yCTJMZG־u 'D`S^)4~ќAuhu%}Q҂aJ\%1{ =*b^Qu67+H0N h撲),[Rλ ]ӓ!ݍDx0)S5t*T2*ms5V_#:|-f..O-^ʱ)AI^#̘ze38iS/;S/Yh9<||<VXƑMo~I˹^񜷙,J#`/VҶ+BW ;KF`2']2€k˪3$=;"gTj+h(qt8ʜlPyJ"u*I}@^49wDʮtݾRO$?ia(ΫSGr2U C)mI`2N4 `u'c"d)#nh݈”IYJ[Kd+*&G' U% >$H'>4l& 3FdEץlaʓcb:G^%_]vc~mkn;,grs v2xH[l]ĐdA,gq$Lp$DD?Yo3Ki%@#^s3P '~|:#SD}m*I;bNۉH_2ZH 0NqP ".m"?v;>K,<4T}JlKkIva8ʐB}t#BJ$ d@=Bw@>V)gϼhg!6A ƽ-3,Æz7J[KTYhUؒxc4_ْhGqelPg5 -)ۗe@rfno|DN*Y9cNKSKH@2="Gaּ4=W!gO./u⤬{_,?ZMSR 3RpPvr*+\~Tb` m"rZ=7? j u*͸>YJTRlv+r>#mR)JZe:!.$ |eF~,ͨ3 [}יECai ^d /<=x447H.{sAUژ}K$dJa ju VZ` 8"`,MM]!4(u/2.jWfz[UKm RW$ $7$؇814yFF.f.ҫ.~lP <;m|J*.pA56mfu^YةUBﻇPF$l@:| FU'eUE:+];-$, \]ШT}U4uYSd2 !`hTj&rN(T5ӼAiCf'h ){ 튥+nJJl7"+ZmJME`&<È9K%PUT1!FٕXHD,QuIrܑWxlVg,R\#L؉P)Iazq(<kEf)+Hw:b+,؀@G14s5=;4}"@b{h4覬P]5?I?{Pk#-Aiab>"G˾$)s%yTbLo7QҮ5L䔪;Dt3O#GcӮG( TI}|I{KکY%3k30[@EoAR>w\|l\3ҏ S=Y4vJI̅c#\dPjA[QYEYZ}9Q- L&#~fPki퀊ru0"^@޻۴U.Wss&4sIw!I$F15/)*l\&fAxS]J³̷hӑMAdӗm8nWeÉL([LVʠeII3^o>slbk\ 3H綖;*N Ӫ.IEFΜA׾ciT*Mb@m5BrI Թ ʎFD;o-{:6CͨA# .mGϷQ7В@$"c(SeV($ ' n}f/UYT2eT8= &-`l6nJўZΚꀢ,tZګVi/F{(ƅ-8z#x'${z]Z I`9"BԲ@ $k]W=*j]˯W=h36YM+Yjiyu-%} NNofJ߶*:Y;4}:{[葾c ^b  x`Tǖ?#{t~ǠPfg vQWH@#m9Kt.,%*'GQ1몝).Lǜ_,~9b:A׫:8lS@6B]Ɠ=&3~^==?Lxu dی1q$xڀPDby:JyE%N+Q#b|Ll5*)>|HT߷KQ>5=$ 68#unR$Ф`@cA(UWsA#wHG#cPN}Hm@ sv8kƭ׏+ {y~XҞ5uWAȌ&zNo5M7 g v J9PdcӶ@*T[(ck\#醝|mj!b;|7x٣-Tܞ=c(ihNg=lmi' }Ɲ`ɂ c$RܔP&$Ok-עǿuyLޑbѤ-hY Zn}`ì5At}sʑ ,%0{dA0Ap{փ1}|mѰ+Q;/6hz`y넿ltP^d6_͘?a,ITenVbH߸4>)= {kz%:ʑ%qs6D|>FnT7?L|xۣ~k #~&#0;׸:O9 2dȂO<  7'周( Apv&#=*6h5 ?$3c٣*ʭ׿ Ot$ Hjpbx DIT̀D&'SR2L_8)Q&? ݣQ/`}O<{y*ǿlӟ>CJx2 >7B(PDQIoAZɒdw1@ݼm92 Neu)[RbyLn:Oe@3 +o釶\"֥PU f{D~Sc@0* I CA,JVGc7$o鸫@=TJw"}$:TLĂ 8't:I |:zsvA2}0ӷsG@|S~nś I9?poRg-AM]bekLVf7$qljl啉HTe$v߿ 9T XIY6'a&\r-"K@c:`Z k\Ф`Gےc>B9sUKա@R`AŤ܅"w(/1,) `MS3k˸GR x!JsXCp|reGWaHj ˓gknfѥI# }gu=4T\Ru6 bO^s\Ëy RxrfL\.,lC ??ߝQmUkZUP iL}Lc?3=(4W'A2/_š98?ͰFˍP 1 1a(=Mm$=sƴ**Iiqg\歎j-!@H73!E5BJ?_+ԀK֛z;T5m UI玦67LW2!I`Qq8`~X؀EG~@'nO@P kMbE*m?NT. _i2 z$ l u^dXݵ* B<@OF)J$mL| VࣨX2,D m{vquN]3ʩ !.,A?v6ΖR}iJO7p L_צ$fmfn/ZIDIL *a_2M՝_*:Dv!x$GJ;vYB0q1" xFm3OWKPZiȨA_mTfSz`'6Q{E\Q#6oпz5@$#n:kT4^T( fIxrd '1LDFu9W@T]_̒Uyr7xDe"r -4.Hf؃t R%jʃ2I sLfF)ŻQc*܉= \ R=ZLI߶b'P.*A6r$gqHE1 Ji ~r^IݻCc'@(RWtH !J|"Yx E\̾o]oLXӞO1IHM61xNZ`>}QyU:M^ JH2O* @3'[b~ ?s{3ru}s{eOl0"ilxFA#9'g9 %\Xf?XN>4&Rt#v3y YPA6wmK;)h**Rˍf  RA N"D0@w(!IPI'%D0N =;sLH Wxa靘Q1~zr5RE?,DjHHMݽ`v0UuhD\'@>H\Y #I=X?sx)XL+vwh Gg>fWA 7&Z;dt; @qyB>{: A?]|`g)P,o=\ y03aAש֮f\N@$p"DAH2D/4Γ!vO-& Pw뉊1_upK0TҕfB-I<)UF!Ap n=ぎg@3 q2$As1iAGlldTT[IW2H bZ <ʚ`9z);ۼ `:9Zf9na;o j IQ%0I}C< #A;s;qÄB6~6|9dHD_LJpE )VÒߡ"HjTS9$Xrſ JLԀ;dcx@OϾa~J L^SFTX\^gHJk E=#{mT"[(BJ$$(1$RBe<% ǧ`w0 <}ܑ) c?uw7/eU%e+ =lDs8 j)Ni?߰&>x*8q80XG$3pu#&X_FN6NޝcR 2IG(x_Ry4$*q{3rPI6&޽?q0 Tnnv1/q8anuH2,9d g|dR($Dt6} ːL{S?*Y˸-nAhL?${#{DwcwT™MS2G~fО#%. YihII%̙IEG{y[v1`k:ʖ;OhT`I;=jʒ %1r?Cڽ3HgUQ(s?Y?$~͖@ ot{h"6w~0۪;^ǕꌒG1yjz5 2N; 5#NfEe< g1hY~yj?:l#+IMSnM)׷bXuIC@~XZӸ2}jϸ 2Ĝ{NǶjRTB2#2{qT%\i)u57x>mc/2Y-*\UBc{ '9Qi^}(~ IAwSQjfB2d's)~ p>me!!c Rf;yy`SK_!%*Dly>_X8 RG,"0D7XΪO2 9(#pMh#$DwsWBVlP[#?qw0\mq|y;*IPlʧ*AHGi$6gCL~|0+uQ0 $P<,L[$a:XL\#";`g3^Jѕ >{G?iS?p\Q[؝Cڝ hU8=-'~UHULTDhQ.F E7 BS%0 |ꄀг^1.FGaQWNRAI}n!CŦiZb:v_v1J [$ͭCLK@PS(&yFoKLRIqF{5?lZIZ{J $ |ՒMV$AJ ^/"^ٝgUTf%Nt*Ufbc/խyAZpmЬy-F38C B&@H?:T4(Sil0Dv3V!Vx[ aI7JM;[aeԥ1{y|}h7 . 0`o-aŧQhm%19n,D(%Jg p9N-~,$p3A.7 D L@aВ{t-s!H)R wEMpeIkt3pN[CiJ}#Uiڬ7$d)'3 6Z]><{;ғʆ ߽H5YZBHR,,z|NN($&,#kE}|RZyO0 7c+Z0P ?HH@14׊lw# n 4 +m6DR~S:d%T$Ah}DǞ{,6A \Z' IЏ+wVT* d.5E`DpKA`is$IP<$OoJm(m$$ zN0 |yvGI HwOzmH9NyN`:IꁸZ&aDL 2cΚ,)-{'ӱ|}P-[IE2BSBFZ=dazZ"ܘ0'km|x[RJN~[\U&Iq A$ƛg$-;}紁M2:BIe%$ F=w枤ZAL>Vmas,_:VR`C~eQ&ꋁZw* ā3 {F. zLDĒ9$8:i^)T\h&@ϖ!>e* 򥨔%@7]oܟ$y oBh;n30`u  }PI3$'lΛmN= DyZ|/HnC^Ӛ{6 u' ]Bb8Zܹ)I 88`;42 ӈ$|QI wy2diw %j#6=AnOӶJio=L9e(Q)6$mg5TS(: o":krp90O&#L N/LH8<vww  ݦ_+!Z T,#gm9Dֵ!k(JA* UbLHer0y*jb@#0ƚiTd>q|+m;ΖdrOstN4"!$_xF1^PO+9IwO,38ALA)VjTnlg38PHr0"t=Jd$\7`*RXb]>Xt  :mQ8 ( M.?A@0"f@G1N&y`In9WYJAR/kwNf$&oX@ l9cRy*$D6>} UD F[n#'hYm!`$NDeVg\'AȃzRD^#{aoSz|RLyG+cpM3o,3$D "NO=*?bX)".@05@ZZQ9tCJf@i="s+* ! 1;O' ,}l2-c Q I9o;B2D@iS#93N!JJ8y * $XſC%Jsu)% qF"&Lì[ ׭Fm4/\C-1$L @ACתz?` { }P& $t0']p5Tҕ\i -^~xYF[t2K}R$<|[/ }-`Lr ,T {$w&ԖPm2 F_zg+ɩ򈲏3'mXŵ6(Lw>Ūx:b+*JR"ſ@;b5Ԍ Hwri_qBq1EYoI`A& {Յx I.tδéĥ?8.@0'n~筱L s|NZTS^}v߷\"kPjn38:uqL`JcSAK]U"H0ߔę>ڟN)75@=7%ˇt(\/srZI~o=68_>0?< # NǦ b,I#P?@аB9Ǘ0-W%}2{9#nQqmv* PQy PF dB~{Q}G)jFդ;ITwe< vw 0&vL?0\Iɫ=yi6'v۵$"G#J1L#c|3|*)= -;뷥GzuH>VN$T1Ì?Â1\մHK\ mg)Ls@)[8_͏O2)L{}d1j(S2 '+nٕR=@dfI"{cHt=b%Wn${!Ό^edBTS8!d9{_NXR;Bqqqm07LFߜA!BH2~#KB;)#93NZIN:Gy Z*X? I=KA4J imϠ{ UD~@, 11FdghI #$c#4V i)@H$G>'z甅 Fk|;`Tr :yG\)o{A0IvD "`f_3qLF탙IG?}%H)Xi-'Rˣ#?5CΠc٦<Ŷ0YRAIn:|,c%qJmw''G}'_JL{Ę"y>z`d$Rd*7z+EX$~#&,&0TEr!;z~x8'l=YYp3ߴv4)$`D3?: ,/ClrRIY&D\v 2`&yBENXa+ ϩ¦$Ldl;ieaL#ϼAHऋD\3{̨!A${G^N‡)3=;>R9H: ۿ Ҡ2vO#M  y#`yTGtk|>8 (Hn^_?`Oc\i*fgcs' kHs1Dw!TVʩn卦AXqeS@yo[`fJL3s;n۴L-BR !4}lq`#I ~I1D( `w]+tٞ`#'n_.{؅nG:YJG"bcMoФ(a>}TUO&L 0{S+hܑy۾4.rs rm`湉Oc6ƒVj2h#o)E%03&qOm*9J'hiݟK%EE@"L9fʔgiꍈ;7`IH#%H"A?q>%܈}g=D`cs$$w pq5Sj*PHbE_0A5 P$E O:|=ѯ{v`FT̒T'cu(AxՄT5^U)Jd$oHUD?6z`t^df1VJmbňO>;v߷#n6O~g!UmBr@ s#NܯXYIw.`6i鋘:iʊREߤpִ,yJ[B䂡ӧ0aKI$3}㞫5Weo1S`Oom^+ًO6;(-P6Nd@WGH9ÆA XzC߯8?3Us\%K99 㲌Kխi y3zfXn#<=\  !Ce oȌ Bt*rՠJ0 dsDFG[Pf ddpIK幒gl?bnpԫJPQ]?xdYSo3%ԘQ= zomhՅ:D.=zx#P=PNvffbDLGD;K@ Y.OOFJUOί%7%r/b;=Y)K$Q -߸-=q  3I?2+  3O298ɎgJU((D!Z Q0=:|̖K6HLuۯNq.B("'98?OTN'`l3<ɒRHQ6@amkQR=gYB͊FǼy? |BI%$?V]X3{O:%p"@ 8ch-`$HWB6#I${{ǟLʄtӬE[|D^f󇔪CDl^#%#DQ$Ȉ#>@RyAG.`hP9cqyФ ۵,,2 #S}Sr0#Ia1`Hb>xchS"&AZ)Pn&ă~ R0DbInzO|hx -彰82[\bNO dI9ۆ&y%G!O>nz{wIRTDF(87ts@=G/?ߦ UɅFP AR} L #n.|z[BT o,4…@t)+o>_O,- @di}/Z0b6y$ 9ƚ4f3HT{ź N }*H#c:_=XyYD厪daTD.'01$qXn`L1"H#῞-, *cE*J)"Q"o;G:".D^:ONXGlL4ՖA13HI_+XШ{D2IJ(>m\̙ȝQ710 d=TMӵ66M}C3"ƀU1얂W: Lcq|wT{Sp@ԓ>_^*u& -$O1m ͏j`?Ad{o[ {h JyO#1db'ArA9J H?`AK}c=^31+`0xvZB *Rcus)*H3-I F9HǶ: Ǩ_-`7x<IǍ0EP <) s`jZS<ܪ S׿!oI*dy|LoyOLVΤ"gd^ AHRv32` yA. 1,I,A1 *O8yKJ HH` .^lXI}FTcszũCSTF*$f?|d~PJP@V[ e5ya<1X=);x=3dvXQȂ!7{®52lM;B"*kPH 6"@ywr'a5pko#p*'{n !sbPy9z@/nث* i+70$}D8>p6=X/'جN( GIK:&n X#OnA8`y N9b||)`6"1?4VxA+P =LAv)o!ԺYv{LЙȅ91 .Oo>]k5T0j0{dwď@#G9G'RRPp +5M9\Mlbۥ#8op9ˮ3rJy`'̜O0@M߮1U/kYH#tQQd L%Gq$>X61}0Vҽk\߷>STRSfE=$_X q#ڐ\0$Mio‰Nb=G~q®[0I8D%.89 )=Ϟ )Ah6'h-%BJ{oU MxP[s*a!L#} C8%#@6TK*-%C{O\ t@\1wN*vO!<"'|‚GD"@$~'Iߑ@ ID_d)9G/  rR~G? ^̛~[}ms*mza4npY=O$'0& O#?'2#iXq߾?"Bg&6mxgRʊ@=|o>pnyR=;}:: ۷LA8 4pB8s ` |% mF2P H AbHb0XI=-3re7p=ALwc Ƌ] Bcm*S< "^ēۤ]Es{Đc0]x lo-mw!ZDȈA醜 I1$:*S`tAF B\@:L(BN\iPEґR$+qD`y``̑H@ c1ogE +h`%FBG={#)>:BJVċl~SPҚO""A|pdD pHU-br{v<4NZBA !D,C3CGRP~}ceKH ݺ°HR d> W`;a91HSKA`"dn;N JL 0}_< " WB~<^ M߷  &>1'ubH6Or'ۑ %1o-`$THz?ߠeFq߿jo)bH/ʱ9ē"&O8#4%` ̕ ۶)́y>Ql^Cj7 ȃ~m#,aDńmK.N/!DFnyae ,<Lo3%Un R; #խp #inǰ#}ZT.w~I-jZJS)=O(9Yۼv1ӯV L /P1 \0uiH.IZVlnl Y}ۦJ ;qJ>)$ïWʤn `+F'gc8PAL'n"dրKgd=zI0i.JI1c`/$0bAJbr,oT 31 dwL ܳ3H~W%?!DQ۩Vd1{'~vEA1&<{|hR{vߏ"Y >@R 6Nr: 콡+T*26k_pUU!+șDoQ \I UNE:\);dcAs{) UH Bs7uTT%PI>H=: u+Ѕ =*;cLsa3pRe@?^+7)0vbEm,h>e|$H!J1HJ?LU u*L)Ck"iyʂgG9t%#RfanL̼%I[e}F1Ӡ~sUI$ʀ_AbJUF['dbkp̤  vz(بIJe?` \E4t;-inq*N$L pJCmfvX0$|iW*iJ19êVd8R&:΢xW$KD(l&?8-|^oo 'qf oH  oRB $ cX"˪r|uJRR`LM̱V6TG;~P"$:u"  O3b%L>'Ձ^4<*>]pRII*y |xsJLIH"7JU#ѶHU9<$.zdFtB@N'*JRoj2$@r6nf_(>*P~^` 9$x"9#"{}' )THH?}0 SrY|Utܒ]%}E#}FUH A>>$c `0 N;h'٘`Aa8x=SE" [| Tt^#m=ĭ)_c`Y+}wZU1~ -N$ml('~A@ >tN+v;ȅIQ6c `RBGgr o# +HDz0G?̍"F+$S`@BoaUTTozH11xʥJ)؏AoflO(~}peD``@Gl&7XG*`B2g9R Z':bԍH3dN'81I):=^ I bGq7߾Hc"Da1z2 0Y k+p'OF-V,DGrOR-\Dթ|VBVmr0$` DN[>x>+q]GqH#8 +w?Ah OO>u%% LDu љF&';DOH'$s* )ntEP3?31?êJyb:wlp^B*p"=>=pc9hdIEUDDq*I0dIJsn7zweIIçAQSc؋|R-y~Ns{98ǷIa~aW=璮Tݛ=׶2OʴRxF%Dq}z0 "'rl= U#=%h#Ɂ3T`3(;my6* A12 78A_ D$&{?01{:UjmxdYms_T QA䫑$P>эQo {%d '﵎pCnUMª0S%1 yDhRf fAS4Hi d^oH T=A *u^ۜj_dRS.R<:|?S $L;#'<aT`䐸L4cv5Z>U.(H / W0&ݕ#4B<$S0"qN\_|.U\`I"c$sS]<;ch2 @yn5hn ŷUf TiԸU3pܞd%)K($N6#MWʑS,%J)Po;ťxrS`VA'߷`~өz.Ha;F5gxnROPH^N#UŦÊrLBOo>q_,f3RTJ}ت+!'·$?ǦB Ej䌩 b;0ptXvQ; "~rdj3jBfa<Ё8iA7;15QJ28@s$y}~CS$3KIPQePz㘿]! 6'mfrWz:7⯂ JA9xHFAq8ΌȟJ -I{~߶?GG兼*楃j)(Qo3'293tiR̕ 7_n md ; cBT.bN/;i\ qD oNbPP#0c3֊NHR0lꓼ_ի/wJZeEФɵ# +N;i&O"* O(W;Tldq)b(0qxu 9%hPٲ#nOiHn%6,CM;tl{ ՜Q#i&o׾pM*r@yT&0 =V&H x :j̕ &" GW )@8$uŇ偠T,L[nq|,SYz\ir0ymrd#ڔ)% H OXN11Ze h8`pdq㓩>:}0$/& $I& 8[R` ܥx' &KBRnѷvkeD{Б7#HP0%`q=ص"NĜ{EKR@1hIhص|; Ӷ j CD^ [LiXY `zH݌r2Nf#ML}9b?* LGz\:@S#i>b|~qm$%d,\&G_[}Cr<\P| cHHķ#y?g2G0P\i;ϔw%ZJ99Ly}O7ocM{$O/duęv2  h9'i`crHs4(`3堭Pt[=En!re\ZA#azy`*s咃0ǿI 2@ DG~frF" DcH}HGKc+R]Rlv>?k̈́vARH=ׯ+@Z[ _7[ %pH3@?$n2q}iw7:BJ v}jXo};AVd$@ uozYL=|stm#iILIhڤd" ș;p4 o2ʯ7'$B7Iv #Dko_NP\IPRL}z`i>$LǶp;fNtFA0Ɉ̀#{g@Ԗ*Hāo\u%9-O*vgkZA'X|}7uĠ$ L ?!s=)]+q9#E";dAfiE$b"&onصĥJTUĩ 'HP#ֿo!8.t,)@I#ߡF?F{A`|0RfzU'i݁H={ZI W@23Nqw*IPTT6$<NQ̓*$z`֡%a)lz]7%jH ̠$z[iP$ ĎѤS/1 s [J%I! ~?<|4[Y9bvפq,DMʕT;E;0F?܌cD]fmgP#6#n!RVcj)iq(I>Nvܬ-QM,Oahe$fO=>M#ѹwLēϾɷ16> YqI) P I"Z|xAfP X' !S G0Z'ky@QQ{$G~H2V%@e<;g8gYtڊymj2D} jKIKa\Mx +mEi0tHc 1$';JȂq !kP][MI^KB 2-`jSo6RĠ/hEMJ#u;{a0H*K D.;x\Q]dl`TrKkR&d<6/YBR`1= yadê}JailUOPTRz8 7 1e2`="xӊ-)@(Y1{1:2Frn}vL?nh2j!aJr<,h<՛uOI߬aoܳ/ltR!߯AqΞ= ؘ;<&L{\>mI Q e>-Sbwҁ-6{Hw_< 璕kܝ3$+TF߳ =9G愜5Qg[lf "vAqqM9z" gN`wI+yG+#up.JO2ЅJutrz|>^Ieܨ5+$|gl g J11㵵B\)N#A&Do醛E*4W+JIdô~avKˑ͘?H|0c=,PДȐHqXx[_ r#H*b0 I96\xAn 0?p vJ٬ R$ ;qğ7QMBlۘfa-CmiHWS{ wNJ0Nhk{R7lU*U:E6j)nOǼuiꩲSiq ӏ:9ujRm y~\W𨒖@H*A3o-xS7VL&$dq)8PZ9פ]1Z\2.#\DdG<R #8f@%%$nc{~}7:9쐐 EOY:u*@H)3n c*RT1 &{MNiUV`d &p#i!(5@pȜ9<3|A|+UTW=A>`84Wʥ3:[i9}9RRlzm?={J2ٿ"GCGC8üP˥bޖ^N$}u%*a`B3 #'*W(.} u?OA_B ɉyGO\mc^vƗBܙ{oR,̒΃/e#:_yR.|p`$$́*D$S31H±@L0 r@Λ4H=߱D(rhDO8RH:|<X2X ( n%JZBT~v*aMk#8gM ,131>9mW+aiB@:ԥ%\>ڏfS%; o,T2P<"yNG_tPd*; s>#: I?pG:,-[PYT@y~BB+0#"mX;uPJX!rR,܅G,\o/X\a,,Vs$=om$JJA% ;Lh%HA+^|nJ)l߼ te(}=M: U2#r/8p bK$@4` m+9*Dg4N: AHW;`}N;`rR*P?q #TlamdP$=332`&@1s!=DȀdn/Ut4ԩ !GKTbMwKZڷJ[[ADQvD+|};`ؑC%ĥ *.yuBPRUo>w p*. o+t*RTD녃D#~Đi2 “4RRҩJE• _ua I"Q偏!hI7/q~@ERuDv;8>pğfp?"h*T4Gg΁ b/{Ra$~(0)EHUn,lOS\[t%$\L~_Rcl18)IU!_ݐAc1ܕH 2#7V܏`s᤮_*ĄA6>?8ׂ@3{wx vObsIPy# 'G:(+.- [ryL'IyhJ1Γ= %3ʐ6۰u8Yu@667Š`sH02Ig2MEWh d @0sqo:o-RDEWrɵ@y\QKd$Ip ?*$$O[~P$H`DD=:0 (3$'+ b$Q i[HI$0o`'w(] [iAHT\ m4OA )w^tRAVr$0p$CQɴ!D{瀒%( $߱zk"nwA\T0쒥a *+:zb[RC!fGO$H2@Pe`>AkP R]6#oMuX@RRi< ;GqV0V4u6YTsH尽R^S+,0P+GOŢ Pہdnj PctZ&IլS3_Xu*Ф{@lXt#1W|QlBprI"Hw8(n|Hq̒IYq\2uX'wbqIN(mXH^wIɞ55!30%DAv]](s%BsY&#xo;a%@ m?mIJRLBvY?~"ӑs$N{VO?:| yKt01&v289ՆxOt IU 棤=X?6qx'sI"?=qO6])?]4zkP`~iL%O#AQnV0dxƺ-R=\ Ws(2PEDAsdH+&/~BMc>°2?լ ``Oh>- [*=jϚm_}"]?' Ɔe"n3NkCڝD};Mo9 D"Dcz2Jh*Цw}R{>ٚj/5*~#Q2[&pۏcO)$@-i8] Em'lvש|e.cO@Ł:Gw3-FH9@uV7iUjIRm+։32P؀"R>uhh@c3=rT/I%@cƨq'N~1;VΥ.S6@X@Qv|dcUe2ڣd |5yN&^2#5rVHJaDc~c&#f$/3>B> 2ivS̄ n=z~g>%9i"'X|O9ߑ d<۝;7YP Ds߿0J Zh>_xIq ccz~cm#Ui@ W,&-mm(Zd|]pʮ #tObOh*-#><sHY*Lwr= J*n`*ʹ}lLIT0)'21&r`FH,h (Jb7g)4-;2[R _/:e&/ \ 6?<ԆTyP!73h==<𪁵Xr[hpJ[B sߥ`Ce ]KxĐ$|?CS~x€3۶fp ` Fٙ N!Y"$cp9΂:\BInIh"L [L{28ymm-qj !&dD]zUĒb(46)<`wft_VQ ;tǒJHT?ߩhrJ &,!)miP(J9Lȉd, $g؃1S듺0͌H1O G/+R¥)JEHXC%W˯oس&/b&_)'-*=nOYN mcs"D{/,`N82`kK @dOH;{4*Lr7-;_rsξPD-XOo8D`/=oۿA)W6㽯PI@,v1gHXw!gaDĞs}iVQ QJ\?$I}(C(G8>=lJ 6gn`:ϸVlG$#x1ȳUEPBZ&?@H` #8jV IBD s>3v,|8f|N)bzH'}czᮐ;Ŝ!04 ױ:i:zAyrp@􉟍sۗMo"%܌ff3Oj>ԧc:[-dUpsfkRd@~;OSwgbY͢"H `v=d) h$'yjqkQ*PBRmasBHo>]=>bpZS4hiPԬ qnNo$u0>q3[[*S8fah+($!km;8O'\,Gy~=-(bv'x'~CHct߬GHm4gU$!J G8u%3N3HgR%3 v{;`J W4t?.{w \I[KQqEĀ*n@l3" *$3r dƚ3A$:OP6>[st$t=&>ʠ.OKG77K>&`LAq} 3y8dF~ z&!G&met.tt&тes <OBhR}BH *7i'ﭰf#?dK0( c}(' !ek*) a$ 0MXV`A"`dM{ǕĐU@PS!?$P| 'I*LI̒y=~ѤXHZ' *qOc#Ƕ:DzD{oi`Ѫz!IXBJH@ ̞`.mD) ]^z;aPX ys̉FF,6(x$A-O$ D%JvI#Ϲl>ge&zGmmуZR0q\@x.-(%(&n9OCA6JO8I/UQ @x2AgX~ G: r,:O~ 8H#$H_3mH'p5&doH;k "VqbFAFՂP s}yz|1 !dm&yo~^x( n"zO?.Kmn`0NX))\؈nLSܪ$c>^aPAđ:nwdd)'$xP9B@v? ֣$B.zb#nS1 ${& :DT$h!H o0)(&loko91 ҵ@A76Ӧ ($Q؉߷YLr3ydQ*C,?AP9{JRHOA$J"oqRԆ̦[&.w}v6\ (% H-8pZ$# "GpDr%Fp"VA=FLDptX"h w׉mr\,X[o_S, !)۴QK`Lg|G4&bvUhO7ݔ2oiŽ'x0g @m#׸u涕f <mIbqΑlggZzިuywSef2bJ'"f?M-@饉ҦsL:Ym̗S4܀)VI`*zaqKr)QzvZ)ԩTh݈؀ gN 8Wlt}`Ac>ݎ0OpM+F.'*9ǴDƵ_aIk[lgk 0L0OmO P=paM@eAHC7f2UIDIi89󯹒ZÒW)@kZZV*RE0z%k Wa'x|z\싶%!XLpH dDX\ <2 @l8-ABAۘ?\eD$L 948lTN{퓤7(aަ2` \3{W Ka#'ABu>w3?`⣙,wQiEIV9´0/ZpQdzY@3퓎 C烻 64EMߧ\V63s=UBaqy} ԣ omN`$_q069:s@ \|InE&O)A % d(n"ɑwa13 n828}yN_h F0siZeiP" w8*PH=&oo#`qRH ^MkkD)}|ª$Hv@}OFP d{y J+]GM+P"0@& IbPDܙ3 -UPªBy;`6d(E;K/yHi^Đ P?n}Q@X(y 4#_ZdM$4 9*wH!w'"H#ƓSUdM:hkaGiVJ6`L/kn?A:yPX $ $m :dr ,:`닄.*f9LH̘c'sʈ!bxՏx9|gRQSʧ?Ao'ηjj \`Z/e{Ckumq}JH寡e*A aV&bc jAWp`tUsvKwr AƔ efn&=_UȴQ"|ETn?\p5C t 7VȌhCi]vt]t57nOP(3*r-ֽʡ33%TR3zE@v>IPc'$`H81ΫG"#S9@2l.'O߭; *{鼌Sπ( \FVAͩE+t^=@~yM!'LY:ۘ=.#XVIH;>9GAo\GuhEDr&c¥RI! JA':%| |aWQO[*s],~ϤXs#jpЫPHMY=cq:wQp՗@s=}hؕ݌˦&5#ir/0@y;0rZp‘T7 yq [oˮ'Ofn!LBQק뎢jR~Ow&?) U$A#0 :]D3;Z$A#9$LsU|^m{kZS[\$+Rv2[i!^H;UO]_idLJBڳ<>gސ.{["a¼[Em7x$F4SĐ"3&9'V U'sr#4&po[y|a(JXD砖QR(G]:vMA5JDg9{8Ozq$c#|R?RlH_n/cӮfc,f *]D@](gs<4[bHXJMFޟ/4uERC<_HD~ Ha ³c 2 9!.JRvEf 89?\\χ2rT}ܫ/EiA:_oC!9y H ZI6Hn$sAHUc|O\bwu*RXݲSF}$.r19-SJrg&=&8mNlLCna;o>톅4p EBD#ǃ<~%IF}w;a*;mU 9'c6'Z$;=uRBwTv[q*l6dܘP0h$TNTvTqC:=B:y{{}7`zTH#z~sV$>łDAc  vN#yD {ED#$o+|߾G*9%䀕OK}dnj:s= Sm'>V?-L}}5S'lAɃ~!w*2i& $`WgBNU%H*O?,a ׉k_#?\7ռe`ΠaIIc;[׶ @L ~i0_]V=6pQ#r $ HwFtuT`Iqd@$ j9B !pe[66|VTm>L9A#oo*Ai%pp7߱>ՙOM‘$85&e2DzO`$08"ts$QG0%&m$uIJ*:, hWU$}y s[dkJem`/7\ v_D?)\tTvTzr9*CcQ:Ŏe2vXnGȜ"ά*mLv87T~bH"I=L|mtoU } IjH?yC- ɂ8L$ҴbDY[JC˷*HN$~Qt&e⯽4ؓi#y#^. mmG[t6W# 4j ́$v iQ9+Ȃ@0v訧͞DAJzo[N ][fy trBGRT"JH[|VǴ @&D;^oλpA;r&}a*P!lHx:9LDt @ 1nQ= _!@ Hv{oSdZi(A)2#F6 ;Sv&?#PaH3-03r$ :{Q6HYp'~g[u) Bf:Oy25M,L*"lirM¼pqazI'pA#ıw@Q1H;X2g=оI? =oMA\,<rD3G@mSpDL_-aDDX`I0ǐ"LG>rtOQJ UF}R8cR& rߨ|j_dT-JLH;&mgf*f`d뱼R\BdTQv]6 P*TW]R@$}~H*}X<ɌNl*R<ʵL 镧L•68p'V~;tQ+)]5 )P*CDL}7Tu[5h`TB:G}N-tP)Rֲp Ԯa $~'1jtx=u*H[K` \(uX=Gm kA ޴̀ŋq$N{*:A ! 4JذPvWfᎽ K޾%LڍO='W.s(e5 rO{qJ֚ r*ܩ7v>mPɒ/c .4k7ŖpM5KTHi\!B @I4/ ;_mؔGQsoiOj]VuE+tJ> T r RP72("DA1#$KP0ZiҾ[DmtAH)E{O؝Ofw@O `fs{O2FSƞZKQbH DQr Z$\t*2cӿڛžsftğĔ܏1Vn&1ik(*|7Ŋ}Z":@$N|M|J[x8 f5ݦ9&q#|Gd6z d@9 :y{GKDlx)EI#6O s7>~<<ŷI& u'URtH0c<? Tf $-OIlD 7KQk܃ۯozewSoV0b6qLlI y 0CL۾|SܬR$<{_UrJB6v#S$ʱ $?s1{].s;Nߧz`!^I$,fovߧSũ$yX &d0c$Gl\2 l  @9G~1ko$o|iSJ M@F/c/ƈ{w=~SJ)JPb@AyI<#TTmҢ= tLTTgap+IR (D?1^Vj`?C@b~&1/O׬AATj'#U5nO%ѺX_*=Hsc?#V+iGO1>飢]@_u_4 Z)rڈ$3cS#*xҖ]t |1B+JiK BfvPy*H5ѪJa UIo0V'Ԡb~sV-[o=qBD~/l~_EpUZLW8#텦sSsJEۤ[l7"Z:tչ;nF~E@4dj&3:Լ"?t,L6&"d8x=T+ArP ԞC*.b?::]=R1m*[NN3jM""|~Z9H:<{DKiM'2: ddjOst >g d&yu8`;Ͷ T J){oGQ)MвTa08A<==qTOYQ;^g4v%H`O6f7ž`?P(2fn#;ΏmKqRrD`w:samQOXtqʚ>q.-H3rH$GE:Te)ӞqGh ,mv$G?bpN> @I{0B9uΣ4tHBy1*AhEAHPKkͳU/߷j< pOEe"ڗ.v>uj !(y78_էJڣ$yb(B+,p#-ި{׷VFz-5 r@ ?MO O$tӤb4QOKNE)JBD$@"?`z]6QZXj/AMT?|*)3==y}`%Ɂzi06U/ !gA (RB->CG8"/ ۾|Gdcj&CH& =J^<[N8X#<_`܃ {05ă#8җV c L`қ]n%P R#kr# Z N!A 1G IIH50Wv ԅe 1?#?/\cQʟvĉ券om0QkVAj0}O15lqOO !T b;'?o@(Q oi8>#E҃</=c~%,>[ᗩY9QZa ol萐*O1vyGCIHqѧ4'! }>rA0 Y n@܈AnO^ϒ\OI:wmk GRP&b/;ALNDȁ9K//RH0T3;cߑ}HpD(1K@<I3/}ZR_I|C9pP" ;v's*1'{:P'㉝1$6#!2 _LGk<EL+t$Ifq:RU ;O`mۙeG'&119So ݂& #;I=3/Ԡ(b L[rwhLxD G7'qö_s)R]kz?=wZN(/ڀTE`H,5:pn} +'$̑H_x& >X@PImv;ҵ$7^v`Nr@hT? * > ~xh&`%G^>QdDHwi0pz=J2HNvb?;sq<$߹UO$77;=N=fV@$%Nqct %X 3HT&~?~XҲ$NXu?#>H))Ig|x9IR}'z}0֨)'`b$L@؅O _&?0$fpxi+I`N7dPVR7/:b>+]g9 Lp\@Pl;tP>w0Г28DbDcE ކ*^ {{jW**zOOLcGUk91 H$Do9^ƷuwJcǮP &Q9vH:O5|! pV&#ďt<t(z^׾4)}=G1LpDcw?URa u& t?sm@dǹƏ]eQQ ` 2 $ob/oBi wS< 1ҀQ1߭)vJm(+- zc0P( #叿AjAU ;fOc"F檦K֡W(3z6 Ƿ@J߮:aH8nPҭ\LOQyCa 縋SEM;[3r]OWSPۯS U%$SF ig0=JRA\TT'ȌF-{vA*T 2#>JZ!e#3 ӅR8I$˿9z!Bw|b{l8`T*l[ C@BFLs< _e~GSD9z~\Ui@VAoD籣4LdnU ݡ) zHr\6ҞY !G1Ne(WߒLFxAOǴjOMmc'M[Q U*Pv2v%k%KqAUpwb>R!$к}PPyJ1ğ+|Ct9nӓou*#؊gA==hкBǥbA`xXv *kJI%a'U*|NӐಂ@ Iqr~jR9$D{f58%nSQQTPՇeF3A"]HM=~ڳO4fJcST𪇜Yc~PB@ 7y:M1e9`Uԫ5Օtul$vJg$sDz tny #i-@HRRII;Ctn( Ti^QYAJBUl1(k,ӫukw/mVRRSQ(Tv@H^3g[j,ںjl. );\!$~Xv{ti>Z MM;yIi*#ʦP1~`Ayj /TkTiC-S+'w7)l>S,-(5~m^.iMVOZ% dZzh-E4^~;oEfzM 7Fnp)NVQH#0$;|Qw6xk [Wn@ gmU=%JVݺ~̽985={4;mRTyI;툮d) 0Dc~'WG\VjbCJ`3Jpx_Uh1( ܅_[D09NQL<1mOJHe7H2bބty7pR{,>vDP +*рI 9$v:1 c?}\;M\m[bN' c|)xI&.fZ7xks,2jܤmҚ HR0H7.} Yg;Aj46KdyJLm \9Ѻ_P{V{EiԤޝzj,FmqXWUiZСVɪ4ޫHgѬ3| E%HФ,sGE^;oƫ~,(ag۠ AR|3U{J:Ed-l;C`UJPH&ɪtcYweMU>ny<:H-dxOJVQ-oj*5*Tu[L5cP5C(T!+þuUzI?[@þO8'Ɛ@;ZǾ+y,J<[ $GdJ:bLYe v`QH*$kK0Rl۔dmeT&Nҩ3Z%e)- S)bE,իRRZYV*I,dJ"RKw#:-w iRƭj X>X8 dK#̲jf5/y6{c fmmCPÀr*"vu WZVh^[NY~ِO-v7u` c>6J6T*=zJyuȯ#::M`iݰ8'FAnK"Ր^da,d% f;yBpb P LĘ2E" DGY7M䁻vA~!}2;=@#)**:oG~j(\"g&{~cprWLwʫ,y.IAåAT{Ă'q#Q-#~޻*IJlfʛq%] Pq:2Rܤrht̩!ĩi LyZ;a?+`2P)$ɒ `H0tL$ۯCBwh>C|+WN̒HsYp\p%`b9 6j 0 9$$>s 3p}NrNzすf̳(zġIqkRm=%uMft燷si%Yy쑗yH 89P@Q{ 1鶴+PTPR:uBDfO2H4ꥵz4|A%!`&i'Jdg5"~ڥCS uv^//WJ^_U-Wp6NWfTԬdY\4tԵLʳKz-~-ͩjuU IJ=P$#_O[ mWOWZXSvd#BN@,I#N5PP EmU55j Er!H9< Y:?BE@agWbBZVmNk*lc~n+Jd$""1┏h A3h1\7K-3sF䍮Zޠ0GL{BݪVBM(j(H@e=,#HqM8 AT؏{} TnBk#oN{yaNNp n"~M宷NjU 銪8m̂ xOƧ V A{sDd-!}[zNPX Dtdzl=[aISq H@{"D|fi]CrK\ Iͩ\}tf+!H#zw?__vU\v*Z \ L1:Nzj_RO:TT(*mu$741QU>Qk_]*@a|Csd 9U3|!Vo_P@}Nl $|iT|izƒN*HJjy幁?"xcŽ8¨u+55UWxKl Z>=F)9MVN^ Ug8BT >pA.4<׭[gPj*^SSD^’AUi"zDTTJ¯IPB¢1 x,֙FFuc7 Ӧԩ(K$) AϠ!w:' )=YEL`ZP p7#r}?gg&90?WRSRͭdI G~xpχzH9E[QN͚jL)/iP#60m`| ۫X5zuZ5סLqLL :6Uy4/ӺQrW+(( ` 5UdžڟErGQPtvE2y.v|f:os~#.Қ$7PKLQfYEj)=Ż!eҼTŷ7Gs(&:oSFrUt5jKaM{kJF=0(Y9bv0PG@[5Z# $II.u\d4.%(SLoS{FuΎy :d򸃿t#麥s7OR(-Q:?INLY82=;E}M ]S}2qSԄ5(˩zLP"n;]}d q l;o_9ßPNedP72 w>tĪ@s&w |- )"NK9"`LQ:l)h퀽VAH;Ǿ0=:}K A NcL`Niǚp]]_kٵOW$owF'g #(*- ~ zZѮPa9 )3er$\~m҄SZo򺴁JIBx/%lvsny#tMV$29PRi$85)Us7H<@0t(2:R5;^#x?Ore)O:Ch]:S1b'H؟7xgBuJӾ oiVgUjjT(rg31EJԺmBaY܆ ZnzW!sI4.+yDcTP7JPt!aϸJI n'Pp*Iy*Uީ[89Prck;[]:֪9ˮRiԍ( ,sU @ԫuU_Vhz >c" 1Qx5)sUf?xT%N6 1uuyq[\d*Tj“IC-o>,'3<:^BUT/4+ȓÜ#gDkOMPw5 iAlԊWKaf(*yM Hxޅ466uhbJ5c20Dϼu?7jԑm8#u` m]C5YEMG$4ҵ@!E@H}ZNj(3 jCy\XBDH'1̵3p%@bDzFk F ҚK͐X6=:uŶw(ZЬQ*EeH$A~ KuvW(BRVif> M!r}aQt5L *RK )$[vEEGWKJjTҙI` hU=eYi_dTH~B"1?o/ɴ}ji5>SRJTKJDX2 0[kqWH*u GYZGgQ 7 Spoc#:,os7鼗:etLTW45.MkvR 0"˙ôfr!L<0q iA$@ 4%pKq0E3CheԎ!9[BjRa|m-7îiSzEJGÓPP ]RGYiJ0g7=6ٶ)ܴ҂E$曈aLCcFᒗ>T JyUX!H Fݰrj~Juag&AX*'-0nU Jl\6ʭN&#e>BӇ׈n-ijJ[qT!`7$yZыkspOԺO&Lf|Yr< (HRe6(vn A8j(3ϸe *urϧuK+nU={+25?6H0P LH0AZ֝[?婖CuIjbR Qd=At#N]m:qt:~%6ږHonʸ]eM.[]̵.uM:V_|C(D늴fwvE^TZ9Tm4LO? s]_ 8aU_*SgAR@ՉT8@HlJ@ @1e֞½ѥY^PKHXLLj[]Fԫ^VzI u2!Ξ\À?)2ڪ=z+ 9T×t$J$`"o0,6;}EKqVR\CAA$R͟83!{Qm+hߠr`T@C4t!/d&1x-x"τBif2zUM dfS*͓6Ow%Լ(n1pSN52WVYVcL89\Tƫ߱iw2* \YTqܩ@k|>aưY!btx\ʚܬ~)܅ZZe*bW]e+UT-oc~^*.]sBQx˟yܭZ}UP$Jz*#w_z%׍=OKS|*R/}Vi^ɛuD6@O'PN~kT-AnDCxȦڛ QDm'FBɐDgI=᷍M ~$gGVKS=zFk("0g|fpGJ߈wUi=FU!MSV6(!ABoGr 8fƚwMUTOeXɪ^azSʖB(EVnҺg"wɵ7 6kS(Pd$% lu+V)݆4+=?.Z)H"+IbHZupȠZj7Dܭ9uu:[]V0ni_phÀwH hi)mm;v`Ess8=N~WSTKV T˗yi.F0'z,Vi+JG)n= GMETZꢻ{u oF60$9gR;A3EZܬh:TRz68yѽQfk'"O5vdPF4D\ uGr)xekږ4A)!@g-j-*O\o^ZBڨWJ#%TJ#&K [E%gu -ۈ9?\'kZ;gk}µBR?^Z.P2#W;RP)i*K WJ6l!z)WQ xppR+lz,ԏe^@ <ƔZi?zU)d&*!!WHp7n?6sڬVfT3NRRG*f2F-eҺO|DTr2ԹZ I6O?뿳1'ufM|@2e])26T}2Tۅke.6JVE,EW!v3٦-̝nn jaא9BHJp~iV>u+CQi\[2gKUljU.b+K̉!j.ΑEbQD2@0;kmg*:zPz T.~+ n:*H%EIm/9Wf4v˴8xj) . q*l\FD3$LpM_ČDN?W5=-V t5 4|R3 Ï dAZ4ε#TPT ޱM'-)ZIC6M풛7ZHUvl)`Ό3簴 @˺,Tb?bUOC|Ud(qY*UKnST) 2@2FHPx9K_[γwr"i*ڧISmR@> kN }WkE2EZqkFtS9MP*j9PR)0oX:qg_ 79zwI9UW!lڝQU)*%9V+S̴j&I+R:Ri Uj` * '1~5ΖOoMy>3n2VCtVeIwDWKV?CZ=*-*&iP?ZcZ7G}1~M3Vl305ܥPJJ PL ݱÞg5#OL;bX-T$$lDp5KgkWPufUZFQRU*Tl8'PG{Z(.Ghg7f$tdj-['PGi퐚@$s;o~x!Ꝯ.Ԁ42;Z}c~IM&C6n}զ"zLmsF늏3x=SQWAU% @c&H>`jHq qo-紗PL澞}M ig* HOb3v=}9Q")$l#a32iSM񆘐Ap5}1x|w1;̌rDWA;Rz<XgVI򒠞\*UX=/; NU'OIOq҉O9wq@!PeS䚟%rR4;caI ߿d Ӎm^%jEx*N 1noN*r5 6߯_"'cGe92;+~Kr DӠ}UHXKJYF <=NOlxSFҜp1IֵqK*R .eR.De(|)j}r";}vCm'"$lm'l-PIJd>7^P/I.lX7i>v>Lu NpӞb 3?Cq)iܝ)T3PyfHkJpp[@%@OZILu^@ ~Zg4MPgYuDf`_x']ʛVnK=rU&$-&735P ap"ƟW*kW*&XȟRc| G>ѝ{_2*zWC̶CD|RMfq啹QsiJvI@31V)r'e`y}}~#OW:"̙BJ&HβBn#eL A1ƍBDvQ< =iF,- H ǥhgZx |ꌍ>z(ԕS)ƊBRd(vmYnid~Utq/^-:6U %*̴Vt f M\aq`^`[ton;LeP*W$Bd\\.קYN 5ikto HIIc逸[xUG%-45E.4RP[P꒓A;[+g+=u5SyV<έiRԙpe!$88μ8(3ܒV9U::sNe<0`tqT`$";N,$ A8HUٞ:ο[*UKj%yRBXq^;|_Xq]'(m4X(Bb:@v]?=P?"$w6x.(eiHH!N7nH $?=QK⫋Hxi[].XlX!LR 2H)Od8Kj.?WZS98]`3 ڪU8e,:u, & <Ԉ4\I6'o-͘zTb A0Cmkq$@2sv0ttgsՕ-& ߩy~^~HQ(%%"`EđLW^gECpT7H)BBT"zŮp[E,/K@iK )@L<ČY|7yS+ŏegHVnR5 ʩ4$I2uZ[rZuY$lT G_/+f#S8~u֢:UkFV`d%(%DnR.|i骳QfS+EE"Kn`ӊ &jg!TAj>*Mʣ$ӹKs/̩ʨRH O$H1q5?76PަI`EA8UksjR,N`[9;$Xo=;@Lg*8ӜԚϊ򶬩+2ZT ~I0 ĩ⏂;ּ7PˊRET"n2v=zc<j*>iTA(I{܏϶(VKKܪ@r7w3=C\֥M7"920A<|093kk[QT$ء<qL*"]ag?:n^ґkWXUyņPr_=#SSҢ$Bzw~xWOޗ l?_*Tn21#KM1_"TH}/ĝeCI/A)K9}/+o#8,B5̨VATʽ)(RAM&v0^8'm] l&A(pTA+ F@zEm a@3モf8kuR[kXB)5o!ҭ*I#!-EOP*Tϡ^Zַ,Q$&I=pd za-*PT$^gmFny^eG\RJԣ=$cmzO0v;\Z\4ePϫ?QHpi"9  93F9@Rc ;A8ZZR%,`EX˺*^bjTXad`|0<(>RiH&Q]y?dPDm׶x0utU O>wP1Y`Cιxdyh%ũT)Q(P>GZ;)⾇oM9T{ajJגڹ@!<k9f:ayfesiN>-:,v֤ߥ,6 J(VJӬ` 4KⱫE3+]@Tv;xuehM>VA\#g n5?ΥԈ}a9dIUKD_rNcsx|r*YTR=I70KGhr V{IYu UmKX6ޙ؈ɞ"5I 풲MS|WDz u.j\-H?fy? KTcnu>wMNTf9[u tnvZ㥗}QT3[9#gN(uA<"@O*"L 'u]G/.JP2-kyF hJi \qd^Q2_8J Ϋ|Sj[ !l]Y#Ș=[Ÿ%` yN+\.ec6x DRJ,,*RGn&3Bږ-\ FݺOloZ2$M_o<.۩qbp;̈'YB2s=qOW]>HR1? Bѭ+c; !){j$!K9V$%J3}wkIO*'~76htѨKC7W?~+uQ6)2H079Λ%hH2m;3催Jw;IPA)Qb:I>7%+QK~ɏ8MQ[I:1~ö=ҋZR.㯨۱8]"eSEb 'scoquwp}w*Đ@TÐ9i$ǔѩOk2!H=q{q4OjY{[i% JZO017H_jY1A߽cRQZ0J6]32RWI O0#IP{At?r>`9F4l:%XP*-~63W8dZϓIĘE lY 6ߴʒBIakc&Hp?Ԕ(FTU2@#$O`G ĕ+XdD : cnufN|,[ĝrEIDE{z\1HQ)+ $[ ក /MV̙XG̙2Oڽ@Mzp>LN {j1;.%U$!cp _9<i{3֙SmTBc ;I%SAqq~~qJ&:;b0xg2H銧½mtd11kupE1AI\L}Ȓe<8>^4%).̙+r#8D7Ĥ)RO912$Z R&z/ׇhHEPN c}ԭB`I&o#IłaFRPXbkoTvŀ 3J >HZhU̒[f+kMS}RM6kQ2IM0$HN23pe stS㰎O:t׳3 3aemsRLx|8MNu{46=H5Q]h (!v$;9ũHoRp1r>uҌ R6n_Π,+5aP1Q;+mV== *)3c5+1boOخ?ҥ= 7a틯kx}prj8uz2)%[тOǼgIxU!{EGÿ:I=V;Ge4Lds)#`zb+GQ*71cؐ>"[>l8P]2(S&'oك󭧙oynYHGyxxƳnzxvgFl NdJP\ ;D"Kc$w‚ : AH&TF^͂Q61hr;rj F $8APL$S31tX `v=X-AAD;m)I$ z?ߜb['HOMQSN: ^-|7{)$QB.ܒ'?_`۔(A}A1Y €< vdo0+!*B„︙zomLnGbmzi)d;7n}6`JH2H[~0bF0eG}dw:)""r';DpsYQ@|VZd< v&Jk.zxDZ*dz$>;}E X>'^< +'߷/G<ʓ,GX78%y))( ̟3}Ӣiv|:[o7ߦ U m @=gXo1XY=+rTQ U!l%hR%*H31 z~mTչ@R8F`* 9p8O?R=zi%2a0@sƹw, *IucnXGCӷMJ4qqntX\W 3fHu- r/)$#xo3s>ł3UפYq(2d@ :ռGo]כ`2I!&LFi۬X YcneQd[tUZR:Tdo'++)%P= ynw 4N_uV]ZksD' t1~!te +Z6U˚SQ0%Z DDj~.o.(^ݽ媲c}&c$n M@~s@.OV^%A3h*$Ox*9FhOxy D{}εW]~>ssȰ3):M}?<8 RI);+DBbmMQp1dH 9!]V +[q>S3צ58ɴ:LQ(<ǠʅS`w܃s(3È2c/%?Yb c:5nKI3j*IE8?۶ImJ *IJ:6Ĕ$gM` })Næ3#olpw"[ 7H'="9ҡ&-Q-;I0>bm7웿<d9r9`Ɏ;AߧڜG=< T1V$#㶺][84PlX#oϳA3RZm\3*ڀ)J$m˷,V6gR@Azӭ]xW><ꛨR@RJq><-} `c 3 w;Xk+ea),}jtkV]wV*&8Ohw}_RCU^(zlhݲV[[s{FVjueo2F$OuA8Jum}E[EjҨ^0$7@ bݨ~܅HU^d*mҨR =-yܭY6[@rBSAd=yVHp$X[c%>.R9BHwp%YqQ e$Ɂ3_Ƈ(e3I^8$XH ? 0IA oaLtI$QӸ= } @хrZ7b:yrͬsPTϳ'W7Edc?6D=Drx3GpHdcO͒dEGiioaFfj>L~9x%.YQӦuM.*HP68lxU9I'/^ak߿Mt[ΟKYSkz^erMU ?Q9Y\]V_]jVUH;Ln$NWӺL皦 :j*Zu.{4&on,N:۞dEKIÝN% 4${(ɝOFwC_ L9& '9r"7'=q_:Q7AOS4VL;iOamM@JcE*v@'s5|OfFG0:%ꦐ+[$eOfob $8ekcWF T۷$wXV6loJ<5iqK$ [URTtJyv0dIiլ-."? }oyi >xZ&.tIĨ,lQg!oLBqw5u/2Í*#z^gInZAVDvJ b$cWX\[_ܭJU)4W5YE" jWBXGc#} %L,J1$ml#t2083y*9}V A \?c"Iލ, @*;9 gҮ\ H/ LIY!)f7&{yETd@M䍉v8W*VT L~dLr=i<6xrh'x*1Q2>ӳ)``F=sG fD}6} UnPv3}89y(\(E"G_Ϧ y#]|GcN;HpeNNpe As Tz(qx?}nsxgN%?[Ied'H #B֗SM=ȕss̛'d! 5&DE8G ~ڳtk}%qoI"6ק'$xOG[kjvթQQBӄMYOΛ_< dUDfT#7"70k'6!ҵR &Aʴ-Vr?c.ttjmi@X$ȼ#9fYk֕2S-(%ZR"A?׼J9jRqFқn+vjtl聊 Y*ղլCL"ԡ]]+mb# +5Ja={0GM/x]sgٽ*v-pBKhQ"x\"5 eE&Epo.q9=M7 )#:+ 5]iPH9yY[M]웩S 8} QL&N.xGӏU5X}4ʨPhm.vX@W!JSnT{dRT[˥Fh]Rl4pHDcjM2Xy[5;$ 9X 낼^ 5m]O,޺Jn,k_ah0)sB!AFgNx_5yFP\ǻHY(skj| G%Lk>"j"jB7OkU\RidS8hfRN߈\W?T o8ίQ6io/չ tt-ME}=IT0W.~|,.)mūLO5X0KKзU-gY4S QUr AFF(yB;(tgTpH5 ϰ8ƮPYcHh_}&55gxKQuue%= P_EJ+hI ȃ{wJghP#,)APYq]Z#&ʖ\6uM)rBv,c0k˻zt.*X GpO9KR\!u`BJ1u2q;AƐ,EJc6u_Zm$-@RR;v](KײJdֱ\AZWGCT!iPI78+Z):O\7 cJ;;+єVUh_UD4u^QYAо=] R /Ӿҹ\mJAcOT֏k\J+JX[7ň}KsչbB(4nT8'CK`R I92_UBʭJiT=Tt]i*V--r01S;#GP#3 1$='8M'R5d쮰 $ mSqvwCSft2IuP;|?9E$U7pbe`w[ºS:Ҳ& ;Az}uT]^ ɂ0$`zTZ2RDM,!xeJ*+?Y̪?utA9 <䇓_'E\"uriRS>p ;E xozK0J$&MKjv}pC^eLF'_-4B]Z[WSe74oD Q1qR(nn%SSBJj Q nna0qkaJXL GOO~Oi>Yqt~MU,2A7o zi.`oҔG)DcdyY1Ww.d}MbKH,c Hn0Dɲ_S_| ѵ(M{lF JzP(\A6w+@Jm T&T۾%.Sj=bR |LD_lswֈ*R4QQJ0 &c*5EԩUւ:Vq]Q,fd$aLJuyAJkq*j@iBTdH"lT3غLs^ͱj[ke̅$$" 3Sh[ $U\W}F[0 &"rЀ=go==[d`I-QTKٻq,~y:<;gX ߿m1PH:F^^d#hZJ$߯|?L-FSYGԚIIi0Y$5\öH(T{.oo8F uMpgצ,k(a&I-1͹< @?H0Pܻ(o=3pNs'FKL,{W+>5* ms :t!85%ij}O$-RTI2O1LcGS JmbN[0ʲh&Toh6'oą@wo^垒0f QܐI7 tz6EYH #"DwS#F&,-M#[4hX:R`XHiŏ hM *ϳ%bgAJѹ9O,+04NifyJ&u[{G[ 7%'Ic]m![ReJchR! k }b.hv)qnMSr]ؓ"91q4,OREoȪ-. piJAPG3i`sbI#vi)Q~:l?a8j2'f5Uq"?#@5֤Yf\N6ᠧ(6˔$b|&:Ma?Ǫi4U}Sj<)+fo1OЋ5|,nQϼ& Kaa,څ: uD3%TWqYڠUH6O5MoYjVr{eclpqJiZ4ˀIC`GI4J"#6$t߯\)ȴP@zU|![`mq$F^P4هԐTBCDp}`jdpi|(#s 1=bsCl#lxT%nfOZ`I:HSpd]V Li7sHڠt `g/y$M|\|O6^J԰ʊ,6="Q dޤrG7I&xOi:rb#:|`ʢ}:8hj7 >\Jʽ{TB ǵNacNу<<4dyu8#N)s5U2:cϤh:ۊ).nFuƜ@cbd:/VROJRԈbD9:**gDǭ{{aRNǧQo?0´6ǴR+$("lAivO"%1' 'qkPgN{}KZ\BG>eX(v3oܺHXp@PXR}RB>X>N sQ̲ͪʦ}U8EP_ ZU(է*UᔫPA`9ǯޟ[ŕEao6*`geqR{:t|\,Q@ߚM01XyvtBK(O*7*l/ DFkQė {S}05iM*ej1J4uEm@.)ү+*SjJ RԖxGAH#S\d/-Z3GVVZ5%PZLYS>S5f5ZQ- %tEʀcܑ?LBd9TqAiS^rCO k:y]|Gչuzm=)(MMByVpdB߭xiԠ/zѨUj.d򼰬$=cR}nCFY`އO]l}o6iE|B`&c3&`{|sOxҙϨ38}&9 ;a xDti;M@$_=/$9˶Zi>vOi◢T)4{m[T |0uJ,S  mmHѹ,EEyG|ߜ+Mz9QM&d)J H 8_fI I `kҢҠ@1A#ꓜFgt-tE64P9;|пZu2zl ip5\,_ҽUV-|yNi'l}HPx$ǿnj ( O)2X0sdm [>ۈ#o$qgډπ&t/VSf9gFlYZ,QUʖ܋`U>1usN)׳t8$ |)+ P!Ia!A!$k NA SpI76"L$)2;~_ͽ巙?"?/4QX3sFZoqKNfWR>v™ʩZ_ei!h~as>)ѿk?N`OPFo3`2؆R@8bb40F32FV%oGәּvֺNg 1ʳ kKT҄)D)$1 Yt|L7&d~p^˹yLA>gqsb"Ӷ*ĐAp$IthYɑ@3xh%cZ-QPTБ6ߴo'g 鼕HXY4&odO,Q&gHAq$``~8.dYIUHTM[mnPUQ+Yk pcb>MHZķl1 Ĉ3|;PCLT!$U%HuPxV-@㹍BbL W"W_*\H/=^sc!O#P;d/0< s@b/Ҿ N/GjVl*$+$ux^u*vIV ̏5`dˈ ;%/5nh#\ :JJ[AYXuiҐ`h /hS\o2ɫKg u)+ċA;kYZu܅YStVU*_$rH1yͱ'G?q-?ԙ1럁 :kakFޝ%XW0 rrN]k-W`@m"'r[M W3~Ο?ĶЯ(y2ڿHO_h3N,( iN ^<52 ?cx#A$8dw9R b`s);@4SH (6+wT!Mc7ZH=uukU;Ѯ˘$G]]7CR#V0i2L GY\#D 2O{=on2q4R,]aD)+QZ=݀Rz;Rƣ)ԙ%~M]L=}3%I08&`:}'Z]. Ba *< zzs6a3NUB)a{:~3__t{Z+J&5 nʲ+؝DZrܥSo_igvp) $0 cx=DU(~.d^ѹs{X A2/iRrU](7(8kӖ%Pꅼ~ud/C7:EB¤^G6>ꖟjn娔& l]~,jҳ'`\obv׶A!(_}W7]߈ۄ2S I"sk񌯂YX٪wfj؟C8nh$ߴ%l} l{;uhӺrf%"y90h%fi|V\ɴ+P s߾6۟bf+T; g" tHtA"9ơIiJ|G(J}o6¹T z;HXgoyg_y)nI k[˧|?GܛgiQCeDvϱh d9?:kPWV**$+PSZQ\2*Oҕ(վCS6뚾ʡs*H:G㠼\x¼0Եu9fː5M%_ΪvCh ?Mpqyij Eˎ"3nRS3n䞸:LBקaF;IO\5A[\uӮWi@(*ՙ=LJF>׉tD|5$qUN~v6\;~2p71{2B4([M3hMeOB t\;6>EuBKvsf:/+l-R,6l AOhիx })ͭȴb>6S}:<;U5QOS {ÃMwINeRAo=F/i Z''*̫T噅hd)@-,6~kUs:tJ.!-ֆ  /75<[V) 7-,I b9)3x!p Z" p6P`&1C.x]ekmNI1 h|"tLVfYiRESx `OA#ޟ-Nn̪SYRJXTV[&KF~xWMjr}2i_D*\SiUҒ~ 񭥚^nl= *=XЖ A~DL}RۦtZWt7S4J);H'i>Ltt!70!)u‹DqOL9u^eG;}m`PDnA #ok[C:PKj5. ()Bڤv:mkM8Y:I>eMxLL44j%z8[Î@z/㤜s> i)ESS2ʶB%RH#n%O+RLc|&EMN׶t.#Iɫ xօ[ۋjt-Ju, hun)PfkV%)g܇q)0|<ۑ<7~~>8r&M$@ &LO˦69@I$^SS!qxAAq{XQQȒ  0r :sZjk֝T^Nw&J]ʒV&8iEQ7N% Z"=ͽ+ R dm pgIiNP~eۉǀ9 ::fS%Mn "ߝX=QYSG-QΪT ` &LXLWB@m0B@{xٿt<yU9JM?mѻiYVbIRD+B9PgR+0EPj఑Oȏq϶g@R'ScLk^ JGo0vp^|1~/i۪AKT8֑ LXa!(Z27(ljc$hT=hN{-/RF⏝D;9B*$\I)qk\kiVJTk83 i෇hD26M~;nA5ĂM3ӿc? Y[Sifz*kSſɖb=N|@! 1SjyMENOZqT6=YˮaCU6-TB[˪(a#O-Qom=6d/Q I7C1I#ƪU^9ZݮHH 2f be/VLG9uv~)AK_Awm iV ,#A3 c:C*,P~Ҿ4~MUS{gJҡy㔂.A 4&QGELJyP\o!S5CRdp.@n;^c>]D!y~@vFzeCj9HdC>ſX*E%" }#1&QK]KtWPn//Vg5XP7F.ΣQRPW\EVfudUsc~t0 \j$91<554OTLCq${#+wjٵ5ʪ^˝mi)R}PD@初-okYhViչ[XR*YHI1xc$LF.?ὭP(y |?ݽsFޕ^5—`AQ'j*i06_wљ'ɹH)Ǽ}k^eXw 1iGDyk= 1b/shrq My|}q) wmW_2\bcqxkhNIHBHjס+!DG21tp0[[, Y-é^61D% 1l:>1T v5:s ZK,&a@>ӎ?u[+9"}p "o~x)q Q"@Onvq" 9yAcx}.U8Z2AO3׶5&VXc'CƊޔ-CC8%cF`)mnqԳF]ۯo!@Z8*h[$O}WvwKS'>^]#ፖCtʹORfwZ&8<T[<^@[u0}R#98</)jLB?GSz~]#i^ !I'mb/%exX֟HZjG2c9m̀Eǟ0YYG#@ bI 1Ǵ`RBqTWܨbf]M=r )&Fӂ$q_j!9N̲QCA?2jN1>HPHvNMWjNh/3*4 )Zyի’S+`I &p /:kHeowg/aUL^!YZ^j='CE}XoxiIk\KW ѧ(i {O ,m0t4΋uV[#"N Ih닐"IMɍ*3pNj 4)1+MI8FNx~SG%Vi^UY'\Į:#'r]+9+ME*+(\ .0ڵUj()V=ܫHM2Uw\'6:o)c3a+JYD]m̅ġ+A6cxմ&2ZF2\ 9TM35hZ^eVԠIRO z/lQ7+R6j L&<ljKtiv5gBf.kYkU7UI r34iKP-<]p_gچ1ז;LRG1KPT@dӺ+jvӋ>үP$3 E9IjiP"dMʱZ7T/,-ҭ0$7$asJw.5:ڬ6ʂѕ ZUd:V'>rEbP.sr ʮcX!h6uMg:P+@P)BIJ"Iň7zFhӊuL麌_m,RӮ:Є, Ū/ץmUR\PgnfUz* X*2 wWO(Qzj\\ QVrYI n1Yny銽cӹKeClԠh&L|[ Vz?RnfO׺U~NQKIp4`~xY⇈1zLd%vK5A:0TqKD6 XW?љ4y]Tnk洌]',KTifHaG@ҭczЊLS >Dmh)mmOh]jWgssS ZHE{!D }Rj2Ky2lRnY<0KzMGshꞣn%f a[m:I%A\LTǍ?|;(yNTioj"Ib^@YҘ8j+.ˬZ!¬1 7A\s8iY*n-Rak*)$6Ry{| ŽA4.SHq6!BADb8z^[D$(uxŚ:&_UYɷ]Q[PI$aq5)ۇ4Z*Z 34eJZ6(X`9&XI$ 3ZO~\8ozOeڇ)[uڟf6[HR`ۡqȝ5=LBTKj*;\bx۩uܻұKʷTIX),@",#+]R}^Z:U*,LZ%L9NbVjAUOVBHߵx4^f3"c ӺPfTu~m(vD azόij :jPfd(-BhIPu 6|Dќ*ziF֙՜)pK*S%(+ iR)GYfX᎕4/HTSz,Tjn?ymĐH*!$HŎzluJiM=4+`2 @U$Ρ_öa^Q{=*bY &u'4m3iVi/\j!4tJRmnNaudžҧZ}Rdķǟ }>~ϵNg=>s[e[eK $$X| gU I\Megu QtًHu]e.jrolGWڕԧI(^k,f%;GHѴkzV-o,یfs}u-=M;RVKpAo6ij!8Hv ~؟n(tz5=bC;+le`I\{;vzuM a'p$NrF³W $g{Ɋ\:\$NC넕W4* rۓ$nA**2-sh<0o?&̴&I F#~xc ~D 3,'4q/OTivHK-& $홃?3 N஖w2%M}nǖ&6ASPR)R`YHm\|\BkuέԩwYJd**y98Ng薴(TW@@IXIDĜh2LJ 2ohJdA>gyzbzAGׄ(x]cU6R[iS:MϩrP9M;Q#ޓC?9.u**T>In)*K ;k'7itumT5#7YBr4I`V9ΣA0yYsD6J NsLmNO##+h@g c5+|^fn={GW~mʇ'&#%HOt7piaϻЕbZpE6+ͷv巜t~ԭ4B 9bDyRR˨o?.G=ٍ3aYP`DI0#΀~#_ ;U7b2DqNW-Si vHy}c> q%0}pfrSfb@{GgNo+ux2tW;L KeD[Z~x z7L-zSZސg#o rDIx{u:豹wec_17UU*3̐jyX56^KiTVJEQ O:;.ȳYKkBҶJK+7%+B;ZN!IҶ! :RUP&hm+TLXA,6KSlՏ\nX!"H\b; [eJ\"hwY~8n hWVJ̐I{`Ec?z^,bʶVjCiT$&~_>SPfH>GL_cxX{ZJQPF^S30Lő-lO/y%@"NUOm߶e<ٕ,.) yu덿6HVr 1&xLv3 #ポ(GJvJ(E`4uKb B#0hTv8q*ch#c'18;wN6=xu| xS5f~C.R؊Hqƕ Sϖٳ{<њ|~ҩ%&Qk'U&ȝ٭k)~Hy(3:+|]PP2Mdt:ڹPRn&?}IJZҲڏ:V)$ʁ1?6W,n1*3A$gyWQ-(-'#uU&` ؉ry ΁.IF=[Ly'S︬&tA':r}GQ!cץurr_$ u+^y{К6$2lmģtȓfCeb#M;݂9ybbTrA $`tF`B0AAq}P|Z#-4V;4Qfu'Bk+]$IRU S* 8 ;KpS6΢w,Vp?J=G* P*) ?eX&qR+;Jekii<䂗RV)I5Q{ $T3j"ѻH!v r DyFb`6 I1ƭ>xG,MlXn]9%E6l_]c<TMxiyw8A܍Yn[U_]-%j2BE+aŬ>WAqʶ-m2.j-]_i 4OL2UĸR`A(C_[ReZJ =Ɋ{wUԞB򔆥#@N}eML=&R`bw1#ҡTArc0wE=ʅR@`{{V?5v(x̵o ~;hMaPփ^fMRicT-A+_ Rh$ i_9AZS;:<&>:R9Oԭ)UE&_Y'٣PiWFiu+5NnsZU=>W'H:c5&TȽdċbxXNɂSVhO4Kq$m"Ә$APILa;bx_F2 +<> LojG'4Iw.ӃeI7=;!1nmxo5wyUM̫wI1@SV`!2&^q$DNTW ^-{=T[Ab2m_*f~ OmkIQZ'= $pxp n$td`WL2s続 7NK#p`w̕d du(SO(J`@ udS)H@ IOvZ)!08U QU7?}SqT@.?E/3}PB"K#iiW- P O,ch*iR4-DbPi J#ZbI@xgy:|$KsڡLVU)T+Qѷ_/* &NzrKT˩tԦ\ ;}SS^G1$q^"Ab]`3$F3,8i2 >^X)N`BEb0iCFB 1~`g\e:Q=I.{'K(9"+2m}~.2ܪQpoZ覧a ~(@io6T" JG{'kuz=<^t*[VZ[}:+K+@nR^"UjwlFm6~=| p7Ƃ2=eVjj(us }¦Uym1=ү3z O5P_@*aŴ%;b[*2'd[k=.z7ZMyGhP0BL尿e,PuJt(Hqr0t ip (oT|pf w)$2q?QmA0~ۥ|kݽ?~-YK[!vrĕ_4#1S^6w bYѤc"3ǥ l(`\Yh% wag"F`Eۤ8`6k{ߦ9ٙ P(DaX~AY[ %Y@C@ IJ=F(RTI;[oNi0f@˷(t;zGS=1L** b3ZZ4) ;I>'GSjIÿ'8.()'|8~9,rО{ |.$yt/+{4Ɖ`s>r3[!Jkr$\q>?--\N1a$wPC=evB%*+6x0|鍃<@ʦV9 3XOUXdaDs&i͔) ugc>Xr5a@{ X@#>$5!D''t3X{>e,$x1V ?v$w'Uk`ppt׾9W*A[tikEP~T()t wR@;4XG,̈́n/{+[dyg=LI$Hrg;:DprqǶL.cNe5strIKu  HJT~@s#ΛRL)&m[5]VTR{R*y?C*5Z֤h~e+TT{xx;ZNUmN2!s}=e^.- Rf CǶ4S1t'+BF,((Uh %F)[/N8K`hUU9_삈?L/f\yQPEoVTmiA#3C7Fი$o$~՞ә]p cpu+4Q8*i)NDNe*JDu*S <;&pI9N }ѳؙf0ZKĴ=z[CSt40pd ~Iԭ\xzI6W#s#$,H>f:@0N'1Ʃ\[Α=A]|/]*g xX.LGxsiIZ! !K) mS,8Q .K:N(C!@=N?P=,{ghGN` $nǴ5N9َ9wVն8ZX8=@zxL4QJ)4U@/ayf,.s\k"ZVjdn(?e̶B[0$,=nگ^ASH- @[i Tm)Yk=OV!D#nʉ neu{Ǘ}#q$9:m72)a])6.O~T`~8LT-ُr({/Y_/;F}6y  cF!%R܍6-$hIsw;2H /0t|;cj0??ac01?39:,3P܀io=mBk8V)1̒=@,ǩ=7o) &cS:9=>r>4v$0;iμJp*4V3Sҩgi$@M8վ42`'Ȉ&>i37)e@Ke֐NQWQ͸s:h43?.|;DCiaB[ZHXjI]1VQ D>ubJr}I&3Y328L?<A$-15 eJ߬|EBL#c"m;, p(Zdq--iZ%J$BokyxנZLAqH-b&)"'k~"SQJG$ X-G-u$>hlEM@1RG12ooܜT|^, (P9]Tz3^c'd (I8֟'K_T ֮bTb0S*aVO#xl0u{xQɈ93t@ͭN~S\gOrr -.uj2Ȥe4?wG!_S@E1 qB:KI''1DcƪvozT,qē{Ɛ % ryk3F*@D$u 2=W%7>5k姥aO_(D{FqژQWiQAӖ0A81"qqxf֕5\O/J{+u칕:J%%թ$or~yYw49]PNkh26Vе%#BDIbS#1ᾝv#uv^Y2J%r~P NNP25il%X iҺ Gk NPKf %t43L *rh lWk etRaJmAںȈa+-I[yZ#$<0-zc~oX)sz!YA6UsaG+bEB^f4, R4 !$v8x^ҭBֲۥiRvg${X%~QwH{w!AYq|#W7'M&84O1\yVUC]3EK_xRH">1x* 8+)nOrӄd!ζRe(Q rPG(<ΓMdUTY P, YGLxkng2e+J-" `[{iB:UyN'aq*Ox"{jzBk@ FPX#yӳMN{"ITm{GoO hkkt:9aDӥĩը͇,3a,^&Fu'Yr$Vj^'.UnDK #mk-j]{a^.g2xQU)T(}n9`;q׃G0tEFYdxYWA\^q% YCwA &NS^Us*ʘUe{FhIUqH DWfyfk?ϜQ9T^o@)!I=S70a5s_i~똔T`'HFqQWFjƫt'RU ;f+-:ہɸ@I1tՠ)ZGa*g ZLW1t5ZQT:!rMVdjYP]6l[QyVۉ$#F>d:U洚1MKER IRhQ-ziϴOTY`2lsRmʆ9% (&@]::5S5N3VU;ᇿ䅬By['uzniUΖJHoQJJ)2O +>m^ӾuMѮ5V-U HeYq֩2lү+}/zhfnԽȡҁ*;3b7i+hxv&ӨIycr#L*VSNt! %IP@T|a!Jj5=N_5Yzi `$t7רt[+z,6GM7x4꺖mA2dߧWwsE=PTp 4Sd] :֦s#ә2*2i7ŠrɋN_T0}޶.ZyI #-cXqLֹ~[Y,v&]USSR*]h<`ZcU.cR䵨͐*8Rʝ!i'ޑ3=B򕼶PaHf&<]aYCӪ\II30Є:ʄD‡A4ޅ򴖊Sҵ)ua.WB/U*QWZYeyRkuj'JR Q&z$sA\eZ;2{)*RyRkl6%*jn _3%=RM=V}lhVJzN+T!*@MLֵkRnopVwN_:NM%fTe"Dci2\y%Er*LT3WI׸KJI@Y 'oetBRdCi[ i[H*3q'|U<{~Q*QNh+{P AƋ (l8N]EX콈 ըR {{bq⮇sFF޵ul[̫QM:U3 ſUgǍS:RsyYa-$) dA _t9EI3f~m\*SBTT&:|9⾂)UѪlL%1NݷYl)Kf-bBUZu`T.rJ0Z'Q<,,v_fr(_OJ;$,iΜx[ZwFz[fyfH)4 R&JG11Tٌ*,+eRthHJPA"a_?4uԺWګ#XU~I%̹.i@&!o(~oVק{[krAJJƽB+9!‚r8tF^hi] U.'ʤ_"$`O6Nt8>3zp gTJyKd؈HwciM:(3@?I 5xԭd4S\rE= i-6#š %pA晘=6MJl)zp**}y>jM(rF'Oi᦯FFz.aDCmU6~U$ t>BM=3JbhFvZ0V:LmYyE*sRysiV# N1MGff|Alʓ2ii[svznp1-Y!h!UTMc_w^Ҳ"Tvv+^IfL4j# 폵A;y$X½_hk1T=PuH_+$@9cnSi:sô^tVњ]2U6D11W};ָV߫!JYܲy.P)r0'=tEJSREA],',4:4/,.nE܀pjӸPxtڄ 1L <>yU]fOĖw~_ru:L8G3']Z|=h9<߈;c_o jޞR(0 ~]F9`_n VlZV-}1?[+zPS٥^z#ļ=DV,E5]~_/; *Z'#?~3XWI= [Ϥ x4]]U29u*d6e Z3z1G230 KQ1qfSs' ٵJOVXsrf<@`D#ƪր`Ȯ `ąV"3Y*6*L\>`LN 3kA'?$Fpw?FB,E/lQe}$m};y#q = }X4JIP2Fg~:Uw xefu46cm?w}Қ B6O?7AkOW ֠skMoz7iogTYzsAP@%3cwu~ڬ>eEԽH.:ik)'InNP,܊Tۇ ɝSzC0]dȁĘ"x "^jUڊZzk?#ԠZG:{?pNCn%3IbqGqZ*0ӕ6;NP:BS\lK>y]JsEVd454IusqJD. %?mG]6bHV֊ -UZWXuG "E&R7I,AC` \NA\%!O0,R7s"Gיٙ}k@.5dH$b?Ə 燭AM\+lPduuĠ8Tu $wdǏn ffFf #Ԯթ+f(Kˉv--!%BnܿF^tSO +u6?ə 0fWIVÕmL-2JA=j~<;nU'a#G&U]^i<\Up \%T`Gaqx<WIS湵n]..TΤ!tJck:/j&aE nG*{HFlxc+s ʽ+iHɐӿSFrT$I/[7~/m5eb$m2x@ %2ޚUDC^dκ>Ѻʚ^e? ܃~g\T5.sQdf/V } !C')ɋ&̠Ey }Wy^C[O֔ qJZyiJ@mDyA*)RI|D#aWԕi8RD"I=Oo?`kxtmcqSSeڧ3~e8Դ@%(A#q$i <ֺ׎񚪎X[NЭRTKM -ePBGCl_GU59qꬋ$4EUMJZe,V!@({ 2T^:jhop@f,e9s|?J $,MP>역@.(ie]TS''Qh ylXHS`cV_O+I=xW,s¬5xѕo4}IamQRd2gd3ᦏ3)52e9SgɸBRPIX}~ɭ?O)_⎝ԕDXwjOP}%E;`zG*N*lRPఉ L*aU2 ~ϬH+ۿc7Fx#Î15qJ+uHc!Vj  < fP)R D Ǯ pw8Q/ip< 4)rN$]Q@JCo=զMk+U7J(C2H:tY#0eep@YA'U[ԙ̪zN H VE .p&ռOo,U*0. TPJA;͓WUX@pK lW? u' vɴMBv0%r)'ϦRioZHsc]6ҵy`Bm%y<3?#5O#q~ڗF2$EG-na`:Q "ɉYÿoJNk M>23fܧx7KT3.(s;C0^B]( qZU*R-Su]h(阤p.I }+xӞ'p+'o+G!VG@rJ. mP_(Z3:#I<\}KyȫH)Yp.Ky$!HBA >-4iq?p^ʟcfmh f!0״ƂRn"*w;6^׺1ooAE_A5͹j}٭%)JRQi@zr( Q**U&4qNVD HĜ c!_vrx*53NYB9.jrTױJvj)٤DqֿbVоsy5/2>wiw=ւqԒdA r?% O\6҇NQfq/5ͳ /C4ug6qe `y)6swY'm'Q25fL(+ SV;Ac/:ܰ) }^]*Hmܤ@V0&1َӼAʫy\j R$s<7? MFsuK6I$G%q *Ԕ.G5JT+I9*IZi0&H=nw-ijAe9JiRV)gpN ?,Sh=US9 !ai ,:Rl X`5b2^ gU6ͳ%Z+ʲUCM#s%G`zs0Aǿ;C>3UV3VPTC*mSkITAE_֫FɧQ+PV]Z 3NT;M d_aaG⯄"|A?H#[!NMT8PZRJ P c'qQ񪆛O^봼Tp2BȢeJ AM mr/9~Fj7Mjt6z.NfXAe\*S)h|r*2gQkZ̷PWT%µեԂrr݀\jofN_/zʡ1 =¾Ģh1by`8`{T*Ӊ3Ыm{٥-#ҩ‡[k٨8R/!=o,5QksEv͸y-rmQdMPgMSX qMss\ ̛~Og75r|É)^[eNRSt-TxX/ c~ NO|;{u_**s^KD8@,ED xOZB:ӯG}U4UrΎKAm8&9ZO t?tFgֺ&f-r$u4}ZfBBS1nf~x^uky cSgyC”)AT$0T&B"xz A3M85\P֩fCo9Wq)WZJH Lۖ>gWk?yK9fZ,RU԰Q A# ^Jc~jը)Tzw;)QF`)H, yՕ2's"=8OaDZE)jtWrD70Tn:HcEG=V[<>i$|=)?E$!/¦]?WÉ_͟9;F[͚Kw؅) 2BhEj'~mDNY/3`?Fhs=ExK֪Gȵ8Z,S%2O;d(*I-CZ+Rj*!“d1Aj5{xRBmU`6dq$H=9+2C|4cDh ꊭ 厑B)}}JRL7bǍWԮP)E^WE 55قZ@s$F,l/Mc¬BpY2 m:Y@I  UH>?5k{VUZjJSWHBDh myKէJ&T/kT{r)-Xy"ULFy51 S L>"uw4$\sӚ2tUSaQSR)m.6sAHU``o_`WρN||CkMQVrLT )٧ RRa\2NZ6u>Z7_]kM5zGVVx>>afP"{ܯWq7Y )>s?QeS4ˬʞB#ө5MZ.ۊmU܊%HBP0 ڡ6w2fry#i;F> xuǾ,qgRQR<,(][u)C/O< J]xֶb=T8G1T$(Pyy- <+j!r}psTNNKW\R =[e>~xkC\(q&LXf]j)EK@!ǂ;̃Z=*+7W*tZ量Rmjj0pa*uAf*)څ< ׵R+-WāfDEe#Ԯ}GA9Ig>b0 Щ$ҼDE*>fnAWgތ2cA~ĖiIFd|d-#0I|ISпwF]̚򹁟IV?!Z+^*4i;pJ 렼=G Z*ۢdUosq׋(j2B,/O??zy.qS6Rq R J|:`K]<? q7 _yHE ּcR'e!%?8:^(Fq* pqvu)RDJ";q [^llA 鉋TJI;H@yjBPW1Xq f ${0\hb$x=iuO  AhoQq Gu*0-$_:s1Sur 7^gAQOLնB ȑ7L>b&`dgs mc<^mE D-0MoNwf*gګsJIUnnO|@\=aB_uTմ."{5HLS; ҴWr=ҙ UK 't+`i snzV'FV)oY FayF|>NU( RïAߧONײ(VT0 SƓ@8֙)Y6GסWZ pv`;3^]r~Sh=āE`B֒IfiICV&ׁ]: hRyY&ӕV"M'3bǷaVG:[3쬟KLBy29| (CxM <,չg .z)ș2l6-kՂ?(Ru+9;:Di d!V̰w'jT9O3gʔ=V%E;>_ v^wLtT RKf<&X'mȳE͑UUERBiHHo)| NWsOjyC*em:┓ PH/ګk2s)lIS$L̃ԯ.}0 "9:j pq߾RCK6D4NFqh;wP $ArT3>g:B8Pކ>x̤-iP I#$%b'mi+s1,|yH>r>^]z0Tyd Afc$;[^iUȚl$ Drv$LzǤcXqk HH1# x=a{y[8nA{0p)haTnÓ;/S.dt']3̾ >YBvmΔԀ#mrfzT6_{P}!iA/:m _.G:w0tWJKK(  \Ñ,jҐB#A9:U)!UʰO,H'G>.GܴB֓ΛQ c߹o^A^'f4W̄W"$b&wFsT}4W#T+q?9ijX% CEE&&z*$/ LW).A~Θ-&wr+Y`c1"I|v *Qi_?v P#Hv|O Nvd jHHJ* <s6 AZny`;[a}#uV2a1&>fJUY$HΫ49oiVS*Z3? !mQi zxZ۬uĥ$7Z{&̲l~B [J3(X;t.2}sF*Y&(3M%ĥp!Z*75:pG$0"tʍQa` ` Nd'9G|c{o=vEIX'aOԜ+3}b=}7Ʈ]VKS~t Jq9`ff1FF[#->yy_Q3oLjz:|#ZY.aon-{%9{>m D|wyN` AN?=qOo DyϷ$N_D߬u:3ԺҿvVʀD7RF_PHLXAA-AO50;BZ7Msj4{2s<m)mJyTEhlӅ IiVꬲ)SY}Tײnxn|-9N}H {ۋ wZ=Ih5-)Z7 7 :A6R kJʶ_TaրLA_8,7jZnjOΚCkJyOm$f#/<δE>^Ko!o~h`%o Wf]eٝs5HXOܭ*JBCChm}gOhט[l YVts$SS/-Pc44VoMhV>i#ʼnR0Dn(UbDyiJ~Q&L:Jl²PyPsokbKQ KI0v 7QCN8#X*̤sk;1! teCd&1jSD @ {㾆i<`~>4FaIVR(H?{&y5PtAOE$f?npSQeU9]s/Kk:jt!ֵ -*RBBI3xzc=ֺC.=4%}]\)C[$y"rV)P+RL 2p@HC˖Hmũm!P3Ӎ@Z&EIByLo[M'k\ͬ v0I-S62QyZ? 7$ ;;bLlN˳l.ytn4 IbSr9I>cFYWNzz`ޟNPa.qV+Spbd :q#§4Fi]v4rmաUʆR9kR{\0gWoF8-@q.RB;1rڶNUdUљhe…BJ,s4 hE!gvm<6HZkCl2e $)%"M" xNZ.0J|lWrwrUjBAU!VҷZ-I45]̬ A+!pKS35ox+/SIHf*!M-%"Iw)ިδg27ďm!D 2 [bZǵB ,湾CR׳PA.#"Vސ{ Wo 'csmAtj`ZS}E'J77Gv5뷖N͑^zKUH>`*9V zL2AiDH'6O|.2}%k|,fN3,Ħ-Gu_Ba2O6H%FH}*|@pZeZ[m)eMgN]TRl22 8դuͲXI&$12 k<==Yj24)K*AaF'̃#ծn5*̻wL('93*Cm!9& x!BL()mԺ-ݝKa@PRQ WE@6+!:-GTi 3tsmiʪ0 X<&@Hma5AS{?+UIe|+tŪnc@]j0δ2PYiTQ!ƐOIC8'֬Rrܾ)EQS<>p!Do3S+UV[z/N5=VZ5TK.rƘ_TjTj~5uDҨ ZB*AyV0o;s<8VI_rD*R옄&mFv[:L,E{"TRt` zLnmĦmN-Ø'6Z[96oԡ"nBP gɵ?r̍~ady %܀@$_vuպp&ҊSe%M)HՊR:eClަPH V`T wDLf - ӸdNP $ Go,Y{uTyZ)i).a\0ͱ*|;i8Ţ+5dTJP(Bਐ Fz95feF3l4X׺k&s̻1Esm:md;Wa f:?ZSQ)!"yA2ƅ< onztKPz4jU*Ŕ%/TǩԼC/P퍗ԧN(թQק@euPŪo:{=[kW;4N)T07&FR8I0?n5m[UVnT:^}\reJQ2I6p@)p _nmn!ђ-j%TP(cc,)h$uClPh039 N%" ewt[N5B2BtJ7:H&c>`Ɩfm Q;@QAwf6~N;_M'j2t[JBvcȤ9n.\(`̼;|ҏ81hکΟ+h%TZKiU1rU/8H6jIpH<ƥw;f5{&-Eԉ3`  $XRy#ZPKTZ-V;2 w췩,/j%Pѷ4Dn3XG$ջ5dQP\ԡ #seŌJS-?wyM9P"PxJ\Gtơfӹ;JS٦dTV9ZaPAvL*cx)"<þ;1xzꊦ+M5KSRաAqa@@b^b5. wrbqv ,0UY^UwSp l*r$Iⵚ|R{pU<'Υ>+kŶ|K)PNw,tkمJ)=D8ϰGE#Wfٖ~w\2ܛ=yJk+\, ZDbL⫛Ҝ$k!A$3<2GE$nd'x!TgfNXXqpV/N7<]&68Lj|֠<}.ucMEOw5VsQ܋#>lΣЙAW^Zkj郩]CPB1,g?YFYQK zYʜ4Sk(+xh pztmK-EB!gӍ&-6tqLd'#\Lۡ O79r L^w~#mXy3LyۨEIml8I!ITA"w xs-[K~iu Q@Q bʮ0&Fʟ]v55ڎ9m\y}ʠ.'-An\Q 7uU*mO;j(5wRU+u*T혈ϾY4[!O-J" DG iJAіe+Kr\LS7;xcګFej=kkfbWF,;!MR‘gW*$$*>_g&͸1mY8*^rRU+mN4ҖKrJu≼5V]Ge(.̃zi%RW`TEHf0ID$FBī+$MqZ\bUa+mehTmPtչ%EHLQ)*+ Q^|ukOkuM,Z@iGxM-_IXVgQʅ -)BIx#J=Os4Fq]EN`ژC,>6P\I@8g[-*!(2n}zTn $,ApcKSEӃ2in#r8gSOEJ.N`.d˲_&$?$UӼA[u a@\o=~i5{nWy m-Σ7Y[*pYT&7=\GZ\fmUzt  Wg|eH#viL!pm6Dg=qgT<7fJVc_Xtyud$TPm#cWNo%wSӣ/nf *g HtŤ*GREyΠY"<'[ޝxKRUj=`˕5i6*eI;[q$z{R!M*kL%CJjR£2@pqeqIդ7Ze݁7+.݄2AKe̚5ycfEK8*Aťc2 -XUO/59aUV%o)iq_Wx|ն┨ P^˭娨h\\pIMWT*8,ă2$'RفRJ.#>L5@-|έKt[?P]q@+ZN96\H0}՟Ŀ iNSMԥKa`H2rW*Ԥ?Q՜/MI@,CSemb)*`  w1\kOY>/T!C8I\V\Ebw##bCy8kni٨[I}ۜiPyI^sʪZLIHx^R=J! evUadLwt.9_'Dd59ơ[5 )hE;$< /,nsspMf Z%%/HxF r_ANo2Z] S PIr c\;֚4}ʚڜ¡jr`V<u`v0tjUj^Y*+ԩNPiF1qY訧"f$F {foTO94>x7әx3!BM動 B?eأQdw97F ڪ5-1:2)CJJT钰a POuE0XL'vSPND$*{ 1γ8SJ'MВ!FIcfs*B!  ?eIw(ᧄ"8^X%.`Fڐ=kWu*₉+"1g |Ks-C®$dy]n[V*-fTj V0[@$}^ѡ^᭪ +$)`0 *$F XX$$?i-0ɲV6Z) R`-6=z?A*c1&KuF^q~BAQ$Y/>3׷6Ƅ<@*V ؏=~EZY6c dL0 q*)az;r n )F[}. u!* r2bcプ`[XՕT[WJQDgq4hsUcĽUwLT RXKASidSHe$Ș0G1AL  [ZWOU'_~JaPP @o-(/Y~aog[ܩ*1'*$y^H$ƒ {D4pjXf P>l8`-{bpMs\AOv'gbi -;㖼nu f$ ։H$${kz/I.9NNiBPd6#=NӋ9"r=i:Y ?R,`+㐜Ǒ/d#0s m^Wfd52I;"~zGMbpwTϱ;:Pe="Kn׏HFf+${e 0 i (n,B|^0}@my7_.-i@+{HǾuUr.<8'81 XL$v?_o ($,*aONkfD{j7Xkcb6i8J3*yURԩNd*RĹx7!dJA$L HRJUZ}X*6@kTW3e%GV9ydDZsl{F.c6`J6nJTV<c=A/ $)o) !@c'd MRW_Ⳍ\*θa;ýC\3,"qo5QZhRZt"V]L^~?S5d .t Zw{ָ  VU̐v&'2f$,8 } v6)e\Q s T^HG17V8r*!@ ImVDAdhG&AZ`0D$ Sas H _}*ʔ GB.> Uڊy4RJU o.݆%Қ+ KMHoĶb9N! po7pꜿRgՙTZ7jJDnAuwWqO\@<%y YS]{nd `,mM`&J (^QJƒ*%nbYT% @4ݕ $̰s/A:,HFr+T9nf3CRRRܕB@@sXRBup /:4^zO``Nn3p-@|}c o*WUީ?=@H!WLLʤР%x$9 2qܛZ2%rn~Xv{ 똒~#=MV\j`*3&g-bG9'M7h>EUg8bGn955AiaA"#GV}1K [1,ΈmTY>䇕=}~r.1j͖9ʀUU:c{FFfc7 xZQ]RQX,4p3E,+;i{1:^ƍƝQ}I6kXJ2OѾ} XM_ž{ok!+ʳ-YZ)벧ܦ,\:Iuj%ErʩM+_U?fߧH[oK[{ýZq BhԂVrw2) |re ȟb"AătGo$w>'s椪9V`.{MT4jfmDrců3-NY}~Мj` mpe!jTTPSss~`**P6GR⠉;Lns~׮Q֕ZIUrME&2UUEج0bic<)p4YC3Z%sUQt^eM.L`)k+(m 揌Kgsv)+u^wYS[r:R93Hm3;qi"ۑ>CaSqEm:jWo2Bv0&t*;R @I#Yʶ2 <\Yχ˒% G omoeliw1d*4) R?{ytᥓ1C% L̏Asvc3ߴo:pN6!J9RI&6H+LR=:oy:DipJYiT'mgwz8^ԨlӚ69]-UH޶6nAYVR7 B$bqG8fL`Se3藅꧆AER8a2YQ r 勨Gů1?BO 2J$iԇ)k*mR9l }jCeFmϻ$Dl{@/Rd4(CzHd]Iۉƚ;H3$D':馏)[\quyY3bUL?jSJk((,ugUM̻^i-R+\MSҜL/)9 -ztՌ%ĩJ?h ew;TQ4ޟWңvS̒Ni>RzNA8=M^O3T=V"zgfPҪgqgοvyV7T%3&=0.1KH$l#y8))ЩM"ok]-:΅-PѢ6 QvfOQ)@q@F>m{J/w1o1 2J .ͭ_j؃k &c狊T9e + lЪMs0$ @ * $xnt訳q&!\BkX|7qYzIu&>]6n2B XRO77|2 UNL;wupԙp `e`Fp QV-ҮKu8r'"d IIͻvϬMV}~'6QkZ̛:vtt[R>2 aZRTcԋv)BSp'{̞@8ڀ`́ Tl+yZQL 1F\q#r{v8x<0Dƞ^ˉ#wtkc6[t9).VD).,px>?.b3^td#~M,VF#ށg~Œe JS6H<ǯad[%BUXe8'NvE$vgJOIďI,:{)1 8Y8xy:CqϾ$:~˸ -@1ġ08$1:T}u$@;ۏk Xji?9K(ï!''j҂Bcz󱚩Sܩ.x -m" (pFg_!P:nxsetrLgC]+s)7]*mOEMh`$͏`}cEYXW2 ۚR7G;Z1x RI@4D&?beT+`#1ROƏڡ@ } };';f|!cT0OӠƟP')aNH_yV7 {dr{ƍ_mn$ 7!-;Йڨ\ieHJJAmaBitMpwkvhݨY!)ܐo14HR11$q1G) HD"G5~,dUuJsD% n!D8A< >#y4p?N q뵿HeC"G&;$F?@y1q{OXZj0[{~Wm kF6seS!/rߩoZJdXT su6 Bf04*V̥26ʐR(Bwc8}X۽j[6>`]c8QZ=R܈ d'KԴ-)im IO$$*%]L[4w%)yuH\T c~11e@$m)?\<<9>mSi)ާʒXSeZDɏBYZR3ib ʅF/mswQhPFML$* 798;Le>w-M%G(3o{X|czO]+Tg2sP<=F48EV c#o^X%!.}]tke9&v'^U=[tƳʂ}% %Kw1שn2C1LLtaC4^#;ObN&=4K l7YԶJRNO Nn*RG0#6O8OVh]Z!}ک }am&-t$@mmo^SoP3I$ϸ1kX$CB9`s iq@=ϷO0ѩʷHT=G8;Ŝ3vޣzunbJW 9! $ Lڇԭn6U23- :!VTR^ !FH$>"c#*60`ytbѣBo@n'u ( 3=q(q$ͿOX$DU$)PYR/ߝ񂴯>CX A%<;E\[`Sd )Q>ɠAMo9]}pq M"A8g'{门2SW:1VɸSkAqhJmjoCƼ:d^0(' 8m55f_dۑȠyB|2j Hl; I2:?irB}w_#ɑHi׸HG'z%FmQTe $sB(QZJ0OG<` yjAzSRƺ/ټ-}}EPYU)\ǘ%D2`̪)ZM!`$D]'t\[4VJ;~̨IeC1 Fd wkiBFaZnI{{SڲMb T~Y.<XamG[lZih#Z,XxzA$N  }Ǭ O*IӺE'AvI-}Yc#U`r e"rJg~Um;žg 5jQ+0 F׿,zB"?M{Wf@ ym X` V6d=B-l0@$Db;d2ɟΪYNXԖ?[Yfmiq]QpTFŷ+9+3(IVaYEI[ ʓIIt<וrVRj=DUO2\s3lc ?OJAbRvaL'cP{:k:VsU'EhRA$쵅RD%"b->[a3WZL!ۡv>-)6tdž^ڲT2H $euӚtQ@$835,BLoasd@ttXxWӿ|I<) -<9Uro}>;6Мy@8@A}nrUylHPxp'2Or=0wo5P^dH{1:\GD 5@IY+bm%OrGa؄9^ˉu+Lî&k;fءҒ ]->~58 ӈ)q:2~JMPRg!nиq%ljʯ&b#|u)FxT;Y+!yQyT;%Drछ?d&$ydFuu:T‰ӯ 2EZpHEt Lܨ*v-y!a>JL{B gL$%JV'Ș̈́N!]S}9ߧ4nV֐833&5[ *~N_$g׋}L04*WNmf/ ɸm6`w&zOǧc\KQ32ùkR %BZea!Ũ!3"mm]'ZLU*+2,4AU̫L "'s`&cVqm{^pJFk5%5NrhJS))HH)1uvRh8Rd2~clEqĬGf 8NoJWXpsII)x"W,JpIQ,z~ɻzz5,m(RicJӢ @+rXG 5YIJ sZwsZ֩zt/JEZH*$NÉZ\߶!&[kϨ _5[K,囡t}ϯAz.#kÉ I29`DHCap1 NшUm1*c;y8 h,nW}9S Φch,I Lno<PQj9;ۡ.eg $ErBU w@S0X=";*IOdWP +}81ί4{yeA9hڦ(y ͠9Mdxx0& K 'g]q;NfS)cĮDҒWgok}B? YAȒ ǗhȷGpeBYyb $qyaIؑ58* S~t?q1<+7uOU9v_M;iڐحyk )"$Zg$-0Ers&E3$x4ܣbeOnJdR@ aZLڝG*7[ rO= 탸'nH瓞ڶ#Xi+f=nvi2ϵJ}Ԅ(6 9P6eF"ץH77GxyɴƼX5n<5JC%-L[-̩C)RHV׶Uq^P; `!֡Py@ /`F}x # 7`3#<:T5rTQ%P@>T6q*dgJZzTe6e<ܪ n)pN?iʊjhYed)U 0I93#Zgug+hLVT)2n ZBNI tޱFӦ~;QrCSmBw,LmPmJ NBZj ΤAJZJS̢}V&aP|:yxC'3^ǖ^/T dcFwZ⊝;6FȘsV~ H4JA#ocCÖMD~{ʏĞZ}V$n-c|)XKԊq/jײ(o^ -Zo N`!\sF@{Ƽ.33i4qjS{dHHEŞj6xZuNq]HNaOJ错5f9uYEf>{y`u'.4(B璞3e/0,%;X^o30SJ"QϨT̈c` Gct6u3ڍ? ,ʁfZ] PܡU'8-A< amA o5|M*u;V~)UNםTH63/d10ԎsB (],` >.̊`19Ӭ\p%[)ACy&?}NlfZUq#ᶌ3\mj*,@$5^sfk23T2=6^6cU&n} G /nRLq7wd H;?cA OV%AJێxHym2 pGΘ=,P' ITZ<4?*}ɰޘ'~v1.T;c`ְ`y\fCK)R7v뎿цT B?ڎ{X$yG\r7 5<^}os&vq0|XK(cպxU?@`|3=2¿bJ h$!ZHAߐ7e*s>޾dkb\" v~1"11?{f 'io%sb@#ĘuV3" ?d2dv$F;9hb՟n܃۶ZZusD@#kvMig4 Rghv(^(09;2pJVsdXaKpaТL^8 pd.iUei3${TŨ+ꚗj]SN:Z2Rʌv?,6IJ,,:1DJn=>{|PnvY<Ǝ@;{.t@bdw.G'W{fz?ǎ3E>ޗHhT3<ڱ*j Hw2!uwE!qfZ6ϓkMFvœuj2ˊRPԞt)P<_7hT ;qGLLTVCoҵ9\JyAG0>|Kx?_s iĬPgu|W[ 3/-dI*b\Rҍj-3EԕaJ*u*Shަ B}LYh U"LzdD yx9JR1ԁ_xw_Zש(JRz6I{bTLo7Sc[O$O_9}fL;Ieɥ!@J|*V'6WVR%$@o371 ^Y&U19hPt[=.$IZL&AhRk,RuA-%*RS-7SEu^R>A!DH*_1ԤD)Ia`2{_\4wQo- bK+;l*@!y?'IPՔp%Zxg':%:TI)L^',5H{.4BII X#Į%H.%slB5I>q6ᓱ[~8Zw pU $'R]*R9"N=ƢSS/jTʉ&I_fvĆʔT2I= H \'u$|l[KCPE1z_0%H'p@  gE DAӡkmƔPd)$$!Df}6+:V t闩uuOe_%2jjTBVr3bl+LJ!/NjUzw1EIs"ڪx{G"dB#x$ڕU  g$1 ` `{#9۾RVTQ*@6ObTJu+9pt3 !J0ZC-$&zO[Ku fL {#amPTrA`CI%<$蠩^!U\vV]^9cI@IsI>jh4.ә>9r9TTLJT3`\iDxs( Pm-?ê 6o_z׏)5mB:Ӯ-w =B ;ZiX= X 2 Dߦ*8;H0>&AKDcȝȀ>Ip E<߭=ž1Y$(*` =>:Ƣ!^Dy g11 8g9Bd,)Ҵ4>lr̆)ʅ!DJ@QŽ;&=ҺV̱كoaJ i>6:IZ-D+8Ay/Y6wIq(Ԕ4.QRHZ^ZBCb. Ģ%5c^ʄ;@4uՐʖv JARsF#VAQuMث{(fj%[ \^ޭ]P(%i  vnVX'ITHPay$2fccSgx_LVQqPgzDQeN=ikiQP -xFkEdUEU e٨m5uAJ@'kt^$5'V+y+d0_eSiW*P2 QUf|9NeC?JE)x̺HX>wOS^ЯI5@VnwRcu%|$xZ:'MZ#$\ wHDCLdIk$::ZujLDTIR'ߪm ÒO!~2l܏)bjĬG'O|5Kz4,984<dčk[OħiEJW)Q*k$ɳw*oJ7bSbL6"M? |F;KJrߤnOcpUL鹿#Ơ%YԨ~K?0R@$yԟ5I>Ә#. RdF1:;nh0*b091:O >#ߖ%]G*z{)U3{m0wCHMO_!?,so|=GP^ =sζ z$}rK!g<(I^қ4yc>Us*SGGԸ2 O);Ne]HԳPШ)R9h㏃ۅ|uo_3"j *o gPsC)Q'arjjZ[ y6q0\NUT'wA=D3h(*m6cnvׄ ,R6 &Faf͡' T  >Q!O-,I Q#[Զۉ '6N>x&A*ě_5_m7Fk\qvr3b/-IYfT0Hu/p<[@c,#h"`pG܏jWP5 *) `:wD8D*ĉ߾l=ړ¦M.iKByKk"L+HOeO6P&l'~xj*6Ji+LpyB"0*`p8i8l- sm<":&|pH& N=O=`'rm**8\y4B׍ҏiDd–/`-vʼniܤa) Pzy|#|;j=qz_2eL|KcR"Oq#xROO"]'rI& Cc#DH*7L0$c@G2q/aT6y K!)&MnqG/yĵPImDHE *69* $z0qN{) 0"{x1Όc<{۩iwwC^ȚCW2 m$% bGKa>W Yq)_ Tg9@uPH%jL#U*$Nޞ[9&>cw$ABU|d IrL ֻmB,)7s3SN\0xQ< .eT(S#'I V2S0Lȟ- Ūw FJI(*zGrFA* > ̃4>Eb*@{~֮#QRR5IPҖȂT0O^é4-u@eP ǭN33z'y sYPQfO s<=s i@dkzԮ/⇥v:n3O~ШESN*řJd;(Szk7]T GQ31W@)NIBjO;UuaI R  s%xjݧ*7(=BqWM0U'̲>Q (6^o,1quN\ylZV0 }L*]YwVf #eG&a'ӷ61;Gm"RPr:P% $v5Iq fQ'iB;\R4IG@…Fݸ0?oƞqs\pG]FyU^n,h[kmʢ9TBI LH$aULω/Vgh4ȥEs.t q{xr9ױS1||DW:ESuB. ÏWB+20A=$fF+BǠ ۍ)aā#D DOMϯ<@l*WObdiQTzm\}H5BccE4ji֜{i?ԇ5iyAF[$TP' dZ O bxӳI>fcq»zp:c${Zee_JH e =eF9H'RUY+3Z+jZqZqKR$I+A*P*" Kn~6'IkFKUs+|Sj-\JuX 6x&ǔޡbHqN q3p?E؉@w>'KkdWD=?ߗ9*?kt Tc'9cIfd2>[ (j=>`kdzl`Epp-z Wf9 ˞i 坹;_ˠ2OF\(HA@Jiqyu*=;H36]eChX)DBDwxޯոSs(qO# (5mT/7$Da|K4.") wHO:S~;ktr֕ڪդFѬ Rܟ2x[u^viFE('0ld0L53R@esA@oAoq^9WES[oRk9c" zb¿9J.+xo-) {v3)Ri]NyLS///vN6){5'' TWWRMK+q*RnI$SGmQ +E3bm|VQTnz:2cq*)0{L5+U4S;Rcԋ%D: X;t7܂miDybcm#S7\ҒBt`Jz^(ćj0=d 樂޾ ع H8MW8ƨ<8ٝ~|I.\4ɀ=Eo;9uֿ6P*LL-F&ST̅HhzcQ+Bk*FJ. UWK%Lb8ҭӦQT4-`FYa{$iSRfD_mv#!9.a32?RP~9 <)ԇjP rIQi' Y*O aR#1'A ̻OD?]RRJH虂.N)4Aj%)z0Xn.8ە=,D8lB<w·*̪r&nE1WLe4A_Y% 4i\ ) /"D$;j-: [i`H &$yx_j3fچͨ{fBBS!Lg21;W"2Ƕ/%/6bGRTO3֍WkZWZieTuc Td O{Fi b|6ys]5i[Ͳzա H 0`{\ lz;mg8ZyrͪV2-8cЊ%5eU1YAU>5c-+W+X;뇟{;JKDŽİ!ϸsê]:uHIʉ@< 1 kccS(|=xF\)d)Ioz_ai iP#4Қz߅ 6'R3޷:{ tn^*FrFXAvU}uaevj:\ !jUkUP[NLH`Wvq%)ΝN-PٗE;e4Vj&?7PЙ\R9v.G:)м&+ڟ+sgsGR# RLgĎ֝iJjFVi%ږ XIbA8!kyw<+j\Tj)z td~V!X_)ͼl1a&՜-x3=$fu[n͡J \ؑ3hFgĝQl`e%)'h"?+7}?}sUstoͭ*Tj۵#jwMʤZV[9GRP6Eڋ?5U_yUӦ  >$H XC7!"߰{ߋ9fN3 4]yI妤hDP!"'{%!E'zNOzJ4\NyoGsm9G% T-D߽u<+k0!1ڦfhȍLtP $2'{ '8} 6hȪjɎZXp'} G toE@MtN3|S&^ɲ:Lqs{:U8R(LMT55 })0$텗ö6^PUP0Zc#HRB*@hLGx1TI=[ae8r-/?XZsCLrw=?LAut^C=j,vo1U #ls;u ŵ*7-Jw=4Uo1!i#mzM@[ߡwõ O_]h%g/UϠl8vJi>S0}vCi|c]BU_ZLֽU'-p yO=:jTj2vpdRg\m$0c@;ALA?ju4Gdb)qy j/OetL3J{P6۰%׈[_Kh/W3iP[b9tUfn+1y'˾".oEHPa*qd7'@U)&H` p2`\ZKI }Iy;kĴR/q*`$[a2 pg-9VM8Gq@T)#ƗޫhjT55fmH}A,x< fK-Es]*j-sS֊B, l^|?+vwIkn-z5+\o PR$AVFDY}KUH =FNxƁzUf$+@ 12=c?ϳGtZ֠ R $w_uOOZ " k\n9t9?vIfUȫPͨ**Dl5R @#ŭ6o=EMU&eZAeC˦Z^W[F}=M"V (RIPM;/jASx9&p=~u%YI Q&D kg?$#>iZNi1%& (Zr(:omFJ8D|1(ˍ/4RRTTI&o m-$ ~?.6ߣy!=4ltfP;I`a:׏v;m}#|gN~Y 'ުk͠s~oPRd&˒O%s C z^FvNi9Fiߦj25HK8P@BT&Oc'3i=A]j.CRVR66{b|=c+5%Jh-@݃QXlp"u_ZԨU(ҷJ"%D oޱQPU{ n_Ҩ"ԍMco.۹}:+Q 2J~[{7 ;9eR$DL~ul~fS20~H1$iw`_o#4+J{ O+V_N%D^{ߵ|UDO-dn'|]XO܁ (' <@ih.!%g R٤eJH;>n&w!gYoX-It6 ܨW~+37iVG*C XgKy8ņ"pUi9Nz.iث/5fh\Ӫ7'-NkE5XE"jSf"8'^0 f2 8zcJТ 9zu[ 0 {bAd4/vTSy@T J{7' mZBUTTۗ q(.s7 zF{O)ͽʒ@8lO1# #urk&'9ʣI29m mtա#4RX (t1XRpX> 8Z|قح3  ۹-zT8a#Iېj#Q,C`̎㶖-+@wOp[Db Iwv82Վ$ꔛ.j1Y{?﮺mbh7Og|Q|SZNaǬw0V`|>8W jJRO`gkqZӊ~b[>Hpʢ!t8Ѭ^ sC#G-wtqK}9)S"]]'xjU=?=NcR$(DN|OK|w:wo^Hsq?ϱļ>Y$ŨA=c@пxȐANpUԕ^Q+i2Va\%3c9@H'a&8O1B I$`yԏ\7\~qLh[uƔGR*G2H#|1mS0?2X#̦I5'yTҠ︀6K99:^?fuyrxUmdS)-9gb U8׫_Y+R}ԢTI+2$yO^lGxY2BR,jeiǴ-A&:g Z;>Q]T0L$y:uZ)NlRf/NG|?̐Jfڑl0~&e }ϑִRvRQ9;_$nO ⣏ZaCxCSI4ϾE?TN&SI($t ~՞Ex~ʸxV}74-R#-+ڥrFʂS?ԣ瞗JWcTUSb$85l5:KM:`6uFCFv{i .ZGO)3xt ; A8e{U))*uńx{ s,T8UTr0`%k=DW MAR:.E*7w *V!{ו2܉qOq.*>YJ6I";>˜Ncdɴt%C/DGy|32mzwbU/i w+#Ӫo @,3^>soį+O>; |7^{"8үs#ŷp7MgδҜΩrIVPrĬÉ>:~Vq(3te܁^ǹe{/vA?U1CV[<`$ g#I=u }e2A' yF> O4yUrashJWDBgr6)RPWn* CT &Hm6CߪoE«0hctNԮZ"yqex֭jMc宠f:iyaIL0hiA_R-)ulʚq@s*gǣ)uUəMgPT!jQN9BϺ9 zN!ozAzqImEVVibE]!"I*A`yƤ-ޚ7՞C zN08Ձ\mOf.V`rGy,PiZ71g<+ ڝ=؂"L+ɖy郊]X-⮶!qTNŤӣ݋ af@Ql(vJ32A:FWN4Cnf+MD$d :TΰWPؕy@PiwŸ?(R O,;u`&ojtQ!0ꤟ~w$௚bdI0A` \/循g$*,;~O':7Sm*RD% SY>ǒRSy0{L|$icŮ&kJ=e^9H)%DBw`Kg“\94f^њ(4TKUl&B0߿#*!n"JI1iBk0mm$钇PomLAu`x<¬ 3PHr *v'Ԫ 3@#AI^ufCq*t|S1ek1P:H-yX5,By1=g  t>}NYZZTI%u4Եՙ&ZS6A&}1qZҨɺ"ʗ)rʙ'"x:ZӨ@@w 4;r3OdF5մ~^QG=]KyA=zIor|:FW[eRm\C+TBR@ - ͳ NɊ\& j[$w܎k*,e4 \Rf zGϴzԞ%ZEpMFg,74 j%gbȨj%2$<$WrJL^og4+Ʉ0D]\}#cLCr q@O10u4ԌSS49[KiJl.Օ,c?h>}~TX8`Djy*S403>>wTKzL)߬XܜtCx?S7frX5JhL.(I>y2$F_^+ eeù4ɮ3%%ө Co Mȹ;6ƕdVSQ$o+=;(\ݰ*$<~`D{|jͳ̍I7@a~z'#(a(uSBҐJ}TFHBFۀQ*s>{;c߽&[*A?\( joV"v;EʨjR1flFq&zX#N]MTl#aKjE?SKujVP7)tCDi1R轇9oGjt( 6v僿n`L =a:ͭf!&`/]yT]:Wy[:>3lkMZՖi"&G{_sT~#p&`zb:\l ^߿\hV*IDolH&9ؿqR݀:cC@$5JV1 k t|;zҤBV<ɟ{v2 /Q ӥ㧺Sq @@ 1_mbe*իgp {b^Pwj|EjT:yIJ $huhUIT$YzEʸ9U 3fʥOQpNfx<{r`f4SgpX@I+Y0"x5QmT:HQX<߅#$ⶊMs3>A\[."yc7<}΢ ԃ4.,Rʀ=*Y5R)PNmNoCJ FAX#`I^ NeH bAOcxS˄ᆫq ̽2}ILJ ϝHf-9|Am4>ῄ'jqIиTCuM, `@4m>HJ01TD\=b\xTT+BCI@}K0 i1JT&BEʡ?A18epP@( B4fͩ gZB=U5.S~ ˸wEGFe:pR*iRֵ2NG)Tu`^S\Pq%* nd~G#%uڭZ@5k"rQ4ў!x]Dx++`CDI<t H$&z=LaJc_7}{c-Ҽ9<$ Ǿw],~1bX";f;7x`f${kdH曁>tJyc?n>zOkC[i2Ao,GO,\R3%2 o"t֛7N@c@>/5I #rt2)7z3`zA?C}:๕Os1ߨ1)pAP,:;_ {B gD@<~H;ϸ9'o~n2i̊]#̳Sr+ȋ㳊59KkM(!%7 ךB#6ٽVQѪ_#AG0)kz6ss=G9[rMK%VI<=TI7Ô#Pl#h!1<Βd&}@pd2?Q+`ͷ~ ?Щow7X`|['q'Fp="gO$xL}]|%H+Q mЋ~Oo%@.67}6 ؎g`Xe^ 7Z #8~8!2d'${5cEBYJIc uV4]o3IISڒgөGhAge}?r|bn-m ꢒIۘcL./)s93}q: h$^Ёx2h#x=]_:>wdG~M-"RbIO;aG|mP7hYSZTN )#aA@1늫ᇉ.+ptZ+TUPsRY8?̘s4'}Hrr\ukAH̥yJJԝS.@n;|]6x:No#/~w8e% D?#9{(?DLfgwa PO6~,ћPT; H'CDw]؏t# ȁopL*>D}:^ >s_6Gb+j(SHfv (4\&Ē:6iNȞӚMѶ>cEHˋJҧh-*1^Cn t޲ʐ ZuE'Ok5^}w=ڧ5Q*~,(BRI $(աNw`|_KB$*LĶ8rP6(;̪DǠHgIЩ?wiSr7Z(X1v[ÔH=&fwg2F;I3Ζb1T"~uOj3E6(EIwjw!䐾D&O@#{GZ9[I7zv$iZ$9A3/b}P/V2.ؑ m Ã';=)$dcg?O)${fy>_ noN`ʮݚ卮 lD\1.n :i=EĶH̚Ki% <㬟2tޠTqIFGiG2f {k2@Şc*T$ `A5ryG1Q>G{?38&? BTؐch"cר^t׮4f@I{c~{Ơ6ł”*xbAίrx:k򊧆:9hMWbG.b%$ ; ɸ]6zj@FJJU* 6R;;iu~uQPfUN\"dm6֬O+K=̕A+qTIYrYR46 oQ kw7 )LRp:ҩ[)I.(pBchv Į;}U>QoV F g sJi')p$$?q@RPQ*$\J8}ސϼTv{OhV"éy۷_5ւkri rx9Д }NKLqq'FEWRlHa7)xFLcu N1RL*I]>m }ӹ.eO4Ư1hA[$=`nRVb$@PrY IԳTcUIfmB33&LNWl֙=C*YBIH P+H1ϩS^FSj j0iMngSj R"R&b10Ӥ/ eCMe^ʽ r! Ro0?>0kߡ-lڭ& I^֐F䑹yT6|5Rҿj*%J~*¤J47 sE&Q댿7O- Vqůy*-"0l,-eݏ.9"TNr>}{bz/]W(v L1S-udJ]1OQYBL ā W 8Mi/UAZ\jCO$vgL@fz}aT1Qz**9T}m{B_-FۜC 6G?MT"}in$uGTꋢ% (N3904 U(*30xc89ʠi8? 6~B.8N3zjLNТyEpyJu3l.V`ӱ:g8ncĖE3 #uy*W7b'x[]WGzhUF-Q ز 25qyoF:nUZAN<ǪU q'Hn<|ܕ4^tSN$; |~W1{y5RhLT9.P0y-S0^ЩN$AJ65u'sj9veRB缕r|m* q▦FΩJV[D17TIDmKVnmʔJ4"uWP۔yr~{ AIZyc[H5vRy#0.HXh`u66~% @ߐc' 1O?~N~ҭf}"aO *#GBtAO*=Am;ϧ\85wFޞ(8 [eF`$:O1JfI|MO@fYE` WcЛ['Σ!f0rpAČ3&qI=4c%iZ ؤyAgS1ʚayȺ@0f^q w4OQ5ɩ2jCNwD\r='lG73GtS  mܶ2(H%clq v#% h.)Wd$-:~sTүs!^)mb)7Q 6|] g8w&kV֊ۓ c{R^a qHmEbHZpqI=2ϻEe(;LBҭ }ŽUթY 32{U)\5CIjmc=h@fRL* M¢]X?iRAs`^Ul>3o<%t9[Nvm- e&0.dfg3OWJ⚨iM$+I$|UZ4Q.^ʢR+J[jMđ(B1Uj=JiukV|'iS$͈&FmӁ}z}H>3[wtsLR${k)ti7Oa7L/d4:ۿ\&:n2'42} ؈u0jU#/wDa'j܍Q\Ds)Te:x>iEWh$idTiLUZL2J˰齰-|@f6&I%A݉A8鬀I8&% 1n=ߋ#єdy>˲* G˱C PiVid73k5&zo"֙$*}KOx~m2jv[iPTDĈ8WP7oquLvһLUl9$HB:Vͤ݌U A1'&L62} f54UjHI/ LȲU [J+n7RKG&U9idB~o6+3)n36ҙ.w7HMC<ۏv;M5Q[C}i+o&g~W0J5k^뾖!REF)! HvI;f({y ncymuJ`.>iM^H> 3w94DuR21)-$Aq},R֥yΡRD0'툘KTҾe+װ`*Ƥ;_iU@Np2 \T-3sR@0"G4M4)j a~VmJWWi#yzu!#EULHN61H:Q Băha9HdO/v_k L(PNm|trd6#eXe{ u:TS5KI#_0l7ijN^ %G_GIQ-g-ym[|?=$ef۳&I/㶤1y "` D#+W)5]Uo1 ?FkuSn^>N @$X0#\< FJH$E$Co Ncw:1? ., ۦ`dHZbAUi?"TQ+z[;Xl§3;^WYuFb,i!*ԠI3Gi«5QŜQfnKS7I*@ 0#ۓ?$%RlH-rNd̜ x+L鱗jf67q Ljuζ82reIKh)Q H7>w{N%6Zh)SOx*cG#/EM+iԥBT~k.nE2"t+}SJ,ӑMBTP#'RgCZ6E $G32={bH 7av+V;f%6h6m=/mZL*ȘXSN%0"/FY~Rs)a3 82 ;4oE-`"ǤLm5/I6W2>CIt恵O2ugu 6z/+Hc9g鮺iG fZc+Α=vDr{_WRm)[+1 ˿׶( *RIRF mlh4)I cG*?o.=3MsUH+/uX7U%4ͶCĒO= vo,tX(:˱iLA<8l)v|h{. AA"$m[ -7hV$#,$b&u+alq**A%U gUuꥨVZJA~$UyC(bAXˤo oYQ58zŢsN4SRU(֧KL" EVSjܒ2uod%.@q#eCگN//yTs?R5xЙFueP~Yi0ͷɐ0zMxGP[nӴI&' 8ЎgOifX YI|kܷ4hݭלAѺIOjJw7+l-Cm_N)wV1;%FL/3s,+2JT[Q$~C$ W syijQPBSxyǃv\u% 攪OBRJM^oV'gQPa/L&UTg ɀt½ u.-\cPnXHʄlY$HqdXz zzVFr 3/4hY$* ^جJhu./$w\7xǽ{4 hir$NwW!W  d1 u^sZիRb*ܩS2;`8f_m~*nym"-#Sۆ9 | ROKqwSm>؟ sZҧ8 IIZU^kgZ:Ԫ Xv* ,KACUMTf"B[DΣ$- 6ۤ* {1) \S|w92G'׼3xۯ&6ӯ2%BVQ@LS|0)+$F`vJIV`MsɈĘ `q4JPP77뿑)tf}M#)5tS8\JR :9TOX|7)GjУΙRopb iD)9IŽɐ{kìQfA{V?wMxִtUjTfRW)},%+ERP+BF+Q da8]Ss,Oe-M&)T$ɰjQet#PyG3N m@AfcT tVy%bH&I:yiv4٩`8dudp g1(}Q T`BR b?8Z~VJpIj 423JcUY NSʧ6O!nI%'y@B}^{IeK1cVhVh)JJPa̬;w] Emk2YBdUu*(AL$ 6>L|l |Xq %+ }yfw>_\i' =D@u;y_a۬tAhS!q式PFpG<}+Z``@p}xD s]Ũxj>#'5}Nd+rʩ3TbJR\zY%$, .q3J鋋q6©Mf\peՄl3:Pukf 2 Ҫ[ , 0bgxr᳅<63xXT@m\.-Pg\beAiP)"FǝJլ֐%' u1!Yy" @̍?U*QD Y;\̎$cR]Eŭck8ScZϺIcj:vNJǒʜ 4$O-uC5;Zo-/mmNj([.%I Q>X:W#uk&-雨_ : H~-=nyzay^j C8-x4Ǘ 37GquT*c_YHGB$n$z{[OA+ռ&kA#Ti'@tR˦2<ͼb Ty!ߔ{`T~};F7~K^(ܫ. UJkm*Rԅ ۭ@M *4@ %I2c֬ I`CcF~)z5e[˲Y%8yyR  CRI2=@~x"pVNq/%j ]%\&73{ĩU_"P@ m%wR᪁J@ac<~ֵIJd8a H3"D ˃4m~ʲ ZUuBi*u-D*rֲÜ쾮+QMYCDJvuk^"fZR-2 s 9x3B.) JJAvcs,ӴԵRh=O^\)`b HbU_{N{{wElڵ4(Au KTb a"5ZCu.q:*=+zCgCLpąPb697;VTE}{Ƶe耔 1~`O_!2N>\GѤ͉\HXލ1A.}<S8_Ycމ,Eb c3 x3؉$$)bf' "LGm#)6?CJ䫩+v~x֊d9Z n%b6GL/K]o5fBp ds/ e,k``  W#3Zm z<4㚃M*m46p9ޣ\bN. VVp&y$}(6ExiEtn[L"PAP"M@:9>e2pSouҩߨ7\ 8x┪_y3yO9wJ㶌Y?|$C,0# J4ROW'?b4t|?p#.uzF n۷HJ\% ("0<,J׶"ҵ2( 7ڢmĄYY*d vRҪ"WR޺E5BCJm!Xm>ڑ=~nx^:4VU?Mkdz(E+&u[*I LUk F*0g튨FpThP=9/Zg6U!PaRu)D{Thy3/VeM-. ŷ 0}.ULfTJtڐJ;y\r0 CzOϳ:ښweC$qck~%z~X0-N0Hu ygTL|[p!p7P1P(́6:mR ȃ^: J A<Ā''6~0 }qtVCuʴFҩfP%nJ05*ɸYƩYU(yIIuR[Q)u)V{u=a,!HCRMC@8&@͇/KiNyH)3ZgR1SS` 33P VXgȨEpʂL#@$ƹϋ{WO6 ¤="|{܁lSTTS%ĺumKJ T.Œlo|Ϧی&xGdƝ O߿iV&ANՁAdȓ9֬5ko%sRT@>cc=(+:VIYaܲ9 S&NcR,HzuW:ۡ V޲ j)2bLFQkv丌;c!&a|f0grI0[qLn-02y" wנnyq[/f|8ČSӻ:'iڕ-ɋb3x<Ҫ˛VD9wN3vR[EKZެkU*iޡm¥X GW( <* 2?zfqE,\K6}lJAwz|›HZi1T'pavO( `uQ鯪P{ucQhy٘>?<N~x <ǡL6 vݒ`GyɌDF 3UOڏTz_Gԭrsf!`&|=AYWPZ\mU>(?$ڠIКmwNd/opbtT  tkO{F3jvEGp{4w3O;6ᦛyZzJ̩T\IScL ---u̳H]]^Ts i=elINZ1ԑXP`UTv̒j2m (OC+N{S3. 2;u]錆w^L\s? (H~{珁O}od3Ҡ@3?r1 ]-iSנ%V"\s=+)IRR!FdsAHG (T ȹ?>ݺbOX\i$%#ө{ zPRĭ*n0&dӪ4re}Fӂ '$cNx×m.pBR9\Iccdgq/*m4P0im()m) :f$uҴ^(p)s䞤_LK$Gu"G[F:;~̿Mϙ)BI"шI8k u|Ch5:gt0]P)q3u>2w@CZg$9Au< AI$Zca !_e:*s3eTYBMаV̓nt:K{ۄ1v[`9'$LW̐B0!wMa6VDsH0lzGNvS.$@o/mD2G|0%h&+ uTZ}Jk!~"D7+*Y`4"8j [ױ>qsZG8z*y (s%=.;X<zӂUۣ-A9LVHr`Ͼa@7&cN}L~;vJM֟ p:1 Tos8iO3}=th~iH'mIB(*#_gp,sP^;/HN`I1WWVwb޽:RMb}D`} (h_Tyh; XSeM-iB^) p7zbsNiB:y SFۿVyiF+L)3PO$=/$i1eOV잝4\n@KnĉH3X-ni[Y[ndXĀ`Ƃ^X, LӴ|w6H Dm%b &:ɞ=o{(n'߾0ߌK"Va9n! D1 N8 c2;I[pЏ >=u:!P+-Z¾.U ɝm 0|SּLNgsު {gT[@Ȏb;E*'~-:=w2};g@W/] _(i/PAeI׍yVn޻95fv-l=;Msip%Π!Gn Omu[ :Xb`X<"IΊ5zP#wb>}H )|;Lh&Mhq%IF&хW h9rz JUCjJAo 7TRetq *rdw^թBAJFԮfA?~4*mIJcV=>HY<( )'8Ԥ@Tm ]#u ThIBZPl&_h9VatmMWsJpM*ugb@$GtG}&q3@.1RtfH$ MGFܥkUUÖ+ # ٹ&SN) EgpE/ej ӨGA^, bb{OVStATn >8u#q [ .!t/SV唯(*ب}qCZj 5͕,P? =#>…Gg3Ib(u>?8< Ө|y[0zհO[bC(L;wf#6,` )$HiXIb? T\A 5σ* 3gȋoS6}0.E_/LK-dH<{;48g$Cy0qΝSSW;\+G9lFM:./JK'/hQHXKn$*)\@zv>E /K 'Jj54VATKJp?u{5ҴK*I%! (H7c :LTѭn.j*SL+lPS&H1U/:խ֢V,'̈@Bb#{yv@)#nП^W}0aPTDn8$}PwXW(FeIbG$mH$$x;67P~Dcc޸i26-/;my=1^$tn!J--Oɡ.;" uS~6ߨL!DI 0:,Ϋ0T s1CJʱ$k@ mpNot3j#y"n?+ž8Ǻ>gSzto0j >=fG鮮W8уA>3${{qԻZR2$nDN8>9q-J y7I?>SNvy̚-Ϗrܣ|/O獓GLD>3$|wԳ6"$~jg1}P/֠?Sdu}\E8DR y3G։29%#mϧ'D A"$A?ܐѐ @g҉>ܐFIXe'dq#[}Qq$Noxl.J=szmMBȖĐ~5Y̗Q9p5Ij9$oxwmC>tU˼bV`OLyaχ-zͅ ʵ-z 0/ 09E)^T~P$p,Y@ tZw.Ե7W9JrWN)-8 y?Ν3Mq![!'- *_9)G'sɰbRx3~(z8*)*W;iyģ3{psG-n'ZtRWP8-cLH0@ Zo'-ǀ {PuH}?FK*RNmJ 1ſTe0/Zh++ФU.Ժ RiK*wj" weOh`e!3U-+iĒ2:_BBQLrQI źឲPx4Y6y/s5))i@BւHۋ\?HRUi-kKce3̢DcqO'H*ޙL\.-%M43|EŵPZJhȆhtϘ2ߞT DCi D H[$w8Z0iJ&JiZHan-nP rғ*l)$^lAzۭePd~lrֺJ:J޵ 3G*Kb2$ @9$ O8ձ:xVN qgĻy9[9O6g>qibÍPGnD1f1iB"m! Ȣź~wkfNiƝKYU;^esR&GLPyB}H aI?{+V+ v*TH.c'ܺU* Tg  J( 2=:aW glÈiiO[C>4 "&w={1b$udžI[.MluMTͰZ.>4zՕU`hۺ)#u[)AH8#_u >ڕ@7\jmޤV`pT\c#r/{^qNRƚ W+Ѿ[}TڛRzXـh>`vb{>CXT40, p1#8{׫[GM2 QKJUȡәm#hmF?1닛AKnVWI󌲟;ɖ߰{2i>\ [7މ:F*Q9?~Xp^uAQW{ 7<9g$i' R݈ēL 1iB[ `${BܩP};&ɲ\Pewc<y/0);~":t` d<ēšφycoonV淒ֵyRFX+w*1^,}Nm*4VIoVVU8B4\RGH$+w8 t]hX p/F ]R y{@@>Sߦ*Cp 11 j-s,Q?]=9 z)*sgyJԠJTD)PmarH)uA` ;@3,_UԄ.d O%xkjZdžuBd4MpxrŀN 2m!( L!)#6KR;=h2NeZ+Q m`TI Px2o(m,J@(gbNÔzMԭQtJg#.B @ 74aWd`vNb{AeoUԙ~Z˵5!inKidmEd+tiOPZd&Swx&:xˮ#Xot^VjA$)&RbADDtp.r=L5>aV2JfaVRiiaJ.,*Q]#elmF)NG4,LuE%66럅TgHY/TЫo64Ij~v Kt[GiJmu2AwHRLYS.eDO-wo8Ɵ]˙z?!밿9[V1$u0s+a* #iby|rԔĕ()$@%v]Q;U4Ʋ/y|½piYJT)O)&|49}*RStOԥ@[Bܞ" V=}UCd-ɨj\49(i%C)#I!RAOG/pUn a mBP>G:JTH-0&`K3Vs~󺬗9Ֆ4oiʠR61írzJveД% FϽn6c5O5.kP[/0PjFRq H&^82ӿ蚑4'1,/v#0p\^4=j'eRH $1?v:UTyxl^OLs9.%q65@7xs*` R u|UEbT|Ďcok @=9&` vu$$~k[YM=:Zmu/k06I%ES@DM:HM?M ^yr*^vT2P,ARRRJhj;!} R Ɨ bV<1vL tzf ⶍ4Μw1x;i޲NN <ʔT@Ju:tj\Zt˿!ei;SW%HP2,4RRj,*- Q_2,wdRʹƹc_ %#x7KºQAREu2_K.TS+S( A_}9r^i&pUJ,!ɨkc5[lJf$0&5l쉥se5-pն3 '8'i)WiP8M Uktmᶑjw*QB^|I؉G_gyY"[!R9{}qIp_\mzNglD6~lT˫O+ lѪ*PmR9gx +=ujNѫB¢-@& )-jGM/+S5 yT,I d$|jר*z`rn/cKOU2ӯeO zN))Jz"~XGi|ʤ%NerGNLZVuYSjCI:%K"I; 'n\pd-HK=;DO{s:NSFڥ*5]uB,NɂLbp3?Jz7>wJTG\mo~>O2grJs5l,?~Q;ccZ7Wq3n#"zA5J+9$$TI3cF-YP'A` GHc÷ JZ`)Av1c~ <5HU  #_SÏSWSV7Cj*=Vbj[Pm手}#z43 zeOLnRpQ] Q|#hqb'懶QYi,ɨRA&G@1gF lqFG@{[yu>xJQBmBrRB{RׇBy39.9;8mdpD d c\=Y"dY@ ?MT/rV̲lT:VeZ:oNQSfeg@n1^u()P%!iR3nA+*U:^-- X RHx>w!Z)$ǐNwW˾d*Ai%Imq ,HVk!JW@! (!CLƦifv.a *=l-#8.9h֜qB*@q fnNf$ul*m‹x `.lL_.!-_h^uEu|:)\v۶|Axqɲa*mY3b.u Rr,{a Sj\!$%_*QA"L}HTL4Ye 1E}Z?~5#HRI ?LZs-rh!CZ2\&"q3T֩0HNx5^jԒ<7o.6ޕ1!T1#Giq6~h3 $uOm7nOẹ2|3OYUTE3/ AvrYCͩ.6 PGX#&huxmש+qT%{-]_W_RS &d o=65R}?xć$NL{jbҕsQj Q *Jm'Ԑԇ5ƝeH,{C(PRk%~(5Vx6AaZUL%2 8:1K=`.c0Hc.d tOLXe/ -(S (]v^ֳͥZE;6FUl{Mhzo*W`< 3j®<2n4Lg'-{ҵ,䒢Ib\&^Xv_llFH "FִÊD*SsrKxr'jB>dMŗSIE N3=~x!#N4RUAn|8qs _o~/x<@#32CTnX :W8$oOr,[MWgJĤ&$t2 OsSJsH `>b9ԼS|7*puAÇA<7!{[}o¢$2khKW>u" a$v3 J#/M %uhZEfA"A@ "14aP v~fQ8}uPsWGe92ֳdsyC/ԥhiBH) ͬ|1)|zgN1>zRS$y a#+t R*wߖ1qrqQYGexLC#LJklJuS.ӨTF10ptLeeqz&p)J U%~%%{U`bԴRG2`xF3m!h)j&G$uLXxr,1EB( 4KiH~ƷwW)Q)54}#;I g>3_ K>muX*2zYNUxJ8ʖXaʜ}R$3 >‹o-DZkR6"KtxD$I j5pꠈϴXF 6a2Y~@ ?DDMZm YNp #ME?a!J*+5NOqFEg/:Î*y֥(&L$s~>kw{y𥱕Uf(Ӷ%As4R*(cb#Zoon+YQZҨj$L:s SXA#t gxFs cpSA<*)XIITJ{NB~>?y_]0@miwHX1?S )RkY27'xKy0JeHJ]?gm"1?qβ-~r) k'Rdwi?u6^HGǔNڰ31?z> N1<of nJI7X=VX7 ~߷3fa6{ J9-2I?}>xʛc ʒ x3&;9P,̙ `I80?/Ԥ@B ,'ZrP bco;^*,H1/LF? 4)y+4,Ҫ`@P'ΜUL  @#\|֋\zc$s2}t-sˍ@s7 /4ԙU? 5ch2Ui]G9m|%0^N*$hw>=yբBJw+tm׶+ĭm*Y;vwR*S Y`DV ULH<ڑuYzBlQ#]UUL?o2xzւ$ȸ|-e%3SiH @++}9RfU|oTR3'(9AI`9%RBH'380inTf㷗}4֒e7 3VDs)&픁g}ST`d$qŇ5xרYS[6dԐ #_JH;\E !:`u?Z/ъ{.+Yn`,@"hOv@# s#<@ծI ^,׃/Pn:X@Q8Mʕtœ% eBg[I~EX*d^3 3voqë|Gr9 wHqNr<$A[ &T9=<A7>1S0G "]-t6uŧt ;"O}7hAA/v #qI&cΛWXooKA!vdq?nbDӡߠLY{0+ "Xp$v<"Appvg?8$r Gv <KtR97P`9d)RH(=/ɔRp*Ƌ3i2}yOtAE/s?X᎔#yJmt),|XXuצW3Jڎ*y%z3U%UIfFH`R 3d4\^WzT&֨f'ӋvtɁ1?k(YYǡ@@0$:y+'A Dc@'қ@ Hs':h:灹 㵎_-Z}Иl-7ql?h$+٠$lm&dmGp8!I7!<..Y'\ڀ"xI? ֫mw `2#v;GxԍN?4Ԡ yv9s͹RyGAt"ke (f4&D}gbrpB(-N#łݿyLLQAx$sœ2I'}C3Ʋ !6wZ\/;3;g[]è#h*tQ$yCע}F1ڰpZCIi-&FЫyi*R v*XIIo}#ƏթePlVЂ A @<exS*9}BEE,Kù_~,ƭΜhJFdtZAMZշAWw>CʐVihgZYq_l0>YE08=$*L÷2Jy"w`TJz^ldTl/yzEtX" vsy~` " RMR Oco_ːU"MiD~P'5*XvMF~/|V>EMBj4n $`cR 0wUOI3{caKzD̏n9w"I}r= \ohzb0:N"W8YH bG)Jq5֝ii!M$n9bߗo%_ӝÂf6=7#]PAt[RTkle;Dz18*f'K[D"O_ӿs8c1z.m o6PL3iu\0ps0v9;:#) U0AZ0c砥6X'ؓJɐf3Ѐ٤w1? 6F>=PfKW1̑';e#;`7x8Y]RMc>z|_ vO9T,YRm?sI"Av톫[5k3:ĮaAB f{jmdvr>-:qx+*O,qvs9Jo Pock^uS8A.\ =κJ@AߎdƿT/'IUNfL JHq};uCO $6k1wPH>a:K(Ao$1&0cXe=L'պ=m2"'TG"hrda$LKH0qml $DOn(BA!{bGO.k2pOS"&u29->zddf5&w0qkhXW*hǺJKTgq#ac oMC2xEMl:e8)M1[Z,j.b4NvoA.VBVʴVʢ b8EA^ꜮԵN* H}ã;en=E;L0̲+2VetTU|*ul$TȎFU9gV "iuQ-})* I ;o|B~.>UGԍ:EU pCV F2EEWze=[Z߾ hRYYUiΨ/f8۔ۥqZO=N/S!X@3Ue+] g"~wbx MP]<#ZTF7^ U(%BA] %Wp4ߨt{oFPS C*A LUL*^'T[ƥQj(x_l NP܄&>" r;cB@s}ե(nc8kNOA 43 L~U C GRU1ʟڄ"pྌhq̂m$z:p5JHCmaȉ8=4=+4@;l&m=kewZ *1>C H10@3 Tk9OJ*ۭHmn-:F9ʋInu-:U/sgl>4x*=]!~9Uҹ" ەܟ=#.y^L~SstOÜOjU+,̲+˶h$H)/=1m {TyF25gmhJ$(H#ZZƉ:V+Mg# x#,WoJi۫Z)N$G7 е%D$B$[{^*xCIk?PGg|U=^ʪWsLD=>?]) Y#.X'}>@DV Nۘ&9ƭ*xB MN:@3q܃߮GZ^ *ѤhBAI1GjBFR~x2xh+%Npy~pɌUDLռ'')'[}68 s-~ѿ Q=]{)B*RDn&{f $$=Nym"XSUDݴ́Ը>tjҺ+s%Dzw < vI½Z!y @ owAfiSPqKܛYBEa+ԖJC*1'=*[B*–$&G";=Qzb,YV![)V$ Ԗ ڌ7p{V*Uj-^eAL5w*< B&BwP6[\fH#DDLOkYȳ-Mj,R}C ^ĦyL&=2҇IRg/*Զ^ cI AֶTG_1JӯPvAʫzKNB¥z }K` 2=,@'#V1AQ7xmy[FI/῞ /]ITs.J_BeHH2-IU 0AAzYvL=ʵV&a(#3Rt ۽*ԄVLN?'g>.84FH6TƧI|OtVz0 ߦUq+VHJByBJ?Ddf=uAH';u @ ̔F NOiĆZ)z[M֜ơ9B;߿65:J-9A C'tpOtNUӫjxRnb 1J fe06L!J_V TnI^(ӝ2_tCyggSRgَ}ߪʪPΈ4 ŔS_.vUSS?Sl6ԒyJG8.$X[fs3vnIRғaʝ'slhWn i̲UT&-RӎVa!MT V#Uv,4ޭZtޒjSnw+tztp]UڝBX)27i#F5&ڽM!ߤftzbdpc{Y*E"҅6R۔O:ڊyL 0/£L+-s12lVJ@[TwOcǵʶaP 0Jl <-է?QBK- h@%v"4R )& A@9d߆}AzŒ ,L!,@#I= RErw<` WA~*(n]ET+Gx)PB (\ rYJ1$tv'sƯ böYR52+#o Oi+܆4PUH ngOx$蓋-نZWE:+ ?NtTRB,n+za9i|umFȈ1}0es46lXm NԼS.zPNZSBʄSK H Y(R4ڃM)L Oys @-' Wxmi5*Z̸>G]|](p7:8iuJ!%Vo<:-WbÂO1*2bνKs2DgЁc(m*ɲy{:|gaSHw#H&/y"~?l=w,Ixmuٿ`t-9 8-c_'vϛ e2 E=fMY@SVW~DILz㮟%؎r?]JХ-_!Fw덋g1BL`G#:;tlk L22#d~n,Ӌm)b ^\3a(<"_?+zrΜ_}p֥%J&8z#\2BIIϺq%BSsR>9G0g%$ʿ12HۧρpSB꣗k{ C$k g2i \YiIHuqS;NSI^D?,k(dn CuOgӪҬlхDKx7*Ԫ*1Y[sa$qt;;tnYKnVSH-$jMq1 RB\=^f6`rA/+8As7MA#wQ(obT&A:=>^Xs4KIs QMJuri#F_P+@A_,id$hD/QY߉ 4(zxژq~S&E8r:^P}>药 Jd4%0AX$4L f H9hvF2HwQ0I{v0|<2< s5ee5q>Ee!U!&G.G0&l 'ZI=n3C*Ȃ-:w? +F֛t30h%Z=@̓M1*F#uP g]Lž5;W5Ͳ 6:Tq qʠH@!M3 UTaO:T ^7³oZ'V/,e`TA  ?h 5SaT '\G{qgJPmBݑM@KTL0Jc:yMZ)5(8!d/neڽ|H P_&g|L9i+V:'d%!rR!%\ >H;Z &4պTYBqsp9_Ӿ(/G ֡E]Rm*9剮ԭ:EzJѭyW9GZUB=%HaZ\\(ԩSe RTN44+)G) X=6{_ƟI|_ӴW ;y q.)mBn-]XL "bK N)S *IojfH2֒m"ۭPVQLd0BrfmOgL6&9C?^N"WfjQ6RB)H Q~3?IJ * BNX[MCfK?܎'wQ=_NU)@$|Dw0%KH%6$JFGpAԂ]zkRDIoLOh$H˳쮗62wQ4a4(dO*˳~2RUSSTS-Cq~I`srɷ1z-* r2Gyo74KS.L.-)SSS73+N^|1]*Z^պo(l5iԡ LJY| L@WTt;ZNEP[Z dPHE$M?-l~6s]^eU<›QPQA۰ |dȿ|7z"+rf9^jq(q+EE N[ĥT2Sʣ G:ğ1Hi9*9W&=ݾ'"!kt;X*֤ʃYkT֮ Pa/}CtTFYU)yD4NhF!ڇ+Y~~Y 5yY"QJ.%fnM_IrB@?Q_8G $+A)1 ƒ2j-8y-Hm>xxuߥNR-)H@CQ5s$W}.΍.oR1/P\~V8"9 uL0k\6yH9qDI@96:>ynoV֌6Хy-KRc O%qB8P΋zzCdt/:TVBHLr-ļ֓;z6Pv2m3sQV㍨m|Au뛎oj?]:שX[}rMR>HYaoZзOʶ+QkMTT|SZd;)yJ*Ki)G?(1< ~+%S|Q#{?.H (Ԥ`,v|RRZw+@RR]س>>}*T J*8UPpP1ߝZFeIR!<l/ qc MvVNTs D*BZe@$D\Zt+C[ QE\5 w*~.6VoY `8;{h/S^MX0:¥XwZ eKaIe|1`[AxO3/¾7k J)i g+))vLA&([JT{>sKk)IؖNd~arP8IVJP`Ww5NiԹKSktJJ ~XW q33t$mh=X"ϜeYs?ī Dm_YLtv\=ϷkUM'vvsJǕJvhHr scŮds. jZOed k(6UEiԟY<&Q^l*¡IG^ե(PմOYJ dIZIGԔpNpTsu1]nAli1ps^Wd~tCN+HbP=J|BO6Wg`LXk ׸j΂ia\+lh* K=Er!_(HQCc%ApzڲjJBYE6!3fFdLDdRH>k bP`=m/ʭ ~_ÐʮmO3]mv8, Ğ9{FsBg(c'{?3:\>$}?\myꧭ4&jN# HP$Gxۈ8~$PQ]i/7Lp`'pLf1E0j6U*HVPO7BbziܵEJEBINcLvacgCJIʔqĉ$X"DG#mNP),ӑx#!ʬ ;hBuVYcw!w2 I b[j+ꩠEW[SGNe6$!@LH3ث )Xmu4Ȁ ,-|X7@vU7R#}zy-Izd^|(YÂgp@ pJ(SSNqQBBKmr2 SUec8_rǷAB}2fg%4&flPkʲ9GlM'Sq)zX''{-36Utm0*-b#Z[ջb< 7G1 GƔ,/~D#z<Һ9^]DhrGks&Uss* "oA`n7/G2zwf0Ԛ~ՆɆBDUZ*OTwUxhO~Lc#Iִi?on$`U8,dױGT;uMѭMYG2HnzRiIXcTiBIEq4޷̚eOha!Jmc7[|M)! ĔzJIc_ե{QSȢR`CI۞{IYJ(I)'jP{dg J.(i>ʝI $¤H# ./,/A9ހ2Z$Kt> Jʔ@u=~T $bOV,E׹PTSSXG*&T%@LDoSx'XxbŪ OUTh:˼Om:E _J;SLa8$@&gOg)dPVPmj}=z <&_hJ(Ӗ QܮH @>'L}9ǡL21`)b﹖UqK%;U5qX0.R(Vѩ${v2S2oε n̴K ba)J)OeDu1#|3q*%Vs-J2T%Ök!’.s'poKt_r3\ꊬ9SxςhO"tvêkR46m m0qLIީhU""LzH-PTxz?zruNa7C ((9M{GY:L94C(nlALJN37U7W;&ʲWKVn]ڀl$eX{a~&8EDUUkYM;H-WJRR$o`c !zjhWM: Uȶ@ 3#KKV*v#uZ{Z(yʠ3O<:ZӚe5^ryUi#%[=^e8I H#/ ><ša]A3T.ӸJP)O:l |tÔJ-ku mR(3Fs`I0H֝…2M4AGt('H ꇹRwBcs۾=jk6hRfw%hQA&$1?؀``JtF`O:C%H"i3=L<|$cd" w{I W;nyˬɓ~׮8:R\yﮩ*tbmANsSoAώE~V=KRA@bo>㮿Q4'O~Ьhф*)ZN6 U] bS ﹪?z:e'~tv(Ғ8~CHJר|4 p OAioO'OSU *!f-$wǯrӸ`kN%1c@2" 3#Y͐)@)UZA2D{$s^jJ ̈́;>")R㔊[iIQHQ+rZ!)0ŇMq?crhJfs{2&=;/Hc{LղU}č?I dv5wDef" (2@*sϨ:Rɟ+m| U~-Q]ju*VԒ \I"|[}AO%Tj'BQ2YA`g LKEBq,ኔB@$yma{I__f@-sn<9 ' TɈa3Ǿ|`֜ STu)ܕ0}Ps I L>GŞ#it{YmH"["U@Qw٥}߯ WV2CYcYFbA:gtn)Q˨u0qJqWS%Rdɹ's nB=<#n8-xDP{"#~wO⯃jVPD~!E|&TE(5P$Gf61`Hb8>綍Q9 uL~{„G0xK>}7x)<ۆ9M5ٕ#4̭${vb]>3u8.B!K'xڴuAM}!Lh$d|ij4ڐQQ 1H;` 8֦,$IU!6-=?/HŮpk S0;D/1U9S+VS[IS$J#&零^dz{R:hf>Da$G8s7;^$԰v,Tw #=?qT8wԈ+#snӍBOI}n !xZꂑh^H\~C3c1p{-3Ծs{aOЈ ᠞X܉f+̿OT$BFDr$s\%A IMw)DŽȀʁmH,gt^^Cg4jq+! B~W~S)HpfAXuz(h  b@$8NN)w2UӉ3oB(2$u=o(eQFǾ86Ct\3QORؘ ,8;|X=?UN3Em]OMYNHu҅fH#pqfB#T/FVb% 9:l*UC 7 NseByY~SR^]UQHFP.)RH#ckb7|/l+P&T {+Rº GǿϦ*#Sy >r3-7(U90}1|cRF2j}ʊ뮞eDJQ;;aS@uTo9OR҂J(Z/̕wwG10Nݷ?۰rjj K7$N .=E朐H9A, $GqԏU $#5!sJҡUyK5+2YqJD[{u,@73v"<@F/$os|m᳋Qz$XZ9vpUщVbI&$b[*pG`Oh'0Iiw Gaj⎔՚f"FkSQβʂ(;Z~3R)$[dmbVaG B~'q JɓWDLMjSZH밐h Dw* .P 2.N}Xgs'mm45Nӥ% [ꞗM&eԐ;;ϞEQXGr,:y[S~5:T%a F[u% GOZM߽ ;`uqk:J@r+ #;|,MOM;f-Wj۪u/p+xLs'#nLk*2? Zd( i]ʦ <{΢^jn5 C 'DƏԙ5of 浭V?[q/9s̭dAiCX@Hy _?AWǝSrml4Tdb#Z燝ߦZ3q$$Ng:HvP ooYaKR[PA[!zyPAM;zYd&Li\&~[u``&^}ELb&r1U\9}D?~Lۊ8LAytoPuI[B;I{q]PyEA ppgMub-{kB$x;BJgo_1ͧ}"u Vڤu@Х[x6'G?r~\߱ZF*誡MԴPxxWg֬nPNϢlv&uxjE t<1 :2RT4RA*BԒޘij*Mvw,LJ.q 9SyNj-:l)j*RI&祶Lf,ղ2Пh6Rc2MޝƸkAZg8!H:%“O,̱XbƏ]Uju*$PAJf`3`CUi 35 3m?1o 4ҖR*!i؍934$B:xmwn|/\I'q`w@=cNxzȶzMpHR`#1t<yKPOൈ*PpQƐ`mJXO;=v{v?y}eo-liAg/XZGz=vh&IzICfZ^U- 鉌O,nOoAkr>VQQ^ tsDep .yzZ#.PJBę.~vǛ4]JCv^$B[$uБg˯xmX^ ""yیQ]vZC3; 66U JVT\GRVD9'2LъʥNy;Ϭ~*u*BNm:z֚;TOL/GԵ^jwd2AyV3i,6L`~[S-IJo Ef# .mSpDan߳b3$+~}$.iV* (^I0#~L7$4='#Me TRx(=ϯICMRJlNxi[|&z?; mg &"vu5:`j( 3)$AH-4pld`$a9F`&-mGcITyhb|z|0vaDJ;AL;H(%;l.m[Ӆ0Oa:7EIO,FW 0 ^L|Gc2WBOXlwNФDHT[ 0d3 Av_| "pD Q;*_^0L1i\ H+tCХJj@8~0vBS>mjedOO)量>^âo08 "Vd;y*]S3=#cp!MJ,rFRc_1oMBUEH0㿦$Xh~-)_9?@%ХqET@F3dDA>mG#lXA3 cinjr$Nd-:VP"6azJrq1H 'G|W?¬K6Š.H 'AwOk2P3=sCDådSQ|~:fxM#- ؉G@A1pd|I`dUr &@ œq9Ό/үH(`|$~8g)`-i9R0!%\)JAVm|EѰWd`Dz;^9s onW7IAɑ}&-)[5%Ww &>i#'5Q9<̆*`dAw#LKzV@?h?,Z*Zpĕ/o&JbLZOO;EN Be#wC3["c, I3O~A;i'!#L !JH%,"R@-"{6B!*Ds^o]m7o >N%InLΌiPDcTUh7|<%B]E Z@I"rOxU.{2 3"`LwIƎ,k #o$ən(VHCYﭯOBƫUܦAU~5nDƪ֤iѧn%~&Ttܭ9VCDAI T?>XTu0:P9B9S-}KR}ÿc̜r=CZZTvvIdk(ӡoFXi.@@ɀ?3-^Mh # Q5W$Jbf]?׷uA1h0@! P0!Fb~^~]g}hdG':I[ &cΣ|iйERhw]jTVAHT 0 XxISiAAQL%SiRPaghQB*BҐ ĔpHO3HqOZԴ<+ rb%GVYmi10&tʔDĎF@1*BEDwU)w2[oYzT6{|8ԬD 62oSHʂnȌHb3'BZog8G>5&T$'mlNX!E)%G=`ORDTZfޟ1 (@??>F V& U^v0#;H,Y0Df}@ 76O7F Oz;I_NHZHJְLiUS 6s_OI tE!hd {N LыN򔤐IhoIO O''x?=5IRGFHz䒥Jۄ3  ~I&Dr@ۍ [+\덍‚vM_}GPJyI$ʅ3~~%}ԸRny},+>bBoHi( nb0~ S>bݯo_/4 Wt-`2yM#N $ּߞ>F IB2Iϙ`cI{(ؘw36e*A ou%) H) {[m*P)$I1b/Zdrf H &؁GA$"0O9Dv~Ƨ )^}gqtzA'l68S f8 `dμQ=Dc?OBp"E^t!bG;y#8! HNcK 1pl"do#nt#ad|Ar`3ɀ1 ~C9QTק_Q'-;7;]6s-IS52 `q:֐D bxsdG:V 1cc A"x>{K?&~o8K RF^w7od5 .{@Δ d#2qȎhJSoݱ>*6#A=[8..:?O~-qfoA'ǃ(N⥁!H'`#L{d3Xp90rs9:1*$''x#Rv[z`3ʘNG:|?{d$|*K`b`C`Na ~xbym2&$As N"xRT`;MpۥhXRL?˯UJ7O?X!!VUH2}$cCILA $~Q{H" zJyLc B&!B@g~VLO~NaVe@9$L@3A' } JbK6 Ry-a±1}z\ ̈]c`H!+/;NݷƷs = }&%rk^e=?`Sz< g9iC3dA?{97$n"GSZ:vnEc\I@V o66@}8Sm5E~Ɲ ̻>1ndmzӨI$&A3*uWRuq43@#Ndttt!AW + Ez,Ɂ̂2=oD溍x2[Mɛz@BE_T--$/ٽ)`,3 4CN`D%A~L|F5!3$@*}#j_"IP@*6H̵;!aI ok 3j\25)[q*B$@Ӷ!\ڳLJ\*ɍV?.$cO-l+u !Ti8Ɉ DUyISme)6#aZ5'R-G"T"JdcE!9R{[ a;}PI}79- DbCchnwt6*g,{,rrp @kT\a#s_yqyZq%-.gz[|y+?cznJ2ǒT3=dFmŔHLs-~|}I? րmFb o>d?|Z?؝b䎝}?ίq '+}`>dm:+G^{o|}OAbGnA ?1?sV==h^r<ƚ)3Rn$> 8-PmU Ыٵy}ۻZ[֢7uG5[+JWj[j0v `Ψ\14cUOTV o|=1*K <VH}|c]g;F&`.iPb}Fc!73|*P@s퀿 .lm@>xbz&k0=G<*Z #m:8~{?,hFΌX?v)]ܐf_ܨ>$c1lUg`";Hչ%?{Yyc:k$U ?t,?}bu~ys? J~Hobq>¯sp7SpPdqsP I 99Цx,ŷ;tO|Q繫XAmm~> ZGϫ$cD *JaI6?Ғ0|zW"m6ZCGjĈCcGXcƜΑ-%=[txIsIG0w|}wa=GH cOXSN<%BVթR11? ~h[K[&b c}ˣz -" I3&AOFK*xx}{[kMLox;;W+0)/k#$'}ો`n]g''NF]Fk%Z׋~®'72k& ?ȏG9iNj8=?۶48> 9b}m'M5U]{q>o/V 23i-ɫFMe ^"wM'M/rθݘop/4gcV>FjN&$P#G45?1m~k< ѭܰY\w׀.k8yn>φe3q>_6q~+z؟ǚF3=#~f"~4jN͚y 6\7ݷhco8^GM F`'DOo?8` 混F:I%ɓfe<x6o3>Vi#_L}ךּky'ksc#'z2o$5' _kgM}f\l\sVG{G>SGz1oI8ۀ:U\.̀O6YWW1}hFGp],6mG/],cnd`ɿn#ÖT76n+&\{sO:S3~O١LFUS}DxeڢZU>5jB=^Æa_ggx]̃+ɹ?Yo(9wҁѼ#g돱*UDTNtWɁ:WLZ28)QԏH:P7?`xxooI7}"?珱+.~}xKH?2o xm}?Eg)s4_۳5tilem-2.0/data/skins/ti82stats.skn000066400000000000000000006042301220200411600171000ustar00rootroot00000000000000TilEm v2.00͌e TI82statsDuponchelle Thibault̰TI-83DJRP&N[elQcMgN(d9Nle)[nVvxOM)Zk(^l(7k**[Jk+J+L-+H7)pK$[Z{l[|[{`*z:^ly&[k*:m(\l):k)[ o )8n& ]>m3V5U2.W8nDJFIFddExifMM*CC"   c !1AQ"aq 2 #B$3Rr4Cb%c&(5DSds'TVtEFG6Wev Y!1AQ"aq#23B$4RrCbs5STct %6d&DEUeu ?))Q5oֶQBN?!oD5 ۑ8e ZֲP J'` 'Z\4`ѲO],# mAKJjFU)l)AfBS7&7RuIt-oNfZJ+k/u}6ZA S$kO}!Z|^Bt@k}O1x=Zʵ$u7\ioQ1$v7"yz!:aIQ )?x08;٧CB)by$\ Z C6U&@!r:usy۫zi׮!nW02z|)|o*G%Uou9 J>f7i* 0*ۀTbyI%@i6$Īå1o,vʂwa EjDt*%|͸zL R@HOT7WU-(cNVK빮e\M;e-@-?kح1Jy0Hl2_U RI6|1ؼO„R5ZWmƾvi>.dZZL&eJNz$ܢ!dt(/M-RrBI:3;t6o_VckZPa\JRZuȇ팝vx FUeUr9R1f2ѪA[8P|f*CW6 H,@(YᅒHt:TB*عԨWN[:Zi]RLi"nfN׸.%{[&~VYJa/@ 0>>2 ߸]Rs4Ͻ=Fu`UH9#)'QZ+˟N؆3/\+0y.^Y^ :ud S HU.g U6 tؗV3E| \jHxem^r{igtTZ{{'p2*}udQ᯴eїD|CTF->U1bT "@M PjdCO/l^8AӨTVI&{ya85l~$m/C(#1@[,U@J?+<I.;sBi+pM6'Y9T3dlZx;4ҔKaP"]i אBý:ٕG.X͝U7.֤aSԨcgWƏ r؁kJNQZ>YՔ>җXt#P Oe?B#mtBɓ$8:%M*XNLJq&Kq0th )hZ)sPEBEx<|AD tJTI xjBФ)kξ-PJWNRL b 7 b"q8[Ö 9{b<ބ} )R\B*IJڍYN+\X<^f}Ÿ{Gv)JZRV R=))B8R&3]&9/fqgube%:ԚkS%>rJR' Rqa $"zebr!R VPnf 8p~ ༦>l)Э"N_v p*^lk}s_M#0Jւq`+?o4l{8c DF9-$Qu]e7DMO|;~1n# fB}b翷.ʸ.tFsS3T&%ӡ^!c&{dT ^kV* T+~?e ĐLms.~d`_ r2(^A1, ;[{y9ʩ$l^d5^^z[E8{{3!U-u}xkbw/P.?=8H𲇁3WVjsˊIP $s"~x2{:& ;cϜxa;kP?lG]O֤/qԠ2e)u +o_ܱ┵6r|6祂 3:7Hs^kZئuAc3(vGvX5R8;iR4&9oz^iY_VQ-3PiuѺ}:U(yo!aEN/m3ӟ/z{<5%H :XMği_Sݐe#mE 3D:TY*2ߗO;"59[+6e@4 Ҟ߯* G*uAM[H+V҇*rG־<.) M’yۜ[q}QCIHO S,!y wZ*HiִkhP%*!Zt?+%J)M{ɀO?,w%$/b-SHfBPvBt&"=+jYnLRh˟寅D%BjI:o9yS|L#j bO_;uZu`#lZ+HxSbG(8 ^CՎ\mi`$M5;i༙M :UA0G+^mZ+t 6,'[PyWm5緞xعIF'iA{k]_$ Aϗ˧rRRӬ)b"]O!`.zF]jdO==}!`9ZPh>}=POode4-$usɒo8zDHW$o /$Vzn+_-=Z;:򦟈MO}x_( H;}|p>V ig HV#TJM+fCa`ivNVBu;󷕥9NMl?՜+@o`1*: g|Xq)Z_F[N\Fڧj9hAMrs~V԰@lwi*K$8c$ eWIp#3TK^-_ }evP_#OR8}bRTՂ%9BPB1mY{)#nIZa<-qlp_ڵhRd+I5LsA\W[U3^f\Ej*9Q?\Tá*K@ OYߗݶ_+.va*7>Vm\#{$s_|-<`ᛤe'r&'o:-<$$= hCZZeR2TgMr RkVdi5I޽Ezk`_ 2Apɴxvw@3;x[w8`4Ti/bNقTKM!ħ9S^TNI:yt1m\ZpBS@NƂ )K5NLCJc;, [QHVDtxx!\ScyNbҢ^]}o- ?ޭ0GA_mG,Qbe uq~vH{xتQ6Bu`WMk5*{,0_D']Y"ZQ[(WS0ۭդYAAQxggn$~NDi!Cu9*̐փ8=6嵣d6(hvL$ (t:ϟFvJ렲ƛ;hZJdvfy9 Nq~PIxʙT N:mˑ}W rqjtZHƕt,)'h|kʫ!TE։"$$cR$PfH确bxu4TeX/͠$חXBUN.Dw+؂Z6 QJ VMIХ%:L -6AP1,>8VOs `a#f2FDzcٶ{*NZ|l, ļS~$1(@ }JRBM֣>&^/%:;{n~I(ҜaO2ڨJ5<?W⽉ٌ]x{ﲤ7A12F[i%r Wr4{YM72[ Pq# Q1W];ZN5P &_k O&!+BV(*$D,A1HH@Ҽ476J 7W"nWe8 Ym$$ZMvJ UĨ$(4J`U6qPñQk5Xn:[Dl2Z򖜽MXCD$␀.lgcyʲUz\%9u4-v\Ip#]N @^ݘHZu%3nO:h$^2Uwf"vB>m(JW M̍ FA $$ (AnoA:O뵱T]AIQ,!c8³%'S1x K j)>uzy,cOEI%ɮڝ^Iu $?Af!vۤ\LI,6X|`b*"a,jQ/*$n׺ vzʣoQ CG&PҸgK@C\` i]u 5.$ާn=Ԉ2uDo\3vyU@}a1V+iPV`^LK9h>'[ jQReS>VP A1` J%;eH6}FUڹ@bSxːPRhєLcЂ"{%KUJohpnOF1C/D .U:tFq^I<~MUbRxV k Pgo;^óq+BZm@ԕw DR$Xmo//+ay.S JJ`Wy\[hpg /+:Xn#&h6Շ2Ze$` ;!pZ7FCHH*Xf*RJoJ<ܾq|g? 4x>c֑K7JC{%:ij_a_틇5v2JRհxQ;r@m_83{/λO23&a!0P-6MᏆ<@{qV]{o4.ad ۛ9[YBl BUiN=q'U)JP5ǼP䄬tF$$RkFc4TU0gDbC,9T4yYẆ,`ӨraF-<Ȁ@B$G2&=6XIq[ub3 SpQ%Ɍ--C0Hh.TT@uZ`i{tLui9Y*&O+Ri -)  AQ|yj4P\e$L &.&u"g"áO[G{-H=@>Kmsmv~\^&GHPM<*.լmkI)@,IB ~GC8uuXxPsT#06j<*WQO#;}ߚUVD.o ;8Nq~Vt$0L:A-G3cc]J RA9Zeulg$wkE t5"`-#(8~HRByՍ!C{"C+M:ok)ή t*w@[j `4b-6wJ81Eq3\x7)e0O({wk6?=+7=.gjaw&jG:kSd#4Kθ$tЏe6#[H H|-ʨS&Tf7g㍪4Q.?„Qx"8kLyݼĸ9P4Wg2<ݙ51 G{"F}oy% Pr6 FRP+mh#IJWjU.t* #[ꤝ-\ܺy6L_ N0^q BWj"Yf)%#/u_uayjT+ZRn=h|.۞s#S)U[/9tT[kKQ d #Q̨5-IIzilW?GB'(e(}<9jrWUC&G@mH ǔ8Ww ru._+>Je L2ɲ4mҀJ{% 338Г*q Jfh,¤E4JZ ړ:C0RZH:S]e(&>4 $mԝ(uiӄk6z_x.a'BA#s  s:֊J[PM\xo a۩zM]P)6q8¹gʉKKl!ԔCy@B@HۘB'ޑGCh%D2 ܕ:PT(zSN>tp" )@q%*첶fTkcI,AAqd̰S3 DSJj $@[sԝiI1JsTi֣\Cm45NdA̦6@J\SʻYGpˤ p%O&} lJb$)ƒ=B$49oؾ5u_Ask:!ˌaSi ZQJT TB=/.KU DLej$RxUs6eN)"2 @@ 4~5MP?w˟=jt~ Ve-٭jiЦU޵plM UָHRG9ǔ79 X,J.TQ x#dxbʓ& G!aI)>/O|">Kwc`LlE~^URb Rw&qj0qnT (:`q%BMs+*kʃJoM<[-KYN[ RrԐpwQU!ffA XrMαѣ0mnb g&$}:m~2u {Ħ`P5'_vo.eJ PC yt̿- }VI*OG[|pA .4E98Iۗ//E})Oבwrt=&mX??m-~~wUoP=v)Ċza) 3XeS\z6)AfjHH?+98Lxv!"dbɞF\J %K{.TIBA;$&Uw"G6ԒR˳m{C1Bײ_*Q#9#],7JBܣ=rL>'s|);yF'G2}#F̤H9ܹ۹&hE-/Cn%JNtA֠齢^.C]H}Ju(ҺmiS4^DTDi;ЎՕX1 $ǀrg,c۩8ؙaw/F<]˼׉iZ SdBS\,]9mWX2za)L+IL\=n/:!$g ;Tڲ1CN1]H%9?Ĝ=HWTbY=54;kj_?^だԄ} HsJKm72$[\nwvJrwaҥ9 r8 I˒}_6LtfqwmTa e2阃U4t4Sj3ryN‚$(,!.Jye * NAD#!A]l9d2j {AnLơÑ,eJE"L-a(끇ƴL̢k".ZlBkqN!EgʵDI|"݌Ō4Ɯ*;3n_)YuIgYNUԤJ VېtŨb(N$2mN%[(啥GP֧}͌r^D;TRZzcZ`uISP 'h.x8/Eػ <>yf"[޼k錇mE#1iRBAOw=()[(Ԟt3]֭Bz 楸T9<)m&q+ MtIJ4hI}Bi(BjNܓԢN`OD 5q8%0v {GamV@quSBj<~CpSFx-D]<0ywUI8:6b,XOJWB=BJyr򱼉y&L5΢ζ,Ť۵QÅI:~vgRE@$m/>8qG<t薌1|Jw>ASRdǡ+ֽHTewqJ<jl&>x2oM LZ*4W:mpe= 7d'P'b`ki饉taC(6ą,r:95& e SvTg d {.O~Ћ̀c<͓<hdt>crΖ;(;e:K &@`U | ƞ ,QkZ7r =t{t-D [ ,X|jJ]Z:3|< Ҷ*&]ȧggRgVaꆪpJga Y*Ju[7:}= T$[`m7I l>;᷄L<%rYHYmN h)ЦtEGVT͞()?y ]=N2i`Tva,W7B';pLT }yTj @]@ ve_Rˀi"8vW4)VlMWfϗzmFv/K'Bhjwv{v5>롈Aմ@h%*P0eH{5;?%ReUH& Xo|7'Hc8{4┝);ѵhi6'_QZգc\.x/tI@nZi[GpmpsCe=PS\vW#i[˟rشH ߇9#M┨SSFG/<=|J(JJO!nb2 R9SO!doW^%G_+^и@n25^5\z#f&$#mL#qFXN7 ҟ?~Nv79Bi}k^7{Pʁjӧ!>CFoRks*5{JuMV7ʌ炫)˄j!Þ!@:MK}V[Ab: ,B]V8%ۊ}}kT$:kSʕYoOr_lh HҮ{xeqqO_`N&нw4!-UiyD#]Öp-Q\9OחMlMcG.u:UO }]- :y8#F]"nv?~0sPUבqxiQ#Q^VI4LKsWe퇈ӪF%4{S(WG^OiIQ_i ݾ8޻3VheR ښ-w/p4|zrXiR^RHP_}krI&Jg_G(bR*P 3:V%+{DT_ I >'Ngc={[vؔ *QRsSJ+it.ܕ(Np'56iO kOG̵$Ng|…wREDQ|wDbRX!Xt H΂}F!O|]5ͭ;ԭLkuyE>3@O.f)tƵ޶)W(_Sμt䉇$:F%(;Zy蓨G+JT+%DT0Ι.Gc&Ʀa0fXFi-L²2&U9Ͽ<& :s* AUh&n:pj9$x]*"۶*AMۑ$1>K>TjҀç(!(l*ÝEm=ѦHvĚs"ۗ >f+ ogW˜zPe9; ?O Q]|†|ޠGf4OWĊVg"MT:[=m2v᯶Rkn@>Z`Ǘ3Zs.DPП/;#&RdSyT+O.ueS)U?LM ?kEjuci8<>꿗q,CvaVͳ 5z]fIRRBEҜ6Ooydfrr5^M_Wi)n!^Tvm1tFS.,R B6[Qf._|f_T-LPw"@RTX>\JM9ZkȔ(uֶk;Nīr#\+ G4VCQ=U H>DR'>rAOڒco>~q|fi Z`*j1Z>Yk(-@UV b2߾0z[<ԯETB*ʰ[ s@Hc[Yg=ݹ Y/uDGQT$ 4"qvxc\ (y\zrY-mZm9٤,o+eGㅿ[i6{,7r)ՇyvitH (ByZzK8N"&6L]SC-ħZʉʐ5?Z1obUŋKp%<=7S Dpr >]yd}n]"\R݉T%cC],*:_8r(%Q`2h>!r$׮Sܾ uAG!9sBFU)_N%#S4#RӈΙ&%jS:6{%q6$ ] PsøLZ H޴;.2lQa^M_Ev^!enCE (I4JL@~2*LOxXWq>eterhr/P̕VJFkp e0Ӂ,XA )n%!VBkFSʕ!㟇^7103_Id$ddOdلe-MsFƲ8{v;/Ih&W1mK"]3B<CQ) Pif'Qu<arwoy~CX:*vc~púp*pRC@h̳l:$2Z^cjk3XnMߗ%wzFV )Ap M2&TJR ;tlI<i_g^rDoO׍Q)խ=17$Гcx5>:I-_[ o_K:rauLDKMP46dGA ^ }nMQ5>~쐉R p$ ʼppYXfDV4̇)mĊLGjAeۯ][kC^_3˝|,uw\ܨzS_Ή؊* D{m+'`|w;DZV(sozVsCꢿᨧZw$ E)NfN+E&oʿ[{&祊QtV?ӭGp qΝmH&>6$_*]CuěoǗpC9mbʪ(oa Gŏ E@{uL;JSmG̬ŹS~T r-M~dr}7c93F'6Զ[m*8(GMض9rHԩS 'm١[WV%L-PwWC\ZuCNdrn?:Z88 بO5_ÙrD2"S۽=8g)f!'"YcjB )^}MFpґӦQh:Z)u)I҆P[h@Dyai ITB9R:)P*rC>gIQ?m|,aaHI_ﲨP>_.!ʔeY(H zofۉxOąĺ9r&sZcP9mЛ- (}S_ĻGSSr' )Vưn0 9Pt_5iMIU)].5y֪*ONAjIo:7@$O3c8G.H;?+D$ ]@LĞ } $\ #)@h~~SN)gsO,e,eSznT=&qkI J+iЎ_ RVD@rڟ^bMReA祌"RHI&~~{ةQ#15ڿ=$ ?*5ֵr-_xν?iMj‡bFe_@Gfp?GD=w {~*TB O:k~\^;>c@[83Tיb>_9f޿D7*k١:O"Kpdf_o c0FjԬ|=IcfwM9,ߞprE9SmkOm$v@?!@բTזޣj~J$҇}[,¸Seu|]59~n t'ٟ1|l O6=D 3LU i,$sP9ikd>H6 $WqSZ;Zн2%XdžM%V᭪OjR@,22>]=h6c1N33,dL`_GtPPM_>QCMiMOEI:x5>Q:P~o%P#~@=pR\;~ٷMuYRS5'1ސZ+-!\PXʧ9ͧ_qu&́<}Y@Tt' DOi!5 i$BDM.Bo6L!tK\G%Rʇ]cHn&>-Zތא4c32A(Oʓ]3 mak;3=Dc ! >x[1(Zu(Ѓi]DJWJWZ֧[n8w5^\aNBЦ֤E|+ӖXR VUU|:~k-=M* H~.|JyR>?^z@(>"KyNfNr.p,]&PVK'N{RGֽ8Gluw~\m$W8@H )@C`/uź:&kmn<yj s/uS1aIp +b+v;߀+.03rg SP =H) NǟX>}wy@R IWOtE-5R<2m2(HwF#kԔ c<}Kw!G>O` Y #p+w*[ePh+iŪ^dtL _iC*Q'cCו; W_k uINu^_R@h}+4RM=|g&HIRt}tqY"X{n9o*tQUO.b`VGDrܑ?aZ.VVGqm+V8DpVB>4Rt) ҚkOám[(aM ,xOmoz}A^Whcx_Zf_R z'CןO C;(뾵:ۨ=O.܏d⭛yk/_%ݿ2}OD(u|mҼ;>(ّxSbu$FbQP C^Ũ4)5wiQt'Sn7jy HkAZRm_?dLZs {iQO޿T[8O=˩XrM 1~tpL×BJKP{ב3K ۨB~kdѦr>*:mjY_#Opv8ϸ}8GDh3*ĠBOk2VFp=PmNN*-~V)ٱ^P>ք<ƝF.u]l^q&j~C??8 B1:${>Z%d4:G-~>6^JϪ1O#ʧN8e\4ẕW9uQ83Ϳ\2Jw¿M9YKQjtgҥTVSW1i46 Uv&^~XTx?N(9xt!Ab{s<^c!nk2:_mK)BMHH%Z҆k]:BE1\;Ł2\5\wi郳rZ ^YHI:EWT(㐯/>~{}Jp q@N(u5C뭶+_u9=uu~b: m_oI~'CmP05&n[wsEz96J-u?.A:SZ#|#YӐzbAJ}^ZxZ`x?]i0bU"*>TZ8btG^ScXI(p[b^| MMUzu/x+8]ֹ/ vm.&&54sCj*bQK%] "V=uX5;Zġ 5Oo: [D@K0 5b?Iz9JR>[~?if չ?F[{%U=,\L'XTUA}8ڟ\[zpChky?PHve`W|EBԧ|=qoЬ"O0?->ȿ5h9n2'[5p^uqDwaP|>v{U=R͉YXd.O;/[)IzԾt4Y13+1v^tT防z+eOF0Lc^`PӂcŵoĀ~p5F4Zxel]YA}Vu]v/$RkR;_ |G[UJ%}覆=~[ubpB߯}0ͯs,WkڔװR ~whIV~?׬ͦ:{mΐ>QM$L|\2Q%^_,<؅8,uށ[xtBz43Zߏ [ .Sc6xGuAǙ.3VU{5ə2+),53?ȟ kJk M@pȸ7 h()>_WTPMj7Ҿ嶄r]p}}rµ Кi)K)a ZW:ץ~6F c)րxie W0_dn|1#}0YJ'Zl|͟n hV^Tޖp^U˦sifW ~M^uP]m 'йJUÍֽ2 LQ15FĠDD<֊҉5!`R؍?ч 5^sz!.% JZ{E1%$frOӗ.i<-µ 3or\:u:x"mb8)5<&TMuiʡxMh$& _ 3 +Om8܁S_Nv/jHEToJk[iZ}{+jO_`G_YXq(F4j$5Ǘ:4=7ߗv𧏕ogn(`as EȏYP7~@y,ZTHP|u>4TqV&Ϧ,W[YDRJIЀ)҂Cά86'pk@/$\W:jEFlqG}d^<0CMOZvחED(P~? PVv٧§AKFJSR :O/[3yW1"l{윉}AT U=m!Mjv:xX%Ԛ_X0P z]*}c)$:?- ouRx~}͋]u $֛W6=ۑ o"dxXB dr5L )f^}u؛)YCw -*)F??t~7K$V<H?im/)5#CBǝ4$ 駇$=ὃ8iƺ5{CBy_-9k`j_x֦DZj>_]|[DSTОG_])g-c晫^__TןQB 9w6M W.gX~_`ܿ%|c-$juޛ~Sxk𴲿JДSRkN_8k[~i1X?5 `p :r˷ZSu~? 3ԧ]j+n2#;I4柝/43W?Mkc4l|U9؄H؏uج oM?o~8c](\lhU:f9WKefEŧ ղA uh@\?œmyr@#nX \I%-He\՟IB`d Y(x)ѲIcoql0Z*>v3*S$UH JBG]mp')v Txuj{'x+@+d=I0#xsEiDCY+x]~c奵j;7I:^7I+IWO,1^ͭU>Φk O?#)C[z՘ k.Oqf(I1ş*TTF|bڸX'Ho`dzvI ډj\X&-dlvdֿ pJtwO9ƭ(=Pz uhvoƶSB) Ԑ7>ETH4?^SPJTCOuqRoGLz1(pOR'r1w~AKJR75^v ڏq$Β~|J?)$4'+rmJxҵQיo$ӆ=DE_?=,-*iJy) V|+8QyMc3cT\Zޢχ/gkU// QL2|gNEeX5~ijvUhSyeX!b9Go""?SbP\ 6mʯ8t+8qQ5( "k&z%#( wu cOmXtT` )UO޿ǧJi˕zוPR<:yYDcߖ=똰uRM;,J"=|E'?"SGJia VW(k׏ѷU{2-p;@B*9#J#U`mkf|OY޿j<h >V_|8~v&!(h@>lp*I'P<lM{j }ڞ~ZoWبF acRs'W鎱f9uxCI1:[,+1JL^@?#[/3`֫2׵P'cg!$qH'#2)c6LTTr+`먮,;kM[AJx[U"qHL!G]iD-pq^O;TUgW {b2H־~VL^$Vkʣ*^9Vdf5 |IT$݀ î*ꕁZ 3%9Px kf;miקK:: M@ٲRBj>ׅ>f@+#̇Pu_--gŮ&!5 X ҼjЉv0WʻSCzZ9iW]SCnQO?¤A V[rPAe9Y?hM ׂj:٢ղ|!"ATeA皃CkdDiր>~ޟ)<, F@9S^>mg`N))j?tU_VqԅG]gnf(ՙ~>ʴPIXVgOZ5qk^峝8: GhTuiUTI9yiW3>8Mo#CHl!C@};Ez~^}y˫E^8jIO)Џ`n>EiM46CU:{klL5Z̛ml v% ξΖ+~(EsPצܵX4W%D)_?փC子7'< SZӘg$TֻiZӍ"m2|EO+YQ!Mԓ7j) r6Q?.B?ߦ,f6,R y}֫H4q/4BO^~Cg+tMk*|TGthT9ß~4"`/s*E>Oi$x@y j vh$FM5Ec_d !âC]%,uZ'Aᦿ W۶;UVTt-3bE|.enitJaSUSMƶ ZTUAB@؁Ok>y)Z hZFJ_ }q@C_ߥB.Iؔ*n+N +K4?TzMe.!&CF4m]-8XjEM5M4ZjvTk->>c;\V?a@`)%Rw];!A ܺi }:xpguAla8%s*e*~$JT[[}rUgVǠ|>@B Yj B6z. /CA[ꆐ SBҜn%rڊENƵ< :oODZg!W_+}R?-+ojNerMG [(P^Zo  yU<Qi5;9s? ?WO0bI+kH&Oie16+u)E?11na֯qE6_ٞ~Am'G2>zlQI]9b{OUA3Q='4ac8𥦔_L|p&O뎤?f-{--Ԥ.V?[ejEYEf*n\[-ʜaKuk6 qDQӃ ůszBWX=z mYUyia(A]+H1ģjYghdh\ ?s⏘1g:C&3yziT$sG*mS<6Om1? |8@=:M"@w̋6s=fQ2|s'_ fZo;6ӀU.4LaEԬk׺wų/~c~iFQD$יcL+C9Ag n&S _cXom?F ador~vPŠe4#M|PRj?[(Фҵ̗^_<7_|Vh:gL(u<(FXO쪀 6|MvK4B6nVëClHæ?@٨ Œ+TItjXeG:WO,“r|F?a_;O|2>%<0ڭe!)J ޯpœϝjjv_}¸۵b+k5"jEMG^u}mjΧ3lj<#L%s }\ u!]2[uA'sT齬 稤 =B±/SDW޶7>_9F'{w=~᧟mEO6I+ϥt 5AO?5%tӦ>6 a v:;kҚmsiV(&:~>X;G'xꥑZU0M6OOo? 9~c{^_u{{~)r3]=YT{]ǕW /NwOR~VJL0˯ViNK7OŒ?ZڱX_0ČtŦoR{UKV̭[)tRI5ۺ|B\?S㌉v|%_,e1}5}^ q/%Ϲ3,X<2m:3"O+Ns,f!Қ_=,c+T;9E Ꞝ _p5;5`*eF.9bIz!ꥨԒw,-)P5"t63 E%ҟAi>eYVshqy+o~ ]~]R Pi,lSAk{JY@_+h'+zUh+Ÿ[[kZ^]>[{Ǔ^u!'?!osoH ~_>㾟W%L}_+3$ahxE2m?6ԯN)Z#dWGU|u;9fI:$S6yWm|qR̈ILxuԝSNGq_k^o_ lvL|SzUoBH.ss=zw;k8{" &t@,4"qN1 #d`yj[ 2仛Ww]B!s.xҨ #,+7N֝~$ڵ8)3yauUP$B3(}yj⺟kK4+gwߞgW~?rJ8 Wݿ?:>TXǷ,g,$WȓOuL0ҼO||1' DU 59>Y**0b2y{:mFjj9E=#>|mKl&>qj6#Ab͸iϡNİkCO:yW *ˆ(9y0ѿ:-jl%%-S )Zb"*NPXa B6@U@ C9?|%"Us˄!2AU5ީļcr{y/<5Qn/kHh:ӰJj~6II)pt:flSW65kL T-5? hO:ہ.qkJKiT-\*se5wH|-A]'㰷y*u"0[ ?ԵSM{h'!9#]T1ʶ|]5†ɤ3h,ʖAIN6ϜvlS__ usN羇蟕 YoJ;rS 8 @񯕼w9XnҥJ'}`|r.8jr!uFو iBw֯xY0"~_{IRqNSjxx<.ZUױU> wH:/ixa7[?.xY\mT#8Ҏ' QKLԚ#~t_bN̰q7~^L<"\< T b/;^G*S#1fL y55l8jik:~cf2˖Ղ:Yq#P Qg3l%pM~>IHrL"ny/]y6?^[mIԁ׏mcHە7*J򑮛?,RGty;5Lz  #M>wT:?^_<3x mO*JP@JOx :xOFԓ#.b~,}  $eL똟:T}yZ*3$- Av9ǥ# &cO;b+Am/d+٣?pMȯ+ᵚ5x_Vo*ySxN|WziEz6yS'+m6~$r/GaqƤUQR˕+Y=@)ezl4N­SX)?1 ?-/gF\ʃ U~fzˆC(8Qskҽ(<~j5]aѧ-4ٯ $"!@M,G(yĔןvǷ,G,c|e˟ݏoY|@T>dySc2ӟ?1ִߦB8ՂAjmU=~ltm>GL"[n&_S=.|t;vϕ-,Ĩ$~x4QĄuk]--S7dz,eVK[4%k\S :kk/ưܣR]*O X|gEu 2X9 {Bi]ӼNà- Hxy~_ջ\f [pnY}ƃ(pKq3 1fQP$@2vN^$}~8n\4U󈚼ۦ)iZHH k@ä1;~at.*&G!qw"c`Ct4%H Hv{,O0( 6ZS9Z;?H< /<a S ]Hyq A))^bi"Β"`I7Ģ[ -<|=bҰs{nӮM}bw ` ӅH!UBHzyIP.b%ꎼ8{n,|#Jˢj m2+ K V`j:S\QUە2kT d_KwzOѭPem}Eɐ :[|٨v`(ZT$“1Y~ ~xyp̖I押ѐ`syՉԥ)CkkŦ' 92GI[vK!ZXiM: R* DIjIW[ nz&R -xWK(")̐{jcŻ'%0t#^^_VB{BA{&,6Bӯzys i{*N0f%+8<@+ѯyt|RR$)YTH+BWZ*Wv}qϼVYtW} kJ `FS~V[p>ϰMYI|ZsR9X<9pH Y\lg+^i,M&Ya)H)jr<_8P$%C^qUXV4EBPaP 'Jt־ j!IV¤e_nT7/qĸpo]zb,b-cX2}sƮ끵6!!J{Z)CKN5, *63$6A^z֖|Yܻ .,ɕ03Ieo*J ?\ַo"5ל^^euMRAm,5E5|j.}~:T3ϝ˦Þ)Oltl° ;G <6OଊcvgPe‘ʖ*T N<5evK [:HItE6Pdva)J"of!^ y\Qt2UDI$P Q<}q1>a:c`rcbЈrZR$M; .|/ zZ^sRE?mOvn1sl'a ujQCOu;G*9 ʑu+Ȩ9}SA`OaFӻri TdH<<~" J$H!IA6y+fqynUגݘ{ʘ,ڿPS%A#MgT3]29@hiN>m>tjiA˗׶¼;EU%PI/$+S^UmHMޜ h"q%B6Y(6D A&փːZzž0e& 0'༧'pm$ԪmmBu iS&F5i7z٢=O=;;W'f}yV8komاf_7]X5tJ`9`[M3f__{ TW+N~^Qhuh=]iit8`ZvTm#;D[WT[/̿UW&bxZ&7_U`-qY^wNšoRziS \h@dik`{,mBAzU<Ϗ+W3?Ө]˿ir*jڈis秅B-*%ƖURh4ە|zK)GhHvMP]]%? A*D+2$@)*qJV(CCZSCZ Cp9D% MHIQFPLӑ~^DIXLnLBOyn혵7 Wc*0Ecd9FE6Vet:R M| #a1.HP&IЅeSPRZߞw_(Ozb0W3Cp.Qzz!b%\% y%*;JymfջRnܖF jU<6DVFo}CRvPO)SS]).D<ĀR՘(xPG"7XZˤO J#&M_4C6?uP'0s寿+@mu G!rJuۙkۃJyxS_&G##~81WSOpvKSZ|^^6P$i'n]jwY>dys~PN6?}'cI9H#b|>mI@ NGM+m5D|7WTث-|^X"cǤDWN/[V5"l$CAZkO =ʳ$6~|: ߿>?G4LZC/1hIyt 6"k?#tkA'}@o H}JbT~)g̒ ֺ| xlGO{n Q{/ :y)C`-O7mYy˕&y stwIIW :obCS_uMA5xonMUyOutA*riN2|J儔CZdoaQ @Q9hy]̥4<Ǖm&/B"oPEk^tѺx)FZf(OӝكEWhҴ D T 7@b:_U1[5k@}8#^Ӧ/.vnPk#@Bx̉?(ăy:u[e6̏615:y^Umoj# [?ylC֦"_]uӰKek[M(rajuoګ_ h4ݙ)/ 5*zWzi-8q僕dRw\q ۂuZo:񖄥T6jTee`7[@A ߽ؤ֍tK~t %])KL kZx𱪍E=US1I)I1:'ʡIU**HҒP<&=yq$Jmz3X6N@$(}eEy옲AYԒQPy)k*˫ŒTɜY좒4P:_ YfOEui 7  2".LU(aP; FY}(j% .*Tx.9_VĈJ@F<,"\JY@ *ב$&Hk kO}V^3iQ;Mk]9tfEA4: !ZOt}O,VT /N$ĎWy8xQ&b55BkaM 8?Tթᨢ"ƞ븗$HCO;"#r#/©Lj|/3J1.񦄾}m)O@Ii4ڝB(9^l30t%Ih n׮mvf I9% &ZzO?gFiU7| aN'N5fb<5L;*I:}+40=WH:y<:؉аPVԦ)\æ#0BVu](\IU6~\ '(R]p*FI'] |bԂBv!'&2:+zD)wnz AK`º{iUo7~b5`bHQWqO\RωŵÕG_jởٴS~CAx<ɊER:yVūlsJY0!#`"<)X n0 >;,_?ue#aͿ,(3Jk#¹ =nZY$|y4Q{S?=*G4f `V>SG_"M_uF H.:sεA㽃J`#OV<#:S녕ospZoҫo;a˘wpU|l F<|%URR8FezkO2_Q]/]== &Bch"u,=SU ><6FۿERɍUH(SJݾ6@L>θQ'lIN?[ǮȾP<}9饾;}arAw+~B0JEvjש4.='2Ut6>]<&PmNO낌ƠTԼ{5Ζ,-0h־4H#aVoΕh!V򰫁8m0WQLGYAx"7$̞P%Evѡc饀@Mr²^lvQ0Q%PRFmSg çvpcVKFogl*);d>i3^hThOjh\Z@5tS>~ !4 }Hs|)*QxoS;ǧl(jZ~xA֡^[lP ' ?diҽ﷕@Pķ yPeQ\89)#K1oY`h:O/oeE(4ן-9 L[QW]~6*I#!뚺ءmѯ>vTpVL.$lC]6傜 o\5z%9QB]KU4$g:/G&WuUw\N73?y.*Rx .%Z 0#J[+Hw5=wa;}ZQUN OXpBn~^daBRdA(Qh_ihE8f-$*dI}0ʔe: 6y|'j+qTs׭OlYĈ˾&@'eOo>dl8/bL#}Z`LsqJG jY9z'e2A J#M6:ydHDM^tCG}$F"A@3|kB1I!}|tg]5XфCC?y kC[>lzđ~xЩ?3 ?-^#N(_T}[Y)=2aӻ\w9Gh o3PY6J_y3JI%l)3 XhIV U4kD QmTe łH瓪ב7Dmq$R5܍h5߭Ar(J EM~t[7Fw#0b@uOxg }ļ , 43WM7٭*[m@'jRJ967&߮CߩUtHQ5{^$׵y :(=i|V%C.ނpSjXs_\Ld:;O9r:I%NӨGn׬F];x'|01H1 r[B 60"lQQ3* j? ^l+?t6$~z~Vr[pZ \N^t$nx<9%1ok^;6 SZɠTT6kT((v`j (5 ~eNa6Д;?aP2O~XR/T^iH[PVӉ btUwY>+{" b?륧w/M+ly}lS0{V&} +K'hT^~gbu!>ֿ 2rzƑtm?_<-N>#RnqZ*vw⿦tk5qt>_!p˹" G˟y`nw<l9|C5D#CZOu@&y,\U8k]]{b cnm9;8ôg#EfӳIi[XHcJečm4]ih2-"Eq!TOݥJN|oy"k2b4IS$ m j)*t:$M x< ]o{dy[(&! }̩) ߎ +BC)e緍-d04gSoKʘy"~\0VUUBC Ze{\\JJ+횓)4hetomK@XhhUE"`J:kb{緎zd&\"T̺sv$+#D(H򥃰?>#iSLM'x`THv_F^I oùה(w)7JYv4mVE6ViSX}Nh; \Lx"!K (PuЀ>M&P < Fj)j)qMJPr"(J2t#xR2%)%%"e}h9ͮτF8b/J&v4$< 4w5gS)l0H_h KIM+O-fu~*E6|ďlSt UjʹP)G@.qff 59k^uhtC3!2Kb$6T›A!J@+Z~+3!}0) biDCS\#/\]g0GV$Ü@j[t i^gM>(uwQwu)@;kK1S&E34q/C*Gt҇sA>61"R+SĨQ¶tyyJbM? #O?ü1rP*<gqQBu֟?٫mJ\ehy)$yT{7^qP-}rh3#b7vw x r# )?nНشb **F ֜} !"J+m <_m}]lhM B@v#Uo08}U<$DW3b|]P<5ɣ(uӟ4M/Dr:#ڻ#_urqgy*dǨzÜJ 4Tfy.G?UcT5<6E_yqQj}z_^tI`+B uۯ7cH?+!VYƤ]l.q S&aSu3\q̠W&Y4ݷQosk~xQuXx-e1 @M׈ޕ*Wff`KYI-Lyh\X@qk".*!^i;ZAGB\S- AKbB~\A)WI}H#=jW#鿆,!jQYCz%#$i4Oom)4$UGY(>V%mHB  t1 CK߭~+BT}iْ7'BUttC&`/"hmؒכ6=vqStM0Li]BNV%Ry4=#q^%c5O/} E-<DžRď! +99[~hz4 ؊30v-Etg(s\ȇ)Dai_~#A#^AN\h&BoO*nV^8.scLEԸ?ݷ(HZn[ض&cLo W;詩**y{) ?#OC1mMfkaڇ!թ"TZ P-Z~xǧ򎓅Q#? 6Q3)qBsp,z"- Sk[hkd:a&#Ew2yӺ)}5~o+@#@ n1(NvF[4pWXlVJ4;{mImRR@' ᨄb8$:UN8GƾS`IܞAfP Q-G`em ^Г΁|ln!<ҶᣖmI5 4R(U+Ҷq>]wg(51VuC´H&OaN>.m)f)R;#NSe RP(H kջAz$Ϥ-B ˦ ,uBXXv@y m) UjM /,KmH}iJRR#P]I6]X1BZmtQ%J֞>\k<lLz`BC{s_;S @;זiC#gfn\׉ Wm 8Qri$+ڹ;-N*UsD7.c^!!*S*hN@=l@9 W%aˮ9JJ'0zM>:FcBc07pK9R%GG+8 U &jiqȸH|0(h'gC,h;)ei [ND$e/0҂ȊMhvҘ[B1ǮABSyX uLjعCfJ* Y/%-!QT =GjTDllz96 JI.p: [-{v#`: 6w IٗHr Ba04 ZK@9 Ɣۥ,YwZc4IT`J)#2^/+IHIϕJcy{ dBМKZ4n[ ۘG7hJs#nIQ^RIU lZ=J yt-:Rl_;\6.k|olaJ ar=TfHyWm[nI]㍻..:^-K9O3쭖]p6BB;vb 1!HiNjRH<^kzj1!2pBPeK8M]cqؤ#`I?=@rH.TT,\KpJ}HSiPiN!B"VAZ~65Bl媃:VC9MO^7Nav; NPZR,Ns1"}|bjUB܂@tK99dJ:}1{siS(ug I.)F 'md,qyerYBwZ]p!EoD;B!Uc^v8F!]jCW{0!ÝrrԞU;M$r) >$Dx 44(&H;Dg'OXq+ K$LN"> " rGO\k% 9{bh^e? !gQ])cpGe*L*E3V7AZo[&kYEj~:VNZ4M~tdd$)j<̨O7g}а@n& xDy d=(`lIx%ds' 4޻χeᜭ4BJО+AoeTIxPJ~~:ranc#wALO[ EKIt$pIډ҃NgÕՈ%]$ ٥y ,tEj)X9&uO,`  P<1zWaoo}ԗBsTd&M_;yD;qBӠ]:ieң}>vL^Դ6J <gLš/>]pT)GIS,Y7};\5A>5Hdq=7'NZe$UwxNObqi+.^UZhua_–w$Z PE>-饩sTV3Qm\MvGI*pm3劋115J=JXruu_vG4_6 vER^M' ~o|R]V.NU̓jJTJMB{$S(89TWZ)*IȤZvPCDtu PUtT?'W=e+b~򰼫T* T?‹)i(PMwj4R KKۘ7mխiKRPM/ GRSƶJR҅ ZABt؏?P*HP9)%(OO8ʒСji:SeOt oJ+(PJt{9l9PSOĞZV$l)sQM=GuscDm|M ub"cR'>h8J^ZPlUd,XqFA'pq."SPْm4=ZM0bnmsզj(hz+Dq؞t:֦.+kN0TȺBTpD1-J! 1>Qq 2zp~9$f)kR:toUbU7d #5jއzd+ЌRkEZ[| EFI'>\RU uTU0hn2a| p8 BbAoos®Ur؈9Dا39ۤ8ZDԂz~[qS/e& QO8V[UBRi]ʔEj%KRQBF@iG y]Ɩ Ε-AEh"% Pξ؄ sǡ(PLAJLIYA GPoIâ%zOHnE<@b׿+9S5ҾïbQ(RDMp9Ů , $+5h*<IiDHu6iJ*(=NrTԸOƃ6oʒ\(Xm (Ӗ#)[FFہA- *u+=ADI8KR uUI*m˖8erg!)AkVPl 4$-!e %)2 $mJB eX#q>v mrcI?<(HFJ*@'~Ads*iחBk?^%/YRF W 698۟d"*~ Dߌ ̃gϝ-IEʢ? 44۳|Zvūpr^Y.Βluh5#[Nnkۉ*YczQ 66HvyT@j(yڶW&B:fԞg 0q0؆\T3p6[R IEA%~n[M.]0f"KͯՅ ]E58\Ij*,wBT:HaGKۣ0en!\/|}Şap^ I J*n4N)י=J< ]reX􅃌ivD[A7 Ì QwWf]+مw<22p+R:xA줕zDH.u);Q 17-md*L)MEJ V؞qƟU?k6h N U pn:ٛ(ɰĻ9_J?(.+ >N4S? hSQH)I tлܺvMQ!_qM$E$=,qt[x,_+<|,\cқ"^T4Yyh;ryDΦs4¿ {$6 N|]5rPƯ0]P{xZ&(Iam⻚ӴZ$H[q=jArP)<+Q_=?(ShPv)`U̢Jr }oOҶ-Zy+=x hE@scϖ*n.;DHK`6KrK^oDV[X4π$]1 :paVUE)7],O$SYTխ%hۑfJޥ>;LřMݻ̓wO칀il/DCe8yhm͞kpcMNsG^IRA ̩Z5FِSeӸyF)^wS6,teΊTL d;%Q};'( @+S46 GBD|.&:TmQي^F~m0u) Zd_VQ%\ ; K.;(hy[LRĮp8wx?rىDw`mmWRΔ7)Sέ7T4TS!4ZT!Iq<ʂT̋hxRU4&H~}r0NTkTy*.TTKYjjRʓ]Ɨbuy&3 w_3dg,iBBz9#"7+. RB3 ÐC%U r(IO<^V.EBb)BBC]ͬ9̲j:6ҐT8H[PDE> 8ZR ċ>N 5鴊-X9H)qHZI4!Q1n.**(gS@PR3j93!r<./UBYo&Ci3.$ԭ4!#yxZTvi>妹QQ+( O!󷧝8@M@j(7Sb&jjc2kc,hhK0|7z%ANԖZ( xptT<@u Ϲb.Z[-2;J6ea DIdvi$(9A9" DSN&(cKKpfmTe#&e~蚰J\5 @f2,*-۩:SրokE92]ttq(|KE*nJJesx9uHKqoUAXԎCM$B;z;v#\xq H4 4gxYRu{#ׂ&2xTNB! 9@P9CocN\m*zWP_LNjNƩ +ڪ&L%o0>|!IJhT;”t:BXfhtKU lJsBBt')V`j+PA{ vKjJ!@"r63cMF@ Q kxWoV d,:C(PL;nD>)qhiX**Mnԕ4[ tT9$X"OfI$û!WEݨk cYT[ROZiz?.],PwkS-Hx2hLP[$Ts]{!to㘦YLiYP@&P*C^7_?qїc>zT.:I0qQl7t:^ґs?kfVa:}Wij) A*CuHF/7GLU"IILZ#ˮ>2Fע{io$b [vX'c.e܊kd]_ l%„ŵ0?5J(%Ii55{ΌSwI<97C0j1`;fs:M4Kx7\,JEjy{а3B-re46ʘW0dC. kSD B2^W,J-*3Lu21=lE%0zQؑp)0\ٮŸθtu)#B6hP)S@w#^5;=D\16@].j`JلCRsը q$@[1h#ݦUQƖPj*$s [Ya> ϙC9D%ţp"1BP3'e$6t-)_,z^EHBj맕A"TU?]-{}kMiB;$E{D'WG$oA2yruj :OTQ@h2/p-ISϕ8ӫ aWP*JȐ4s;ZS  N#l1 :] lRb6BE.iiC+<EFw!Zwl6) cnd$)):J@znl?jé4}⃁^ID1Q֦o>>SЬ @u#V a"^˽h97rGt)9ùHj-JC2I XTx`k;Ar P$ԄcJm - /ql=ـi,4@5 P;KX 6ЎI,D;V4KhI& 46NdV(4Rk@Jhk&Q:]&!bZ.ՙIB\ӧ'̳(g(iѧP  wLyZG_RA`L n~;^N&4K]*)yimqQFB$uqِ˫Pvm!*Ҡl-^P0mnVņ` .ou \Ov#ߊ\%\v!l]=╭kȵb}#8Aס\myoViP†,s/ z&wRF=!q:ĭ/U$!J,'pNfz Ha%PyY!kW4VaiXjTdi[T:wH& A3h5A:{1&갍?,WV-emp끁n|TRFV5:V&N*b ۘEE;0YŞ * | si-Tt\P! T,+PEkd֍D$qi j2222J_haP#&}Neڪa)ҠjJfDo1/Գן0Be/\fc"J͂͒ƊCyIΞW'W4,%9΃QK2w{NQ!JJ6;ۢ?x'+#E6yS.Kq0 c2u:=hwNJw2w1 N]q LKIy-E&㭬|;RFb3z8j} XKPVeJp3T0yQNaQ/)1.S-8 V]#̲YΦRy]2i AKE<37d%ґ JSJo֓83mDKXb[V!!Fn5 8M}5=CJjRbw$1ӂY;hV6ӗ闃pnWXr嘋zq %!hv!JRkAR:ZN^goxaYs"Uڕ"!cfq/wݙކ[%}\[`rZ$aZ[%BOS:@֖ EhYfP&"gRd3EUԅ $NEG.Wc-总2{v^h F^}ICL73@0|:Z"pZTJ;>vm~8 xpUPx+vwvyaGʲ-dI Vlj1;G.\VۍW.4>.y¤۫%(RkqNWUCE2^[hX KIS vn7s%J{($67V1:F'3H&QRƣܱ DC--zPF;\q{wq*J[5,49mn}!8pqA< ߭DE Р;һk.'s;s.9Kxp$ Pň5Cf׊=tZE̠s Z|$<dZZ_۬8n6!rjڤ@0 Ryr#DȄЌִ K0mCYfa\l-+JANnVvTbm~swHe ia96A_L<$ԭ R[,QP (S]ARR)V:4b(JR֝+R~"*rz;4&#!f&Oj) g fsĢuw&OTq->jTY&TӚ|]Jw)V2|zIa.+ Wzؙ7VMC6+"v{j4u^VSiMjP^Q1`udfeCQ~- 6*+3ST%* ~ ):9S4 mb֧و_LTJ"l uI4";Y:E}QoQ;t{1r$f+;{”'yV5En>8%Ǭ^zNEMDejNTfN(MEzC1aR.P-5steZ3$FkY>Ts!97wh*enT/*T&sm,:%F ޳8&(:n!&2%MOq=ywK'y'L/D}5XdzQʻ2 QD֝6v2*69F BlbIfòMUAt6Exũ4āh-)jVcTI'qY7rMfh+9X2ܐU AF} VjUzPJKfIP ?6A3C|qίdC6fVb {ˑ}+,c);bU Bt4HP PTxCʞAy>ږI:n""#l^ =ˡ3rUxd!IZ;vRH˺]Li; A2u\5Q'NuD$DчOP\֧E -tuhmSa:@nN=D`#݉Y/< l/i@ӺM9sgRݙ4-ŜcD ;'L2M  }'*@ޅONj1ͮ:DbEyqjRBEр rf(5}@(Ҕ OآZ" MD\eޤ u&5BRBa}V[A=U&so'3Mr,fN|s:B;sϯ.-b'koK%ς (kMF }̈(D$#Sj5 zۑQOwK ,a #"ApZ&ikx>9Qh)5\֣6iƋT%i76mƗNp^M4sŬAvמ!bR()m2n[6j'PJ#iJ[%9*u-5 m-izNmڂV $%@l@\2eC\Px۟,9ҝNӴ 2m.%*:lD]*MZ-> ?9{!-pȪT2RFbe2iҀ6?FthXeƖVZ;!k-pz H ΕaHU%*I 58w#<y/]dbx8*)ǜ܍JD;gP/͜i]BdkA=:gزhai` ׶YÉ  +2RҥQ$"L炩3T2C:3K!*5Tf-و3׭w8[P*)F嬋2 bCP;>VԲ)S^s,8YBkkM4'M3!+i@Pb2V!E$wSRx.fiWly'~C@9Rt54:S}skYeٶx BueCז=GGxnkAA?̟~M^KU %3>ysH0/xK^H[5ɽ+u[8GZ 8ں;eUrዅ*uSI@=w*+jUB H@M}`2TPŐ*+J4M<1oiA:JXK)(JFj̑dFv,F9ŞVJőejM(4 ka4$ҺeVw>P5  Ti_ S]~T Ji_-iJ,P'-,|y =GPSCJkAMRwh}HwחIס󱒠~vatP\k:jikSSӕEhVެ OXV~xJ>ҕ4xPY*4)sV :mKG)j/?j \~sW 5FnZeyx8FRW6 uD%! xWUIӂ7o0at .c0J6* 9UD&s3 F^K'`'@I_9XuI37z}oV\L$A%s2 |D@jRŞ7 Nިy;"e0N,rN ﭯ9.t\1 7J؎T߉y.f*cԓfqVaВ$,1-a-!-!kSeT!cXSk (*Np zF$M6@!l:V }paa!Em喖C0fi|2eaYn")kpЌ;mXX75$BHlyxRۡĺ7^&u.y+0tTuܥko<!ԅL+OOCE*,AMҌyVKIPN]šA9,%YhkM>6KXWͅ7v.:52O{=ܩ-:[NjKInBLȊuOLd/13Z!@S]i&{^(̨lN)z!0!GsL-#6[*6'SRj*5ٽAų d+wJAZ 6WT9ϮB<ʧ% BV4€|?[$,P_+ |5|/vhZtc;"b'ǒ.crqI5Jk lG֟SC_^-jji񳔷HGԈ6zDBQOeʳfR#JϠA SVK z[oi('UǑ[-V*-ht;ӝ:L7m<1p/E2z)<<19t`PR@Ei^3K v}9Ӫ:fXR.D|>KaDrq%-*q-,'2JAyIdYeFiFjXSm!z=%`&QYQq 8 Lv$dϏ,W˨JhG=}_Y+inu x!{r)@UmrcCtkיʖr,ꏉh2&uj@PAQ+FM.SUX%*mb=mVMv:{TC7km/TTQi~̶ j{E()1'p7{auX;~2*<|G+|H ᧳𷢮U  HM,:9̞QrNHQ$ <pϸkoPn:zio4(4ހڝWd! JBFE\kyK(V jۭA)L@>V $wIY&Mwv)H:! _m7!HP^ Q\%rTB*  ~ >JV~]T)J)`HCuM,)p5ir96y^wl 7ffP *#rt`P`-* Be#qAZ㬇JTR@mĩ@12|qYl%N$l<<^ۤJ+WJ~>:[ZNa]d>yz 17RFa㮖CBON|.Z'E buM5>'7e]T/;p"lpv &al-CrCj6`X~~]l[0QOX)~bIXyvӑן/d>_u_ĨO=-9Le7D]q/Onu|׳ޒRAPk띕HƴΣ+*&Of0iPLI*W"w7\G409LjJH VGd=;MĿL\CXTW25S(x(ڝVRԁm=9'lܫreJqG4(<8*,=|'6UZV\N3iϳYV^--@d)R GK Xw8ialAPMfo ?8Hx4 3|9"]<`鱆ۯ<۲-xtK@BP|ҜtN]Sw$У9ک=)]Gyv,`+ PNPA`Һ{1ؾL }톋;io<3zϫEEsxOm;2 ʔBfm{&&SA)<=\B">v4ldH{j*#}#EU{4K`E{Bl!_9M1/v0e-zҭM;6}9X ̀).JPEjtUÇT:IB-t)m#:V%:[006Jё[{"]DQSb֥RSRZ҄l-{}q?*$[ڇCT>*L\'elT oM RU 8(_?hYLR-N ,Dd]ۻ6L)iO7تFn8{iq,/$kܩ_war2 @HT>](s^^bRZp%o6Sj!@(:0Dǖ*9 jU+BDL`D<7ew0~dͫ!vEWa" Oj Aa+Ve/Ž7"O+| dKz3}",c<a>4DI]TPly2`"V i&xR;ոܔs0le'S@hjk6nEg=p>d]M|yUkUUW4 ]E) 9Sb+BEvۑ?88z$,!n̶Nl)8fYMPI(Q=M~vX< N0T}ܣ('/`lu s R6 @gnk,N_Eo-V\6zt=)qNաI6Aw< uJ?x nIvnv9˦h흗Y;4ꀋ"jG`D]ϲ -ވ{p$\Ds8! &oin(y%*U Wx67xEA)Bt LF6ҞKD6HS) *(AW}uǕxived{31 QeC#keTCpp1 m-) PiW3SHK[XB) APj_jҨ-:DuŎ\3N;,ygW6X9YVRBU6H5lExww"R\7n! Qv*U$k29)EGM=:D<,<0TM%)!eP=+H~ 7#Pua bNh cRG+poٞk59Vx˹]afӋ|m= &6Ƶ3Դa 6ڤ&W q 1C;'4BhDXum\|4U}']?uVOZR=ܾ4pmKU0F$eo$ޮQsɵ|IaeDKvq YCO)d8zkjm(l8dΫnhrpPmŦ vwTxz:J!tZ J{VЂ ;m&l^v)5-@D8 ]*%K$ @9Zl48 MSC M)5)QRF1!I&I;OFMrךKR^0@0)CCDL1 %l6\GĸagqI$Qnxc"^94\4{ 6 1iyMRjHqA5C I ێ>T - ¿{CkTV! ք 'Xy'I{K%htxhV)a$(l$[63*Ϫr j)2SKP ,}䘝6ĭ tyu2yk7JI&0.=*bKp.t l<2I]iVdZmqA ̨Hz.{JQ=qhH!#iN UP\:ol[w*nDA2G<:åd-AE$(o 9%]T`poM EZ{7B[Qs\s0}lˠW55JB64>X9=L ӿ ?<¼JR[$VNk%{rrEL Pz$)VC+PP<>QdT4jbx}؏N Ă:=੼Lm0axQ[a.&2pU z&yɋ 0ə`)kJ\g/ x`FnI+q%j[KiHP*-+ ˮ-˫RGSI5ᾶQ@Bq s%h!Zs'JZI(.]VBMK/tjo>Yx؍"7#()!"ʏ}9\mBTBu4КpI?^߮v;0o--%7\K;*Z4y[ >V$)X'Qmׯ[_rJ]@^_uH[&+Fv pʵҼ`(< hۜmA(&.~~6_6hK / P n}TZQbPʦ |b˴6>K`T#P\ӥ;1[W`oG[-F3[SU򁋥5h1p22HE/ERPnCM_?i$RhG2=;U+O˯3Eq2Bb h}ӯ'ׅŰy^O/K @P>Skkpӥk6sIIϤaӈҡSIR +R J4S6jvG pC@GTTzNj5ET}HxBXCu<%+SKHoa=UCT sٻRii~t "{;0 /Ր6]'ʄOLaqowΒIw .a!Zv%F`s{|؉.M.]JO&PAD0(4-)AC}>#pwݛ7590b/cԳ Vf3'.QV%'* tReͩ-Ǣ).S"NBw))ZNud *Y)6dw},|4^syڼ2[*vq t2n @AWx@%%?{Jtmg&~.Y2IKš1҇:)T|fP:n"Ym -Z* #z\Wn$}N#قP2V0)]YBR Ԃ A&V}E/-$ᕳYUyso:KJ*%=MwZaI<{"deDlmrm>xR( )4!$zR-"1[%(=xBkKt CmRFPsHNs-ο*q/_KIc̒Cl 4Z"4[Aq q'SiOu!2Fe@B*NN}G@D/C1BIVAUr6f*bt=(1~$(;Ie44Z)z 5L#:Dȍi`~I&bG/b; ]9P365owrfVS{ԁ?09̀*dO^;N H8Za!Ln-Lp2ˑ.v *IyZ`ߊkèxNn*d'D;9D$kKsf>HxlEׂ ":Uv.<'yǻ~2tK_WvYs1y/$U%O$6ԉl*:Te$T['T))")) $)pbJJL >wu/MV)cK: 5Gh3hX]ޑ\+Wc>&9m٘A(4FtRs֋'?{_]|<%v:*6_9{t޿.] 3-iKD]@Zm-dzjxJj!MX{ɶ܈ߖ2|M YNr x0p22}͇b2M$riRF$db 5.m΋bӫk$xoJ}L(m>BUi:mj{'Va:}$;V2KSTT@ը$w?1)i l=7ӝ>{ $W8$JېR#]}=2=+Ȼ 'WbLɩLITI~S&4zb8X8m+222 w$\\'@{[ jYxgwFݹ2n-3SEU9OڙW]9e5Lb֞}p阋tjMK\TK w%sbf: I4)J(kv!)H w@S~+gPY\g 2EeM/eVYV x-SPVۚRSOvWFi8Z2{ ʒ$\5~t6nxLLT4W-u6h,j9z|iWVfbE7+? Q9yZW߽l]Kz $,k6ݢpi ĵAڊw"*|#RYQ%6Sx-9h=BC!9 DT[I9"\eiB(E*@f\s;eIVu)Du$w]1/3͉2A.p7$R''1~Gq%Sr_DCK)Ƈ:o1VQT%O?PLm"O.,WsVTiKD-4OBtN}yGL&!TWsWcIL1PrJ-PxwNrYh)Awi-gw MB[u˚HB=c z-iHt(y@xBT]PJS„Z+UeTٺڶxmUȉum*sG#5 H~%ey\r<"^HBtZfUئ 7[LJ4(->x,Pq>6c"qV+TomBvƼZjfsKSqna?gk*SX _S)XT冼  .x8K^yi+ƺt^[0iSys%4'|d_84W 9 qj6\@ 0kð|ɮUԒ]4=/DceFGvC-_ĩ:Vs^00{"Jwd\\u/0MEDҔB!Kk孾bQOL{c7 D.ÙWh7Y5$4TB'[+/+5Z*||4YRVLW˨M(r1&G˽;6Ʉ"[I)5;K4Wv{9ѽ 6TE!Z <{7"a0uOnIҦ@=UG8o4EBMKl!,ʸʚ7iz^)͂P)@/TBG#K8=zU>]ل%0;[y eIA )B(v;ںqJ4JiaKat5( R;mijvB &H-$ `1J"k]+tgr$QG/ghgfJuZhm,6U$)diٸˇ&˟9&gPTaix4P\- b b}pk }n_iNĭYjAiVEw 7zrm:Lfo8}kqEJRYZbMhT|Mt=% /ٜFF93*ha&IP4 VcBȍ:Y4UP ve@$΄wR" q9ӑT@m*Lp䛏;3TcZI(AaBH:,* .vGzw#]9sCg^*qX߃QwXJ,iI#2隄V)' /b4 fǘ*;At=m!IfYHDI];hR`$T uV^iYQoTEQҨY&] yX*lQ'\rf ڶT~(O^ޖY#>CNmiR._ \{-l3 P<.pnTh%-nk&7O 74O*z}'˟K hUaG@J}ux W *@M7$5>@lN zG_eq̨̰sY o?l jW߈Z_jʏқ_VP!s$E|iCo½4E9RT,&pHIFFM(+y{:ԥښG-=">{G=-,R){U'Q1`F֫WTD|8JAu̵?T?jו4M%&TJlR@1|[/JX?d j#fp!_';1l4 ?qy-w:Z8a3%gT`i v/YJ݄vZ Em$*46T(RFaT `#q&*!Q#CJI#(={,.C8o'q9_ M^3+iä{Nq;j4ef1#inIRrYZķJSUG^I R?K^3ltKPeI7J_'a )MSΕUSPx~踰2XL|ɬ= K\(j|'^Sߴ="5*qd=tfڇhTȔƭOƕϫ@x e;#N.J.) OfoBz رJԆܪ9Xk_>M9~'=Qi{׆B'Oáۯ[HmʎwF |Wzw{#\L˥!ȥcl,PwfG7WGcTŖE%@vSt IrU =ŎiUAP`.I)3ăK["QMwB_gغ@M(+^xD(nBEn#8ЃDtá RTz)խU#z!F!w&^{8k+@i*uCN%e-1[|R2WfT^R64ANצ({0rH:یASj)"ZXޤX| +<}Eo|N(,7":kAx/RH$S^F}QD*^a`)D;9Vo_9Y3Nd-% VHOx7ƧOVK9uBR* hNI<ʽ'V]49;^ߢv/s4WMxL[yzo5m睖C߬˚iTRBABJ C3nbA.P3NZ}{;^xfrT fT{B[uVդ%ԥKmQ[DwMm3b9xcgabΜrCsPO%n* @4+~|-BtS(kc9ncCZNiFsӝwit,5umcSk ܂a]L}1#q1nmpKBB*EFĶ Hqa\Ĕ&֢,& [! l h'Dk|<࣮fJQWyR }ܴ[DhZEkRVeDxP*jjBBn[xχWMba!fn5S%o qR’Rj9RЖӕl٨s"4|7_KkjZB՚XU Ec;"@mñX^{m9Xq!Z4k־^%:$XmLb$msx(Ժ ^7 mZTiiKD`R ;RCȍi~[ܩs|ڑHqMUSdZD|WOݦ  'pwk+Y),CZT~WO0>\'J5k/8)tr!5-eDkl!-7/OӥՒK%)@CSd}w#l3JZq*pwRmHLu ^ay>SL0[ UD#t3`|C, ;"mSO=NJ֒2 JM*4;6Qb`Gu1,: S iRmhr4X:pL\mNmGǮ/978P,3 dFf-5҄85bZt-F]3)56nxm8".D@Sey"!؄'3Bv̛$'rs,s3deQAH"CZУ1˪B.@Exo}5FuBs&v?žzHtq>}2aeA}j xma@FMliZT Ozy؎ 5όTT+:Jbr6NdFǢ[/z5Ն\Vw )$ ~~޴ye2|hҶԥ^*ZwEަu5TėB #Ǥ[)ok4R^""1*uBT(iy 'xla!uze GfQжPщ!wR< D+(H+ J #(snײN'˳Mt+Uơ"lF*F/v< m\C@^ps| ̢cŀ,ʘQ1['bwn]H!'ڈLgyIqԸwHux\L7Yz07Zw#[(R[ʒ$59^>kwמc4]D J!eW ҃Jp5߳!_mͿk')i9Ҳjpj$; 3 lf~*Y(~̘Pk޻y/3fqH7V@?>uv.<<އV|XSuý,Cm! j4 j@FKW]v)[ҔJ$mg5Fg|sk2)YiԬ{&#+&d#0rtIQoY@Z@2N0BnzsNVMBY9iE)rYld@GM=^U.bPMTTҖ G:Z>߈w>~ ;7x'ThO6@n1ϫS=#ZoBa[i%)PO) i* B]Gh‰* m 'g\;FHcmUT2DC4 &!9T>`Txe/ o :f Yyg9akSaM{4&`ZShqfSQ;':WkirB> okTpuGqUA0|]O\3`45q!S Tjj% YA+w, ^ؕ;9QODJSդӯ1K5Bf7rItS2 C~W4CZǮK#,#=iz k!)T@VֺڷfbZbA ITskKYG>9N6q>2P[Jfjhw),W|+xyw4u">2\ è& 닟u )o}At X0ms:޹1xT$&T8aJS.RKgҚlHxdd^kwRvR39d%(n0Rt$ok"`V 7MɈRڼJ JZֵF/ )t!<0ۢ+1 G%B|Ӧ'RaU8k1bSҦ/-- k3rI玠gjFRK^E T(%JJx\.^ktZq| .Kzב!Wk FoZl㉼%U,@((kw#}B+R!#%З(J] V"0 dsZ+ATK$Up%J ʚD0Z"3k' O:/+b jC}:\H( 'oEm)[Jw[m5&[ $$  sO3}e]*TλXR*$T6"5 בqg%b.Kwpu3#<#6 #xFR7 BHM \BpԺUJU z8x[*,..8 hd(!?gNHxSyv*37'w'Q8ZQO"}XC)?q+O'ZY +2YFu%(n5D ;맏;DV78q/UڕJqNՊRv!=7k::SR :’QI<ST 'D;z_CB],XuCVM>4QN\K. kIqa]6$5>{(yt8A\uէfA҃ږ ["ԀXI#sPWTٍ6Vx1?. `}{$ SXpcQ0qiI Z|/5E913dy;N9%#>?3JwZپFq;Ņ~1Cܛ8/ÕXYQ&jHH GXMp6[WogBaTwD:32+S==q.hikFQ_RO UU qofɁ=ult$X iE:4$P[1o&3f2&aq*Ra " iYs&14םm>הN%3h$G55ZVQ$@*hvh%*+.?+h_":p~R,r)+_mji/*g&2ulu`*"g"xe狯I$v ;N T?k϶HИKov q5ӧÕ JHJpA$!RԣT;@l01-]K׌ 6,BСS:5 mekmQ#]=kh2*k/q*fRG(2 n* S8JBИ$|?=Oc'""'3kPڃNjJE Jו9Jپt]26KCIHiʵږXt ?aoޘYC'3vԶ\H($AЕpXyjSl&HköO p,`@qNn.T4d˞+K <2ea H]kWT9qQNa+uDԶ!1:-oAbׄ  }#YT[c#Eo NifFqq~z"d0J9IF[ͶT4(m Kq>w^񌢖QUM(pHl*/a5UHK!FT2Kd21"x!I9s@X4Jh/2$p_^Aba,AqЌinA 9 ?n4c~goŒT\\[u޵'zٽ\O(KlͯLl vtLl: Piijk2.!i)hԴ!BS;)3\R-+v˩ b܍kxfb%3R!pq. ԣ+@ש,]+%n-KjIVmj7ڿwl_;uo ”l #H) ZJƦ6^/ ϛKzX; 33b̪C'xkuTQeLW:kN8):J$"b-b\qwQMUg94TA}H HSFom6U^Lb<shI+-7fP4Q@QiDO;Ϫ4 ۽q 8v`~9B*c@Җ2^ރ\Άls)o?IٰםӮj mD&| {@Ÿ e ,Bu[eLڌvoߗ[eڑ,]ip.SSx$y|-{.K[X\JР?iЍmվ'8g˓p+É"  ̸t"hI$J~v DSeZJz>?HpEIWgR`r(=:u NO¬!e•Rxq!Oj`_y)[uɮw"eHԂL4{%9PTNPA*kar(?ctK "قJf-HrPxc='Q{ XEOPe Jka7n."_.Ř f*B*RJslVOn0uN FzAu:]DDN>eW26i铮4nRM<>%q.L=~ E&!+aiI*RW:Wwy%^r\/sЯ%v!~tΐkZi(a-]4.c40̣"C0̩kQiA]lGpumq0𐗪dQ.%Uf)耥(*!: 7zf009<UmTJJg[qO=f'cb(RuԎV{!R= TT2O6^iWeLmԥtٖiSRf.S͸(J;)p`}ĶP GH#ދ[}_{b%EqCwa!]l;Rz`&{zf8'LG^i[mZ=0D8%`&/&q{~ q7xo?ҵ튺> +SeӎeL[3o‚&cxB$p&Z_h^!bߙ{" }_ >-*$K8QL`c%jH$IOO'mV>V E)K<&˯ -)I9PIm͡N.yvާL$:RB%T.4RRVr s-@Ur ɛ5 TmJEl,v-Ot$Fqzacoʢdc)Cɘ!kJ2Nh&: ž0/wWnnTsTd@r a-K)=( jv{)^JE5r9 ĜB&e- *-92ys)D@:j_JO x x!/Ƭ^bw+#n4[3U Vԡ[n6 RS#\ (d@ 8tY̘Y',28b.<(c]#ac.|*qk+NeJu"&^W2y\ ,9Dr!SO8+Q-QwŏRȩL62ϙJ؂H*K.')x M>DlyK1Syl?t %"!@®篾stl!+XwO3 $M%k ZD[RN3GEE75{6>F*g!ĹZUİH* ҩ^P~R֤ka(MIks_M~kBkiwY I{;bf:R$md}mNp:JfH:fl[1MS̴gJ-U xcSP9_mg[A~?=GfHaG=!RowPD#m RkiL^S )PZo]vҾZrJ^৻MvlRR!N4}HOOGXrC +ˠPq!8)Yٺ.ŋ}_B )-B%  hAw)(Ek.S'Hqz1[c*VJI$ ё sXq] |CF] u>!¯Qu1s8,8/aPtV \q\h"̹{qq$*mb5k) o&y ;I(t-ɩ[TH]M}zF DG]ż<u_fʪ,1 ^WT Dd<[-.ey/ȝEIgPNCp&* nmR(jBp|vm(BpWQPz| o7qd/L$@$)cbIPZtw flf Fxg=?K5?ɯ' lZŔ AA lG*sCb Mzmf+]pFbk"NbfB*Fӭ)/qo n߫?kl2V"- ?~De+f +OLVOR]mˮ!./:hRK~tg9}6aH FL)*zخT90dr̹T"PmD## sn<$ qj|㴘 DlȔmU0Z@R3PrQ \#V( I f٭67J_y#$0Wzn'1HDSϻ;ZhE)#=5g)z-P>8LhqBD^ll}N'VcS%cI!*Z[3$?^c ^CophDsPGJ%Ķœx%)҂5vοs٩bҨDuߖp:O هQ !T$ҦҙuIM-nmI¡Vu%BJDOu#ͪu Km2 ]0pqwPڛp.% *w)[JVHqqRԀMv)W+¢ i^S2 >@[C6A_e: 2&KZT)Is 4)&bv"1y0L*[~u. #ZijuvrfJ!n^$O\]Unj8TV9MMTunQ]PpԥJ%IIZRJT;cEʊj~uBV{МSP`A: m$‚r疚&k^k_ؼL\eU|CC#iΡZP$U<˩ߣ[&ẘ &O Tl"ԗRR(ƀҽl;**))Ĝ>ÏL&Pb J`؛I7+Z`BDF%@=犦E◭F+뿉] NgeFi4jQymK"W 5 ٢Q);aW{I۷"L`^ŀ,HiK[ΙUҲԩL:҂{tY}eH<A$ƢtFkz<*´Iq$V5aցv`ϒC,-!-WFP;ӥp=lX%@u{hR ң_H](G/;]x:ң1]Bj^HZje!_u&$ X3:ڇ(i3L-H$kM/38RԊNcUI ye]Ϲ׏o4 ҺPa: NP*X$$jvr6Cs%ɢ._0F!WCK_4HA(`t[=Ẕg]DjӫOلA>UZҳҸX w7|l}q +^<> IQSM6?mg.((6'!CF!~E--B):6;AO`8̣ST" *BDOof[kCZ50N_f)&$Ɍ>VIiZHt: qCtq&uJ2LU~~&ՄEO`KJx4M+@sP~@aT%N;.v.ZHu"DP 6Ҕbn}Ie횵 ڊlĹQPr].6 $\OzcNXkD;s_˫HO+ݷn.KKhҙvڛf'Qwn4ixxQTz"KI)匪R] JWoy->!I#I0Aaq SyuK#f鏵#h! j+hkTb6'bF9M])!jMwAH4 קO y :3+}KB@eCgeX( ٠@~[F(B>V`]h FJ6N v",Ě TRtIAJrSRH( |Vת TR2$zx\ujYTI'myl P/;&pTJZ:s8IN[j{ ckc2WР +vkcOy}sҰZ QśZp_]G)0ZxQ {#-WѲլGsev ƇBcoF kN}햣f S6Ur;l9bMݯ ^72^ߖP)TCr' )֔iH;>2NjP\i1$`$W2&c#QVdy}~8jЅ}y'X?mmcB vvX c;w*אZ1:Y~UֿѩJ*З7 " |O+5*{JT[ 9% !+N~ѥm/x"<n:+3 RL$.gu5Ri um4ڜqj! J&PP̈́2nd+0!.y.ԅRQُ)rJ y>j4>`!(ISK*$60 ŇiT8; kMŠq9r<|dt|bY6_Ӕ :(ȱR;'aDSs@]h H:v|H M܄ ϯ92s")Vr#M×fIJ@4IA^װ\>O0͊ԶChmrR~Ϻn|4t]l! KP#h~S Da~J\z)yNDͭC-H.e$Tu *]n~8N em$zX2 +~ռYSVj+i㒹SJKԤPOI]yCvjJAҒ)Q"$f"HĹ޺y1L${kb\mJQ SHU NDk#UBLIpQM(00r~.$4^ KmOI$#˖%jijP4XMqgǹS4@@])O9\ +^sUXpG}ŒmrGx0IS1jovVoD$% hsB/o+|wxe ׆aɰi+b [ŷ*A@V`Hkn,[Ty{\$rڡ*r4yd%.& A3(Ԧ/:P-GMG <˪n*Lպ4$RƧTe qwPm[V_!a0'i0q+FDL!Z?1eLvI!oTe -{"Њ*ܟWZKLO[@?ש''|[Lꚬ+jt~Zsz*pm=ZkRu2iMJj + I<⥞)Ҙ 3%#SXDi ^Z~=)gRU弰 r''o,$JаڂB E:ٛT\VH޵!^zSQV͍ૐ\;5G0rvК [8_U<4 j -V  FGUl3 .N$6+ ޛDrU&J]D:WEO[P*[G,516.%!j@LhQPJSܢWZκe\1G&USZ)O8]U^nMC:a:B$R ~x\(^%[x/4ɩ[)ae*@y|>>\*qjFvFb=l_0+ΙP-q }O ôERenUQ)DLoÆ3 PBLnI9Ir${A#Omwҟ0~f*_]əC\˓3_+2jեI)H:SSgJyeMe0Gh8ڪAj-m3$mC 1QrХS)K`0P ;_*I{P T 7'Q4K`Mv{uggZī%ډ\̽ڭ̹P0$C]G@ORj_mnAHcbw fsGNxG^=O}|TYsHW܅W ,tWu75(+O@?V[,[:kSX8uU?/tc{e'UxRޝմIH & U =͚i$sc)_)~>^I\#bꔇӺV^ve]h%jӕ"8|_\8%jGq_5-^qR8H+P*5;r4 ?qgY0*mx󍇌jXZπoe$C5[V֎ >HU71{=:}ILGOpǢw1[e޾ _MK*)`PSF5 w[|!g3>",1 w4êr:!S 8? [gﴞ,O T%%$DL%"bqQ7yZWa=bbBB(akIII˪)k0qYQa-hdT1* O8kFK@1s^9;n0\9ߌHE79id>,v(tpї&&HoqeA\LKa<79j ;$UHbnUZmmH8yx['g*a'R6nSWb"n{Tv(QPZ?pAz$JDocA/=0eiXIdmPS.9QNYHlӔ)+P r@ H0>"p;CIeӏ^c2Z7R Z  KD;Rf %*A}uMXqŬptC2RvY"Bt Ko)`֫'Rw)& -mzEKrꚱhcIQ)#t ƥl9J-P<1kbnjЯYfY*sOS+>&vv+hx&FbJTlD,5#2H#tdrP:tX}˜A˱3EaȆ'XgT^8 CJLT0ث762ΖHP/(z |772qRTFm:u_<!%Dnޔ`GGjo}rtT{P#)+p.6ވ70>;7y(P)3Y:ɥW)߿Ix0716}޽R{(}N*)7QOJ 5}}~W*$%)Z) &T4iE6eʥ!0R [n{~1LЙypĜp|Vی7ô2x_^ AR.YyqgWT*a~j}tdQi-\23eAbw>!dȧ17:`4g7]ATG.qL.R,0i,'(n 5||b5ħeX}5LL -zbZT!(r[ 9Z~IU2bdې]&ˮߖ"J} 87 .f%/Ji2T1אRJ@$V/X;{!/t‰^rj)\D( V%$)n%0;z({,t -IB΢$-(E;E:[oH;|r"\[ ..]3֣e(}d"M{kELvJT7N0 `\ Kdi_?|0*E*IqJj)J`-DD|m+/CJrJ!4+%jʭ|SQ!2Њ~uIU̟MaRJO];lYBU 2eE|=ۦB#h\w|E዇l1贷!LdcmND\Z5:li0`17anRo≻R tl+OLg-6X$T+Ryٌm4,L$Koˉm@!  A:F<;zBa]crpu {a?*RTX|%dĐA[,)fV55LTAWjZWew~cj.q ͝!k*r%$_ s}*,5zw![60wǫ4=vBRCm6N#}a9Wa_~_Y^H1搩~kw-h+RqATh6O%ܺ˼8"a mzIyY.G^8)9-.`ՔP$SjُoKD (RL)I*.`awm;[9= *c@H$܆~,"=.& 5/K}qg{s N̿%R xVS:uFXIk7dMXҦ%JuJ-5j\q\W]ܫ:39n{ ܕauB{/9rҙ.euh=hM?f JJ .!d: d LH#X*U=0Wp8O~c2I^vM/RԥDCVt ڧg4T^Hg0;ZiKZN- vwҺSN %d`gh gv(4`J`LKs xƥ .'u%@E DKy:4P A*{1"b>)^iqZԅEƯ*=t 8A6b1/ b U%9,<SZuϪŖ蕤D)AU唊+Pk*m j`Ҡ?t ʼn'8NS<5%JAMϏ?b7!HnI%&H_)_ôÁ*L@Rs 齡蘭0:6)]+Lxi['m{ P i) Phz8׳KPчh.)e0s* )OAM.c8\\j &NG zuyi>JVˬɭR_=:z;B3TQf!~6qrUg ôVWvTt6YiiڔN V ;:HH&. Li늇M (H[J2yE;wOIp&(1 .ĬT+̛sW>R}~ )5&)3'MKX+sOVfZOV%p+HZ00ҵ hTQ3-G;EtV@t)Y9tj.O>R[w\rni&_xó$:,Q/et?է~Jγn+f֧қf4CϝHOfaA *i芇ŝAD/;e> m,%p} Y-"*Cl^)?3 ?.lDBCCz~a.(LҺmMIS ڇlq!?^}D4<|2g2!IbU@qPe+vEtZ[D>QQ~f\Z^%k?#XY'OK_r@.iC:zbXd096FWNM1@b:։&.Ғyښi~ds.\bn̖*-.) ;'2Jttu Nw)٠)$阍yl[`8#m̥l0-w k}A4h/V__uN POpn7Tо.=I8DRƫ$U^z 9[ JH]ZIP<;ax3x90z^X댺 %4"><{=BdN^UHYvCP) th-ܝj֪Vj}BdPwQZBun |h o0IR?e!#\G$~ݔд*#cmR$AҵCz7/\&Q7f!3gdв(vh,桜ͧLE5&VC^ji )iLIOQ-أvhRΥ).t:d󽰄Hez(xRzvj=S8#c,. ٻDpH?$0R(D a/:)JFi ia%b9[A9; ukCme9J(dQK@ 7q\f;V*Y@CYJwydM\qO!V S ¨FNQA@v4j@!I@w^ZtQ<^\Yqӆ Df)}l2W Ƈh;{^HW|anEESj7t$/(= !5"ɳ<&uqWRu M *EE3y&ܫ)DߣtnvL̉;N+sJ^([O5Bh}Of'2Fl7Qm6/}ڒޛsg~DC]e̅n)tу/{ьsDewh&$=W[ FVH҇gemWUҺENnXwR\&Iβ48˨'jX%+hч@r"?hG/ vipM9KJ¼%+$,SM4k8WLb&g *ZRI>_=nr7fQMBqTBœG@OeD;Թ(eI.Xr}1k{o<JXa:A 3 :xjJ IaP(Klb;yn[ hy;!l:fJt v|4lRV OF9bUR!`&BBs)Of@"(Ц[a(*I$|c yj!Jh% - 54MvBcxu[qd*5R+Pw>-n7r^K7fKv$O B_3RW: oˢ5|.,Ιze#y[O);#Qx.˪j*^2ڧmK_T)iCwT'/>8m֔q@%#uoVDc!E.뢩]wKka ] ߼'ȝiʓ<] 01T,q0JW B] e&lEg|W9tB#fI'ܾWQ*)vڂ$E>cTVd#(Is2[5 esKkRʊ~ be ru8@:b 4%tF@:HI %ה[OP<nQ:p{.> Ε4Y_ R4Z=zuϭrhilVR:PЭ$ @. 1@@ڕoeiSNJ2JV^Xy-4-U;kgp3n{u㞖6M4IOԓIdeHQHOq&4J:R4_.HIKO+9d}+Ϟpz0^s;M]@ȦJe䂄u 2> ^mKBB$jkg=gcJj $Gk-D2vWg_&#.9SM[]&WEI.555UeB@v.oHN)cc!ZJ2 &t*']= M@ )P;n| +3ƣ;RC:CPP6Otp︉l*d-k3D:>%:ԑFfvL 2}joDKh`|AS_Se.fT͸zJn)7gD`3K̩P} Dݹ5wX:ꆓ´I! JSQBM5ս)H@JB2#(MН?+ymTP)nEmZZ*yڗHp*P7:Hry~7ʡwA`?,a\;Q$Sf}iF׶)ZX֎VrϧD(A)r[ ) փ>[,6IҨ G{9-fρVO:^[bFHf'q1+"Ys~Tr.NZv>_=KKK D˔!OҡAV]MyZuPI[xٷ x;%TR z A#OWlҖ#}CL v鈃͔}+}jGߧBu>ATxt5НHNm*]hi N*0I 3UPeAZIBt7, 0J ́[Z/\f.h£X3 qYRVb/I*$U(@%jUT JtvY~/;'7"AaN ]݆Yݒq ^6_qn1٦AT)3ST4JRH?,<#]Tt61MΠ7ߧN-08i>o3nB"l!5Mtk18U2é|JD^ ̠"ZaQQۤ)$Zଞu/qy1}q wa\ݠRº(ڍCC1"G WMy[豗eqUBcنTڞ|*TNVH$Xݮje mr$+:Ğ8RbN̮WfP!.0ؕΊ2ȩIcSmΤ5fb$ߧc]f $8 WbU@At*oHHNsHָ^(#㤭+VY;W__(M_%}UiL؈pEMC ӐCBP)`)ħưf#dۏ8(}]mK[)5wfX1)b"a\ OkL5jf։7{.ros nC(RPJB@ulSx(OYņo"ԇ!#ED E[W~vPU]jLP4K*J]qeE a#LbGN9҃˝C9)! IYQFr&m.)JT*C5-&x@D]nbc2R[ ΖlF2B\e;>jQ6H #tt ۗNWGvn.w{4cpWzO֢"XmeJ qf) ^M kJ%K,!HX lGc_c6kk )$FǧYϘ3G:B1S:L-aJKKj"m  &i^3.s l LZR1HJR 3fOm6%pa /{xD+# . -'C&-B]A mhԬ26,bԪV!_)SA-ѳ2̏1WfN乻yu&"M*JAK! xku.Tж8JUZH0\i]ޗc/)eŐHJR ~--[B q֔t(8ӝ #c<” RPA@_OX 6bR ᵻ?(8w$s,)b64q QACjd${bg&2 IT;Oľ@ީtTҹڣjSqis:Su!`1EtTC5 ^<Ƒ".s'8T O𑜪ʝc55'^ˢ󽁋C m U3$"p~jybmĜ@M.J|ť]ByN@Vy|l˫|lQ<3]H[R؈N+( 3 q4݈Ic*e3y1|K92}iChe(TJ-TSS]-6oO:ɗ|G \9;zE1!Ӓ- P AJP0nO'Sfs[MT{Tt+C5íR$x$aʖYmƩ^+JpG0Rm=i8!{VXW?w\^dKo[+iǡK)kWxVKS.bO,q"v24LZ]GdP(RPY{$vGKk)JHU9r` EPTTr+>uُ^׋k+3>$kmӎk|И Ν0J` 儸@P֚mcHGN&funĶ?.qL12ĠtJ[ںNg*l2Mŝ&Pg-MO&% ͖KFt ZĔTft4vwP_/S<A<Ǚ:~e1w~a8KQu$ם}}U&KSƼf%r5:C"qvŇ5m>X2yV(VkZڻYVR[eKhAcJIQ$[NƉL,)"{܆@99އĶ7v]ChcK Vg^Bm I;%uw.5WZ\U䅙8yj8D6UPt7(q.̯ujfvU=zc)LpL!4ʄ-:NJ-z8W6yd*h cmդhVtM,4V{8S/@HRUnW )qO^^X^Ψ JTj*~}[|6b ߘAuqBikC#R*H*:tק;]UlluZg3 iTM #hb/q5kH'sF.I^H$>n ץk'ء/xa'.G=u} Z38j3$y&*P:4\S#P54XYF$j9/*{u:u奬\L9e!(/Ѿiu X/y´V]Y1+Wqb#^;5uJv!ŹU8ETTHkq+Q!QwxVNDK"5JuȆi@ #å@ Rr^y\{*+,#̨R.Tė2Ь)4_$Ź ;ü L[~9|5MU!:}m7ļB%S(%*_yAFL&I&Mr~iB>?9!ظxȘ7_E?{U-]MvbϿ ! K*FDFXhۊLeb+mȗ 6=Q ,Qw}om5.띂 1L1iZu-* Z6צ'^nt)>ZV $ZrzF=v'QL8Pa#)"[]HU$9?3q`*xZM֚VβꔮΞ6d*ኵ㈥rTwCDzźrM4Аe)!ď9+pדpz\ͦIB-1@)Ҫ[QkeȨɄ|Kp~%Դ4$)Ťi$\<^`mifC Ҁ:ihw#^K2[b[xA)44|;AI'Jhv++ah qm:L~}2ggX:)BIHyy_иwS#h.M[n , UQ ּ*iY0' /9yerO$Pڳs)f,q]*{Wr "zQ6O`b1ҔlѭiҖYx/sn271q1sιBMɷ1V;.8 [2 ,]f&hLF!+aoA`wjRk]jj:(d(ZjS}FCn;8"SLVƫz1:M)ou˜L ԡl@YKnQNC!a)mTe>?ZR6P sեm)ө-`k~B[dJH:u[v7" *Oz$3wT+P$Q܂?:i?j c>y\ي`O?;TIT_Zlm'rI*vi@@ӃB*XZm3y ,)0A'KLo|T&PqB“ڶ@RAFՍ9_\\k;c_/Σ\ S-)J\ UJ!=ԧ@(x_*yԡQX}0m!D$=:V7&kБQۮ4a.s:4\D*S.n/ybx zx]m"]ʫ*Ar&=MCM )J`u㆞\WuLX^D䆼(v&Y+5IM:cF`x{1> u1QyTỌ ijZְ:ZxS㫂^pc dO%b_8$gdܞo0!@ uJE54<(sW٦BKmOر)IsQ:0{r4ܐ 8TH.~)=~ 釆\[М݇Ê1au"SJY鹴?ˆ~%K$c TTXj9 ZXX$3QUM-Ֆqo WKqI;8j]BQwf:(V ƪ;5[f/.^Hkq[PR!! 0i%4JxY^5ѿ Fd'Dp%A*v:"%WRJI)(U$my8JaIQd0H>:+1YD**߹}lI^uԏ4Z@E ruTT-'a)W7XN6L*6yI<|B4R!R4؁MX'/b^3̯]r/$2f17]*-dԄåҰKC9QM~ZpOcFSxm"߉mFS` :MlK'RxZ_ihp-AKHZVwP#q[(k0H4! 7f᧦5M4RVBd@x|<5yLJZHF@2? X|0L%pV! ࢀU񭆠қ>K\ hh !vn*I}Ϫf jSOZToI~[DT?;4ꪜ MA"'Dyql~W׮&Pz̔?; ht9BUu5B=_efBURsTiaI{sq8N%]|n۾羧TWP!) ~ѲYƌ>)= -54?3޶8Nf֢ZmfL^)'C'O~ǂK~NAXGWZНj;Ow!6*;yTG~Yhy#hZJԨKirmv,qXGK@?%l5&v6İ!䤖})/&n-\@RB[R+eKpҀWo\+@ӻ]M9}if'V:aPM@RFN$Ψ]o/ i*8Z#H$&Μ!$ `}~\cӨu).kn!iP hP$liTw.i<~އ H §1F>%,A $!$ :Jy/͸Q-%HV4Ђ)dW8'vs1ی<)F SSYWXN]AIP}h+iC)dƘsT v&oHt4Lb\LR}h-'P!KhH@?keJaұӉy(2IJTaq7sMN' Ǐ";FsE|BFkSU"ص/DTD$< ?/L4> |'ח=L%A&TOD=||p4i[@1]΃}נsdo#@~8'*?<~yማKInY (B kZ;]z>Ee5 s,ewx|զE2* j.%os>Ըup X[ VE" =6&cj{D@H:t )gZgái[ũ(WN~~6* >^z{M&qq$k˞\ϒ^j;) )D&L7WS0L`!D+D <98li`_Xx,Ieе:GuA*QJC\=h3r+ʵ8[ ҥ9ߕ,]l.2.@=@q>қu?juz՚Gsz?jS,H.^}r%$[2 cٮuN Sys!-W%NT(쓴asvaĢʆДt5 ic}6iSn*imJ{ZP%BUCv M;EoN>c=UI;J٬$y,n_lN*r_j[T:eO2$s%$` h8%/;וFSlbe#|Qv&Q /gM7 lN5̵id =%.$4R\׍h|Z0fZ6MRd@Wui/׭ "zk1_l༴7<x=1JG?PK&>!01 ˮSO{\S[Pe{Zkk'LJr[E|kumMڕ˾uʴGȔ3 ç_ioZh+($8'c׊ҥ49[5#_hM$yہ:ui_4@AFb9ӱ#=^=fQ v5 BR+Ʒ#n$q?SKSjSE (4!?PxY%D+d.]Nj]zRxf 1LG6̺Ԅ-ז+Z F7G RC)D }0H܄`-O_GƟ((2|i9$64 7.᧐KT<[[4Ne)Z(<8ytFINeB*ihY&Yq7YWy r3L;!d/v# {?pah /1\]}yMeyfRe9t[md d@@$A[NEpwQ3]J#8 ٥.%mIY6qMHEj $,GREKr\&]LUS'n!C:-Z1J'Jt6oXxPy3(:Ap89 *ie72 Ş!d-80UԘN÷G -8r- fn?8ɪRM 5ҷ>wUĭaҤ J.)`Ln1kfK*QyħTpw)$1@{?eN ť#.Bҩ-^jn1 xk5#?q^j$n:Mڄ9O˞d{3Rs6wpSfѹ q<ͥHzWVJԓo\pWP+ pqLy٧f 9{J+13nY7*τ- %F VuZǵ5oCCYYFcJdumͥI-J@D#-\"/ VYL}cT,塧}} J Y) . )TVk6UTemeP`+a0pѐ1-B#3O6B&"%it!A+r ZPRRaIN/JHBJ%Q M-АYխZZT<&.&0~C" ^@)͖Mh(6{I )NT[?pWPxq#/ 1tnңCF-#7pߞ[Sh/\(Db%YKia*I<-u/ԕU+*6STJs To`(!В"ŕy-FkJS-m :'LX:BUVRu!{֖ j5ȣ]Λ?OkB:P7!TJwVfQp J~yr,<Xۘp_gi!WI3piuAm#ajR~c*2¨[mP3ffXDsUJ띿}?VA^z TM7~D@@<܉i prԟh&/ -mNNo٦ [K`X"b-|OpN{GOTJԪ9K~{R.$M"ӭ؃$Hsj57z:ٻT*1OB"+hJwtҾnJBOhmiƖ{6üA?#4{(g%ȁڼV8qc[/pZoH)A 4M6x8tDxFUD RAһlk)/1]̿:*2}eM5;@AF~ߛÇ+t}ħ/ ɉ!5 3-Kp$Ҡ$o0n9Ҕ KK0vɉCԭXPBQ\kjhOjUD P4{R<\RL-$Uͣ enV͡(djB@l'c\A/Plrs+FNy>?^>/Kqq;q_J{BkOCbO7%(m:okzakJSPW}AqyK  %f |38+`MH?q˩oNVvy]BUEQKklmDxvlF$Ї( ̍#m9u}gחnt* +mhRA+t"34IKzЦHH"Sz,f!+BMw>t/Y̥)Ti4ԖАg$$ĞVwd!!Ir>ޅ,zy* 'oMl q\c '0v:c]?$ٷ\-|Pi@iuKFAQ6Mc-"<_q>w;Wڢ,%+k"ƨ@kNS7roNA)]GKh !.N >iM_EN+Y_, /uҜChC4RPB'[8m>)p[]ٖ]yvC=LUE*yEJ8T)=)XyQ.MjZy}ԨԬ<}=xě:ˏqof>,b%vp<ݱ'BҦѹUJZQErJU3@59[Cqw>fdߛ)2,}RWMO+W80o%M3 -eS$ {$ uh 6$ۼ G+|1O/(Ƌw»WCwtλrv=Q am %n-IQY[Ï/ddIݍu,~br J-GдTlQ7H;(JkCi*V|Eը4B@h7zxK`6q!|Wfu#n)5Js f~Tqu39t^AEZq$֩ ~CNpN2Cp%ۍUZmمHWJiZu,QI-XF<.,bTP|泘c}v.+..Ryt@ $'!I&BJB`EcxX@1 hWh9WKΦ *ґ)J*U*v#PSAAJNU Q JH#[J!24ӂ%7)aC)klElkv%Q> 9H"ևC%/\z {5!6\?Sҕat)f3wG] _M;Qs`Z;k- R8nj(qLIA1f#>d q[-ˈ12,A{;e?BwO@+,)<(-E4-Bs;{fFb}T-RTI&JКKO>2Kc (]xZU׍> D$m^^Rrl)}b*ڥ$RH$zUfB`$`AXszGQDCA$8)ȈM#(Q=<6x+ mhɆ)5ކSXMߓ6۰yu$C@Bbf̨t5/JzshU8] $SkLAa?G;D< Źaw!-Lf.G)%tdQD B?}6(qMJT .,=U(,S~ :=-HH#XŌF3̧CS9kTA-qLBXxc_y8r!VUR'=j{Z <*l::Rږ*I4 =CbQz z-`1Mێb D"(1tt,5XI5+ôԎ4T wIÙR} 2Jb-6M \-,UO0yNLqD$xJ™t5]uTSJMiZ᧗Np` $aP1+u!CaO6HҾp2x(f0[Xv@̭UZ]yߠ+yHcPC~c1LҕRN,OAD_iu?ӧj􎸟C0 ,>`?VeJfGfT6C [k #(ڕ * ֥ r#-L_ C@$֤_{i*V>KrZ0K,7 bni&r&?h5I v@X+sGA /iVçf̮>#N@m *yfUКxTM,]՞`$Tفϴ?@٣ &GS@tжYe6px0ytm9XW@?_<q)'^W _rW؟+Rf#4?l'p)I>i_B!%IRmBۧ\'mkQ˯(|M#;A$&HshTP=VbR TiA5t-R|yW9i J}??-)RBmԻkZ̉T$^Ng6v)9EWNs;vqpT:m%HJ̭ijƜS"\ҦW”%Y}P^DwTv'b,nysPsu9iԂMRk@j)l+4+(z[,6iB`x$I Rv cRZ*rH+M#߻~fO^yKoLgqDHP*VTQQ0ڎڠuep{h97|(V'mK&%@F5mV>!4ɪS)JGb@&R[0=Be5BeG0DI2(xt)eu!5H/m[{̵F\#y(PO+>lp;qԷ2ye)RT]S]@ZUV]YK0݃ ,vR@yY7T'7CTTu0))gTll?Yv#l6.#LHkìI 4)~ݬcm8Y9rșqrI@RBAs.[I!ۅa[H l@H>)tu/~S3j2 0)X}i)"[TPvMִw+ $DmH+%giIR=)c7jc㝓O)܈ *$КLT8:DG=yRқJBHh[uRZ9[F]YU{ΕR BCGjZ)Yʟy-wPvS`HRƦOC(aŦP*,#[Ў -A94'OjRPi˥pyD }롷z'WǛj#_;!9I+W}<0n9k8kT2G@'q7tιV*NHgU9**DdJ~],|2W0e=3 9Z馿Sy^*eLeT̩BI8+_NRs!:gcᵀ“{.TL[ei <ȟM3)G4l2ФBJIo^D.wI/KE h-$ ^D,ЕSO;hy^Z{U*nRF]_^%ՇKj\ !D ű\wrʽ([Jp0 > VVօ(kTN̰9@RI^RkmcدwXT =l2Bk@)ZsueqN]uAUo(%!&mM+ҚڧYAR)2|eJƤ@UI;LhyGe 5lmOM|5* BH*ϔ u!I:G$*9q\ b&Xi%W^viZB }DʐIh' ¦B& |5^"Ef SMG+E8p¿at);%I W0_)~Q\7C9#Z`˙BC9nA4 MGCP PF=<#&*7EV_iV'LRTf .Kg2mfm6/+CJtbgcn^Ea4ByIHHP#cAΞ"[k26#a^1X{PE4pJRR3ejH?jZK-i !#Z7:ZYCj{1P%LѢf?yGB~V4W455]$HLt-輸k4jtD;%%Hu%+SkݢMtA٬幼.b1T(F4 fа8x|d:bacRR;:֊kJu@|01}֘R!$Ē2vZmfQ\EFqBTt A |e8_}rtgY(fo9$ěC=-\zp6Pk:y *W$D(*rEzSom_xtWq9H*OCCڮ^@%ZRLd,AlZw4׽P>K*YT~X~qs_23 yn\qȇRAY'Fl) %U zyJ+* 檳dPʛTm=RhAQ*Uh_N^;CzQ)( 6Q&%ŮJO\6ɻ -VT!&*:SMhz{MîGD!m!D J(bv1m90qǛpe L;RZ]K܇i |SMN~`ZCrںҗ7E) )31rDL_8qzJ8em78QGCzd9U6Bߍ)`qK륇wp/>%xGy0lRZ&<:ڷGh"@-υGf8ntUT{1զ0H9FUW>]ye,nT$%%$IT$LܱmJsU"<肼Reꩌ ) }r?{j޶]@OdCt@%hZJeA H:Z&RZy]- %hPqFcP n9kvMdj_hfE9jKwRJJ@P '#C/KZALߥo~GI?dyj?;VAnfH-Cºsk;ĥ!rgEfmZ/q4CZkO,ᄑr6 W3UM}&a,HBD-J:Ws؅Cv09JݚvmfUZCHIBG{Ʋ8 3v=H#\cQG>a|?K枫{5'!Hza1QL:*H exh2쏉*o0o6nkJT(*tlI9Fj5Fq21YpՇ>-ݷvG )1IdT1pQ]zD{I./.Dg+5, ľ^\)JY)EHrf_2|{ ŷ$-2Hv)V_J" ($[GoT~Jf2dt/gPf˙HŠ*[(-RTT]Z_1or|֪K (I:U1 smVJBJi+@ó8 qU.h(3!* )^[ Gj$Pyvz ;Z~zH9қw!a M׍zKZ!V{P } % *I%חw/gٯW23YiCbKGtԕ qk&jv"bO\RHIwӯ$$᧸.>`tkO߉N:a%0HHNy` T(vEwM)ZђŸJo-9Ԗ5Cj}!i !uk^T% v<[xDqvo^WTNELr 'f;'a4u N 33N< S~\EߩEJ{p@U0P|0(kVùrݪRG8GYmŴҐL5 HGlNuymAԡ AkotRnU$xV" u4ܝMsx!)áM@ ߶[Rȧl0VeХI1Huhg`}R" rMXC@@ԡ54J j콯WSymK^=l_>V`jJMFQҚYw=p"} ;2>챥kBO>YKq%԰V) B#b놛 z1m!EXS((RiB”rvNȯR[YHRրWޑ^ ɿW6ѷ J \L*I;vaTkkCuWg/-D%;IUjHOĭ˹EuK}Bӯ)m! }UU?)V-3uCRa*X&ngƗP_|6 | 02T_CJ*0a>dб_u1vnJׯzn&8n &_{ JڻЬ8L DlavN+NM:3 6 j ~]c%* VB{PH܂FβTRBR6D`\zs*ԭ@4AP̥<"(Fz8:"wXWu1TL6i%-]uEhAQMQoc8r|>Zp{Au *'КG\H*?t 6o$͖d>7'(NDRK|-D)HVҝSMּҜpzzYDrV 8Z 84Q45Zh+RVY {I gqn9`P֡ ߺR"dxp'ϱ99 \KŨRd;P(,xwjA77v_ "" K0ѪF!AEiǼއ0pE4OpB%2(1}$Q@ tĨ .v*%3\iJi*CJ)P<2<3e\w6Vr*G[ OnJ&Hketk8O1UUf9u-!S*5j61@jj{zW]tF[H&xoQ5H:+m4pWQQZu[+%:B\J@Yt@<%=IJ;A@7z S_56n]bEe<۟ו^Byo<) j>܏ t(lJ'1Q2v(\s^aAZlHzaVqҜB?[-ۋB=V5fuF'ci~Ч:*xt){+݇q,hP<{mw1ua[h;z@(@׮\{usnq6Џ[ p)ʨPF^zxמf*~&C%]M*z>^[@!FJ?}ܙV|v**mgdsן[o]m/Mכ*Cm}x%ѭ{м.p8;M﬑Ljv3`)}j)EFVmqAE7vRku,o_?eoIp@XRS6mZF[ʩTЭXo!3V  q7db"/,؈ ONza(#pbuvFG9$,,] zL@ bm=!,g(Z'edQR2ʖê'ZdH(Dmr63o2imL$[̌P&DƢ'ZTWZS5NG\JG2s$d:TRӽ)WSQGIHJP 4sM:Ҵ'!T?|):+ka7]i{iRnGis[!HVbxKcLt#=a9+J| vzpwQ2oĂBH) A$zrpO.=IUS%SF!Ԣhr*iŴo? |e2( 0`Eho^sjYaW|9psx8~Tm=(=1cJ͝Q -YM}38/Wu $f^B^vƒ)HړoY4|- x#8C*P*Y˥w^z$Q/n) ERRR PEy<2BÄ!\맍;d5HėEĉNͰNҒ{` ͠φ?2_G./a\:ؖ/lD*Tľ!C6¨4ez=Raek &qrvoC?kKH<_b3 `TOeYd; :'C0cs+nsj罖;Zc=G>ӎ'eZUРT dم-75HE+dOp>7 "a=֓@}pS>vv>6`oK)r IU(j[EFS+Rh=;3 C J@s} i:Yʔ6A>\Z%V8B{g;UvIX)Tf|l-:i dN( AttqS)%6*(BRBh@BIVÝ6ޏF;b!fsYer͓ +ƭɶ#Xi魣 =Wɻ=bJ$sffc#Z)ZRV 6 iKq݈؏B`8XtbؽX[ۈѰJ` 0D"oFV_`)P&CJ2dC۔­j*ꓱ:A [EGABFD&1߄y˩ mԒB((H5ߧ!ҧt0(Dt?KݏX%rg5Dc#R(Hnvƺ!N'U5< RP)D5ۧ?mimISdQZ UM=0մۂ$n \oMhIq]&7"fOLXmLFP\NUq@BER{R;AQ۱Rfh84\ԮKq]9@VlިVww{VGY_]kbsmd!u yhqǴmQx*#G=? l^.p] ],9 &l9 1QqA+m*j(O~50 bC&aTX!؇a!i%)JB@ n6gG^8q! M*Wc݉ŀJ:< ]xolC|q3XTN!YCe4LPl rk&me@AxA;²16Pu8jHZu#gu7؝ |\&HfufV]m T2E'ai[Zs";0weݙ]MN8aH/+wpHhi*%-I( '-:5PíKp4P[7ۗKy,蕴R4Zf.bMq ``O7Iہw_{ЎfP켁/{QPEȡ( NV0YNlMy3x}n"fˣBSq^~ #cs+) u6i ֠B)@HnҠR)RΛWλL &/?< -o4{qw-rt `b!b)[u*@)JIAK~f^aģ8Ŝ0 HN$즁0mF<#i6$ J ioӓPmiJԤҧΟн&k[|Č3'=NSOVTj)Zz]j>ғZJ )J\Us 6 fq&.#7 K '}Uk[>-f.+X+ HObJf(i%T! n`oc&N?/T%O(`\YY)O:Qf i/z.ӭ3t1&4"yqZ))_MCVf nH&%q{/&2oy>cV sf\S+уw?xf3Iﰨо+(+%JPҺ DbةkUZ-/xYw{f0~݂.$D H!;=wkKYVSEP*PC' J@qNCHNQb` }:)i Rk #\l)79EwrZJ>56Y¤Txm_4 Һ*wI'U.b}Af>[s#wJu(:}~y@ý%:m,Z%"odZ,:Rg*xnV\|tza}K)NKn?'*l m)?ĻPlή+\Í?/oFz^G 0|*NnZdKJ"!6o}Ɯ6ҳNcÚ t=[(!S_|E/ʇrLIh͓!>|uy*Sҟy^d(4kNkaD}ەW WIj \N9,1P̤%Vޓ7᥿2؉ӝ ӰyUq(ԨS-]c7xH+\dJR -a*vּm QT'ǖs o -ZB!_YP3R$d& :e)t)+\0T/pI/=`􃼊j4.GD4BJ} B(6mO*]1&Y T)Èג6%d-CfqV8ʐRip,GP +w #W8z]AH5ȡQHU6[I8]s/4`*B AQIA19O u*d.Uhtp^^2_+ō7:=.LBNU/)>%W)\In[ߖ!du΂ɽ9yN$)J{=AZ-7_v0s: `fPiySBEA:B,VFBE:/JJIFPhMW=)tm-I9R"! Y(o^A(ZZ{23iTuCI @$ȋ=&bJw2XH :/&|g☸ۍW9#6RPmfE1*~$P׆HC)T% V1y,Mg3x\LsaRD,ڕB+@9SjΚKAK(#حbM%hJB-|9UM%S(=U4Ofhz*Q#11J5hҶ*]xyx^I-EǐRT䀇JF`E :kg5@ EZu]ħyx^ܻw^$w (6Z tK^LĘ(H}ġ]Vv̰(uřBhw%Х7%Drc,a< JdL; GhƮ#e8=/N&Wn9i7jɜ!nرUR$[u3?3`? 7GoxdKՍ[!b&BR55[w%&#gx ȉr)e AP:,b a<5f0L.? ӽ-WCq$PǑIt:)ВI$u;JHºm ?XuaIHꞀZq?9YSQ v)})4ڊ:# i 0Z\@ I:J z6N!K:e)J 1}L1?hd,` eȸvhJeאu7[r!0Q]^tg5/xS0TZ"]D JMW[6RX#)HFD]j:}k8g7(b6$ ĎLeg"!]" ەbg~g/q~Xf"gOV*)IKQ!욑dEĹ1SaJo\MHQAt:[]|>Ɯ:\=ѭ<bi) I?eP5QK}9X)Js$ܛa34Ii1R5JC*s:G]tk+_OَlOձZ[M'@MEI^ͨFZ@D EY%GhT["9CW۔:x/{u-IUsvݷ&3 Qa<+G;,S7\={/d"!Xy*PRNvy׋9XMᇺW08>ٗˣ\HBXڄؐSa(٧BR{D;][L-&}9q*(xa Lbn,kn}a[u 4 4IAY+T bJ` ӄtE+bl88fБKP(/Ss} /S]\c  TWJTSQl5Mvv] #_퉳 yltcpw8BRr($SΖ} Wqg2-m:(-))YHJ*5;} ۽yaSxI\JJm%%is v޼7ϯyQ3c $Rj:mӨ}v1٥i$ZtEHLSx0aT)Z.,`ǏO.ʉln6\EFiA-J@SAkogPi0iy_\nU3])DbWJ]քkWe)4[m=m IpW&&0V[.!NB@@OY$*/VT?TiQkx7籗LaS'u3J{*ЭSWca]Po ~3MXQP)'L!AW2\ZZ[e^)e 9JQ&Ao^wA:*@c#Ϥ D~J +nDd[Фsmk{T}?A"8J$*tvJ\R I# S^^] Y?߮Dݪ㼙<Ϯ29JNPÅz!2Gƒ롴 $m(O;OB%PW֚h!~N=*~|m)t ҨSEY")):A *!"8mXm(BR~?UsH?Q.ęfY01=v Be#l Stք-%$`[7 h,1Ğ/_K W.l&^z.l-ft.*םkl{Gc ,2hq! ]ڻBJ 2diuU,H \4"cmƬOۄWN]듙[kLl%)yn{6rК*^@±DJMGTx0k+Ӌ#r5"@1( ^u!bpt P!qOO}Rg̪-jTU\ە\{Yt/P{fЄ)$Y3rQ P3զCǕ._\Zҿ>^~:mcArqkt%&Zonz$.D!#}ޖ<' w_ur H$ΊYHyi*BL%EQw̮0]x#`o 1@¢-h.RCLFŷE.w6Q)f)FzB(D }QO 68znf\$D<˨uPhڤn:RNř~1FDdT+D?2!Em"$o[0ȏ=1SPg䦊JPj椪L1nAKƃ+89ԵNMQa*T!t) [77ߗzX]s RlhHe)Hԝ)ԸU CǦ:ZL$n2DE #n!YJKFu.Tuy^8UӹJ!a:giP!Vm .(12J*fZRvNJ;O5xDxybG72c"e8" yȇX -e:(G[$ҼK+qۏwNTU2}6BPVh7+t0c5˽SK->T4Afup>RNS  2CUsy(%..Ae#QCK]{S*3vjݳ:)/8RfUy=fW-7@&La9(n.nnܷ&hy$)Q:+AT:0lsikr/ojlDNQo^V -m)Lؔd񟯑iit}h\Z.ka@}//51{RkB $i{+X&eT,gL-TTiMu5l׵PRҤEJHj[H<^ATI*QI i@5:xZTp? dU=WfP}Ŕ6V]XS ߮>#sQHյ Q+L>P0f6% 8]˒]0UbǫO+Gۄ%_)M:Bb('a3R 3݇t tp5%d{⸽ZO5g禿6V0TEP'/3q^^#: Hr5Tu׶k‡z5Ժk MO_+!s':q QyB\k)hA 9&jZVK@h,$pܫ{&Jd@lIYN3Faݛ(,^LL6 !k΁4kJI~\÷ yv3W[1Q {N%,)9@A/P(BeR+qײp$) ֕:Ecmwf\riOfYSN") 7TBѸ8*ٛY GĔ&;d%?uiJ T $D@ Z+TП?|:iUxS/m( hMU.(릚SK'_wciC*y{9Z)LqҢe,F %`Fu<6`Vѯ Ae- &%ە+åI.^ ^)Jn#N|A ^0/Qt wL.H&?*[,skèjȆ7Kesfs*5.@SC E@ta/9Fp:I~n3j)0[Qmݧ #8\fHU)(Z;[ p RB+]6[5j$Hkb2^-͢f+(/Zn4JZ(Fo㍛[BJU9 !ZW8W1Z4H: kGS<*4C'Sh-kzS0S+q?Mܖ(԰ys5 w\qpxlpRh0ԾsRu$mږ]'m[9UQoݹx~7 k̢aRiwjҚx Wވn.8E;c2ѓE]1d -4$iRQRh5) 5JCZ4QºYs&{ T,t. "! z&+ AJH5VuC#(s GߩUqg h$!E3q /ж!Ii=Dct,d;3uRJ)SnBq+A)'PE4R6I[](R2y[Y"p!!ۃ8ɤ(xms5zឋ.x_-ZˑpCPS%Yʧ() mk 7Veyj8}@bI&G *qQ⋺ 9RC5f;C(`Ԃ5\c,Y1fДœr""]ZBI˰-{\ۃ|W.[ /\KSXB"cccayȈҐTM -2aJl EI'Z}1̸0̪s/Vu6QT%KK!W* lZ\Yf D >?g}s*8+Q45IԎCO@=N:rqEkxrٴS`ALCh`\OćWl_ɯly 'rZVD%%fR{Q۞x<'~' ~ʕrI>@y7(~-o d6uxK{j-12 )Z GhFZ;[5Dgb$MOm P`y:|Z72S HX"qGDP#S/qԤ]Ң*ۀ :WuԈL`9};q=䟳Rd,;tc إ0vKRXeJ*16JI*K4 7zW@~ۭ8Y/5jDQqD:ҟ8BI#nGdba($ji´sR?-m>x$;T6ùkm]em_[F BgQ⤩ʐΥHdOS̡R߱]VW(+qkK=(IU: e-a9ZE-JE Y"L [SeJ2\R 7? UfnTXrTCJ G<"!UwOѺG_C! !\H8gr)HRҷH_}%&z Tmq1T4kQǐI ~׭ϝV`C&/nX8GB7|-\ٽq$a=Ȓf&A[f{u6d$VԻ l\FU-TY}P֒jTĈ6Wt'nB@E3Cm h,PkZo˙'®2rH,c5@07b[$eB U=l1ȳg)֊ ֲ[SQ N%DO2T5Ds gd%$KNTq EE#bZT[qG#ijO? tͺ [u1r8 ?c.~ۏf1,ԅµ]B(]JA@PnfoHFkF>uJDĺO@ZJ<:SUU5SJNWgYR κƽ== "hu%kuǔbF@>qWc09ƒ% m KRڴ(W.6[;B+8rѡh\*mJBT;$(R7=juX? xXvcm:|.p]RIS򼒑5 ͩ-V;e@ud:u;_R [:1sc2-Ȃ6k`q^uI{D̢v>Z_xUzh^SARR+Cʖp\B[QP |oǜ.¬- 0xK 74hZ,%b!au Zm6GއpyLFTSU5+2mԦ4Z:Gn&KیީbTTO 0\) D+sׯgLSP}5;ĐZB[QBU73{MϦO& CF+!hm.:A 0cPI'O鮿+".rC/RJSЩHERvf[hos;ɹ߯Gi^A$ONC{ᣜSЅ+|)c ڝ5f.uTkcni_?̯l5dbNCfoMsb̔ ,UQws æ07q$I)؃Mx,yó&p "M)v|^Rk^?tQqдjwa'48 Th]NIeӶ[e^q)G׷qXm٩LIjgO?p;iZzt]$>'_r^}m%&=j'bjӿOTKC2NŽ)Ho%&Im)\1!&H'mqt,ݬK\m *_hm!-DAhq}k>`z#ݚNcIz!p\Q'~|[b^؁O ~dd*̣Nj_/a,Oju"HBL&kSRR*$/cJضji/Nt~[Z?gqÈzxwtM-FIC0٧dAA9gI.Gxp향(Ts%m@=*@Z>Zl! JBe&Oy8LzlH>bck2>?l1M@4|A谭2 ڞtBJiL1J,$I@]6M+B fpP/6G@!Z(4^EP|kLqH#mccmuD<$ Få8AbHbXk њ]:LfP̮>vn4P XӲB)Akkw]YܭDIQʦ{""W6ڒSj@Sp8xl8w/ln2dO%XIT<y]y} ;ٺ!(Pҕ:8"%Ӝjs().=`+mgQ #)R5:H PQVFe*J<|?; 5)7:j@!+]5[/*U@(隽OS#ʜx it9wL+5WfiᨱTa@t$Ȑ`t<8 T8R)0$cŸH,! !JY#>P\'<1DO[#qGR:f.2tR% RNSP6#ils @O$1f5Z4 BI$-ڼ61~[T;VN@ rmnCXӍ($[L10gl~X'_j Bu'_>Sye"NO?})ӆk"(`!2؋%e/ قm AZ[I yBERA m, LHKbCA*"X s.kQܸ ^OIܧ&W)'񹙀X;$!%hAR5؋9`RH[E;[irY!eKgd ۽Z %4\,4oͮ d~aϺ IӵT#M8Li 8- v8%(A*PJJ@>]6"O׮´'UaBVR b2O+akhl{ *Ul:rn-ծIТQYE |;qL2(u5Zʔ% *)&[[+ II FR9oktz/,ݢKOU3)rB(РTSȉL鎄?gHLj'\8tPƆ݈:J)r'1>O @,@^?!奿]y({2꤃Kv]-̣R).|<[&5YO6PHCi I;.C@֮\n` r rVk5n3qo88I8HYdp ȉ+{ )尷}uI(Rj9К|m_*q?8%$J-F2ACJhAr4̣QJU9&l^p69Ѝm%-qr@[|q7 s$q0tpS.{+[ '-/!2(,AӞ靅6$]M i߉-þ ['漢xxu-)D))"{Rz/ Q94҄Tkk_Iq78AU17'a-I.Ɖ4H -zLߤ &RVzW^棐[,7s1f7 JRFΠ*@E39VSkY}ugIPpɨwŴdjZx.tC 6BFAMS1:؍N&GMOa*jkKng.%➴9h<% H$e2*B*=-NJp)@Tuzxi['\_;f - t>,W3&!n(VRfgYq 7x3y68rڇL"tN,L0IqkpˣP+ &UPj v=*@e CT2$T6xyA0fZJNWVQE{Y[`#BQ҂>c4;7A.)4JXPIL"{Fu.Z ӽAYcNu:~4[.%`Yi`w4$xyZZ!xƶJ:>vpc3Jk54wڇC]=Mjmju1Ӂ֐A H h OyC )܂P-Ap!Q:B*U`JS_ T[%WZQS(%ZVa*t~{v:M%ʄfObHx( J g"Weίj"M{hwWC4*)m"i 6YSN(Jd5kn2.-$Fc&dK9O#DQȂiFbN6yNİ0n:;J*k^zCqDA{YFaѼo>G_Z'Xm:f$y YEk"}r,`|21 a /~l(#p~Y&)kMHЭ[YPT#ت㡿tWۋom[cT SM]I"JiJ`ccۊb]FrvwrL?.|խP5u$_wsF?raaJ)\ZiʻB< plp;74k]=|n0!L]y:Ar1U fQu[NܪId2 1zPeȘh#T_f_sl5s!y鐓iVQR/ܵ 1TSn]Pԥ@foqfh]mb-bTvl$-3 ]UEOfDW!Qq'2OgZ6J]&" ̕ 9oϝ4n듿/)E PM,&.c6a{1Rُ.i׭^t_ WInP;ФvL~ҧҗF=x`s":dМ=:jI*Sqĸ ȕ'\'J-k I.B`k jtAtFe1j65@ Zy-I23O8㍦.vhqRA(*!!SdYo@DLk 8B$j=0g;J_eA Pb`T Jҥ+B5#QaYnʐ--GBѹ) Z#]E4D]yTdM b? Q ICjh/9ijQWND!S8rZUxd/KUm}5u B'dRW r;rq\TӼ X!E\%g#klQPl_- Oy !$e-!KJNԯNFjqzi8ċUQ kW~6 EsH3MNBbތuV@J(i6: kiiC7ǜ`;ܦmOtdiG̰!YP\M\m$@lHѱE)Ӟ쿆8.|ҏ8z0KEBQQyJeZ.HVV:aњeyi}mi.  I* Rw>~[ָc 1ƌLUmGz;+iRi39VF H0 qJ[I<*Q"uWdlDb{2 [J "l,C>'QO?9V1]KV-Un4&3/eR9XKiCjWf @L^ص r12˿52{1L|RzvdRB(}a0<ŜX9+80rhW1}?6Auth7k"ey׆8KevQ$j ¾궯2Eܿ[Eɡݜ4åпX B^`QOMNl#8{6(V[ZPO Rf% qjRcBZ(ظ%F ߥ<5|p {pYБ?MDUTі:vpW6=4MEM9WjsqO]f"쁸 ̱q**t(MuV'|3bb I*>HC_-nMS_uE5oZsƪZS-wUByoJP3ܺ :eԒ{$FB|,oa6n' E29h\T H(U*!UR/HLi]|$l CPM eS@! NcmWxǕ];M۠F+-}@0U:~ӻ2:BQ  p%) *{6|2N2c<s>(|?uhHl *!;|h|Wf|.RT爵?h‰R2h3Sbucc UVxkbX)I$};c5:D+ e)??:2A)KRvؙۖ1f&RPA;mJ3I^ gb%Q,sGQӯѦ$YUNZ-uk+T#=oĩ̴;8iΞ_6xk#_AT;<9~xwDMΧ}5 ^w(;9,#Ų#QLVei쥲8ݣDNqЍ'ζ7YiT"kM9}S6-6΢[-ԘU|qR$FqoL Tt h@%]󴸽p}\8!ޞ!1No4̡a޻2,@Ky&&;2m=ۏɌ\\ H\i.\ R! & )s)S7J$um I1 Nغ5-V`žFWL J=mL#@$DӺ)֚i΅2Hvԅ2-ZHQ; F҆ ŹͿ08 )MԦ]qFg19Ev c `"bd\bv&)-D!4JMj1>uĨ%IVB Z{%TɤDk $bl2S M'CNQ!]T?'N5CxwJb/1Kd2@v)D),ɢP 4Ǚ]uu#Mu#f*@PiECJ$$'LbZ_̃ ӥJ(#D=yX=ޛK8ifWv\NB*1Х+ H֠(t8!o"RB/:\tzm5ّ rB\Ko:M ٰ×Oxn ~nZ3hEEJ+t!HyֳsLŶ]Xe K*II[6 p']Z֧[-@ )%$S)y[5~iUuĸ.E }s)H2tc[)> JW^}ڶIFGg6^q[Kx+1NIw7f= aV\y%'R6ڥf[J*NB Y:>#v3STS*URIwqm#Z(I7h!!9aTTNlX̗!J-)(BRu$s֠oMm0FU ;B8D,S - u I J5xfb}InY4쒁EG@߾0EM:iE3^˼(@FU4C!慡$E.ʂF~xw b O?1]tV!s4*6) b![GތDT:n[HAZ3 $%Ji[ 8kc*g?.a=Z*GҐhe) E&\9Kh_nTj;HRJBB@vኜn"]^,ˈKMӾULXp)E!fJQUԏSKHʉqA*=F6|rkVA2 kjjjA4_eXO?᚟m,:]J٧gkoyԧSjRb Xx3I^\fy|y9W,PAMA 8Q'Moܩ3Y<2dTAw2BdBTRuӯMcp"z}oXs2WAP/w[ZږϬ%5l?D@|+ւk\)9kWeg3~K(uiIXA'qn1)~C1\2*"RQPK m,2i~qZL<CB@B*!HIW:֧K2¥5#-I eWڸL ҾejNa²I)f'.R#}E)TQI*mUl[Q^Y~M11L3T<H ]CmuD-Dg/kN&s,/ V JRpʐV$h1%x@Л^2yc-f TL:BQ UhK|L:60݇$^長2x= JmUj[%^yܖ]YL\X%7~Mȗ;)`BH&跇_8ro,nnXy4K1uФ(M-{kᜒ=Ϋ̍$GV,WZM`}d\}y{*W{S;2D @hS3bi̊%QҩዌA"'Z!MYRM9j~~~fp\C^z"IF;c'[Z;rf[YxcpKe!d2R!]/l:{7jUP8jYBիHQ1P$ǔ%R\J^V]T6tc2_=/` -9RMEA4Uc`8* !t(5 فf ^\%:[DNٸ;:'NVa~d{e|/e3 mAA 10`l1Jݩt1ӹ$"0h&K[(!!I(mM!(IN) Iո8Z̑$j-˽jmVJV\Ru&dvzFD6"bò?_m,_i蓁 bqf]zP2]=f2h ;p[aa"THBRr-t$ۥ"# ̕n {̒TPa,?n\"{&aF:]ilߏ/z}[4Ѳ:uJAxNN6%I1%9 D5(p_?m|+[yݤ{*{0/T Hꒅ IܶI&y[˖9Rg2I=wý ^4͡ϦSTkjqX^AJFnv/HǺ>,]Y7z261,N!Жa#u_Zl%J)RR4-eh*JZzFVSE}ضJO0s}lUHTѰ*¡Դl&0"EM[C-E`oӗ/,V[[q%!.ΐU>(eq$Fߗ+$$Fv•YQ{9S):9x?&ҎҫM$HkK/^Ea B:iā3.;0 oD+"qGҿsz g 8jfrH;w٩hn,_gِJd|,Ieh (ڦ6밷D X8Qlm[|2JXi4'+M'n|lϡ}6y ^ֻ[=loL#4+W¾T&-b[*[Wj|:ҕzg["8΅>>pqPAJEUMi"wOukڟ|3hHRߵ'Q$T篇*Y5g}gNfԳuhZ'bOvkq9 Uu?k[ye.]BLiq굷uP.i#k q>xAu4"H(`(ܚ<)dث'Mڒ'eD` N]z-fqPCm i^JЊ;>(݇,xW3q R*VIsSTJqyILg "O!8p~mIL懡0H$895?Vr< z2f 50aLD<1U Tmfe"ř _JZbV. %P]v54rn;u.vǣ*;7aT̍5SO1`Ca lݨIBȯi_6)y}ΣRuE$.& @릚H7؀oKb;38 Xw"btXivlj[e]ujEliæ",JJTϽV%e(+:TFf#jD(Oyҩs}H= " pQ:,!YR>'ߥ|7LЧ^TBšZPpak0W+$}[J=#;Lg=49}5;1❊z%:RiζAIH"j1d#PU]\Ds~‹e+ Z(곧-'K屬LfmI$*ƺҭfK4Ti*H)imt8iױCHXQI#Q$EO|XMNY, SL聧Z-v^\l۔SOB0 -ZRPRAЍ 9 q6̓wt:;5k|h So$ʹ]X8NѴWHl>+nL-3-DNXiw;JjTMMOMfppm ̮_rE4ˉRP:xYytiPiZfHs:slNdkBR/՘1S*ΖqdqJWh2']WLdz&$BŔ$Lh;yUn V3*zJbQ ZS1PJZ$vZQʑ٥Rjwֵ,`$*ǐIiM=ze=SA vyNGGe%N HDF5ù` Nj.K\Tˑs)I졲6)!jJnoXyxl&&iMؽn%LĽmҳ+ UFm1]| ~rH'X}'Mher!S>-ЖRO޿Lnws< xLnJ 5"2<{`ʒI4@ @#`{Mω1>bb+{"J_cCB kEi=\@,i̵c;\vaiK\]l öʴlA4#(NTkJ6TW$. J˹4ۋ> ՔTQBMUmy|PGΒ(h eL <|JE!85) /͊g\zLDs\P `}vDi塶A!- ts~q)Us9w5 h'jxi ((rE\Ɓ_#?k;Ä!i* A67 %(ɲ #s:G/ Z@̠ <R7q̗/D(m8X,V[m(Ƅ])pD(j :Ss^z\WaeXk< ƣ43'FLeiQ=lSt&®7=nvXk*RB>醻e逖zq oV1a %dPvܡ5A!k&jeQMe<_qW덖E07H챴!!H3 e4~! -$/:(aLi* "Hu掤߰u.[6-4 Tk]-z@$r&-dC0SuBD[)nQ)*R4]zğ0!PuӘ+jTk彿3Iߡ^dS 7MkmKKkD2Hq Tjܹ%`T䎭gD.*6W2`oNӔuONK%`[rgPҘ[ʖп qŷBH"ڏr,XRu ,8s]܋x?#+PȺ(&t[ܥ?KS2V`%J gV=m.^gՠI)e)Erv1a7 llu l& O>HJD31u*RGZ--%(qniJnD j/m, ~;u[sbR҂T|=MO;&UAp˧$uy[\ CKJP(輴mB&oⵐ.6 #EfJ[*[O*j+#ǕN$r)t}7/7d "0 Ԛk]< &hKy YJI4* TIh2ZJIhiTCC#mB֙5bþ.Կ &H;;p a,U<1GD6hJK*uVܭJIJ HԞALRstE&D 뭶hLZ' 3+VRRt wlTHSk}껍d!Z.0e!g0ZV5Ӯs|XL>2k7QQQv2y.H v^ĸwڎKe.0Ec'%q% fP7|7,Ja aH&PlܫPM9Qһm?TAބGswu'MyԪduvj6V~DPK/<(:I*I"G)gZL'ap/&];RmN6Ef"iuq8ۿK3b[1묘cJ3HR$]ڝ ISS{s)ۼR+sQwrݨGH'-X)hRT EAkVNwt{ JyĝAbf (xyuPfM$}݄z5aq~؂Jx-ס@ԠNC_gN>&auL"bK0O"?,!NE }  Nü- Jn %5/姈yo˅9 &\U¨ҍs::zT M40~]]Cn֐ˉ BB&ώ3TоĶ-ĸ=Aө0H7#&}ֆU(P M'b"O)ţbx~⛉nׄ|*̪12K%)'"Tiʖ^x, s޺x#VL=緲brw3K܊U] I J빭}09^/JM;iδ{hoX땆(t8^jIa٘ @X ؓIJDHP2,X/b,#*U 솀NhVi+ Fr02\S)N)IHJSRu$i@46Lf=;$TC mkiµH"UuZ8$ϡbd|&Sv^[J-8(RG23jt((cD'~}0ޡFRUPJHRAZB㒇rY nkSP)n܏mc%T,uִ;;~d4Oy.*މs1 ̵յڔWfu`o<lP C@9{$SK K~ !%9yԛfx79~KNU%F),V! i1\w]:X=I&]+{%:JI]EjQm<Tp_; +AwDL#n6%-(NN׸.YONqW[m JP%ғ9ZoJ}+;Ķbg Һbjj(p`m~'{jqMT }^^ v8*Y ث vk nQn-iϔZ+=#2Au y}/\<ݼuT*6p |^8AxCv>ĴVT6RA4U6~i*R$ڛ*.jo'S8sل|+NwK 9UPi4T6Ѹh Z?\m/ry !BB)Z柳\ze1{Iݸp |;\5N%vRYENj2Hջ2qȘSNJʪJt{3|YM1^i2@ I? O7(HwNV{ב{W.&xؗ`4ȖuS!EkP%,6X}0Oxۥ%B;)fSTCMP4܁JUEa0hMڙ40%TSENi]@b ޹h9:"!l*,@2;? Cr)h V!wj@!Iud̂lI8tdnSfL)VN ->>~8*_|=b, -RQ;0ó}@ESJj9K9m`L;KEGC0129!iYty RJ/-g w&aaPd.v3Wa=ILwfXc:bTTE3 ͰۻCyA)݊NU! RRFشһ wT2D']~Viς+3l>/ G"1!Ppi쪅Y}잚>1#"2z/8zQ\1Wq1_yd.Q+fi"8RW)G>TyJ@BiCˌBzfSLd=źhKΥ娩tq]⚓@NoF~>vw5#򡜅/9N_Dk)DեշߛO?3ggIRً-E4Jh@?#kiCWd`7s1i?p`DwE  i os e$x8ZYL)ՃnE$ȋt1& A]v`XJS}vpZ 獰`-zkURH_f x•PŽ J]u'O;w*%h#0RLzK% 0Rc: ug#;夙C;W]NGbfHϥQ(Amu&&4ʠivM?.sy N`(ie1R,&·z]>ʛhPGCPm*I%NǑ zy#2LYKfXjVayF-_1&A$ļx b7b_< ɮAlŨS5(E6ZtȮْ =;8X? C \c,Pil )_SQ?Qԩ)m`v >Bش]B=mCqkR[=5'P;TjG. mOf_"Eh6Z(*fzSwO#*JJM6;\IJCZ*Îg@҄ۨ^ [9{0vKן,HzI"$\:@{'[(@3o yjuTRjQptBL6et$劊W_ RTKPJgG;jW+\*()(;SMkQnѣ-߆7 ^"#&7j5Ҹ׮&Wߔ%G6V)MŹ_až02\d9"`!ٗC+iRbIOf6g+imhQJ\- !B D4%@:3yo8N+؉%j S0Pe+JBTSCP@6C&3LnnLc~I7}f :V7TCIRrPh褤.E u RĐ.- Dɇ:)P)QL}yO[A&k%kk7ÎAgFoׯ$h{{}H7>y>Fcʩ}@dBRmHJ{,@5oXQa*6tutyPϴ9@pvg?Nu-EE  5Cm,Py@ P>7nn'TŁ6c]ߍ/":Xeξ"K \J +]FZ߹y3DGDC"^NÏ!!!im{v@mXSuVT-9RϺ! u&4`>XoӶӣ$ўzI&Uޔ\N ;Ki&4JRN#ip~"X*)v_-J!)])%#~10e*"fQazLijc-J*T2ۈ-&\ "Om@V0;A"'{m.pS'Tܤ vKZ)VDV5!H+h!L$PPd%**4#O;7H.5ALP'F]mе& DM`H&4Ħ\D(Vy&q39Rf쪟4K\>+mBiA%.'nbJ^Oã"M}V_Yܬy`զMAGl -1*[ij]NB1Fk[yp7mq+#7ӅtW,թY)ZTPA.~ Le #boF^t<*n`RX; jp+Y4C97!q}Iv(FleII1 V_%-&t{&w†qN\f*07rXi%'ՆHap^lW!.rBHܕԫRk ^Zy3#{B# Mِ-hVb#j m"e^w0BިW F)X[KAx!0&<DÍWPﺸTi'SzJH@I+;/gvhJ5U^nO}!\j+ʁhWSRk7e$ DJԮ' 6mbnd*+KC݇WD1 D*^Suj][z4,4|$`Ķ f iK!{7B4hu2J'Vsx=nhJZ1a^+_rIU ,B{5ÂA45ӕ .MɼS"Nc)Ħ僆[~ J xWـB^Iq jf2:BhIJ;2MGfuIӮ-/쁪Zח.ʈqEKT+ ΉM ~{Re'@:-мe2uJRêA cJ: CJҏRa +Uڏ:6d$q}ffW*mNg[ARӥ? -oHxhe ˔؝'m7T?jx7`gJJG~<; g4S*=b$"#=öQޢ>U;y-n672H_\r4%*)tѰ祴oeY,/FbE୹Lxq__{ʝ5i<14 D+@ڍ馔gU`J-}4ʃfZQ)*3h}}wt!ΙwA_׵̞N$ uJ:;` 11 ԼSK I'+*΢)Tn,JL%}%CK(XJ҇‚;&bڌJC!m>MsʡNz{ڇ8+qtaH#^q`Z̧!*^Tt{vffw#q'ůsfPˊ ;xsBᝪH*Im;Ȑs9RYR=}A@ #UcLCͤ 5 Hۦ˧r^{+Ti$Fh\"n a(Jv<ޮ%qcMw/#a]IȄx*}x9*wu(]-ɘLr5̥%*SOs5 Y6yhjvFys<kY 0p&HVU 6ז_ 0eUGxac1;қkKS5̮3t BԁOobm"0GfIe%E)@Fgƨ-7HHZBd(sO_nhhUn>p=9o1:]%:ضrO齝L8›sK _ڗ% HF)"!+:siDHe!TKHEk Mz~Ϥeƞ0FD0e\r %5\: mJ$Y:qNC "6?F3<5΃";RHlX z8HW>wO"i9ppqj@.C2ضCRM ގW@7WqSiLM-iZ8MQ#SLLlCj踕*XlyQ5ęUB}g T8:*m,q%`F[AMcDwZ@ 'Btysmz;J[xeP)34S]kk>9\n*"g-r~ĩ T(4='7po(]x;Y:~GxZ ;Ňe'*kϳ`[yxI@XCK&:}?>"Ohkɩ>GjI*]xdqRI\4|i֓C5&1bY2p%PVW$$$s<̙g0=TѶXJPw+9DYbOaHy˱An8VSL,-.%dy2~fV{]y- Cxc 6&?[#J旍4Z!H9JRk^X 8.u}BP>x-UM{Z-`\9egȡZEǒ(CA-: DH5޶~4KiURI$'mgٽZ**e )i0 d^ɩ4MeA(I0da>71G2[IVpOl^cJ\[/ikʣ%7b ?" ؗ] 0cswGNAHU:h)kJ)I`tSBTR*5ٻP3A x ,!QILZ-H?{T[{rE w'LAUS0:OuzRf dc)P5֤PF;[2 w钔D0<;̩KAU3kn/z)d?yʔA;[uױ1l\w,m+pJ ;rM88,}M#N(R*;r 4bE 77=buiK:t/OM¥ָ#5.#GB12~1HIdC v)--E߻[mܑ.;otdXteޒE{;hXy)Цh*忿ldjzǨ>8՘H1Ic+œeqY%.&Ux܄io*//dB2"4 YM໗\M3H582h7Vʋ`(.!BmWCS) W[~l9] xXTtr\*:R7*jw'^ٽn58cS=c:odR1LG3"h⏻HZZg_OP[.")_9hkRvv9'ЮVYپۊ~ 9Hyw$@_vma)(j4[yj7eфKTjL2 8(t 77Jn6wb_6Fx2{ӉRk|L"K\*ʊXJJX4KPm7O,%&ަ"k$ B=Զ3UJGtV2ۯ-ִ,vc>٭pȢYk"EʟO]H?5 GhV-Z؁bg qE2J{#_oLjw~ܴR0ƿWhdj@$#6>VWӈ,bVQD;!@GHD} :K hr\QȐVT(PMJYo?bvPEE@]5$]N3{23>JTj(Cj?vDWO0kLnIsw1i<MMy˯nٿeo eąFwR8S-v5On$5] hPw(51Vc`&8`EEKP+.9PJ|*&ZR)ZBRTP"MuCV9EYO\j$3`c{ *)&ADX[]Mqg-2R+@&ro7rpH$)ml^_Kv!L ;'D\RTvJM-N,8Y{(;$zxpqIY=bӥtڂBU@A"9`9*W>P(X ؎'a㇦rsh P4+$G3vs7&WysխE8XA +=)\Α@5 ^q4@)\┵LE-@yD`%b4S){ZH'C[&)pIHkJ'/.U~ZzyX*G8Zn[aµS|1eEu~~4VPJkZS_9`"tkQr"}&w (j_ > <8kN!?]Za TAT{4ӻ?\n,IM]mPx xseN`AJM<ZH9#a?O'lRS]A[S>mםZdX/|z JhJvl{B⚃^)WjARR*3hFSZnf y`ԕP ]3BB[*pMIͽ!NV\IPZ2LG˘avI򸿆Gs?̫O7Uڝid,TY;w]AIJRJMN`Ai&fLJavCDl6[p$"EyP(aaEƔR{66D\l>^V\fөCNe%H#]hFZM~XƜr 23BISɘA)Mb}c6c|IM70fI:m,MQIw5ְ/E&z7-_z{=)ڟuO+ :G;,`?_ yn75hm&]Mg.tdRw\ΟXLuҎ9G]GJ;B/k;91$n4N}ibHf]N inf[+T(F忮8<Jg#6SvS["/8t;+yżC86$bQF>\& ] *lPk`)PRI z¤ |7lKoj vo ѥe!Ajq7F O=;3G?ץy ^aW- sE# pZTWoez1)r7 r]!ۄ,Nu5ؖfPimNK#aa"BЪ%7PKe1 ZUDiZVVz%)wu,_KP -: HU{zdoӴj&Rloa&y Y^Յxw.LR:X 4BOB:;^=xsWc+÷~xs:FM-Mߚ79}\b.VXGfE@[V$jMAOmPNT"RO,@Zzm.M6zcd5;&!SB(TI_+mɥUNDmSmaVE%5̵>4ij%B*a2L3N8yA9EjӕR x$PFz4tTlzh µh Lxڴ֖3 7BXa$uG0ǚ\K5~u|4;n8ꂊ]I(H.ynj."ĵ.6i[gGtkn6m@Iao6$_Ȟx]eAz!H"l:rۗA?i#IN@exSv+;IU5%U=(I< ~#ZburInHyaw_qA)°NZ vڙ*gЯ#]wTsBB*j=}*AK)U[~T?;7\R_G"!!JyDiqucWKj.]+zTcG8x ¡YJiPwOD~VzGJPM"F-mn#"}@$(;D($+9SnӼTO#eӅ2hw7UO ZEhPq`@IPo9T&X4P#P~ivk1\T qPf<1IP'RT0bop<<;TqKW)'S|)HJrGן/-ٸ&y}]M:56-J[Rv5{T5e(*Yș@}9\"+LOX#~I8OH9Mku vJCK* =!*L jvֈBC$E9:y[zdl(OX&ZI*$wV2; 2'@TAXi߇]q* c U8xMo8c)2=JtVT=t(.ow-K+!P y`SϦG /3 4LDdueLKۤ3(1 BT;H"վSM}ƦjH!5aQ@HY-u[RtTcdSrO?ֻXme-vLr YZQ6LϜ,H>VsX_rX7c\TƛB˱.%t[~x#'»a unԪTRR!mAAROnAfظߋ$Sp*$FeRrbhh*24 Odjj;S7]WQүSx- YR>~ZЪZ*Xb Z'~sm㍕ɡ._ފ4l(RX1-ʂh|Gm+)_@r!:T@>͹{,Q9IDb3qQí[o.^6RT4=0Kj06)#snq/?+,KrP"a,KL@BJ9I5茴s<_jpuSiT<<3H-6;٠@)#3uI Kٿ+r:hC0B\O4>j_sF C@Ux9'R[JiJhV4ִZ[.h*E2(M(h=BX_$\y)z%ZYBbZ;L‡ZM8K *ZkS_/֔]6Lʙi(VޒAUU$GU [NCIӤcm,83QZHyB{ٙg\J@ ҵӀ׭hu;uc$%U)G2ـIM(b tuyaSK)w4|w4Og[$en4{3P 4:ZL<HFÕPo/}L%5;m*k4oC[c|X=LALeNeo6M6uLGKP[Oe+THj,vȑ}zߞ( .')JM>4)"K9C^#&BBg~_ba磊$n_/ (;ui. [ݘ|ccB!`S aRqW)Nt|2ǜ/ rLX틥'S)k$)e1&F'\ON<薡n(!$PBRWbK,z}뭶{4$J%?B܀EEщΦ̃NpFm|r"BjIJ #d&v牣ǀI_cGFN0m5~);iYۥ֧ scb".ߌQf!GŲB'@)5 [6w D+CHCiO#ke#2|:3I?xyn9{O2\ĩnҭJ$ (%OԸH$@o(\7Xr?wrĹU:TªV'N[heU6TwIjЍw`T@@S@%=MQNt$!HŷIT+tK əy.0W xQF7^ibg>!J\pr,8J[Y|oz nX9aD;tbh|dfʒխ=xq0qM 6ٷ{!8Ua)$@!DAxrş-ƅ!!& :~ h?P^ rưY ̬}gO2-jRJn/cW>!zֺX(EC25OiWQZm|96w8Q9}؟`/a7O+R9LllɨHrhEhR4𦖩\nc~&zƑL+֘yXBT@jg ne!YiYdW^{r!B2RS#+MehSkUZA)[Ad-<|P(DNhk{؝_LP?4)2B QQC f4Δ,;PBRSR)Oʽ4@0sQ˥uP̥znw-iSG!(PH}L0tj&/q'ϗ01bbeP&*g/ulGKP[1,>KR{o =.J0H$'@n7=&;ʸ(=YN<@>3p.+0l_(y݋l:DžHuVV;s]`DkM-+҅FD|ˋIWA^lTJ/㾶KFaUӌYp@4߸O @?ӢimH -r vͲY,$co15""/4I)iT9_jƟ7jg W!SYKZ[b !J w~va5lT$}V,q q FaiE7${{&u$xO`@Bh=/z-礊7_PqFu$ըȿXuɓT)UDkhp0)Nĩ^pqT)G1*$빳 *C2 |t<yEDC4noi 5P!zD=L^8K4Rx^k9D"'ArNw[-_f}}R~@mñ6ߘ~5m2 E[mަQZf/yKu];К}o*&+* ]J9c}G/- NϜX*T5)`NeU#BIl"%KxG3N_Ɯ6J/CMlÀT*+{:d[~X:Y3c?\8YʌX[49o)fsyZmQ[}z%jREJւWvX=ԨJ'j ,E򐠘 "I_A@(ܮ#jY) MjGEm_M kѫ].ϑY,e!4/nBSϥ9Bsi]G+#8']Ét=L[G]DS\OnTCeYR 9H~prK}*TC0*e:s2-y9 m{OGk ( @ Q$7'IŻiu 힞A\`NmK .DYwY ;Hk0졵BSTQ$]E|G!l( 9 y| (OjOvV*5o,K3Y*Q*$s@ x 5[-}<* ?^X0y {[->C`n6 WJ^__m+EMMʿ/6*0$3~x@wXG؊b{,bQ|2mE3{>Ā[+dFk⟀^ xPG w"Hĺe¿aJKS1U5ZJPI G1Ncdw^ʢI."[/BaYmmeP^RA:[h\+8uqu9maJRoٕL;A1X8^6JdH$sr8- JX5H:ЃB5ԉD?ZPV5޵bUpS"#6+/;Ƀ`VJ̲V@NeIxl9 ?o_nmwEh{t {K#(ChV>RԸ%*$ FiU9%iI$*& YԀC :V8%*F|ir%^[1r]܌R<"I!B$hK'?AhfS ?&2h˩R( 'W26O;x~_;@*׺@mJݯ+HФfI:tkyVR@ZMe }JURR*k_/>\_r%+"9L~)#6M's=S7]>Zg-yGwa1MX\ Z)B5xV+ vy,!/) iN*ZW * cͤ 6;aLa iQ^^>BڔM5s$r8R7]wT:J\I<1@,U Gt0^9xOuR t OkSMM~j,~RԤr?2wFY>__w| QCZ}`lMy pC{v@}߯kVn'sxVQ.g뭂fx(;xcN#mcKG}|ml<7lW"7I7Iߦӏ`A$g>k:wZJ'>)"VJ ]>cǐ5RCAmbQ֢_|l""HOrzyrFqNK"ѶJT^VRM\a[Rl7s}ypWulUH<ƒ]O[bւockT`I` i72OS-/u×K  OS 4וS3xI($`IA@_ʶE(SRcBT+I%O Aa,lj4&s.UCQ? >6!]̮Hb7"6%O Œ2}{kM}*g֝z_Y~C k]=oےb"w0pe5A_FȗIJh{R=/~u &|iߐ(6EHԞ ΗRGZֻam`2qZ! $d@I?Za qR6t(wPm?`td20\(I'WĮ,+%Ug {Ƭ`C0 ]쌉Ze)TZr4Ho"R+;k׳‡;x2»ؿ*i7zD)ME)-%ytlߍx{!*Vi2˩j# jؐ*gYjI 󿧟Qq$:M#L'SHd+ѱQ Y J[n,H#Ζ7^%fr;0[)2B%ea*iQRBm֟>NA (`ݽX@Ke gBKX¡aj3him !)@()n~On5UͽI˦eZ> Iḅ*r@xx oq[Cz`CR=~`:??b(b7L$k7 .. d;QP 6uPx==uDG]j1iuUPOeE@&ttUA{*jMN\) P6 ZK-T-XD9/2 nyp-pGgx,`me42祪8Bs }^)QTk2ޅ%:%mytkO6 )ЀANuּ*H%3uj![ig>'Bf Uu]%Rm3#+|B%ab>cD\(1b6[ Og ’hRC)ODE*E(}5һ[F޼"!Ǘ@8@בW{Vf,~ ˗9\E0eXh&E}rnJ+r9k(@ H&KUHxAmq)G0Յuim־}E3J65~{^c?f C+̛hCoR8EWv$x}ƃ0)c4q(:(ӞůҸ&nKTn'`5mU?7./ sҲқVBIF˟g>p1ud4T/I)vlkN7O s|%6TLLbުT8O}IX&4X1P7u7Y`$VRS KU8uZ3num[(!/ADE =uښ Y!1Y"wC=ʄ1m{%)DnDn6;V%"W+Nk]u#\<ꓝ1Pu?p (wUd$$&>% vi>Lx.Le ICHyryi@S_rm[H I}tjltOX1>?$2DmLb!hf^zgY=,RˉyaHWU$ُ'Q;X:rDk{RGh♜yN|1MKRCBREG*6QTRqsL'$&x%:$SISI)RtZrzh> p{s̤sVӧ3ODaHNcgS=+K)޵-CA.Gן営*Ҽu>?;| NMiV̏gBD!](zI?;c}J!+&1/ P^͊J:FS6;w vvyX9[Ӑ=:N|_Ԗ_#/‰D9l]N 8;! \1]/fy{JRMut\jj(,*JK491;rF^!Jw<>Xɤ!$Оִ e_WParj M*3T)^vq4^^5|u׺ Qi(QIjgz(DvO뉴6$ZȳGb)\)"~__vYΦzJ%Th;Ӌ}qc Dn%jOe=r(M(A5-J7adP+nT0!$TH)ږ'@kH)\- `% C)B@JRe0Q)2¬**m)i $MLTTY!i0:= 1zJ?_t!DZ߬8MeQ ר><`PGhqȩ-ĐM!Ri*;fTkHjRWRR U`cx bM]8ِ9 D^ǖ|7,He{7ZC4[m2L#K8Z+ͱmR PA@P t? Z^qNPVqej$%ED|K BP)E\i)Pj+oA &BD@"tǂBSQJֶ҇BSM~>A5odATxo̔Loec-ec-ec-ec-ec-ec-ec-ecZC-G6\ A#Jga1J (Klz9ef`$4RN 郺I.Hەۻ! 'F޵mPjzfpw ba}̘c]˂PkUzk[,fj[o xj1-ʀFgIkۦs1%Jj]I㭢)p <[NKTQĢf)n-Ns6"Ol&l0ޣ.PYU9 MF~\'@?S"^)X(& 5HJlN*z xKJ k8Fhii-8W3ʊ4k\a q U:*FP5Nd` @`^iv}<@E՛LT2bk ԍy-Ê>c;BҔo i*4̓OUr= ޏZp^U0RcIrA <# niNܶ\IH \ӡvMzeժ;}`^ע'tݴ~#mCW& Q%-*h;r%JG,MhaelB)BI"vec^mK W =qtn+( 9(  GA!LH &;h!I 3T( G UqV0w/cG *Ա\)=0(A-a~M; Pؓ.V,|i2-|f`Q'N fh&ʶh#@@{{+ģ*\Ŵr&@ϏU_A&PN}X989O$WX.r #1ՃѸp'ЂUAayGXvKv^[}R`XII5rGp!6x`Y['`H )}{NH&ζX@*}1?q,p(ȲM! ØϭFĚH#.+éTSB5egS`MP}t*ͯOE 4Od|!ʔbmo'ؤY"%8e H#NHYI ,gc+( vQAF~B@ ;GiXFV"{5=FxD88];6B}{S[aCϔ PlsSq>r$!sJȒ9bMPde.p24h:$T/'P[\k.1^dc%?JYpc\ $mi;uwxxJ˞BR̲5 Α31i$v]Q SJ ?SyDK1wQԣG.B&F*&$ylh>+CjVLrZ> N_c '3&7k0# V0|FQ4l$} &t1*rCj.@6w)Pjy&$(UFvͮKɴp})wYk*2\0K+}$ ,,P* JÞ,x>q ;m&;N_R7[׈G&A&IGrO[va-]rܣ(%l͘[[=! 'YV߬w#+ͩ=QczJR+^HxAq 赣G~<_SJr` D`RG "=xTtYB꡻괠lTϒPCrx\c\d 3dóV_ҰRRM!SUV aww£sO+`e }sԅA ߾qNo_%L{}Hg2;;uNqaSؑȯs;y2֐H=Hd\Uڣrz`(߮M)b PHfǟ!--!Ju-"7Xfe(W 0~@in|$-Tf0X((X.dj0B:Mc YZAUF4Qn2f`@? 𵺝rݪZ fo$&FiD>[PVƪ@т;QO)ĬcԌʥK*HbI:Ә炚o":]f$p($a3գl$h? c'B,ӏZဒLNQܙ܅5ME('؂ ndItC!kHD;!K:pI$D X UvIऺC$̅)Lۺ upK'WG'2&2NA岣v-,@%W4Fn 6㦙B;AÉ#3OϺpĀEY F#džjAKF]U#gi$\#)a1G: 9! +W66$J"VqđDs'WGWm%Lc|!d>h\nۺT&@p@ c߷?ϷO@Xw.5 0g^##WB'gB@-Q3<IB8Id͏.2^\^ q>iP>PL` }{ mPLw) c>aA񻧲7Eڥbۻf#Pffg$mլ?rV4զRB2 ,rT$}JWO,y2^Eq TSwUPH\"asّ)pOKHV Ag8oC@Qy)$cUMєKUhyltD@by<zi#+'GDۧ˻Y$!%N2FE1юL`6fbI!G%Uo"i3T(f$<2>#vDt`-O&P*fpw J`J}BB]$r18H(*4p iAʾKf 7I{иLP"$byϩ?(I M†cIWT R$һ@WA$ !؜-)9V_P*%-%]FFV2b@IWxIc̲I,o CP"ga fpAbWp$ !TdO9랸ՃaOx șDcsb.e9Q9NP]*ĆB׶vP(-U\)'v8מ1FtXQ&#j0ud@,[ Y''SC*̬#Pt- 4wտ&01}$gZ֩OY 牏8E1Yh@YH!TrUUN3. (^R"łKjSήM2+)O9i=9bL !B3%r|'B%nYn"GII#F4! ] %[UbC-f*žtT mA$<^I3&cdK12)c&YN W!X0NŤyu@/n2u^ON_e9T/OMK OWò4L((4pr 3GR@(/iBA%JX!˯QPۭ$ihc={DpM Ēq= z+P:Fj*b5*pHRp6gN$NTqBBh|Ż݂>0޺ RD+*mKHFp"lP3eE#$&,GƬX6qPu"i{wLe 33A Gqtvd1ČIvcSјKn,16@ݰXS섍xw")&S#@RĈ@.oz&JNf@Ы ƥW΄FJ}Qw@jX`2v_6k۰M!r "< Ӝ;L];T0w w14ӓGҘouŴW2ZI QK+lʁjђq)^<\Kʨ,#&2@]n#:6QzZ{|18G7l 5_R6u[4C{.T p5S |*nRmCf<=;Ӯ8$&0v`zyvA[KPW#rBea2.NKw!1;!>{{z0|[`JYuV/Pȍf M>03/ToP$l7%i9J,nU #l:g RejI@2᠎I'_%*(4 &c=X {Uܭ5:"$L7H fAnX٥ "Tҝұvږѣǫ1U.k:WyV%&^Ē2b Vb ar5@~ LgSWApGrރ;0յbN|;:`ܴA<H#$əvy.vXm%`}=cʸqI#ȨijKl%FcXAN9_!Drλ `BCQoWU< S ! *ٜ}cQY  m(cCڨpŪXJYDQV~X#*]"j1q{UU:]{RuDDc)sJ*8mYTǙ  H34(CNRQ\?7;G}ѭ:ֲsVJieemi","p漖I5%pg9%Xj;e m\#Ǔa-^XҪgM;[Ww[L2 X*]) b|`Kèl/%)NuQqi.w fJ)qJ#vĒ#F[!SM?:^Z ZQLӗb.V ms8鬻_nWf:V6mLf سRjX3 WǝvYSp,~ZP 8M t)E(VX[aOB4\4i,TUMfQZL(J!C2%`()Irz]1vکIZe/uY c! #ܒ EejZW_+ M5YiJ.2ϐWΡo ˅E#H UTit=Y_UF!9aE&5+0lY "Ƿx:: ͣ^G@ebeu-FdstV:w+QCrE|U[/jDP GQ*XFX+1*H]oc3,=$2t=Df9 i#+*+U$h[[m a[VqPTm/H@5G`X;aT(bHTm>9ə@"s9>^Idw<>}"lӮD?q9~ 0l5Ų64} zP A9h&uRt+6vfR[" q W] ͙P2+)ʰs8# lby$yPD=q; 0L1dr)]Gk08‚UVf*ɒ .FH^WH*;Wls ;x%UP#TYlʬg*G|)ɕ%PaTE)e|jU׶UUʧUDR6C9#~*QTU;1$d'V։܀a I1V@மՁ(H*, %!q"E9c rC gTBSٮ-ފyR@%U`r\LπOŽ]EEuH=_ bUe:#bUơl W*PS廍.> c$H?38MUG!̟~Qx$H#*9\fRw0#kp>+{!#֎W#NsP^+|2,o|ٰ~ 2GzPf cEDZLJ[rpmwSQa=8gP%ЂTMH8zvSQ$eQF@\PB)O  TUw%GT12i$y>H1**O&j3^$rDވb!4lщHwhEMy=;',,XY٥#lkygWK`I$eH,%{sq4JFK]Q@oqߨ5$36$XFVT#]<TT+YGs)h)!Vc-q(4ZXcsQ!Z#)b#3ӏ[G'?e$ * AYEĪeɱ?oi_mā$C)P 5q\ .@P`)\8'0״vrS%VHTIH X<W  j#gI#Vg5 F|dd -7oYDr8 cBE'ug#]ٜ!">H H/ҿĔs-]enKM# ݨ QFIC]d])d ܻLdr"g_ѐn:.)? 8zI6YH2™c,d@H||/# }v0FH e(4SSHd^ Y c]$[{v;`(S1) QD#JaD8ܬ@ 8:=!9) 2DC Y@A3WnEBU$.A)d \0p#󤚈J,䌩o ܆{Mj?25/T3bGPJQZoTpϢ$M{$b #A#*,I!řUG4`”t2 nɁtMT$]H;UNEFt#;ǕU*r98#+pd ?B\1,ڃӿdTG #+%FYXn6j$evUQ2O҃슪DeFEV-jʽr\/a Y_(䌙YLNKA \hBT.hĂð<'$qX;IIg1fg98P 9آ%OW Y t٭.ҧ윓~qhơ/-DE Ēꛀc](rU%m̳QUS#P+uiт|],wi1 XΖ@&@0Ib3PVev b<l1(o! *C(}g2@B$7~@PrF?\GSp'8On$f\0 |2He! *`k"$K$+# ûpʼn.gND[v m%% %I`L!Fwˌ*=Z ^ )%}=t2RKKN Y*#' X67JĽNh2sԣuj wD-T$& 4 FֱH,kŖW sf,Tac ӈab필(*qb$ d^G-֖E52H>D 1(.J~qgޒ~ڳǖQ[3'U2t#z+<#8đN)1 ɞt@)SqK{91O U,gł\ p"?N%1+:GV e%E(_6ƈJy6Xpw,}KDPA:EF `! A <ʬT3 0ros^$I'{HqȊ_T蠙Z ݒ5)RuKLPbH!=`! *$iLIPp\{cTSb+XT2-BHŵ2MN+lN\&,~ ?`H@3w!DDLO)݁yW//4Hܠb7uMnefI m .r!;#g]}H$h؍VH*wG{T/mGG(Nc`K6H>!IU(ônhQX4 Ic%0LHeX8D9F- 6 #X/|:>ŀdu?SL JRG>r$wr!ASPǺ\f;eBBK8uYO,JefXu F7*^ BIrs!ddvHE!&FWF[GrbyiHiWaw! 7';u|qJ=%9`X'*؂8;+Rin^A ĪN$Re Apci[8)UD0ڪF@٘+ps|gBMzŵv*Q7v55$UfeUl`L@uMZTҪ*UV!vlAVe*^$QڹTT[dy?k5:޸\}56i]gTn~+*ST:jY6:m%ҞR[+Zʠ 7I*TS#u:TuZuP/-Z55}A.EE2GO U X`DbKRA,|l/MR |4p[?NljJƲ+]PRuel"H|45+fARU˴2}.5@jh#~ark}-\YnzhsKK'G*E)RRU2 kĄrj=C<3Fv>#f !N_T4rM]%*Y%wzN4K*bݣgr$Z]xп.4!QIl$aʰRJ(o6YAm*ڛ&I:i8V`n0y=EԊcˣQ, eOOFyTܘΜO~ZXo=kSETv,*$,P24K{ǞWpMb806(GDvev(Fl#[: U<0QK,JնjZYkg|k3dҭi=JdRG`  :M`U.C aU ;H1BnIP^g8%Zi +1*Z׍ GgUl~_[(q]r [Y5iEK°R#Oʇ{yѠHGlrUY@éo@=p'U)z_p!{_uw4*C36Ug!0!G@$.) Qmn O aI:_WׯJ:%J! @'А 醷~?Xmzd}^6/3@ 1 <$ XJ9jʉdO27 P .=)`)=<̑<aSǔx_ j-'l K r#B033* /ϐA¢FiAP; UWwkA ^!X{bDhUm_񪣴h8ƚ e0_ČFӸRAοpk J) ݞl)" oITH=,͝JmĖ@؁۴M?OfƋTX)bT.#±`> ePMAO$MkďSՉ đ)UuBE%=`r225J9 1 Rpf ?/jmd>Dg1/rwraIcs$}LtnF U@ՄWyL?UƬ?Fm хPIb(%d20<eV9Xv)ь^%\[B˔X| Nra@|q~x]}81f{{)g$GBA %T.޾[99m0IBPv,V@/pv ~`eQPSH!@ C e U\<p>=7I0Ns0^%p=F{G2Fafp3&Yb!T|0hꪀn-PrCY4ec*0GȒ '2,)depSP@o˷ϣ+2 !v!Ub˨$.`vfsvH\&#Gpp#MI.N5@tP'@r>*Q)9b( A$ ȠxP;5spي#FDouB I d*%yϬ =XzGN{g>]'"PF$hP( ; 9:.UpcVِ3FIeTqjU2b|R\06.u*̤~:GWEpƍRTXdd!°$`,@@JV6&b󁎓r٣Npl)_`O|s5B&h[Dء*FAUX!mSX ʧ'#oB+~dЕ(5%58Uce;(%Icrđ܎}"G,I>>}a4"UUt v ijve "%Bf)fWx|;j9eVHRUh"XNKWXʒwUAh7lr}HbT_%Q91?׆rN>s@ĮQvtwaf$ BܩA%1I18(HK*0|JwA0v`H NؕegAbv}zJ /RD90cLcP.|LdI:6K PA hA#,ecA u 4?[7!*1(@R@ 6~K_hA8<uk8%rT1\|S.LԓR;FiUV۶ Φ5!dpchԁRK\V /#G~i.;т[ 1;?ф$D8$G$}%S5$VjwjVe$ 8Uq5~סZ&I5NQQCrem'+AM˭rhh/Ge+i0K!Y]شueHCxQJ  IC s$(]AYΩ8PF*:l)Oi_>s:}U]q=N2͟Sa*{r}ÀUWmjRq+ IZV̆TIu?kƠ( zH1ze1AUTֺu)X1m4勹XzIKYNT(#tTQҗiB'sTUejTGp9?Y[#rgfor:3=Oq^AzRUR-O$/,NȊQJuVidM[`I89vN檕 B{*b!R&6A$b6 { H_,Xc>2X+xti춷e,H6LvC*s?IK~yn>)k xF̏mdFpYdbtSkzQ+*]4,.T%LR$ )rjECw"@fYUXb_W N(n- wJ̹r"ĕcJ|dηd+VNsIeA78ֵH dcgx3γUpGf%2ʱڮ5tʬ zB J5C_F*=lu]Ja!:z2WtԳ0:?(uZ)^=Imf{K'c%9;p=?UgH_14<"n:b]ʱs1xy?XE{yGu4`. ].TtU],OF}S X.[⏶SF*g"Xb$KV䁞;$jY`CbUKa0 7ôv閆UՍsT%[rMFܢԪԮ$FԣRdv#IDJʅʬiRDmͦmwbK3aZ~GYVG#S[OF12E CWX5uLLw0k*\@쳐K"JGI1'}A5 4_`Heb$)XgBgBUXC;]T1f !B7ឥ80Bl<`'U\ܮcCB *IJR5ɖ@OH Q^!90p.72A互2U:n4O_fơL D;]JK%ιm mފM*$N$VNЎ@J"#U " T&E&dX1YB`\6c%pϼì׾Uxح4k겞e#z 94fla}Sw'7 \w暬ٮT8h^ S-, o|;V4Fh˨Cu\(A_`PPRc2;$l ~tH`wn?zA׬zr ^EA!|ikj:JXdQriuծ5ZT^MGtW1JBtQ+r)U- "VLL4HR,rDTkY^wTEJRիP)+ I[Q"-AMoV9v5mӑ[gS- O= 5TZU$IMt_gSzȹNt).Up]ēGC9Ԯ&r%Z`U+0 W*;|3* omyQYS䰨4U]ȥ;mD -Yu$/+2D((rFޣТLHmȐx /Rgnzk,Vo-UYx1[ <~ OOL,I qqVuHp+Eq/4MOm'*i# 憢U9D.j&pg*J]7e[㞊IEE$Ea|<?o8OY5Gsq*9Ar~\i{i)ܩ"8js5,IM/PXdXM4;eKA#4k&ni :;SI!|? /V5\*:tW[SA4Ə,N Mp}iyCvWj).iӴX%R-(H]f5R*+z]/ݒn)_ɫGf?|\* S %H疺T4f$Do/MԾƭW(tiCQ =Mm-i鉖&Ӫ 2Jmf*t^ 8qbit֥+씁 < j -q ݶ}Xjm1,fRW;?j)i%DW>Po7 巛#CZҮn=251hNwYW-W.K~Fp~y˨\6o/UY]J9Ce^JZgRPE^o4؈¹qBЪ!u,R8VxҊ v)Ĉr` ږn֐soR'LQo8 a5|3]eٸW3[=%E tYnUttL߼hvxTU 9O_%iquU(lUm%Lhq*c-DCǸP JtӎqgCjn.xc/i$$㚝ԫA$꓏c]ZN]'TsNC9,pUqzuaQIHXS ,6zY/ ;7Oi*ܓTZuop UJD^YQ\V-" 6n5;ګy%9 w#])exSU?nIO$'m>ȭܪSԾ_P+*bY& ۩(f5wCKݫ5U~t*IQI<.ZX6٫Q=F_+$ܼ5mDSR<ۢo/pVͳI0[tAHsn2܏UT.#n ! X3[GW0r 9yU܆bOUkcQZ"IHEA*̢ThC!i)l<ꎽ5Z*;K*S _ܽ'u%G%Y˰Q]}Bs{WQуy5MUDHMGx*x!D Ӟ]Mzclul\ӑ uZMƈ JCQD!y8etJҹb70Y`m3ؓ+f}MmOR=aI(:M\%U%O)9Al-Jȹ'!ᖞKma߸b[0d'h0'Y T3/wZK?54tQPzhQޢ8 T>j 1Gl\#}{VAÍV*%]w5oTARZhR$uR*Jd#: ɺNnsknqk[)&Er:E-l]SۨEe0!p7c:J/oRqYR|v$&>0I8hX#g(6D>G8 Td8%rjE<+n!@8WrͰ; *TFFPVA+UcN 946p1Pv ́dQ .p$H8pJO'ӯ,lNΤrQ,H jxe4'ԆDcnFWUR<2ĝG]G@,fl9lf!vu &P[gH0?隌PSt-nLR3 G2P*P*?$x&G !K1 aA7J2HfR ]J&a"K*(]Qʟ vg.:I$ 9dInd= f>X*TH-'Ǩ^K-3F1UP0YT)Pv2\{VƵ 8j%4sD=Ȼ5:IR .*Ơb5gԮ\|`H%:U1J\ 32L*mlcPvHfz*K`{0sU?=F]5trfa{ܓORE(dB0C+.J}N΃y)^DRRW$xЩ؀sڞu*nԜ^+UK;եϙU&pg9'eUX=8:<_^V2|HpP Pӯ̙~uŸ V)VI$_dRu¤c.<~uIijz(5C}A{uiMm7NL~qGs?U;_SoJt+b9YJ0/i3D&G%ӱ9y%e MH1r~-P_I ;W?\s2 o82RI۞8 geyd*#5clzl ꔁ ğƈBVV2*j0Ƕ@5Q;YsL0R1su7WW۷J)(??7n"2FT2*~tsЗO3󊚘 X^HiI43=[HyQd@ơU-Y|sg,MQTԟ@\U,wR釐>•UH me)Hԩ["1UK`e NALDg7Z^}򝨩%/))jL, N WO_8V]ǛPKnh 'zkn3YM4SGWR:)*0%eKf (WWi2[Bb fu s*6>uZ6Noc0oHDy+;6C ը"aLF=S: X" $dwN7۽EƲ!2wPTl30nuي3,m$a٬pI:R[)"IHm4ݴ-3^;2>Wf*|ېռEIy5Y1M煌0yA1#$Jה_8fg|G\j#;Y_ m郄*_rבT Wa!$&{}d_T,u `C̆@DB;oMQq^3KVTv%5QOMmB(#RT e@=yUE5zU KE,QjLo!|+d K:N#0}m[DeB,VO}=AF#«_hBƠ~"1U\AkP*Nq'h3[R[RP;&3$(mcj%:1t'S"$VR|Jbz'ܚy`x,RŖ Xr!*TbQ\Ӱ 910+n@  ?$wSG#djX]Ye FpA_@fa؀ # قrD:gu0@X f l=^1B Ku/Tt0,S U'BWUf-XRYmS&V"7ePĆlMKvY#¦)b}y U\֖Sp]@R0[?My-JS/ 2+cDf+1Xu.E%]D#},J8GrdO} 5F *6YW~.#i1q7EQ߆ Cţ-=$s$V%DغDa! MiuuRc%e-wUs$mb Eg.NG&Q"+jv:1J+۰/_GU%E'#dճJ^fP؝@E<|B ,Y"{|++c::ઐ3kI$n?3v/UuB,6ʅuWKXj{Gr.]Xg=G4UIGhZy 㦒Jgd ews0XQ#XGn񉥈L 겖!C4$_Zxi$`= qs'};*CLdA-+^kE%$CACSS<7Yز=`qGmUNjOT5UQ{A ff 32f4'oz֋˹T8E% .H:|;VOzij頖 &D4Vv䟲љQJbmUHzeӵتҥf%%\#/၉XH#qzo+$<ӗ/pi"Mx;Gn[ʩ0=\䇚+nI.F8$]=пO[eӅ$o56!Eڞ2| YF2Z1 H) IUr1Kq( ]];{Td+$$sq{-U#[(Z T-&Z樉"T$vWtbIoߟoXV.9(nYU*!R[ '~΀.4mʮ!іTvMUr絵N%$sQS>dTh Aa2hlf380ښn6J2d$x\e-qΛ%4s,UU[-T5+ , 1R̻ }1#tk䫣;$ȳ l$fN4n *G\_Wns1B#3.FX,dO\Ē2L,TZd":".R?U˩XvCd=ٙYdW[RQ LTSffd]B%ջe AH;1VXlH\*Y# YCd(%X8qJP߷h9eH:@r9gVP)Ag]T12A I]Ќ";+`Hsa W$UeqS,6[cqǦlF[0"RaĒ4%dPżP\Hi:ɽH IL,ubt=Y!BǿhS] ہ9R#}Ozr>)>u{M%k_xo$pqˬKWlGR)$B;q!f#,WTnT.$=9teH4cM )YY|>Nrg`V5 %W 3P?y%P+Xub\14Y11@j,|B DyR;]^=00gJcl $'J};O:ICp\bd{4FBN)]bc2b(OUI=*h+azyhxdxu`PImKyTŪNv"eFV [PDB$hṬbX>?1%dgO6tTA$[` )`<+85U*|JU~),AU]DHS[}J3Up̸LW'r896h/׵uc"RdzJ:()' mdN#(gI]Gw|&yӚd2`XVG:Bc~G\|*_ՏT11asە SU1ƲQ 9V>jN򽎛H&ACGV,-a-p9>%%yYqPŁ;$`Gr@5 @D[ތ> jPC tS<ӞtѣUxYFȵ@l*r p\ *7Ig2!NY©1KcY 1!io%Q8EBꪨLvҽ##N ]nQ*U݃lp Ĵmtʆvշf@TN&= ]WqK XTH":wEfԨcH7!)h;tidbR Q a~X88Lky_Lꂤ,фhPfcOZuY]B\ʂX%A'= iFn BI0š'uQ$v=-jwUL¢׊oeH4&J vW9}2<]NpڱF뇪:F_ !Etg7K7TD0qh!y#pXΚ.mMF meL˿%خJv֟]2K3ԵCP˚ʡHH$92W)ݝ@$zfv`t#6?T*OUfURY&֊*?oOPy7i\ӫR555%ADr gI!_. GPx)uBZC);i%MYlw(RB(*Xl }XֺY.Ծ@cT COEdHĞ)?;C:'2`(QɎt-zZCQ1'ߪ\eH* ȨHa%@-,Aj2ڷGkv^/g'52`;@1*Ԁ$ݥКX3P Y*XH h hq:X=gzg4]fu%<reB-{yI5 YUSL`3v10 '8WiYժ ֖Ir:E%?(YA - ND _uuw^t\4e>X&!$loFQ-8-d4t mȁ.o@^-4<ElB#XN1`B\귉TtKe!Y%Ē>#0I@sԳ(&L@9~Dsqkf * H41ѧdՕvxջRMFa!6-ݽ}wRW8ťa5/mg J;GP j]X(FX6qKLDtr0VE2I$p$&v9mv3* J]3-OON.& G}1<=t1 `F)+`\po,>ͩeurV9"N# $!ĕ!@Ř]xxWKly O K_1w`jK𒯇;E+D\ic<'j˃}X8UXe p[@$s#* 2ٴ*Po1 *+HUaޞ7taJ!5RJU'OJB[(ē*2ZtxF RbJ^h-i peLzWM'#'cXg1K(Xg:S6k_| [*XQ^Ԛ3e̪N˦E !-L)dP*z:(gRLPy8EiS HL!xª*ݲClo!bFFL4F܈Ǽt  HgEYފ65dYU{7o%F'B)yNUI!eXC;:mBpWFi (˫3 8,hh"#]$gF,':b#_i"ixQ7E2(q*6o?u6" tkfU 0$Lr;8WנdYJʓST*?!e`&$l[z_'ڦK۠ -;L&LT0S1X*0 zucм4+K3, 4-2@&Br !%6ŢH8/$Dˮ_W؍!dRi&( &x#suŐ 3xEcj*$qvMx^8FQthd3Kۨ @pfYY6vռh9sbDf BB*"C㶈@U`C?t 8tcI,ສE lN͜.M[Fq1h$vt("8D@#1ܜ|gz1R=JIeY +c 3l0p~u宒Iީ l!3,xLgb.oO78M]yL+m&IV0Ž ~qQ8u'4K@\U*Zo@Gg6 d$@0uL;lP wBEYVv혥V :9,#.V,yI.X4i%D$I9\pvO3MG3F0ۇRrU}S1ʨaD2ͺ+0<6 . ``\YDs0"xDdOn|DH;P1>TXz5ic@V0 c++HHjcYu,6!{f >0N ؛vC4v%*DiHYc++,0Ab@7ݎiŞQa&E %ʕ SJL%)``FA*s#<Ӕ*&x `דF/HP=MM;B%.T$Gr5HDŽ9\>]tPF DV\ ЗU`H:oǖ0,A^JHO/#FMBP9,;c|䠘@LNꋿg)S4O3,Q{{`YC7, dn⧲s%J 5wVo`rA[=9P,% &$teXrFWTFX /NGGKdfj 綻 cPp8U!<1c$c^0A9fO&NfZw*)(_Q#$ Q?89W-xd~!XE9Dg5P΍w -[k}D*.@2*Tp '*_ ,6Fp+d3)}>2 |Aw3q"`|OHԨHp'91ǯTyq|fh TltU%NTB!cc:#lG!O H Qӻb)ِB veuʼnu">@C rrkjFd DGgZHԔm[א}}}Ӧ7׾ZkD +JMOlc3D on[dr=Lc  2(Qnک=lH̚hVZRZTBZG̱TI8ܥ$ (hU9su å 2@aNHI zux eMP1Y)QWV#9HBȐqfd!H>ELAUI{I0F"Z15 Ύ=/bERb^d !dúI7p$t82OO=D&]`43AFr.XE;E9%fq<x|s)0mIIw=X13#Tpea톑`Dw,cG5:!Ѕ-mlE$(_(ᑃ][C.e:u8QFǧƨM.qhx7bXʁ`􏝂qQf6,J_m+̺@bi٬iXQITU)]dX$N:k%*vNui@q*dmt:%[kK)=Uhj E\$XHY1ZU2HEP h$*;Hԁ5-[,vG$(Lw3qXjnME[ESW2견S Jmc~>hKuZRwfhbU,ANtc\f [; aJ<1nBJ 6[1h4?ʬNJȄ9;$A]WVBZ̦&eT `w9){43dUiT,(^ѷvax W%ħkm7Xi) ]:O #52"uxrs–:k=0ҍ۴d4DK@,;hѡ C}i+}Rt}$ XU!c͌9E)ew 0&A=;ҚY8=8yƑYd`@Jpm4-T]rƠm[M,HUЧ yT!pl2FZ2ŤMCK**!̮J 2(,UʝS0 ?1Znə8 f3APcHcϟϤmފ1ʣ$v6pҢ!dSYWb`k]b+ 2"؁`XHq?mǸ9SHjI#jC"FYg[$ܛGxa)S*\*FR)pq1Hgąبo`Hۤsy9Xԅ\;E#]J3XaA$lj"F40+0F1 wte&[.*g 45lfANeD| Hk8YEPC# sHiTܙ?3&~$ :CQ8#y3%05qw:AOA L Rtdo嘆 XE"A"Âbp ,3!aʹ (hD9+#,;pE m؂`t'Cp1}7w +'c=1QFDkIG [gL(v}Y]*cU@eE3A$dh$,P5̥`Hp{32<16_@̫c.dEüD,se˰b3#$O]!TLGл*IJG#v@7mA;.&P iW+Y{*B:ge-ճ78?NB$KfQ b̠4۶YW!v8вV*1@1#$@$j-*,ͲpAH@̱(v %vvFH.ITh[YʲJhUveV*(QKIudL+-d!r^"IwrT2Kij*ieTm'i"0dȑ#t_&ʁN2۠tǝX Ib1uPeύdeTWWjrtX1 Ba djt#TE )|@t[l2E~ +X6[)f({+ Q$V9HUl9RUv'qbʍ`bWH `P2]؜4b9{.tUv5Ԅ2XŢ|V8Eۊ`: `LԛjLsg{.ciJ L᝽Y$Aw򯑏-4Uv +;2bWzlJ;,5GE@7cٕN@h"A >F˺M,3,^<l PrpAZasQ| v 2 {֍T"ފ/s裢W ѧk.QıBy5ỸA$3HN5漇@K,cBV8X/`@%S|qap3>ta^㋽lO* t+9PU&(AnchdkvXH=IB @@gPbMDի&Aݱ) _d{`O=ܱv gb1>Yc_hDyaJ M- P1K!7 \NQ!EQ -%uU e@` ĪؒSSaz[ffD1bf,6豦Q7q*jz:ܱ@$w*&e,c%$-d B)ř!jmv$BTg! >J2]&` by1Iy&noq( bHΤtIHW]p~X{F.Ӂ8{)A}Q%R#G @[%9 H(VZa4U j s>S ޚu*AFNՂdL`gٕn0ct`4=qX?xx#i.u+ thHTHW8%I2Fiv}m+):p5RNČ=Ymu]Xȹ;FVr\+xݰFR6|  R]rt*v/#$ vX>;dȂ d}Dt DAvđj %m O;9aU˜t:iqlʥWBS`d!D4yl/q6UPkS6dy2K", @$+.!f ls?̏\G*%#"pU *+z|(u`@PrUTij、4Ё!dRG!  +/eTz 8VY "LcYI@_Pr Y6MUԞ%I5 r(Wݎʱ,U' 䨈aHsI>AgA%]XZ&BE@Xk"2̂2\X*#T+=@o)UyE4JˠRepт-N*PX.HJт l}LEb.H38פ |{}߶;$'=;bW g\FG!RDT?F2K,eu8P}RE;VX]TeYW_J"HQG!P\kA;+:!-`#=| #9SDBؒD%7o_.&°cgl+d(Ö!X2$V!sVLȑNTt $ 'aAH4pH*EefH$V  ALDZמǮNORUPM Ȳ! +b]X%V#f `;]2NTIR0=MSbi,FAhQ= `!;6Fva܊{ u A %'\F x:I* #O 'T ##qETS rVb.|$.FѫWn k)Yeb*`{XϢ.ɫ0U$JjYcv)bnUYQ]a 0yi39e drF d2<~ J?Cct{i 01+U 0!jcaR"R&aCڎ5\PO)Ф YQ]O%X{ d,rM)dI(]|fB.ZĖ$I N}OOI'&Ewݣ $(0S #rIF UtfT H՝RLFK RB(!dQkPčcPB8Ls?~@"*3&U |vI:|P*ƅ:b϶8…,X7ɕ*wAԀ1̘匡C #*[c'Es L+F $)*npFTxD=DTx"@ -`|2DBĪ>T#Ssbē(]Tjw-W%̍OLk*^!HB U# m@Re$fycߦ{tLcǬ =bݒU!*ŕ%K]IHeuS,UHԲFɂUB/TS(I!NIJm3BB Չ+Jaث1S9\9l>qeZxV;+32HW ,2@)X7ٌFSJ1j@D8G֋3DJ܊H{Dj # {T.p^rN@c 2AufsGEj5crKف9l6TuHƲJ0HA$"THth?q 1u8F0԰m !{2HFd6UfDBU@IN]%,#3DO8tB`GDc HFHaF@}rblBo r3*Ieʟ>~!|hK n)Ov a9 $8NHtIq#xPyX`i 8PT'.g>*"D$s,Uꨭ óWqy!A F!bb ]0,Y]TT fr"1B*oLGL4DzI'fP䇍 ++j`$9?#"-^ #hW/|Nsl1 3-)3r˱%{R\9V$$ƾC1?~ܖYrΤ囷OTa뙸f)0`0{=hHZt)Y%< xF"Kr3T~hLF>4P@Smpy:7joC+=4$;UPH ͖9{REnG*DO\"8ʑ̍uI0B~jʔG4!Jh@mUv* @I4 NyR"֑">c&HC?Al Sc!H7'0I8 :\ieL- U꫁ 6<&$U21N5є!XqGGF5G=FI `5MWva*GQQ9Lj%%b))x`A\`X`+RO2s̏IT$ =ڸ++t΁zJDkT@h`$ ˆueV$]ie,8SC-Y [\o,̈g?|4xm zʙK}h吉!Zz:ILA:EAgQ'rS2(a@u H, +/>]cnӣU_(D%L$PYkiʴrSRH$$p@ЮGl^mIPOTIaf=g8ˬ}4HJT{ K>:oM)Ԍ"6ԪHZ@!ރQQDEʏ!Dz(%c6!ĔE~H7)֕t$N#Rru-hJ JڑVTH9PDrŗƻT`lnܒ\:>"r ItSetZ38Gg_Rv0?]"Eə&a3FF)ƅ;aA*@Y  %j*c߶f!#@-)1bf9h)Y@-ća+v~@ۙԎcH˼](i4_!PcRtՁ:2舀P FR5\\V\ ۰IɈY{%%6ῲ~7U"u&+?62A- >\3c\L(AMǴOϑfg$@o| xU5 Hդb,NI%C%7:᨝)I#@`ņĝu2jH73ahD a9[,qHDXv)nû l1( K| #?j{3zY;̿%U51|FH g.X%sRiAt @$UM}W(|pX kd ,l2lc %h䕉JlமXQ93-4A"%Tl&>Pij;/ʘ-+VRJ&@{v6g8/$KzgtX d)Wg oB*߸Vy]~.'(#'OWlBg9}'X/I-`ΧbTw_ )ʝAJXǰUbT>vc` IƲ1 J΀ `O~Y]c>Q<#A6bH 8` #Lh S8 VyTЩ@1gWBf02ԚP Oc?Ƅj=3>'$bW]pXL`芬*@Yv;l 0nOL YJ HɪFe,7_rWc>mL"&EmÀFO:T.UvUР'bSc$@;];h{),LVd bozeH ~S'?1\g 0Ͽt-1HJh< !CSUu? Is j00 ʡUv0i ë&trY %@ə<ILm{31 WtD, i1 1e9\3 2bL Ugm,K< >I@ tR#V1Ji_oTJJU՚<ȑoy_$V<`>4a!m]R 0T)\USlo]!u u*r~)VT`3ރF$#|ԮFsMK$! deKl:!yXmъÐk#@K-Lr'mLQ건,C3 @UZ'ՈG`jIFUVll D=!P{ϯ'g@q0F"HSa+,sȡ}!idUbJ@J>1`Ys3Mi4,j|сw,AY#Ơ~QwC#3W&|e*Hθl* wE b7ő ze,KخA *T疞`zt]9 9Pbq$;TI,rXF 4"4qJ`;RO\jTy Ȭ(lHX؏퍔7>9uA2izU CXAN,i cQ ȘYzsך$0J̘̀w*#88W`6>XA 6eBL夐:R?]UB|$}u28;e!X3`eU!u%،|Xj ԏr܀381?YX2xljޣVF| g+.Iϻd0>HPJdٟuLv~}RwDXX3H#j=AP,[$ΝHf؟mCv:U}C>J ~)y"$TјWX+a0>PdŶ:*0,8]2dV|#H#U7b93=3ԪQc@##ts|rCp""y?pY\pXx Q{J6% W?e.F=#*5B;r/#,(u` ݾG Tads Yc%>)$Caֆ_hZb! ,{迣Fp(laWmQB r"6ʉsRQʚX#wL_BՂ-쎲t4)bFv2%Y%Uo6LV˨#+T%f$\U`@Y &U@C o]Tu2K,hJ{ПKC:qK&P~ Gxw3 FjܫǕ#v[:0,l2űJ)S/B8 FQZYD<_-Iiy(mI :Fq=):D Ӹ@CIxaAd, djlVX.-'1ˠXWg };fg5hy:{Z*.ܑ鑒,WdzCDǏu1.lF!a[Y^ e!\ 8 Z%*lY̔ЈrE-+E.zouIl-|}p&s(A/ _lYO a9ĉ1}Ğf{:fNU!9J*7b5UDWf \Cj.p:eshKXRs2 ;F2jc3۵(Yd}ݤG"X9[) 5?"u~AJM|aq:׎Ljl.,Dմ)2C^=KvƂN3!Et.M Y,e5/gu該ߎ.U0SZ6権Jx+f |!CsI$E^ L)( VBx{yI lmTch3GDRDBHL6+ ҢCܰĪ| I޲5ZtLe,L+P~1{љ59#'E5.PHBQ(2ճ(V?G:[M3._0$悓ypWGN酵J-4.Q@I = _SCR*]譆 `I1{&nmahD]1\01FīS+eS2J!!DT]H|17!<{A#;]ZU_8`X)o'ш*fX@f ̿Uwf#RǸ:-NIg>];Qh@~ڙݪAQ|F J$@}q[ +|+f Ɯj骅r’Ԓa_áP\RGV B iWX12DVlEU2DzF??1 wL@G#9&c6,XD՘(nP;Ud |Q:NаLC5=+%6I'b>1Z  (,[HS`y_#4HIfE`2 _XNX`)""6D`Duc'] fV_SrK26q 0Y:JM< R V 2g*rJLljC_e\Rs[,PYKbwU!6Ԍ+T9Q$XF&viJ@ eB FL%UdqG,XlP͏S8PYB$c7ca(eYvG FTݰ6VB]W$Xdvg},j[W`Y],^!- G(^"(y Ru(|~B#ċ$0Ie(]䢜|` )F gv Uec1"3:l M%s I0{K6!%PA 3ݻ̬O31[QȮ5! =X E/}$RKGUC ANARUfV|ch>+D{=p@3Rp$q+`AGm>%:y%!.@˱X!wG) U P||(`!UB@*9o#8-%GDO8bˍZ3P@K~L$c>Xf= 6K!pِG?.iؒ ]౏|\ +n: bU lvn@NUyF{m;aPF.A##+`]R )ڂ~*3փݩ2[HH賤RK љ|>%$W;kG ~fSq.by /bJta$9w%vV_rCswN'T B_0$o}sR[V@%7lm$*Yaq%G?tu } @u |߬OOc9_s˨kւ7׸=NG0y賍1ׯF.\#>,ag_UStNyX?r#M+MhB#Vfe*^Ym9?"Fm*4f*| e[H]EAeNt-ǜH5եdYE+ W򊯓pUmv  'pEk4W{i8df#tׂN]f1/j6Cv)R(WWfR˳F0lĶ8CZ0igK!t0dhcoWh+=ĥxy]6,#_@U5J!%vطR6oR֛btLFVUXu!FiVY"*#~ |yc5Ct (qܓ8@Ԛ@R‘ޣ"T:ţU Z0#*4ҡǩS!#q5S;Tpk#jQvX!d(M:wh`o7E15P*"+B\PG-:UU*!̡T* Uudngl;ZvI#1C t' QNqM8 22{~OLhª-L'@ 賻 M@ԠeYSALZRE2ȊT %\€ޞ9lCqcHvzx? !λ,r9v*{oi7`$dFM<00bְıݿFE,>rFZI2|8=b/A;Tfyy1I+K~Ť9r,$:Nھ?$m_Ի8D1`4`B`|)J&!՜1Wf^ [e'oPeӕ"81IJ@uUSmP5Em~"UdLc$G-{}p?t;eB4+ prKH R ca-[,P,Vo"Ywb2!uBU[52G"sڎ0v]Lj,Ce[b 1~JKk%h΄PA ;(r}+z> 1FK$Hʤ(8ǜY_#P"#;THD"0*{eq @'ET@ HIecUrůS=:@, )eybRc#7218vM0bURA~`Abct*&d>t^8ALJ ,Y*eX's"+4YϪH5aGe*Š]=VbĹ0_ʕmC2o>p$#3#%LpJpxc ħ #scOD;F șV%A]BՆOu3*5': Uu,*2ǶIH‚m0IQ(h/ PߒY0$u@6W1EF\| ?c1 A>| G<ӢIQ JȤI3} PB*\a`qrʂ.ʐ}"6 ?@$fNvF"pT60#9. -_83&@8p `f}O^e8J೪9Sy d@6>T2ѢDBfo<\TajqUi5A*#&&Y㡤-*RG‚A!OzHzO$'$FmBE1Πۗvpʡ0-LM g2D|u>%JQHC$>3ˏ`5Q(t$,n6'£p ,h *'97n@. C #$GRʻ\)Ƣ^4AFpT_fF`uouK/"ڦ` TCpQ@F B0A?y''k0*V@Mj`sۀ_Kƪpo㒣])DS%\T.4A߸V6RT'M=){礔#e,ǶGqBHWl  0KR{qIӤ'S"8]GC+9 5P.p xBje2h2e'&+NS; ;DOE~+{#q߿B8ֳNNƪ6v:bclO <6CXY("$F mVrۏ/*I2U/-@`N~>]gEw2C(nXd NT<,!{7vlA4|V]˵Ғ URB2On2Jעd"&>dĘ7%˭ŒΝPTGrLc'eܟc_Cur1ƛ:e.{IPaIV[)֏0j#a!l 02ʡc~rY-[@@o`=} ު#*LqY9-.@8&Gq:gβIyykM"Fр`Xi6$T]RU%;i jFFQHnU>PXb6jEKH7G#2T 2=4YvORugfsampC+ ^֫I55 h@DPn'zGHД>.9cuϪUp-R_k 9 Er%"8wTH`,K-t:i{bTfXR6`|_On^iXdkS#̴I;Ng~GpID,[5fc0`G|.#: y91\bvGO"{^J[G;2੗l+jMU?Bv@+7guE$ Q\$ӺYJLedqF#_$b.* * Ħ[1ϰ1p>,CSگlQPx=ضʪ=1>2EN5*J!` S1_J3:#t>E vb+CX̌eD\Gr8N$́#q ƟA'I JD0vٔU50y$\ Lg d«gR{3cƢʃh+lHxpK1>ǂ>ժ[c%: o_4ݙf#:}UXbW&OP|%tʒ?Ѷ$l TlAaҶB))\;* 8$H F `Hs Ak(YœoRH_9 ɳz` 0^$ |H@9oPx뜮uFˣJ(>Q$ * F1%SAĬDC'vff H²`~DwVٵv.pY9hU‚02 b쟅y % }X)`P`f)C!}cu*/W,W6beFԠԖe2@PB'MoQr. g J%u_))bdȌLڠdL ~50=; 3> Ju]Mr.lU\9I+pv̥Wl6 K! k&XM&%f,]>X6<2 HS>I4 +c_vbK.radB""'힣.si;$J5 |.~+v\AJVc5TՔ0RTv,ŸSdP'# P0Vӹ/yAhʮڀBG` JI@QO$1#T.I@s=*JX噲@l2Īlu^ە9P ޢP ˁUt(`70BEq,P[U) Yi(P6@oʹȎDv9=NP7`<=q?)  Y3.!Bb ²#vbcK$A \wEF&0Jꄀ4i&'`bDY]Z$Pjumd (2l`SU]dxú1KF[R@ɳPW\jMDG?(c8Rs}]tv5cZ%ğ$JU@uYK v98m[V:h8,ݵUeee}!X87x˄+vfl1Y%4d H*7@d2O??n))Q$r86LF :ϫ:MPW.uK*"QIbXvVJ$$ ٵQ;0PcĞYΎά]\`Ilo/䔫b4uƆ2YRٕ`_+ V̫pCTP>'AUpJ 0I1*Ŷq xHc(bE1q؉2 2L4HuGr++>J*I!c9V,`1;o=J :d0O 2nf(DiY[B`#F0bcQĕgߚF!#&*?,[C!FmX@?uHGp är@>g8UD+2H1c3˭IO)@1/38P@<}fOˣі{joX4i+V).j͚"ɳC `Io۪029WvPu$ԯ?GuǥͪxIcNc2 z xԬd%bpHw|CH Ovke[ eFFVp3M\=*;d]㪙ზ,3y#FhaҚDP+~]0HbWwB3]DU8U j邜'y#$@c!?R XvI<W*ѓnkS#G` 39$uj^.ƶGpYJ~JtWUu$+Q=Mš|rzeiU@B$:$9f]Yd,:O  A(@˷zCg *l](#0Ȅɐ !y֋\Kn'$mm째Wo}C};Ỏ'_{%9t&xi蹍Z5;XݮYenꅖc,Pb4fW=>ejNpdz ʲ ;ju%}STrOgQMm$ԵK`D"Y$8qlf+[PdVy(\:HlMNce`yAbLOD 7'2o<f3֣#3buV) rI-C~<ǥ* ^O"@GaVy^!p` rm,+ ;!1t1Kd^gt58bղInH%Jti%FX-%ɆLu i`|Z1巍džJ<'2o>t]3t v2`w3#g}dgx,aShm4XE(.m4X[i!I2 ɕf Dž0#7IljHxجi"J%1PB?615\DYA \ȠUC7*[?0ۙY^ dt8bHodE9h&>Um0.³r"dH2p9v|V_cl?lꍂuA fyoT2%f?”TR)lTFPIz.݊y1۾==q8*Xv3DynJIYa&rNH YIUWbCc9U4RPgWya`©}K+8ό`l}$RM!Iwc$ٱwFL@؃*WU$Ɯĉa[RġBUf(0KFiuA&#Ydz%rRT$e1e;H!;ge2~VJ[fB଀ Kx`Al-T~VTU-axZxt@%00+Dms#^},M!aT` _B[OdC"LFXvp`&R1~()*QK5+'Ȗ0cRC2RYGp*]M*#*w2ogerʶ,5!Y+PLNH`9*AOs~eY]$ -vf V#EFVO(YS7f/mav TG,!7$U3L" IHʫLI yK*,#ʬlY"HV;xʑX[8]l@gI !vgiH C6tBRPH29Hў@K +8#ov%6.P`~}4 ;z:/FuEhbgFw'ʩa̩)iEXT#,¸Ebda >r )Se&d"< Ău`$ GA Hޣ>3q$Q}?^j꺫nŋTV|+`IC*@H1 1-l&3B$,UAr# WR XFRNuR$[seV x?u 1'<+z8 Dtj#0Yp'rqb?JgbS[ɑXmÙ"V.gV.2J] )6W . Fƍ4, ;l38* $RV 2 Ot#@nz DݔX[wpBJaʛb8" }=NL^@rS'V!|ϺC*$s:vv}`:@+.Yj\T ]0e;؍L G Cl$$̧b<h˟A`G&>.2""ͅ.`@DS;xv0aCy P-Ȩ,aH*@>(0r4R߹dPߖ`J@$-AB5R xiDq<r$nT XwS_b #@8_Pя^zoZLqFuPggXbrb6!*6egW†wi| Ԃ-Dh7,9$\.`(VFUْAQU/#WFe^LFG w{{~ ($A~}9\Y$2C0ID0J쁽96#\U!."As!8 |'Q $Q"~YY!O1?0 ˨,|xLwvl,jN8]_1זOfDp@Y#"v(ՋeسXj~S܈“ -< $q=hzMO,̧@="W$`zRdD'm4@,#4"HXI)aWmp"XaŜ0I*~IȢkNԒ4i:?#$3F*+&9l2uN;F͙XDFw,pAF1xΟ+YZǪ"r xiw V 5@=̫H sM_H'{ِK35WH;W( 7pYQ2e͗@$3SQLu FXJC$P .V8eX]cؤVY_CVKFXWF@`#3̫%jA$"uaS9V s2V"l>b0:'`U*QP.{?1=[/CU&w(srʡ"*2 S.q9=@`ͷ| 8nڰ;=,VUx_BUClG,f #ɕLHmrsJ'bqYeĖgo?e}'R=H;u4w(%Qv ,di6._Qʤx܊9!L ϜsW*LF>  ck6>Ǩ>˘^^2%]g-L#UU`ջәGyԀ1`@: xϳ~X'oi\*4Fhĭ)2|eZvPX];5ӉOgX8yDl 4" u;e!2=8k+Dڄ$ed´B Z5n8,형#ؐP]H Xxb'cjL zC$f r'=p;w  L ?t_rE ig d@$ CݪEسI T_@K`g\\bcV2m{5!ꭒ3 ! ٔNʽ[ܖalA([TͼZ}\cwnF~fdQQժG1VF`'9ǁ# $|E) I: Uw֝[R8w]6:ڸql3j#8pNI >Lr{#׊BGq;\RU YA K3HC(QL`3FBL"LAR( I KPDxJ,dc`쫂BEIx~)=x~e O2ېgA "FIO$gQwJ,P #Uq䢯A YWlutv BDI#3II{LL>)y_DYl;j2ϖ@ɀ`ԗO,o#J[?,RR@\3$&BM* 41#R`83cD2%fÒ U@ 4I&FD|#x8J `^x?]aXYQdYz4$#dv ]Sep\Q$YbeLȎfq}T0`󪲀G P3*329P՗QS ]4K.ϨPVm <)*ɛˁcv8u0$ 91*e$a21@_Hbq!K)=ǒ= ԫ b_U!b㆝5@!g8-bS9 !HHĨ̅#3> ()?f#ٌ̓1Gn:*xw#r)2  WԹ8\r߸|8p0 oyM+Y0XB>pIv qծUFe \pb "U`TNXUUqvwI&?, )pB@F?a6XpB9Y. u0 $UR8'xt!S"X&K߄1g $L% qccܰI:H͕m2fRX+{G?oQ@# ^>qxEtX{,>1*18:r<Ʈ$\0t\$#{6I X{jzv$nNW2sXu:妀 f\*PT`5}F1__L=6q" _Nѣp24PȪY_f( G@*dL5yXIkUdXU$nh$*JU2–@Q3tYH+"iYP49S@ a1pPYG_S2#"3=כ7G?^TJxP: ³mؕ7HVBTeV`X (* ,+J@R@` Xƨpp>X;$䃀>猎!ќ~@R1tA0lA8@TphYFdhNήI \6{"Y[lՋ:{KJGPG`+f%K{( [o28fC 8zHVf1>~`K,H*;J9 5,HvoD_!@|`1SU`˲="bB6Y#Pp03 "lF7|ly+x=Ĭd(A$@ Uv`H>Clp3)J'z q~=5P#p&=HъfKs@B.cB ؐJ.Sa"Șce X2 $j:; YeHl(@g‘ObfIL@dd` ,j6*AS7+:aQ@*/  oLϯNB&Ub5qhOkSJFv@}aG ʊb@϶YuPWT*"y|eؕ,rP RXc5^cvceq# ϐ U5N@.=GZ>n1Ӧ |>7ҥmRE؜H,2چJlƶ/fF,5lS%|W j c*֊fz`Bw#;g`2Z UPWfR[ Y$}؄6WTe\)8@ jD"Ap|xĖjH-Y;BYOqlQ i*Cl,㶸E'Ns5wOx!bDcʃlG8-q'H ~U RLje#fU]݂Mbv&P7tG$ݴsUgTNiu1REDC#!㑇w+DXc \G:=fubJ)m+L*s%?i5BX(/hw]ne`˃IfSp=-+aA}&(u" bc;>  n:d p ;(1v9G3ʙn%Ŏ^C"%\`N5yO0dNє(8e!0Ԇ8o6d5 @I2jRlѝXF\9fBaҟs*x{ojAtןn*?iOQgXcd@{qXJՈU1Ί+1 %jN!US#!.͝wb;T]4dmqU$mH҃/@(F|Tx?gY%)V4WG =Sp< [YzZ`=I3jK0AWxQh)V ZH\A\~u?;IfHh3:U$`ƏQ+0>Y4u"ZyM)MQS$`63G\}+nM<%4QŪUfYt%ؠɮU#X̕| ²Rҝ #ϩ*PYIm]|o/Uw[1  HF:Pb`wȌ#I,T)UCL(J"j bs"uRC3ʣRB@$6@`z@Y* WĎ aU.xU]'*Bb (.(F;c$*"Co21mMVKWU#1ɃL~b"{3|S<j)b¨ 8=`G?Pt")i('i#2f:>` Tv$1VM<2Zq8g7Rͯ#!b L*+ BBr$ ̫bK?g2B$f)@DYrIXdy$'Q`X$R @=x?_NpL8ZL,a`"D[8\+x; FW𲬧PgM lX lFCTIJ *nP2ǫF -u 1FGPƅw6 M BHOvz GlLtM=7jEeRISsƪXb !f َ @_2k. \v PrI"`.{"I\HYd.YH*čV)4 !3|ave( nIa^3u20UI!G .\ upp@fu,`*FA +@ @Qfтd4o PB e8A G<Ŝp=¨|`1 01LO|=}''"hVP `*~pNHG# 6.Ν8XՈ)$KH^F,eܩ*c!#BQRCU(4,W;+%u*I+H.&鿋s#۠(Sn. &$qd(b[R j5* ABu! F dԲKaC"3cZRcwrq#BJJvː8 FrW܈ # w|:O&WJr]Q2 ~C.ϮY~=Hd1+fL K+"lC1R᤭w.Yw, )pXg_YݙLذ`bYjTeu?H1A2[>A>rˡ(6]e }:TxbX  =f6*HDbc@w19+yI^EFdE lRxՐl N`US$u%s\Kec(K$2Q3K2%vg̪wLƅ'+QI ]XgxtSA #jCeUʜX0! MBm] qR6eNt2(pbN20+ *]l-qCgT A%T #8K"D={1>ʁuf#r(NYUTڌmAUt5M`4e@feF%|Ky"7f>l .ip×_$]F *ԅ (Kx}K T:A9dAGaQyt c9 qᤫYD$n;01ERTΠAs"V9R`ù Q!`P$c$ d)h̦wf&FgH[e+FPS uQ?rbH"c؈8CC= }S&lAgշtB2]l[p0ʟXQbbQA=HO DTteUW(SrU]#7_nӱUR2)vDb *D "d OF6 NWSM:t*g Iq4Ωk͒9O5;U+oƱ808?`#H9e: P]UDe{y)ȍ.M'$exPX,|I/G-j;J(U8IIёc }Y38E5jQ%N7&98)ߤ6p2$vVIتd+Ә0Ȯ?O/sG99 SHi0#ӿkLdxyV RBB?Tk!"9$M9fxvqV BB14!%jDL'SV9q9wnGdp;y} 'j%1`ٶ_ , zRjDDOH q;T] >C{gp"!9b*Lw~+XȥOѺv"\bIq*ܕSMQuT;)$8+::wc-%GEhi'#3wwv;6nvVCEL:t#+4ksuIFY0qCs랫|*U`#ຬa} =itz]gB5=$2G4`LrǕ`k,ِ (lU(5G ?4{QhYfCh0 g-Y-21b,bvhŘ?$)rď0. a{:~V 9;\LnAKU,Sذ$`6$ .>!޴ᝥ}r@c«2弓p1Cx4kS3D2IQQ9$7RY(S<)?sT3cHF aˀ%asb ك|{<9]}Q3nʫU<`hcf0 +#KVV1&52 #$$6W?y*H#(L;2żO HFE%KeB@T0!U?<.ICG@/[O8l0dT_>ʐwe P,2?X K=5`HRUWA$ni#HԂYNCNCAWx^1ڣJ=$36Q8S;13F1N?QMbg}z<5STRl/D:axy#PĀKP :* jkFhђ@bfԠٗbcKβLL1#mٶ,]G0"I8\z?N=cK4EHJ$g͖W,VeΊzV=j`RC8h%ru'lrT()bLݵ.یhpPH_PX꠫dj Ba(Vdl PQ2$DT85XsG~H:PI0`vN~dUljA^U <q<<:TGVrF\*r w{I\)U!]wM fՃ&@,5e>Y\lO,E4<.# ) gىV@zϴ0?ˤ/|yzc<`J׸?x9̄$߀Hu@D_;L ._%9EU4-N٢dݝB)[ ,v- SxI3SI4&nB@bY4N}Nq0$7mT 0n%vqG l\~@hK fl|/feyjNJ?2LCO.g9 ˕ ĭeE]Έt+*샹4MFFߴAv8*N@Ì  EO'=r~1c"ԤCb5=-* de +Ӿјefs4rgV 1#mBbsq)$0Pl ;#IcȌUG8lPP\Ie/R72D"2p@ynpL1䰍ZbpHђE$)RuC9h)< ᙈ$1"A!Y91cTZH_ Υ)Y"wFE ;3+(!ScH ~_2O|_]&#E3*+2He@bdsSfbO⏖Y+!-1yŕ+I Ė]'IUC캣Ì) sB@j$ Ϊ.wL4  𣷓}5>~F,b1": {Å' Ȗ lH^PVe N}Iπ&Fԓ}"8Ce$|"HNqgJf LaB(@\`+Pe ~'&"Uy dL#2=@vetqF\4ql#ؤd #3} \ܒZgZ% 9,f`MA8'pTi$~Ǥ2:]/w D}`t殑@A< tSoR hY*~GfB+5?*3*b@X YP_au&FrMB򍊠RD 9S.K WS9vw I0`T*F@Rt5dx0 9ZN[?\DbG^NAwJ$Nj+FܻBP9I6Uؐ+{*f'vYXyI jJP>JDɽ],;F(B*d;vB| 5mU,VW,=uoʉ?Ka"Zs0̱"083V-0E0c*OasI%-e%PBT6?*YS Caas44.UPZdP˝S#oJѤHq*ul)4N\jJ1`,% fx葑t 64Ӧ6vg`5.Xexq$Z0bDcgkykyH#~P{z [.^fm6HU9 STW2ǔٛ)Þ>UR#U1I%Y30>+2[*nۅ1QZ$I4K?TL T!%,6sY;|@/5UV9A&G"@I #PphJ~G;v躚6 h8؁ثbU PT̡uu>fSS*:Hz*\lfBLa$` UUs:c-&%RBsmY!{Pŏ.˙E ;MBb%Bkr{F8epwسCH\3,nh2&@" =jQ~ >Q0`D ,k0®HH/|_ qF qV~/j v rU+;1UG"PTuD|:) W/F@>T$\z36ŏ yd4P2eW._͗RS𪪓w+19ǩ?CEة~O`(TVLrNzS?{D:{tI$r"AʸUVWc8vm@ ITXpi;XфgK/b:E?UHVqIuQ'iu jej)$CO9BHGx>VGb00Fs~Iz#8H# $S8> a=heu=7Of*3F @=ȹ)mqrR]2 (rKFCF@bWm}X>_BF*3C/Uu-ޑQd9ɐ(XcDuU \V,0$s,{ ,oL` õ5J0ٝd|cT6{wigJ30T p J1MPyOq"C*.w|5*E۩C"eՋb]Ϊ_$;ɂ>whT1i6VbU@:I5@#8:hS8bӯP]@rbn 2v>*41!7‰y5ycy΀m]&Bw` jR 2`&JaT%A$/{t Sq4Wd: 0 'b`ӯr{&98=z`¬/gbLJʠScUb WSS9[1!Ąn@C. -֊CٖR*@p/Xd H$3/B@U+c)1`O"~}g50  7© !&Ϊl0\J"*p[J$\Աy"f̀;1F`JTS(cFLS \|y`C{ |~Q$9=>?^Tǯ?:%?S *ge&İGU'PHʤLrAU*+%FyCnIR>6J"1b16IƅU@ B1#T'I2DwC4lp_\X*q?Ӥyf:/ c(PҐ0,50v# xEXR0lW!ٔ @ \GEԢD{.$H.hI 4H 9b4pp`1T$1Ղ,T(2cI`N>NVcIwP v%î}Fr`'yLca<X1B2tB3mK3E(PlmVdcBKG$t¶X- ⍎TS|l@%DAX<~ӃqF{zǯvhh4-"caQx/hS'9`lQ3fde C8V:ύXduy]/,)LQT,r7h2/gC"$B 7_oK eRT ˠBIx.S#OԵDju eЌ~ޛWSoJʎp="|BV/Ǥ !uYL9gewWo p V zuƤG1A,I>bqO3i7lO]8*rc&=?׮pbU+)yPbl*> zI #Q@_];*uH}cfVX [l7p>e=4Rii W2A$.ɑ _s?&yX7A1"3F}si-v]XJ$Е *Xp*'U/KDIHt.JƇ*PUT$,,!R) 2Q3õ$$.oBKl ]IvR-Y¤yg۞U`na9`9JҴ`)Jc/`%J\Ǜ,VwhS"1G .lCs:eZrxg;#Sf`/rtH?LH$Pd )ݖ &sр8vVAvJtsN~~_~/I8c~7ѫ+VUΌ+([e]i>jN²q"rm > Bl+aA% ,H(#?yea,,#6˺U\DkdǶFU( YXppYK S9`|2wjhܖw6Z̻s>)>B@5j AE+jŐ;ui;4 1muQ4.A8Q3 rۈ1k[h@>SAO&{Aۢ;O~8$+ @^у߫cv*SM b>IT9.hW%chݣ÷}ljjPL.uI ZOBz᝷! d\Ƣ}w說G4 F UJ)@$FbObd7gMHx\f3l|P0BI32:yjM9hF=h/3l2dW*??WyO_0U\v%RIeJUCeU#@FJC̑chhUat]rWٻO>ɠCNU@TUĀ̅q|6)n'Zw3EWuz[pCC(*T%i l"BPdnv(b}-9s`j\)$.UAdnnGպq DHM*vggR:aXW-d嗆fhՁƻFAYA!De NMgO fR-;D۶f=F*EZ8 "x&>RqFʁ#eWR@zJ-SaQ$:ƬHZ0Y"vwԷ~&!_QA}PsmN=O UibSI"Hެ]cb)Q}R6iNVdf͢93 t;2PS xӸHxw| @`Ad)WZz4+x ̇ $D 1f*0Uq/jN AKvԟo{g-a1OKWVluiRQUt+}Lyiਊq1WrA Sb2#L - $%" U$Iuhs锽q_,%e=e_oZc.)(x4TUpLa_*]U7197O9}=wYb =Nd1beuP${|֕-3d3x+u{?,7$o_SUIwvUv 69%sT-'>I,lOw{cDh*bL `CwR" ;_hROb,WRF'e$Z&Գe}e eV)~ C>3ԼZ.L[GsE.BtOv"K,|zƭPҶCd6YH>~nbZe#΢mL!1B@-9PE_zeg{1, Ya.'p!x<]D54wb I\1#y>ߨۅx~ROz}G}T(2"n$:C"Tj@#Ԍ@tKl`0UU t>+lkLu1dhl@9U1Cƥ t- nEXg) rk]=#S'& "cۮg`Nvu1KI0Z7?IYcXaQKòuEQYw  J"((C矚#en+T1fH͒UC8L1'!pW&tQ2 HY `bqG-)(!nX1pdd8[xb0|@M+ۀ0Wh]ӵ9GSXepZ9;8#z$eUSsP2M<+ee^ʵ&]r@X3@M~hq$[xtw $S)6?F)h8\m Qe)&Lhvbː igD60VX""!4ObK`5xbg~?d t('d*#VI$\2 q,Rʧ+B27 >s.chFS/'b]T4ET0`iJ(t: \|N8ԎČLr;XmKȏ-:3c%r0j-(+Z$A<' K`?" I--21$߬I씴~)A;UR DU-Ǹ}RkeNr%Ya%JJJC q.{bԏ"$]<` UPe!I2mf !gQ~r`_O* z*@+w)mDzJo;r J1 [YTWԫ*3+JyRIU/#D7_ض@(G2nagEAߤ$ Ib LhH1Y-M(9>;EǀS lhP!*2R Zf KZ/;@33'o HLxd4KUn4N-3qWEPLძH]K{wz2H)idI'\ F1t|g%CihQ.f(Nv ޜh"+qN5l4 *$rȠ|_MT$’Ł% }H۴ g=89hMb5ēC98RJ+* P1?M(A.&esV #%tlprjN/\  mY{ 6fl{7ωK+xQhmwc_6?E$y_5exoNe'zU9'8㯇lX1:P>Nq/NS!Ef R#gWS84^uyUq0/3Gb*jI:|jn;+ԒX T(Rt!as)?*uu+x 8 œ܆$;`#pkD| @$y$ OFP0,@5TvOYt^kS ǎ~POGW'_m7ۇQ񂤯p 2#Okn+ߵ&6j% Vpœ?>ueA^B$Gy!wJ:"pX(ڍtvqL)K9T+f\jmxAǬg6]ԅB!cQeA*'- Yb\jPYIy؃kKkM$;~!@LH݉#3LjG4YTޜ$;d@=fo?boJw,cr})ix+6KQ#U&N}Na ~|* D"Ȯ%MNhkc iHPeW%N ʌlg'{QST^FD4Q?$N'AϯI"bcKDLOI$̐:z1$VXg2cPJv^l"]6fF8(gqoMFZ6gP.bD 4%ڕAkU;Kh F5zG~TVR XAd`#]K?SqH>,隞% *0 ɏ$ y3ghGdnuU1G+8 )X1&hOYNvLkԫą| GpSF+R̠R@cʀ 'dĊ4@*C:`*A+RV" V19(:<Ξ+s|Nz|SӣOuq%,C"e8֘ Bb@uЃQ?'$9Bic=*8J*A,Sl bt$2jYkoriV0%{FS0u]ZYٝ1QJяwu.EËM0$Z9UfXDP*hi`A fds83 ``hx*"?-@0x:Pzd꥛|q+G_ejkMEC3w%fj9)y]*RVy\;lwN n+/ Wvb-CɝTd[Ppڌ)˅fRr2mٻ5 ![$V2 EiRFN6 &>c>&I-NS77*UBBǾ`:.aNz$e}EV_h*>$hU lT8WœҫTXwKؓ~_Ԝ*+]ʞk HImEN\jj"Bћ?y]t`zE$TapBC{5g̹*)AxHYDq RE( VJQQQI"]^#6ս1Hsd(B#C h),\Dm9\HO?bsOxjҶ_l_UcIT# i;{r)cDσAR^L 3vؕ,`Olv?#P Ieu F8cR!5Gi+xb8VqE֦*QHea3ZoO|#y}\6袨!Ҏ4ndby2;Kמ  i*ptxeWeeP\.Jaw@3qP %* GpP5g9ie, `>r,-EPQHQA #=YՕj׵+9qMU@Lh=ݐMw N0չXZ#`i#W|v鱓Q#0-7 KN5I\+,)Hvh 0j lLݷ C1$lg:FWU$,Aټ65VO4푷c  w;'_j]V9nSf(YO䆻2(?>r!eM<&&QVD2KN} mwҡ Ճ ٱ?buS$ڸɸЕO n%_;6hI_P?˥/ٰsj`Z;O9>n~ݺdmFH#! z ;+/rO.e 8c +z2f~awrd8rX()eVu;|V%Y)UXwY1;eǀlJU~9?OnO#g`A fHu3K0N.3<}A{ʝAlŰś/ѕaVzr#sN9Uz0\08bKJL(H;RW+RVu'q`@YaIr2}MeD\qةta{Pu3}q,!vs~>Q |;FX)јkWUQ!啋3#؆FRg jH3!M#(YY6 Z0څZ|` N$=.?n8pi;[oBV1]18L! 䲨A6B #}WGL d5xYpH`@ yVA.ܑorr%60 %rX{zd" Ý,\U6l ~1"{^gt`DrNxP=[to7oLTWݙ.IbGH Κ$NcX؋#U J֠ #؏rWe] [`ތ ԑ*g`"K ]eؔWg ~A#>ΨLө"G$DO[tG8zGtЖNib9-#:^C1_V ls> 5df騎&;!]#r" \ S"HkWHZLRN̨/%N? l>GqvHWPGyc#%| \T2g$OAΏDEͲb$ȮO?Y3҈P!L,x X;|EeRyǶq#~C$ !rR% EʗNQ8|baMqrCH6XBkn2h ONt; AL4 0wv;[g WO]X8r:R 8jcq@V4iX 4\ */.ڣ>1u-rĀ2vŔW K."A0X.I#o crŀkRfo,r ,,Tjs2#rTP9ssbŃ_W(VKIm%AY=m ~}[̝vb6U\U82a3X=S,k@FHB;*m,KaE!U8’qv "IpΪ Hb;@TJR sG٥mHwB{gwN1g/Gnq|FYҁTjY5\eH`j@fP$bGଭ#ξ]c%N<QJ Pb}6`| NHëcD|Lq{p}X@ rL"%%;c"sj?SFXvQĤKMaX#j<\o" Vr2R2QZ1h%Dǐ*q D"pMaVr=b4/#84usڣGW]ZB 6,Iʩud&?/!ʹWҼjY#:3~[45mx8v ʚF{3' ϴj,/ᦸpy=Zx ,DyFHE (ļxpVc` .g߬mSlWSO:w%VR bjdIDo;!Ё:ē :@(}}F9x&GY TUuJvUJ LOܑN6F֩Jr0Z4 ""o_UbQ Kk97Pז mvJ|Z[HQۊ8"UP>p᧚J;d륍On#V%,SlbSڢ)F誧؀2%}-A'yj@ `x8/$9gI{GA!dQJh֪FYVDY}*M cmR'L}G=פ(ѥN*Gm IjSH@0608<ջ}V]63@ifD(VOH%S6u=Qu,M%RlЖak}t(< - RL$43M0Y^jrT*I#)x9|m-qalPpX*.#oUU#lz*=hPR 13na`čH HA_YUBq@GSu'Xe[E]XURI<|k44T/lHImRk]QKJRU뚌AM] eR'P~R#g\@I-T_-Ɉ,uPXR 󦥀9 n\oA?.7P.N'˵qw+TT@’iuQ#*Ď7ސu ԝ<\ef)V)nSA!i ""ZUՏɖ&nҢ}R_ cepZ7Tѫ^i"TF[pAg/Rpzvdd.ʱW3F@Leoa t6)WyOU՞BVՖlj9 TU%TSPFA VhUo^GK%5*'7{gInGZZ ƑcgWH־6 5 UkU\QEJjTD OĘt(C2 "1 W. $0~IPW J* $8 Ԩ~}LF>MҞ]}AcGɸ=]T=m٨**l4}]OS]6=IOoǨ# ytoF[OymF̲EF^S a m0+ `HyZE2I>_El HĬJ]YоW1pR͐YiaM5-_WŸm?!q*ksib^)0i*%$G'ɥONU踗\K!\~ZeO2?BjkU۩mL;PVZ\:ڍ )fV[)-*Q*1{EURw0ee {qOת.rڍA;o@% .6P@S6"3l228elFVd\'^&ЮWخ##r*j) ^SܬI::zzHf3BcDkM^,"r+=]mTuQ)XhV j2gYkToim{F;*ףMi}ڝ(u*V>`7MB̃,S>X&IY C0rr88+% EaÉUCku r L`E@$*U\l@4Tq\c!*IT@zi3O+ug>I]Kij= 8q,3Ӫ5#ߨOLt:H@a U²>*$".U_rjHX6[Q8 u82ze{}QiK;2X mc()9% prW! #޸?&?_m#Zjj)'URwY-ʖAP#]);C8 @&@18#;Oע:]Κ$^*&(br #>Yݕ'+% Td$[v c/ԅQȪ)lȰfPH ~XB䒅DȑϨ |9*Œf]-JhLa\ r[_Pc(COxyqUCm~3' s1}Ѣ (vfWaL[ojiuaImWRmlb=J -u*B2ߧ!nʅ$̅HȌpHH%7BUJ|g'ƚԳ?) 11D$b5$aCA1QԆX3iI3%gS^(0I}"Ltz{r H /$no.#h%LI X,Iҭ7ѨBL*r !հp8eR K oدD,KKBT6do+@~ Q{0c _ 3(IQ #J5Q2* ?Lu |G0gcL+x=//%!ThT]CA&aIMXSǦp@->Y\Mp~ `bG%|#*=WWTF~k{(X2 77IXHV4*SQb̦*ܝF@XNOx ͂N18Z&E$'Gob`b#tåmOl=D>FB,U c-멙+2\bvѨ*Ec'(D(@C#1Bٯ3! V Tzw <M bP [`ީ1UYb,r!.h*m#4v - Ys1 Np +-iYT\t1V2dTmL{ùʦ#Xb\2@ ! GTAgtT%΂ =Ζ][OM_o^U5K/j)#h[|OG0( Oxɨ@6]0vsHZY$ؒYT0ˣ*@ QT*r M A"pA~ 2cOՃҮ3m'iqyU}r?K}7^i8uU]_(O-R({=MN.+؞fX}X=N=OtWx⼞R[ ݊+0yʏjN1?Ӟ~u9:OzM/Kt 7>Iȩժ355A41ּmGש/'@}B_.wu.nףY)+MDWkEPKLWD&值J)}xN{jזiX}ޝBֳTJ=vOQ5:8[p*"ԯʉ^IkA 1`ϯYыdd륯|C.]7.ܭO#SRO#KMHihl:K/']+9EQKέ${W,OPT"2CϾ i+f[QqOzx2L겲6!i=v]Uӹ#d県A$u'e @k _1}j}+ol` vɭNֲQjUB=F5<CnjTQCkTx)2Ď#xeo]6tn) ^Oq˝At5m]|e5)k"&I վu #QQyEx%H(` TUMeGy;Q ڸZk'_#j[]ͩKu6?sO,52Xx21}aUo,*T{qJVP+c<I<-~!kg--Z)U YZH&T E<&WYk"xQ S܂ Ȭ}}Fpa3{yڡzUu5dP4QCDNrt}oq4Qzh`M\Y7&N>[?Mzyc]oKs[:@-c:ԠZMںWwwk {Z ( oi̝DZk=We5*biop2B$Du?WS7qͪbVydm)(Fa*tVH$2$ԓGg쥞ël];¬:}p.RVVWO΍b%Z%wx$D@$ 查7_8 6s' &YƾέIxzHk e]_=3Hv j}}\u ;SD{(Ӥt*T Aj|.)},7+OJ f@% !A$Tw W.[7}=nX#ZJ9)#4qְ:He`xOr}~RF8)~/d:垨mMʲNb85VZ/;?4n-=?W嶏r^I,\n>)jE>uwڴ<-GzKJRPy*[:֖T0$ Ĝ 'q"OYYXwY8B8 6`2A[w<5F*׸kiXE7hnW~Q_j΁祒ZYcVyjB6EKg'-WWzk |RqWUG%MJB> /pK?k\ǍEo5̨8'*/ocScqQ_0@0c[ŭDiQ*]YYߒ&_,ҼP2a6~9dҖ i:HSTrw*s#'7 :}/N?5u=)Z5)%<%Cu.Zʄi~(Hx7X_ΚF\oīhtT=kW%D-SEm W &}XEa_ŗSqK3C_Xc\;4V껚):X̍RӵmDSfjס4 t(\ޥنV7P)lXಾ.4Tq~ $$a~4I*}%'i4a pTYJh)UL.^*iV.Ҟ FPʵiҤdwز3)^>˴Ԃp #UOTf:ɻdK;yኁ9S ;N^b*I X"<3~poSm4KUISwVZOJʚQPcwUye9]Xa8T>$`ی@9&'g\t;մ@" TQ*REJNCZ64MJuKBHpw,:2m VʑbPN#?ys8e)mˍ-U5T$<3U .KвPx!4iw6ŬZzJØh_1 -{Eڗnlve=ʶ RީWAOUGU;M$f OFX>եn\f \Dtz,-l ԰Y}QZΣ}AmmޥjU4j6Ce"-[M%E;Y1O뤍6 o2cp2@s=fl_((T8WxnYE=z1SLT5 V uam*W(&C{tUXQXdFp̲Jĝ+o%f'cWTO:+8\˨qYyo7~ VVZZ$h*5w?'֎ڇ˯>c*Z~-a{fn.R5^kR-5=Mmm4ILbjU?eԞ-vfh۵DsNҡrԙ*55dsLXJ^wnRN0 Ĝ$uGюq Q xY1$Ju3 @ =M A [),oUVX#wԸfH(,̀W8b! ~ko~ øOoCqNWmg44MP(<⎦SAh3/Kú˸E9MHĻ׼1VL,^eSǏ|a3HuyjQMBоZb ALmN[b0P _y_k7ִmG-[9USe; S G*Ҳ eK,N4ًcl? -w+O-[PC RJVm]NXF~ܮuwgIEJh(B< hf*?-7oꭴK95,J1Pv"6vFth$jA 'o=FF?>U)pwH& uuꭤPf-R͸%!mI?"\g i%gI eVyXiKdƟ}oRJN3ȩ&^u(0֭GQŗ38?Q{Ci*[t7 mMWGmii%UR4HM;Пҧ Xck_yN}+qVjtQVE*0YVeL笷Z]mB͘JԮј_c.gY¹گV *S)*cHi@f bYg?ޞu}] e+<+]ӓ2EKSMҖO5މ&h ;SLIo.G@@,O9égP#ُp=7پLBrFRvPW !b ^]}}]_joo [J4V´2ݪ#/( P7>`**x?^UN!$Me N}3#3S_@=>rfm~EfE۬=y%G\RZWzhY &BA$*ƁB!;Xz9R7.X\`j?euNWH5e\(RH X1|%?ڧևJ-9ҝj*UmQCMj  骞fA\. L=:~9-ZMʑ[5G,]fZ@*;nS#@0[JpvJ||5] _OԭtmT@I+8I z2֛=4<}/66ukζZjf^VV2EW sgk.tm UpUe;hqq$T*"NSiZ r3:uVqY389uR\RAi:c,J IRmفeLVvRkj5ٷX ro K5J,EjdA}O,duJ^G.;wxoN笽I 5V "Qg+k~I>}[~:,|Kut;=Ңo[^`j(+D6iM ߚ:dZ7R6 3ʸO+!+(*==HٞmIf 2B@;e2 6Ge6N]>@o;R[=AM* Q 6>BKuiY>u @P30|0z/cz{OI>w܊VmTcY8촼SK*?K-BA4UWiiMVߺ3㩜tZzcoBU\S-C޾c 8j(9 ר7m)-.ɒ]c,1R|*mU|:ߩ3D- Z:(FuF_EԶےG*Dj:jWz}6ޥ:%QMUGcZ;PFqqjJ0*;-GbjL:J2«10&0F7@03Xr@ .Rpmyj*fE$22e5~4MLvS%8W%Xdc*N2N y!*52QQ 1-/W Lx+״εNpJoDDkSFiNFc>9S2|ۗp'~C`ih4W+"&Dnj(ٚeu.YE[?gўyһUsK?؞*;W?OK55 w(R窴%Xv_lPE\ HK:&Pv8*]7\^OY9nwJD>Pol*u_7F*5ekܵԺ%K//UP[\[Tj]1*dHY_^:' Qp۝}4Ze=숕m^R,iVi)1yԣ5nu2oCx\R9֮>7sUZ\QU%T:yV &SVxNJ#bً7LTqB:>GG. (o11# :0,~vvx*~Ouo{@|m|iyjw|M.!Tw-kB]`+g$c'IX[RO㜮v?a9Z-EYOԻ7wj "EPY՞[orKժ*YoTV+hXnV]vPN7wSiԗ{mA⢞Rn/zF(ᯫ렒Q%\B8Icibceੈu*ģ1GN0,R|ejUlK]VY5 QQ!/+izᚾȷek.O1(i%hF& 2x—XTj 0xi,&Thg]MN} #K4kw0FVR W+4 ")/ FIUo$e쵊TӠi`m:nZev ag8<4;EK?,+$?V.Q+*ZzI`?b,rjVU~Qg$w: *< RNIp!G>AЂsN?un sOKJ{rYz/7&QizE%nXЬT3CP˝I#vb ږ5ռu, Nhwu]]|QMMfEmA|TRHXeo>~? g ]:yI-5M*)PӤDQc1 ׾VǗqdaNV§@-O QȣY`aPmqQB:գTjt7Jj5oja\_kJŻ]]$~ ~)']QGkNҷ;NugsneWKS̩.57 uNUS!X\$R4$EHqr.u*\?VR5hz⧆C{l (c@۫Aȿ2GNv@`BpJ˫V_*uA H(cgO×jӭu*үƵkZ%:ThRJOv\T.#R岠_)v7JV7޽oP`i4 |0L Dgw\ـƻ+cH#L'UYm/~M BL4+`Q$9%8ITm_bK Jxc;\UFPyq&]p?eiizVx))>wB۝,]Ooc?xYX'Al Qn 4YI榉7#Ea&!LP:Dwr>ۻ eXհ X%< ϫ9aH۴nwQB""M&#uF"5[8g]x7GA[k8qP4Z]// fC$񁏧Xťhw#R%3ݞqMޣI*:#%²Ff`{.AW?)ꅺ2Z.cuF2lV QHӕФ9s$aؔQF~#aU1JԔ1< orcNo @ mXqDHl=j?oDTRP;[8#}S}ˋB/uERP*hΚ*X'R ez[2F Hl5E۟1$CRm. bZWw ̎Ϫ2ȫUTNXdʛj'U9E*[PTjBӣv!֓8힤,ouELVY2J!Rʠ/VY*TCo$< &O veA*#Ym;\nėW6D+r|]qݧdpM#2mŗΧԪ+ /Oϡ@!df6hin֪bQ vhde<x 8.C.Uk,ii^GqSNb.#$*`ČAdāJ1F.dS w]]&c)nuJj#/RQ71 ;HXH $]*`TP1bNGԎkv%X'*I*&agf>O ̢r 1 |V< MeD $K>5]P:A`۰. ɡ-jXVG^ؾ](3*LrrYSuޖ !AKrG*cU*YwP"{O#Spg"&NycC:$؋g ҁU}lT{'ԥ(喖aHLVBq I;.3 e xk),(zVʹPRp%&#.$*AA|0ڀ1۹dps3> {{~GP▪Ȋ``dw3T]r9*C)VfmTf:w'lnY rɔObyDݚ eKeQdL_UPYTX쌱Jv fc {LBā C)`rZ 1g0x#`vzerP1YXNvpYP4Gnf5fA,-9B,WB > Ӊ IEiC*?ò+ l(fl*¸I#H3*v&XY[_5pG0=+zʑ$G&~]CjN 2p#؆*@ULPeT}.`CamFg*$TdIأ{J6 7Y5 qd_H8.U:LXxii#H5le'$ MQW2>3Ӣ#EO$K5ZB;jeBP* P$ bdcb< H:1m1y@jREgv!I#ݷ' ][#њLUƫ1.X೫ *ʶ1S*ŝ@0$sNn?z?1_"FPƪ >KqmXys :yUg>3]!8 a:K| P;QºȨ hԱr7 h,Or XcN`(*AP3(GWr=Zפ7iydU@U*Nm}$yF VBbT1R[~:t;!c Rq0N#]#+ݠ`Cv)v: I ] OGF>Ϥ;AA3#Y ,,\ald|63{DiT.C 8e`U ,r瓲3"ڏ?䐊̌H V?E0X2:Dv yw @^C7Cs=93)HO1?2< ']2!3 0є|5Yj2)BSR]12 5ZQ/!J0q3 H ;}>_^}G:o::($l,)\An2l# ("+!+F2uRO0Dp:&F-FrX+(`c5+Z'RW%0p3_SA ѫWʏQzB /IH,K\ؐc @?Ar]Ff'Nl4@>X \ ,5#*T*#rF(%cl@ b<+eA }?X\ܠs,$1p_ NAFXy)FgHpYʁ)Hmd0TmFFy jn9q jyLO!4MA! elr& y.D/̎Q\++i);AIG=i"cXL*Tu'1T"l&lԒ[A\U|8dHΧUe2!2ׅx5WiĆeMvxv9%iiPȌ4vd~dzjpsn1˪ٷpR9602 #A VV*BQsi}wgڑ鑋2ƿTw f8Y@Z،vPѵ;1cIvU!0ϗʜک#MZ!nrK*OKW%cYVuX@;HPߕ|j\=P?竎"̠ @R!UH]`J$)1Hf,Yd]?]KR b18UI 9I?Ӥ|GL,44j bHYI#j ꤏV'oed{RGɨ J(:; dž2?µp.t`woX6,c[b@ HPUl``edC {ĉ^z)#e8$9b0[ B"_(46Q )BeFTI!~IfǴtTa, !*vq\0?W4bTr7.F|t~~ut9߉q={>ӑ:eJvfd T+ $j0sMɘ!@d;dulF2 q٤XYUBU* ;)֢`IeUR-s"#\`vF<.]4sA:d#otGůcN;ڮNS F- AyBV@c!VaeAl+ !@g ȅHؤV2*:rumAcR}PPN@< f3x"a۟hOxMir,d4h'TaK~AƠ|>}D*g!fVBaPR몳eN0>esd`5Ewm*|0R6Ƣh݉$)YA9,0F9,QX8-wW {zCZ y(ՙ]t5$mK 9b_%=,49XC,3ol{ET Aec# !Q`6B|l. QB[Æ0,%(RR?/1FG=V\{ٍX@Zd.hRgP4F&0e11V]2_;͖PՔ VEReWsLjY:Is!" #CAY*HIWl\ E4sa|$bVpK >eHxj@pǫ}&=m>6*j4leNJm+E1HyYuز~ é6#"'p1-bRI*q3 r*J}T3JgB]BӢBP\Tf2xS 8eO2nφ_Up8BsMsDZXˁkB+d2> VA #=>R_S}X2]DFĮؐ2=LqF?aNfm|K-U.3wQ#Rky1,7]Do.R1pK6M\ian _pKg܌v]gѣFGu2?hݎ:&[S#2=H8ߪܷ*Tv,rlJ:l̶~4k#S'!m؝jr o~CU$bCeF6l}uٔx?~dW$͇*%*G+PvS'cq#_&)E\0PGT SQ,;u1o?W.Qأ9@Y. Ԧ+RGVb–D{e, IP%G@豬c$,T#&\rs|S& DǧsGꮢiwGn98{t~/miwIE=§2* h0.ͅ / X)#v 2,+1 `d 벖:!ux+M$1 P0_A)\ J=3";q똎6Iuԃ KJP؋ B;2T4m$q2&7,l !-`*If15;HF! P}X!&!|p DgH˫3nl,@ffKtX&X|)-8s"䑕 EG. iOrXmZU*B*!S{ 1 aXfGhKwu'Y̘uTRGR3 O|Y]eL` cԇbf؀s:`<'/ۡFI' 7eXefKd < z>ң!IgC!rF*c,f V ,U#;BE$^5eTRQ[$[ "82]6q~6)ēۏP1T;4  Ϲ _?=:0^ʎrqUr͐ rOѪU99i2hHR\#hT%>}2M+*KHOX#-BmH3=z۱& s6FՂɅzSwJ 26 @%eɈBJ d FC\S)슣9]T|b~:l`G`v2}xT1wyIcY0e`t!9>X,%%(܆*h`[WmP vD_V!qpG! 9V @rThwՀ. 6*t:`F˹Wr~ 6 |폠뤖$=}Ltt$ƴ6=PΥk ćpr,`9HWTOT?Wd)Q^!*Y0]2 qE:^"|9_r';/e;5UqnT '1HKlqa\KߦxoRU_W. ښ՛,i!`M5oo^ZU!*Fp\vR@Wp 9c['f0ReϕԓUeVK0MU]k*ZG3*!@Bv( l{ɸP @DBı`}`w=7s¶ʦRԜ,Z%oPiHy;fA.|ip-گCU~' v &32x$5]Iұᰙc%Bz0U%'l>~BISU2 ]*P qmS[z=&dPnFBb9C!*U)] }xbӪj%<QǻtjXy(.5DA G3U5U0G0,ˁ-2BPX+uJv$=p^1AOGEwTa@ D5IrUr:ԩT TdC&B8.FNռ [Xoj=!N*SMjи@rѡX G*ͅ+`B*ҪJm nY՘ 8"E])rF **=@|7F{rgE. 뻜 . )=cR1,P]V:M)JcH%1,[^!2HnACk7h상VJNzi1awWXRgBb81;IrPDɨ_r&# Fժ{wN+i4OV5Q, Ħ@*AǏ ĊxtHzDGwIoIW H1E6@ibz?gtጝ0#7,JPV"t$5ޅC3*RA$#+7̲^%]J+Ve/P/l_l9Ձ 捛l,~'\b A^'H@aF3֡5 1GLD\Df\J <BHC?JVqR{;V8DlĸĊ1R 8]T`UG-^ʐl ZurRNg~+F1(鷖"XG&@:h4V}tP{hC9F1΀i.;c,D :m `D0qzMN4jAv>d]3SF !P2}$!TaՏe +:XaT^?,}à2 X$hIE{8?9TQOfhjIYT;*apW|f襈qOcJaI1 Ldϧ.' v.Bϫy IfLR$eHzlLj0d@@ɂj mfce@%YU%\p޻)9' GJ!PW`T*>* C+klZZT^zL` y#_y[u)ݕݘ\ lI]>qtӫ=WEM+WPحMEuٯadh`Xdb*hA*499KfBW֞c9_x]OCD2JFf2ªegYe,tt'II'aU!2_)>ilX34$Yā^3w Y{mYUR)SuPe0XcZ$V@Ԩؐ*F`}},GuXT($=='ƨQA"Lf`W])=v@Y(EB!941K319m BAbDzΩę1]@l +e(?;@,ߜ#ۏ_W7/:~*cKlqu^1[ixӛoZR{9Ki1Ϝ˨>m=TrN1]`ۦ,V'Хvꕪe%xU,+csO--u] }e7vw].QX»rzu4U]=`V"Xc1Yp,0vnWI 516(ɏ$ Gωi:ҥzWjTvJhj-CEڙv(PKу[g1"vDNtqi?C{:أͩ!HՔ$e`F)~[/F !QtʹՅ8v 33 I;U=5l,]!T9%+8I5g']TQC|0Zn`=F~^:O9dqѢ;<9qYرFJc`̸[ *$<xl [s8\6@cj]BmC)8eñow *0+c(||ϧׯ벃>va'ՂYNx!GR]4 w;n2Oq>B>2f%u= ', ;FX'`vzrK]І(q#Q#fJ%TbX[ֹ(%Jjtvv'A,`Bke%UFI8_N6?4UpXl0%z*,vf,, 2|$z@xS$bjZj11<TR*G$ J4:y~&K9:*Jm䖊.́ ہXFZy$!([xZNך{iiRr⛥6•J@)L"z״o}oZ&S,*~]6ꌲʢImI$>Dv'R!c#Ue99>"C1F :$f'Veqn:ZDXo@ƌ'%&KK~:;v l%`5\Utzeփ\ָĹQi,Ssቧ%Ns^▣mM4iҨ,Ԝ~*TFI ,A'p !dX1,<|N>t|'Wz!ӋTrk,Pi(k%YEmUvM7YC!tmFH't1$o Q>K2K唟fm[j-nέEQN%f SM6%p7Q;Nr/L"xāg:ݏF>~T{mJ:7ƭ+*-rܮ;ž~[*k.* y]POO4]t}'*;*륧b74pNkUI{9i8qb"Cۺ$%DG&%T́:[$;rU2:)\K`e coojU-|_nqR[RҢ֦HmՉ*x}9u_IoSTTSQ]iaUᭂ`Vx,16&3B*y8,PT1V6?\:l]'Uv۴w3k%<5oZb Z2Rt&cywYiuuNފWQPE$gswTP9VɈaA 0Оrz{gOx̓ܖQ?s 4UQ N330Iǒ>/*I9,p`Ŧgu,s,<7}<rr&q~u-AA*31 c$(cēk_(te3_OGzR =j4-GV-̭QfS` x{L:;3\i=@7" ;v'U5&I KF?` j|13L՘(*f|cx/9TGݒ!Z*iVc׺у VdIyg+ .~S7{E4r U$#iR=SěDpHD]VR#xN{Y{t*}޽ ԩT5@Q% hӔ|S\Z vMEjtًp $A%At"ˀJa62T[mG&Yd@FrBto`f 2Kkf5$H+leu\2o!ăhcܙf@X 0q8`$XȃH$b=~]Z<|1G:ߢSbyVsu9^ƺQK!lٗZ.UfYoU.UWp >?B~Sޫ&kK*;h@Y ?9o r}в^h`-l:HKWe%lchѝ:|xܔTH#k{0سЩ,V: p|a>,ja Dn<>3`k'@@A3/Э'e0ȩ7/0fg/(KйPKVTAe@e70 *a">t>WE2S=`'rIjV^WYJ}!XEU ̈vFXڐ)МSƤs'[m`UL<U_(xOpRv౎M\%Yd%J)(-c+,;!BYRr*ʕejR6 cNBE0 Kt: Lfg` 3l|>3.0'ǡՀlwF#q~&2lQ5TEtUHኍ9!NF "<2àlPɁN_8U`Ra!MјOW!L0f["FdcDZ WvUL2ɟ2$||*Ͼv|*.'`AAygR`q=eQJKe ;t߮'Z8rʐL>kå?GAe=JOr؝$Rvmh(bΩ*޸B;mQTTK =\Phvk=% SvX ڡEY*'sC'YTI*(%X  pFr|hcm׍N'F:u:vPqXRVj%*T+;ӢT<4Ԯ.m֩UԊR@O/jK>HɊ=#1bg6C]R>%G2j[:@oDd>J'-"*:?OwKy-o_fr*'Z_S6 $VfYy4AtJC_כ-r.SqT?F~ګRBU5a F4h{bV%;=&M׵ hkfXxZf꽵&zU*rZ&<[]XӱULYSC@PZ֓!u=B=D[z7 +&,me'TP(bA7O?I#p35QfW!!8o@.^yU ,N'KM_]} %)N;gd9UyP*fWt٬+o3I]w3/SB,N&3HuF *UmjWmtRou[syY/K)Sv Bf5Q j WOSռ[P)YUUi4P|ڍLjRY̨Zr&~UznnqKwBl \NQr[9eX*c̑J>+]5=0朧s mE+̬Ύ~ġXzI2 NPOKKULfP"pI+ <.On`X#(oFVu%Y9!UpN)?H;ʿN._ʭ܂vlku pU5im]gi#ΎeUyMRM]:]c[g]3˧16UVRܦCIYS73UHmiM\SR6"y"IwCbj& RⓀ ='dBIX$Kb$h!Xlr=HwZAr1wP{Hqc;`lA:)-uFI._wgoG۪.Grxǝp::ktkGKڸ\)j$UC+Y'_nqǢdGp.7Ԏ)gr(K5 Eoh'k|ԏ,3P"R֘')K H3~miBX9'zdz` Z2Mפ֜NrM%,%5hȑ)&*\*F4Q4 Aˀglv=CB-A$+wP9xcthScJʰUA u,T;oL@g%BRR>wXXO6{5ecUB% g?-҈ 8L(Lqb>0HOr11f9<鸁]zg:}8+uc'-RVRtj{}Ax\$DTKWpM4(-]IKJ`IvP*1#ŷkMSO$-=%,TЩrcR1 qYp,os}Ўȩ'!K^/WMn)wPڮIki!531cK/:TWTE,bL&0;KR r55TET*H. 01] L):ƸPFH #4$یc]ʅ`BB`iI>_|v{?Ux'Xxm'p_KZ!LCmYjY --+jg߽\Z:_=?=.^m-]¾*Ļj*VJCmG yo[Я,)BmBd(A9 w=Urŝ¥Gdދ)EڥYNw)8S{v(ѪZTm=BN9gb aQ&GI}Wj7KUoJJLC0v,JU Bԅ *:u'~/-!7mDäkI+9y,]XlAO? `@#SE% WATXG,h[VBYkhhդDԏBxFC^@a0F2N&UTb?  *5e^J5+R ԧQEDu1*Ҥw#y7JB%YYHVydA8sޟEpw%ZmCtL8kYL"v2XhK'5wx>S*a wkHY|VW7YŪmrJ ML\ԅCgwPAy( ~p ğh_ xTaUəJڌaѯzjXK>S!Lq&q$_`^ʅ`"4j<a+l!uo_u1YlTSG\EB)\`I,QTВIH&% O\"@"FtKWGˤ7emEΪ,j5mGOl;R]&rj>2"ލŅ*Ҙ+ɪjRPI!0Bzo iwZ֩JcJVUiѶ@kTrU&j2h/@'C U.;HP0*cIK01cfQ ffC<˙ZBHb]{{DOF-G*稅9Y5~ *PQW[(SVMGRA! 0** e:3PHeK0/lĚƳyrFWu_=Pm d||:KRf4[]Z5`=r͸H!J5 lURSPЫJ(R&ӹ!A,Qƾ8ONxʹM.xhu3KOqLR uAh*8&)=;OD04g+!auua)bv ବzڗij>͹ Y1H]{oRB8bҢ;PXQPM}U֥>ʨ Y($Pt3 y^!wYBmpMWWWC,R$!^?;D=rp#8o|:/ZvZQU껲\L`mR TxGR鬷M75BD3#S=̜zߢ#31X啤$1E%Hw+DZuPwj̞!fpSPyЁoxzu2%2``LH}?|PJΒOˬfn avY m{|ŀPvj"S3Hcb.UxLxH̽ iG!(K)2BG T(\.&IZFX+Cؠ\zMAKMyֻr]be0'#T}MR@hZ*Y9ETUtdbEeW-2:;+31z ?#3vr֢b{s]Z  {|Jw XIP[ 5 DZ'0@EɭP83g@,ǂK஘NVT_L JGև@Ԫ&c<73Ԗ2!$xcxZ90G+,A'a XbC5 XhzRDLBS[!UH€(3>pd mi/zm^8.$+b=QX+kJdO¡BGz4$LYe];.I*"CtfuhXH\I0%ĤοZEfG9]5gr%˅ lc@2UrTe ;H i 4fQ  RPLOqNUNDcЇhY`姩VhRB^V{T/vՊDeVb/ |+ $l*[ӳo>W$+u-=Tz<#դ’KMrjtYWa:U}Q6Kպ] |U: tdupWI{-|h^=u UL.c~ԫ-tV-kzQj#0pj 7ѧZ4CڛmB`D(x;+YůBp:]=*HV+֨nKYSX0Q6:{COJN+"ӹ4qMJ0 r¾_Yۊ5UU(-cE5&H]л.223Q%e,w@ ˰P|V g?1_-_ WvKwKm%J"!0@@&;U,#2&oI/.tuV ZFf Z,{1ג՝D,o!pcEٲͱUBYqT,4} #G(Vνe+]0>>fr+v# U]b.C7À 쑻񛕚z\m^?v 'iܶar.HTG"cLJ~p<^Y,= Zx7W-B;\w(rjެQh<4͔pchz׎KC"+>QZ[elυ\XU_WMrWکk()9(by#c&Pۦ\Up}q9󸖥eH,QR!r@ƣ> yO^DD>[UPL]?~&1+xwNz*T5Gw1P bʢ|S̤)rKDUϯ]Q{\ܚ.aўQk] }3Kl]]pKuzzu4V*ViYCAW~UH%wGSs98m\jk]-vCں^-ҰeeJbHf@zَeBIl~2 ),v뫄*N**K L u3XܽvNAq%pui֩[g AmĂ>I$HtW$}R /RUrk> #HgPDjڭƒB#Ҧu$cW\R{4Eb5_JRTX)KrKT7h)*b0lVAV]Ԙ3( ʛZ )XڅR==Q⦣0Ɵb@!@|Ow*+y \jvUK.68#\#mV?"`Dc_;OJX5|0HPpO2S2%–[ 5(2VڽKZY?6ܲ$}G~HOR(SRI4zm gs/IR-ɒ.y_nϓs ֶIu_`U)6F e|uQ{2El"6#,P}뚟}Vj]xd-:VЏ(%0NwKgfc_j7v .HC`" *h@H\ģYq),T |d}~]$M,KnFy,uR6 `RT_ڊbiwN@с$AWc,(zLf?ǩկ3qC]O5Gc_%E ұ*k }%P:42Od,q,(> c1%mW닩2`癝3b0UY *-beE@¿p(e%[rXʝDV7n|2fi2ȃ He5;;θQM&CF2poR3C캚hwE٠FRn}iF|7Rzت(! eFms6ۄni:-D<&\+:-GպcS=VZF:f#OWY%a\hN˸# 8h¨ES0'Q7ދ7C?YۅRuG6Ihy"G[VOW,&X]D1L>#p*u 8 _>Fg9%4i#L"8viW#r\(G:iZH۴'#Ϊ?*qB52PLCX+U+eDI;P+ [RFzG1Bj%o2 `?0oT>^fG #@$>#>ՀMId‰=z\W~GbuZH,YVCV`. HP6UQt ݩ_ K)\@9Obo淿>ɪ\c@tYriB*cE,FIQjDtk3+,\G*)I;K WWdz#s}t eC_H#6zcsڜqԌJ*w!b=U@Rq[,rkNoVwEw;pŗUm\#%XnH*tev @A,Aek#_!+ JTĒrI:*P # I (d|vn, Dۮ.ȊyIE^ڪERnFʌ!vR~1,2%Q*YxhS|I P#<ة/uL rFu*-(L$`1jT .rjR7%HAP>\g=9{;oJʁld*+џ[y$,ַ])_%]U,ʁfAgxP]lTW mH4Sڞi>^Jh 2T:SvUȏwn[O.,MqYG(>C8}VZc-}tUAtQO#к2zI텖wS+Wku{sCVZַ4jTZ]V#bxmowR\:;U^T!-"Q@f,JL}e{b\OwTn[w-)青Z[Ҵ $ x T!V|g.;|6+կI'1Rq=L鮼V-\2S̴3Z'vvVAo꺶a_QFڅqjV5JmmVJbVcVPs]תиjuA])3PVЁ^ 3=|׎Sp*tVEȡT_)TkBiIP$wj,D̊$2+ͦgzGq4uMk\mRA7~p)E%R22};e˩ţUH"{<ՓEM"5faXˀ_$!;3+F|U]WTn7h~ R]Y[Ү,T-+֨tj ȫh4<ǥ~BfE ;6"ÛM$or4n]Hz*Y5 GGNHcT0B@( ##G,nP\2; Fu̇9Vd PUq?>iJZJ$@8zIRDz Bf-dTV$`9$K6THLJr5CP31fC, ΀6As2``U&&R]@x@ܐ mARbg {1siT;={;|+܊r>ooimՒ[^cVTO H/cXIVvt?WG3~OaK)~TQy#E%V=t4hԘvY7n66YېvGOnڏn<5SjǬ*?chLJRy/Eڎ;: 56;}%Ey sqNZvOPyj.NJ:vѺGQtj+YTRZisCrYUŝ}EVwaYT=Opgm+*H @ῦ5r'D-7 %rӗBn7iIEQ.P۫bΩU=dM4FGN1}ӈ8-pXj-T QjSNLw$S&Xʡ6lkѻR>p)~r9g5uPUJjj j鄵U)nxڦzx uLX4.^ؖ2/8S,(GS7xtҬΙN*]閗wZ^]ayR *Sib&Pk:iImw=@f߽HJi2(!8CiD׸Gѥ` _E;8A\-i51D5d8uI'YPX쪫nı er$>p&\5CeUV(44P0=Is:zdI1?Lߢ"'Җ#uf#gUPyAq|J I_,݋r %B l는lN:+X#ab,Xr1-t&kSȣ;giJ˟(9Vx'Kx:rxA*nUjm,6@0J9{JRlT;;f Y1HXR1k5N+ɭW4j6U*: aXg,3j|zO{iVE*c* q$8-?%Wp.4M2R@h GٔŘĒ}FQ8mxPU)MKͱTJeeԁizT_N/Qf*T*gQIjTPjaչTSF9!L.x#4UҜLNDv8'ˀH|U2H1Bv+(p4f u% IV|ʿ\8!iJ92  i4g%18,u¦}XrEm<îS<@}Z4ܕ29{SIJ7ex+Ok9M\Wi'b-`8Ü ^97Q\!۔u1[eX0" Ru'!?x"s9=Kk\UxDR{Fװ#-2]"fE"4D0myq5P]NPsS^)9M-o[u|Z槰Y,)_0[)RG ܖH]_k zV4Ub..ՅqM) @L. 9tu{k[vs]hAQQ`D9<x'aM)Wt\0S` _`Y1~ȬcZkU;oS 5L0ܸƺXFȱչDHDaU+)U2wZWd!)F5[>[Pz~>9= u).v"?Jzi 7ASR ,\VR)Zf D6=8Үmʤ6[#e=5$7 HE]3X(,2@0$z%%ݬs^"XlS<~KL[a$cǷB'yde>@ϰ$ol6PH;+xϗY tg ov[ҫP)`)r7rwStw`јcFR[&H 1O|=}n-"ګTZZ:KEKdn,:% *mKڒz0)OZY:uUd)~*X7Pl1Ul 6ʌ4c't+iJ>vUS[䉑1ߕdzrp:xd%4w~;EF(#b0KR=@U?4ji4ZbFʪ(gFFdI.v(~dc=#?/?DZ[.z=8Ns撒gIäfGb*Z*8SS+Fvw0GL?K(uE] Sew 3mʭ!YOly-2n$^88T 46>+ditK-ia,T#=S7oD_> yg[E}I,"]T*M5X)[P/wH,Ӽ!>L:ƦEfE5Ddw'=G>|ii:gh][YK˻eծj钋WGJ4lk5BW+2O/0-BkrB9lM2(i 2=R{]+ZMUn}9NKV8_ygRApv12ԩGUCi–|4ym$WTUm.IIbg0qJ6z> XRԅsinyB,B,* ;Я;zR B[]QE`ġxQDDLGuy䈙[ܚ#a!Ps,RNv${'^{ӞmKqBu\zC[[5U5lih 4X,*9E,]r',MX(SI\6a߸Ij*Wi 6:{ ZEmZl`HK+lj|XQjjRPsBc&k۪xǕywJզZޝrkh㮥bU&EO]kVڊ::uZ4S%U\RKD $ՌL:b)##^_ )%M$75m:PV$/nH{"S$TOF8m_i҆,|h!KjO2B0SUFrKxºM= ZTmU*%jT5+(CNv@qg5/j_f~=ѵԮ}JFŕZjZnRBjoV7_. K `ʋ(Wur!#*u_.غIH(waVZT=EUepJJ j*R+nwQB3s+4,?f]ɕ{oT;9l6 y-Sz[5uwkxg5Ca<} >)GXe0{s0{@'ǧ^-C1{`H}齟|>7CJCM7$5H6KƒM~Jy!=g#E ]zh` Bci$ #ZF/n_ؾo< 7)|N,&ڿ^K_zTY3մ6h}=;ֲGK%3Eo#tsˏsuJEo\'Q[l^i- F(ҽ&u h05`H\#GQj؟<uWfʪXX,1AMƩdW WJª3N6ÐdE/цPAM*^"!H\|lCZRL5UM}}|zF9ښMw[-ƒhUjkmV,)(N!aD9:]KЏuXlk|L3;1ݯ"~[SQWM$K-5\$GFb"(T"@ n"wm09Ib'jb5{rJ]iF߀uP_h3o89[↞vZz?k'C}]վwЮpdlR!(z!ZIfDVbˠs/5:)KmI4,ڀ yTm ep5%MEUvxTjujF/qЂ C,b5O)` (==1E1+D<{}' u$Պ k,ugR:qM5iyhQ,$HD0qMY]"uDdCU>2F']Gʛƾ ;d2چcOK'zXجm<봮 C#3/GFE~ўu GX<My-*[dYu]fcxNݞZzaA CMC PL1$Iq*ig4֩Zh )p)h;`uDaf(dIuA.2d ; ͟$gi `-R+ 9!/B(Mn+b%䶞)x=Qɭ,նJ{5]+`ihHl*x??\נ] +l<2Rp[ihabq1ֽtR"ME/-I5df%@G}3 s-jVC3ҪM_6;B1=Sumi)VhJ mdwN$^YԨiR]zLWe@viddZuY렉jh^1*6Ua:AE/r0Ȏguuq(U e۸Óx9Ոj8HoauEQxT*=-tp} 6b`8#ơpȥ*rG$u[:9QOȩ1uCI_gC#oצm,Ҫ@d"HK`\,['G->>>} mc\XmlW#hFX+6s@*@ IbI>ǹ? PرَUTTE գ.1!`<U P@-}Ikt59ՙfųn4oQQ1jMmet U2!7. nAUtufGYcx"jĸbq*N7NKmu\/U9ee;xd(e**g'ZbWTJ)#D"rGdN<P5 UtNDR. Hb[O\H,s}wԥȭ;R!H4ROY/[^SzmqI7)ߴF#+G_q4KY]S#}+FbR,dcV|aKzkɺdQ>)^"ڜ;T6Dy ؤY8OHmJӼRD"1$"oA(h䖂ҫ$ԖՋ3P2eQ^HHl1,|+eSVRҹ@RT[b/ aWѶU^5aT"5 Qmb2*!zkM`6U)rI&mf_ `)@X$S_HVF"l d1>:V°)q5*,*co`2oמ|c\:rmܫvV@qZ@)s mLH=EkKNѬDlSjmP]@0713N.zy,X{2/$2#m\ H%ݙ#Կϑ=d%<!.:,HF ]?#HeЬO%e<f*J!Dw߸9"E@q«^#9݂L)5gcᵩŽgc~ m+%sWV*vYf)!RKlCS5DaX?wVq{EH7wɾ#ӫ`@~ r. ʨVqk 5ۑPJ6O-39JI%`K릡.1ÄS ]Ym zuY<ԥYUK{(V/*zWZh: J(D;@C.Kel^mjP쒤]*hAjzfYW"ĐkMΒP+ 7m*梜d<@,~OxeuY<>9cg{MU\r5D7D"H]%Y0h`#\8VeIf*0_*HQǞ4ٟV/+5*wes6BԷ۷ Q*b2(mzGz=AyA7k[@|"d`C.IB`Ǻo-0,ST-3!{3(Egx}H;.D\1u+G+QS[zDE/m' P~=Gf" <=H.V&kU4Shb!!3ϒ_ӰYѼF_+eA `TyS+\(XDFPfhbRɐ5S(f.QCW91+ ;7R,Df L "$#IPy98c+d|,FN0H={g^&6(f1edriW,5`U/v8# (0r vP+4A@Va2!J.υ+ʳ,2W0 +3ed+s$\| TF3ߏ\~v"3϶??juKSJs_UNtGV`RV\)v/nq˽ߚK|p-]}mjq(O O+ÊӼ]a__ZUEmP/qe\h䕭wT`i"2OkG'm*JjH%jYXVXw*D%ܜxl]tWMjTVRs$X8<>.t5\NJ[noZ-5wjz[}KH.SQ$Tu '1_`?c(Fsĥv/0\5u u$mQMnÙ)mV|O0ъV6X43hI|R~gWut7Q3ymjE4ggFJ-D7 ̩Z?*Q噈Nӥ|l ,v/4&֡ikaiյnwz6[5*u.n&tBUV4DT.7L*̪ |4sS;,Gg9_瘏LQ˓X*i^`K*X:2j!1Wqˌ dO%DnLlBFlPC:Tj;DzN8=E0$3֤>D>+K<'/~I}:J3-JoHz!SqH?ӎG(=TqI2ا%^'ʨ\a ckO_r;Uu$K)͜715YH<ߒu&Fb*x Q_ C`Ae׫Z QN ]BLٜq=UǕV}D `q 3^u/@yB㼛\.wg}}>_uj.Wq:1S@(qO_OLDZfAL|S31n e,OS#8؜䷩EZԴ-U0S݉`u XKZQ~U/ݻq.}imZȭw )gS+jG J4($BÅg|p鼗I8'Qzqq5%"HޮI\#*O,Yc 6c< 3( 6Aƒ?=!ڢNWB#EBŁ-^m^8B FLt4{6jj-;&`O >w%=4̉UCGcF1VAdFC"aUH#`W  pܮ5:"E&N(ݢP 1.$,hVuG$f.C.2)kVvPG&SOl$uiRn# Oc!eHL{1US# W$@%0uf+ 6FsbE,.2 C|P36 7.O I' eRB͖RpbmIx88UFTY1RU2@QHՂZ\UqrITV'QSh01W ` 2w#F]B2J 8*@!ԡY1ۦޒ;CbA'M_j8?Q2_U Z]% *XbͬW!Ze4؇flԾ͂jR9`5C+2!) To' >7eeOJmk 6YW#G ]jt>}\\yFvjRuU w)M4GZJ7woO TV cim dTR R >]c&`-*~ nKX֮WOn2ja*6dQ,2c7Z?e.0Wp@TMIէş#HI Ϸ}TQ-\k#117hU 0ϱ)rVh>ވ״צRuMԫҼZAЉVYH9ˮ|/ظ>Էi*{z?su'O>-|QS*[frDCMO{FSĶ$TȔQַuVH>UOze)&4h&تDWT 徟}8sQ$| E#+2W,eVù s 6TyTcJZK{ dr@.>ʬ%+)ԔoԬI, WnjL F-N~ː#{u{k? qoT\:FmwޮML3KSQ9y*$I*,^V%ɻ;;3J%d# &$c (|9P'?οqt;+!…r>re'!}J{5jF J1Ӭ] Zd92G:XsW\(ٹv2j!#$s{o {HM\QCݿ'SyugS} ME> vj{dDBcHΪ;U,R# sYAPK `>&ꮷkk w1bU(O F`X)`R`3J` n/}֗xP,+T4֣}Zo…Af!yJϮPl*J*y` ɧY e'dBLU[V;: ) H{b=`I>I`1WO1Q@%Jjt=Tz;BYb!jan!3%09G9>tU3c] ?T1?\3`G lG%P l* 6P_`fmrX3 dQm2eK,_fV]Rw` q9$:eOդ}WP4dXp UE 1".LlpC#1,7G:FlIwR ّw*Pdb'㊞E%Zy**6#F w; +t/Rt6ݶK4+֕( a1Q0>a ͯT_Šj٣&`rn3'9kjFKz&sy<Ի1aJg"b2$XGLHôM3E7KxO>+:Pȣ\ JqSQΫ7H 0V̻E% |g"'($`jK9bGrŋ}i6P"}vOc߭@7W;UP=0ӦS^j),Pƻr#v )eJeV@X2jډ0^C!|Vfط Cl?- U6ΪcYc8pY[4^2ȅѷ9USyHPkD[c3 FK1ʒH`遅?e?ybjr1Mv1 GG^ SFqOp}9IHKVY2,r|5w)$ #.bnY&ءƅ 4 2s@NeաJb`sD |ymݖ2XB 0;;Jq!@moBx db9ny=nʠ5`0YrJSQכT}v2d@|UMT2m $ LUQRŶ]mT|6HR{X. m,o619w;HbH XFpA uc&F GPNc8-Fzz]<Mc[q=eͨANQ)tڮn_U82˙n,vXےekеJяo>K؏)ɺ8 rYu4aePg炮IU3'j- 2/WIlot/D֨-}E/W+Fڊ:©PX),Ve_ kĚzY-h\WF嵽źj%BUx;JxV q(G%$4UT2&GffVGy{#f$%%x\,>rnj.tzMGM^=-ARZ xdn̾3,<;ԡg@-|˦Yj87urw\o: ti`t&굑,-┄7H߭m:8TTv~[m\zykՍ ]XnIjdI4T3HVy%B:U4=)ouz_PJVU uꩠ llZZuvƒ ?KKg4{H;S%H;f uWHt:OWCjO&N[uzXe))C% ݦ_؉Izȑ]6auTG_XFKc:Wy G=uM|z9Jhd$C#dX@@5396 ?!Ce3r1@4}2R{yemuwBדBz Q Q G|JLLE ٿjo FjjڌH2(ʂ'KN2,rLo9ն rQ`t[^q?J+4 MSOOT=e@gvfjV*̄#V o5|F;xoGXc^[ RGJ)ҩvhhk}e DB$ك`K~uC }.%'/QA PVd2BhVU!NϹD* y? hJ|$j(‚|rJ>tЩWu 5>%0ErAk6˽cVƖ]SUQ|QKy2o\|;R-M[{{];LFD*͹JJuMvu>F٥spYjD?%ʀȉIza:jp.u+n4Qgb͠t4ȷjZjhٌb)Z7h8t<%8\*9E+-_=Qsz0_hlwS5_:[&qg OkI]Y _GcV)^Տ__8Y8%.k'"}Ԓ٫n]nw$ ,FKEK,IQNj>mUOkÿ+%ޮtzⅫUZf FKIcp=|48RVv[]n :Q(I%~읤NDc=9:AStul "r;iW4Eme'@52ʲ*ˣ+WykmuF.[m]]A2ί+2:fCPGi2o?+|˫r_윲UgC5uM_=,^8uJxDTrغz{]k xqaQUp44Uނ}jiwVW| JWlogyWLSm_NZb67VSamYj@mrk(WJW{wkRɷ7Ȧѩl{ګuUE-kmf&#\4Empi!HP4b@#lh(w"]DԆ,;7)bNOM=De5 Gh"-wY"(͘ 0$ƳX"-҇-*B7Rq۔Pw,4`;2SwRMF*7)$$7U\jNzo.W~Em.$urHRX+RbVCّ&)dH܋~Qo_+Gl5K ◎X~S}I#_ԑ4𳤏(Fl=B*\. XA?X/t:.W;$1ʦjx]#HHRt~ZĬ7gY.Spf6JO";Z!eeFjb+haߌͫ.jjV:-^^WӸ t4v7T~U),?ΪQ35%W@, UQ?N.sծ[8Ŏ m2EwWȨtI[SiAS/_q ,E2z[K.Jnp<7MoIq])YWIL`Oz2[T?Z@<s~so/\K+]kutxwk ul+%]mX:ԳR!pN؊ tS[vKt]w ښ9U"p1䣘QSSB0WP3 /~0]+RWz`O&FW_2jWn BW7)%mh[MJUKt1 [:f0jn̟ӥ?e SfjT7쫣ix" a5 KͳU|ƺBF:8;|[|i!kw#䕉J-@J`#$g4ui(̂FN828pp@ KIU'gRI KUR<5HÕR@82T>zu[^Q ][ujװqNܲUޮ5JT2 پ?&yi^oPm-t~d"gQг6uC*)Lnu3S:Iw+oOW]lv[s=t Y UM iZ捣%a\Wͳ\5<Yao)M?#f_ŭ++eQjm3=3]:T(}BWr+9' 8^IMD.Vzxq5Jzj\RhV7Zm:wu4fN#%NP|zfkAWSs4:šP6m# @7~<9"/OW"^M'Z񪪪G[&/ފ^9UUR4p hH4hOlV(Z>CW53q] +A߆R,C_ 2Z~]Sts_PfWR_hy 7X9n1c9%DIB}}gwEߺ՛gP--"q?nhgciZ' ~х"yeAji5ʗnlOSt_\Qi-*U:ʕȸV1>h:U:ye.骚;ۀN3 Dߥ=g2:u׃zּ7WXrVdkOv촓ҔS$aPŒTT#6;W6e*M*a4t55#|)h-W֟uWXnkWezE\4x&j{9&R{|d_Z+7 u-KtsK%$_eRH+VSoمڍ{DK&4xҵSX4]t:]aNo5Cv05֕3ޖf`jT[r0]/T[i(J6{ḷebʬK{)`c!X v9bR mbaRU5<\:ˇ9e `BP_p/&g)CyV,6$,^b>%ґe7s H,d 嘆󨀶Uάb1$+-I.;q:K1 G>t^} %Fݿ6Wf $ ~GTU*xd +& [P2!P}R-+ 6 8N6IZLQ}e+2%ZuǤ~ 2˒7u2F-y'0+J. d,|)u:c(,,IY8!Y7~ђTޠ0p2*(1 @1'z?3}i2! N#RH#!Q VASMPAmu  R ;č"*G*dP1@$hO(P.Xe.Pz *UuelaD9c @B?jUZhIY%frH+kQ'AfoB3 Y\vP/VǖUٛhWՕ8 }RS.D^uFHQZ9U(TKC!%uGc+ڢTz))%ZL0#oX 6OSzV.7Hm5\i q *%X @J[a#w&q#*ە6m띢QQDU ^m-MifJyrm.U5:I9$|%qxn€"Y6;åi٣b B Iq<s4>'wf\?z4j8RI 9t#Jc|CIml#F&mQW?R,Uo}QCz3+ѹ#LC(Wb[Ω C YԑE ?2 Qxֈ3ĕ>'H:7,-_255zIY8pWvb4g>}T-uQ_znYpdԜ`]{/ 䜟7#8ee뀔4ll.|@Xe`"躕ŘP= 6RlG=zԁz cW`ށeE =N@:%%v^~ HHd]B~ V Jy+ JlVSE S,%ʃ0ϱEvSپD@/nX938C-^td#QYW1b <^̤;2Z?pgp*Uz P^.VŨh^:Z40 TBBi]ņhɮ/_~Ĕ֊t(r$T$Fچ(D1A?6A*?ĨxaG{R!1Smvj-zcAbbpNIf#-Ѽ>:IA}MkrZGç<[8˭VU[7[RUԥ}B;}ǿD;s^m-]??J+m?/5F7%5/XMG-1p2)zxv4d,TkMSN& Ve5ۓTTFg Z#;Hv2 Y~ii5L7kUz(oDyQcW²v01OBʮO[}\[t:#©zlS8kO|ÏsUO8qrJFVMN:Gqn)ǟ:l]uzͲvGv<}aGuƵCNW*BU,T%$*6Rm \+$U 0%70]X eI9e,KJ*/UU""@@tX d\8UWƬt6I^$9mfl`FeDuDWfېE4:V3d'\1bvm4KU&u Nr@&y&-|#p>_.ݺ\+P:/Xqie9 }] =2Gwi歑JZ a-l*7l+ rr JeeJm YTr ;"UǧnkkOzaZel;UEJۭ՜ڨԻ#Y*9ii[(?KNyuSqv靬_:'S,۩Szuuj>YkV죟lG%WtS˴!%gXFU+!V#W|kM:%#UȺ<*1M5UM޾IQ@F&JHdJj́j ʿtrʑerr1,&}Oi+jzxCT[Fx';^IрbyV}P14uRIaA9P~$zSս0MqJ9Yd0t8?s֎t8u1u]v뽞nƸ˗?OvWzmj)lt4ZH=M-XTVuF`w`|)9 $ 51!S$CWPh7oC ȎS[ݴܣlaxG820:nbVh&1H=i| UL*8a?c* H}7_3VrN/pmk]+FSS[GKтUK[aGB  jCW"Eտt*T%*J\Icj Do"F DD"bBVkH!u %8wشʄ*mjmMʹmQ-UXhn**mߚe[n 'm1444-wbvh"cEIyJAGOęYXHg9 }>/N%OͭJNGs{E=ޮL5rr;uT2##Y- V{M ,T$_p*Hh*ZEjbBӦ1LOLQ1м 551Wm* k`1PmԕiS*VJjƧhI"bG [ZJ~7ʹ?$6Qc>@n/-iuZ|MjԴDƚ5K Xq1L+ ߊ 2YaV{Oe0g]$*K6X.SXTPHԶY&eRFX0MFąlvóǕ oy\\}tξp_0W|94Wz {5oGm֚:(+"!# LDϳ̯B}%uZHX?9/QsUUq6hkڵަ㦸c;S)tQ TQbLO 91WYJ9t! s(rIR118*׎GVpk +]85E:Dy,. 31#lYzͲ8o RC動k߸~C?J/Nq< u_Л]nI-0?ӕ}B%_E % REma7ڟןջ2OR>ERKMeڹfK\cu(bE E麥wIB̦w@Rǟa˨Tu-2*ឫ6!w%W$9X~OUiGh+l0Փ7\Ƨ$ZF^(C1.Y+awaf׫]*NǗۑEjivYHA$K):6Ӭo FLzDu'7 Uq)lS\zCh\fJ4[R-lNn.JEZid*)  c20 FmgIE.*祴 >(cl:9JIwk]%Ί*ugdr6V eY$r \8frOEcU#HM#Uh3zZmDŵ[/Az>]]V^ ]jj7uig2Rf0B ЮU??Zrt[N]A"MIO)rE"e^2K3I&}m3T<7v$+?Ũ$P $|?j/V1wYêHZz@ꎅ .De1c|mi b{jeWwaeF9,JX-HP߹ƈ Rx"Hb;~9 u\W#%ejI ('tFe7Y%]]YY'ԑξ%U*NI H$1$3)ϜJ/7h# edkS@ݥ+;Gո,s* 5q%s ]HW(Iխoa=c>ѿНµ@A2zC̈xp*8l)aa`J:]6N˰d!p3R XY~5rnB hΛb\`v )?Seu!Gl NC.Gizzـ1|ɞ:22p"{ o&'Z#"48 %]ض"AcU(FBU"Gtuv;!U8=2pv8RA fPAb@bTYX)f$(k0pe_ Ke*Gn>\GTjNI U"ӱLT !hca"͝πF@[7VnQ%/!hu)%ڂYehWx[Zwa.ܩ*㭑Yb%%,/DlnjpI=wN7̹%r#~|PYy$vL1ޭtuIGs-/@dPXI_ZmP"TP@;Vbۦ5=M=압EV_p0ijU`pY?. MgNө|w궆v<: J<%Yc /ZU-Q[mJ9"O l]˘jJ8\wY^,teg1PYN_]k~nx9?qJXiΠZ-8 صNQXPd+~qo o:uʶ/Uܪ,oTKr x!JkV6U-8Dpcv3vWTZw5wV扭3fO;A }@DU~κdMxN:U_Q%9]{RSOEl=cȏm]z430GR?lykLn:cs^+E p$({1E!a[K΢>TuyeמT@ѽi^@gXq9QվVpoOj,6KMg]$۽@uY%IqM)j)Vw˙q#,IXnJb QOvg{GsopD2873r'ﯭǒeej{#a*0,/B -f%>]X@# Hlm]€AyKI}- '\/UVzb DRiC,߻Oy5ϴ׊uy6S(V!X(v fB"ֽK&ԭVR NǿvsY[QPT{zOKx^%3A'FU+/r[ H WqY lbd2vX$1f W𠍘Xke:2W3ΓY !I5 ;g +.8~C׫,cun}e=EOҮ_n=VԽU/0޽$ܓY _Tk[Zuخūo=5]Ymw:jd)zxE6Dl#$%UHpY Iv1΍H!O.Lʕ'E/*Gr  LvF;BW̪dI['_LzK?0ܢSɭR|:[n/[. oܦ*1;Nwo>1HGX=X[RzKJoDn)y܂I-O!fJTCYZ*yX^؋S1,5f F<8 ƹ{>=`2PA_:@VUZCiV.l (-]n jR/UG[ur}.{/#.[9 s}s5cʪ S~:׊*VU3ĹEu}ϨBi*:qvTqIoO="I^(an% e`JVЪcWl!u8hnwDRNC2ArYfmVf_bG~cSWQU'w$9DuJ,R*>*Brwbwed_Re 8@{mS $aLSԄOP6z6lIKQ 7Tyc2(g *2^eO,Iye\%uO눪rUr5vES6 O" q?>:%`'\JzZ}5{}9U֎XgyޫfQZ6YiUV*jjxQ[+Cv?Xt'ՎrZ.?v~Q|sYdk(mcԬI-:SQJfKDG章^9FMtA| MC1c$r -Y ʴnNo@*Zcf) 3>Z_Ѻ &MjV_>e5h80&cr?~='}q+JN.s70 ܊Eާ6*Hmh'zʓHiڦHSI_q>}a9>sbs'y,;r9SޖY*+ӵ4umԹ;; 2`| \`dQY}4l?|}Cl- |_W%KP``N33$f`:_ PqV-]eU+13;v~}Ym4\oDf45=Y|۔\.6 T|z5LrQҽ0ԇש_гKn窜v߰˯Q ziNULBr.uW ' |{+5t\)G8.߄eBLR'Xx+rM̒`" bClನRNĂW|]t\i>l2n3yUxddY.JlJfJeC#2>/_PuMM<"Zo,J!F,cbłUXl@sns& TGBYND39ǻ .zUQѽ0'DR20%Xmả#BtGZǮty[<\&~1hOL֡Qr*vh6U̵E^_sm\>V]w_) w!)zR =)msi'R ' MX*ȑvοϟ9 UZʫPdʸ(ˁVl5f-ݤ&ZLI= .[i'zS{`ZiMW`6s\}L\OkCnTjD֩-G ʹ"V#ř^X=k*޵ٸޮrN'7NOzOi%Qs.i,녡*'KUqy Sju>`+#SyєEIe #$ ,@ L:}X@gRa O} ;&I0u)roBVQ*m$Y7i>}BR)t[ ;%Um;GZUIcCW5 c2EO<1E* uAeh0szZDicAvhc!5T_*so,wꙪjrY8.h ѻiWeHK!I0hP kjKD4@pm~GYzվ󏮝.kTܫe%x)!M dvA1cL@!P{ M| 9;8VdV0I': *yŒxit} ^=NUxFmm-UʮnHa4U̲䑼7ŗSqӮ)5j8M'^RpsGSb#Y4!/.>WP8'_e 76  9Rq[\e!XO@eD8EIfvRR1;+cUj,US)QUee'ĂZj:;NC?Zo3c_U  '~U\,Kj.LlX&>?}6OIsSղS ޠ*nuOcp]*h'rQ8՚v("W,XH%I’JFH |u8UbaV6{uuQn*﫶F;˴4(RZ+JP yM" 02ḨXJxzȊT$TsbMUAPyrʓ t22K1 K&"ll=*3 r5H1$!ced؀Wπڂ1@RvIٗ)i0!e21lnu*þ`f$I?).1uf8c~EGI6R~ġR(Y@VhDǟnUV|i,?Il]e4-"AAԐPW:]FR@(at,7,djmǂ?Dw!YGzM.,fݰ!vM )80=7\$1mh;jP$2"'ȁW}F];4su-%M]ZM@YF2@øu]#K=TpƳTz*no*agz>t?T_y.j [i)g1O8z8Ă[@Q^WR:)߸q0Ig߭F v ;H/ZH:ŖHVJu)AȣdTVQa¡$j^r@+|eJ*`W]N[*[!H4_zq*Q3tI > ?j/u[P9e5*2_ X89.yJ~7 ǠG:"|1j.HfLtePIRfUYYpB K)xR~dy, AS`be<#I ,ʊI&x02ͧ  D\keR6)U02l|[y2 {_^(}#z ) `0VkH ddqFD\Ged r mfRg t\=t!s@܌& G@&tI+TjNHr*%@$ x.gO9b2,x@i!m ِrPLdL`{M#G)E<3( P&묃[՟ C}[xBmQ(+J %~t|Xjhhm5ּRʵU5LOUR$OTG_־Io4.+xÔáX]I>c̩YzijĒTa;ۻ[3^cki& JIXZ]\R&5Jv+ըOAM4ђ-E+Fd$V ?c)Ӛ5НXƿB}Ԃ`mTyIBr*4,Wpٽ c?Kcg}>q:~>!my47˷yO*CY="%M$v<T tC^}<|?{"uG~n0>qNUzW5&SFZx+-7*"eQ^QJ?෡^sk]6ҍԵ \CL-[+'˶++˺ VQ nG%2Y]uH\+1PM|Bs߁UD&Qؐ+/*<'K7~X-N :SKrQϺ~i-u6Me:z߲qj* 4y? >߫5ֺz5ëK?@ᾢTPSG}U7OObXeJ$=jk5koj,uVgW}ڕc@ּJŢiWAB{ipݭ. |p @ KUP&TlŘ8UĆ,DMoEP4UD@E0g+< - tuRϔE_b{LsPRfՊv ْJ<{^S_d-}ߊ4])De' 覡] SKJʯߖYb0ɼ(U,W-_Mj_%OK%–-Y34pR姎YdDts@םg;URE5Vq/,QIJkgLah([5p[m}o]+kh q_ī+ UEGr;p0j>y Rp m[WZZlZ{jԪ5ߊY$*-%[tP<6*^RSG ,g{ F$$H'#="z- r$,;SROD㎆ȲT̊ʩ"ssOܬG5KIQ9(LJJѣ83Æ}"spQf}L}*.{vri/5VjJaQDxl˙u;6&RsNYy[K=kEWxu~ux}+Ɔcu{{KY:򍥦{ kguAVfkb:WvrCM&ܥfR TjSSXqUߢ]bpIvE()^% G8_ 3݉jVX%];@_>uOZJ4'Zy陡[5]qKiZZ\'dZi ft233WVyS-~_lܦ[qESY9 8-RiJ*,T1K*z[WShXޒs39w(h;0U*Z4'r1G"Ծ/nk{/TҭuaRPFkZ$RƖE]kz@ݛ˻iEV]V]Q􏚩oA ks dK>E]^^8_K8]xMT] z`ڪ#46)^TQ[,r!|*˒?B0uR1l > -7lKE չOqsƶlq R9"E S M60nAiT,Yƣ r<Ô<@/u6{gSE[`(ٶj.TV٨}֭ziQ?NoP4h mT`;"IUHh9g?jԶ}}- %ڛMuU3 hGgn)(UBCa5(Z_x /dgEY0R6\k6=cU]y UXomj؆(EUUPS/<@hB!ަme-:<յ3Rª,4D)R@VS_СmRʯ*VVia$O~ OYujڽ4w݅kz­Z\XЭRa|JS++#*r+3uoFS;k'KпFSr-}]Ә_-6 Q]㡴S]/vT$4pS@d,Iv0/VYFB0=]95u5[:.܂EKoPKY_YJIOr TOOBԫ-ivֵm֭d ZTEd5] [jbWh5EZUgT vLDJ1=_!q+Zc{}ƅ% 4Rw4cOR $M(pȕ/$MEHp+$QchՁ Gp c_'wjz0%j\ '5AǿsV{(1MO-AګV+U ;I#)0 6b\cVTԜ1,Id|6>jK56ZꭻPYik`o(S#ݔtUXBv e>62j!_'hwGR2 <*ͷ8H5]_L*\'ewAP#Bws H.. ՗8e*?Iϭp~Վtj:? )L#}YG27]< T3C,dCܽS /AقVXjT-zY-%;,VF!Q&ҎT'<'E5OKM(dgq"2*X3V8++lPK rGáSjI'Ln*WXթ8HȘ$ʫONzumh ~|^NНѰ1.߂d$E01>sWkee- \$# *d!54n,n60 &Ge@\`~yTU*/^@-ס4䦶~U#M@C=Ej!WWUe_{ب${7dg[_~$/)U! ex YvH?ҷ}EUͺ+PX.e| '-0ԌOv?"+uDrifج;ɬh-U)}xd ZgyCOrq qXSW|qU FZ҉981@p`@e#pvo%lN * Qr"llꬺd*Pz6+l -*n(]T!B˃j2G!Cl kWeH~WVޣϯցY&A1ϥ*cR?H-f*hFT3!l(r2[ &reJ1b<ܩU), 1bU`|r:1;;Vh+`+d\sG;OuOיŏr8?Vè/<;,5kK=hraiXD 쯖; ԋjjNG/hP̯s5`w?ILN;QiZ%6rOUZimHm UXS;T+.NT_]W ¬JEk|L;]4⧏)4kىm {M>SOZ+ZЩTXUQTnIJԕj|AaAU00p?lzNG~sCp[+)Gqn0i8i㎠15"UU;e䡻I.o[BjqNk'$LԂLFAc}{vzb!W4`V F$*v+`6X?l`# ?44ӥiRqMhЦ**j `0?#(U,^F0$F3#${s(G 5ˌR^9?OrܪOfM&{V-).+Ŵs"S>uRkj*,OH(78:QS*6d0R0.Wj$HRfG$9 6$!:FWCM*z9' w8l#9*ސ~ȸ_מC%ߕ%7ץ]S~'L}/©$qSR,FmS"`>Ip9J1\A@DlC>g\ј4 3Bl1QZ26A ype ly#QI_M9I y%$MBIneZ\j]fWoښ+KUCp*Zy0O H?yULfAܴ+lwmrJTj#%`$3${ 俘*T1J"7`v#p#wtib#" 43PC%?eBK*GlaJ _bvA꥛ʜU AMej]0gV34AD Ň qu{e5/;йdsY' xbfFհ #*P,!Lϧ]\A=;щ%kG!R- Uu]V\[c5*E:9%L.wΫUv۪=3]G-)#x'bd9YM\c,6 AN::EiI_'K@;iFEM;vkrSWC b zz#E mUrNV8QQUUPʈfI䕴U@XeݫTyD!Iv @ ӘMV]V \{ ?%~y5ޙ@ۨ )UdbK]Գe~sڇ/5bg$xP| 3*Ű2Ztk]PR-ؒx3XmFUZZI* Y^S$#PW}tZzՋL h'"㟲sJ)$YF"ktĄ1 Il$ Axc3][ k I@e=7H2wsgWϑdS(8#Io4e+v*Nyi;Rļ,e%BG#f:$rw\d |_J>}EԮج!ufsTARdqgXOS<=_v.7mW+ V[.{7;m†+V*'T[Qu>zj`(0mh O=:ũөM/* .cA%s^+E{OnFig9C%+i3r2)1P a "e^2D !DC` Py ƫp<M +12sqPVQSuI.{9*d&յ3}| NK/hK8@nSToԨ b+yB #DMG1Rm 1l)8jژK< ++Dz͢HѬhKFȋWRfrƩXSY6U^'!$QKaѸe9MW*nEx#,LUJaX[Dǣ((@$7 /<*ة](fR\cTn:~|JӠhKBj(1AI`A8=P_V%h|\9-T5"34q<ѕ۶ hBbI!䆡jX^5ԢR3AՆFT'9Sۅ>U۔*u]|.I%"@)2B|A\dA~yh hM>;Li2G8ݭ['0B DwM~(vkx* )|?`kmqq|KEƐF&vɫ O gB;57?2 $ ?jjyNT"mUZWPeaCDccl:awujgDqBp?YBqWX݆\!m]@S bW̌ŽԲ@RXٌʩN5V+nq6Y$.刕2C7*8n:% '#gpU23<{xeiR3sъH2ttܣ˸%2Wx(qTV¾CWwZ!+Nr$5,R5*ڨ ĩer8fQ zAitW9Ն2Lq7FWro¡blӌ Gy'g߿T{F~d#O~@d2FI\U?8P2F/΅ x$ 2eI%A9ƃ+r= EZ61"g-S 40uG$n)-0,r|( S"gIX_ Yp4Qʥ-$mHӯ־~Y~Ck˸ ^]zC{uSRבU[먭+j))mֹWUקܪx,Y<gZoy3UYojஒzHޢqH'dT6E<7.c`kϯE>>?5%ڞEȨݶJDVwHcdJvZuZ/$Gjm$0Ē0 oyuE)٭]Vfj7 kQTVS1U,E5!EH.RU)8VNGMq>ݭtTi\)/pߣQz{sRL–()i8Ăa~39V.l_U-[rCP ZetRȲC4p&NBuWurmsn<Cl3țXS6&FV `aɚ&UTT 0bqr 1;xpp !*d=e5ch=H T.˥^W"f*vIv-X7M <G"'NۀϏIFPHc''` Nˍ+˗t}^*,\NƩzkf E_ WfY`Lb@T$#*`h{z +A) L]/&o˧ҭM-ۆrz'}kQ5v FY#,L|GeyF梖ZgQC0r:={T(Q@VC+Bq lޟ1AywR=G~{ZIw[%zI^^eL4ӞWDj84\:8kMLXm8'/q5s^E=w'Rxy -ѐ4Q@)꯱hk G7br\}$ZkgjS<%*OV-UpF *9!r xcPj+Kﴩ:Zp"TRPh$0S IBߨە%H^UR5-紊Ք2S D(UـuzY;c N `z+!˯I WSp^.ճ\.7*Zjڹf䒢ygg;.2Zf#VxUaܚhq* f 1FtǝtEM 4Rض)IWtv7FH:wkfT J>ٵ P!qIhL pH*0;@0CqŧE*<1 %dž0be MlVu$_8+TW,Hœ Gx분7bO$H8?>tSu$ d`p=(^D־_Oߓqk=S4U&L։fۖ%5&ơ)FC7v&b(* []΢Qu TLC4nZ)"7 VWs W\}޻Y*,`0@Ω}S$'U(਩[g]"Qk&J9ɟ;5gW[ҟPTWk\uKmMy=ail7JhB,W:i;\z.1/w;dUӥN+U|Y]U%MMK3M!ieF$T OXlVQ\@ c`Vv75+}GBwй '$"0VWX'ЌVG9:l*N΍XGfl u񗮭(iVE]ZQNөm Ɍ+$o*8yQ|e\9$Xy\[ʹJ B7HGrjpyL|5 ÐCҶ4l$ )>G|'BŲX7/ΡZ$S(zy.AGdPFbWlP+|nIFI' vl['9v7W s>JR??ϭu/;u/[]t]Zf(8l.u)#Ȯ 3oVN3~'פt]Ҏsە5rey(fySYhżRROnHo*ְ.ElˇZUueeCB$WDI)7X0\9>њʩ)#j "IdFaT,Iq[QGͧAެn۹,xsޡӻu[+Z.5;iЩY5$6 ıT}v*=aׇUmҎp>-KE[wݪ+*J]n ##'ٿZ~j|,}/[:|U=}]=V+Eg0\}mUCLOW#M9((j 4Ŗ8Ѥ=v%`)ذl r7ZH3tGHo' qcw:!WRZ-5*&J0II ̞u5-ۺ7v)Fe"*TmkM,R#gNY CH0%TSE#L$weSˑ&NJ, Ie8.r:)*`\\k55JOl ohR4!8"+lJԫJ34GT;{uAJu)"RcJ^'H 4P[:Ki䏃s=-I,c]icx He,Ӝ!dcm`>NoE"H(, >n'$wCkwUJ)VO,)mjD!`4 6hעkzNyp?BK1 @Wp̧m IWUp -sz{I*9QKȓKYPWٔTnpƱ[+n?Ω+c+5KYhi} KrwD #؀"C*?/"ƴ X,WXhROHq*EZ^\IJD+'F(BB9f FTHoVuxQږ "縬B#b퐥U "CdWydVdYE Ng6A$ $х'EBUvaeSkY0>,90H׷Ϩ<|zҸ:̃ƪ  NC ;PLӆjr\}u;G"U!GMd؉D7wUl!*7";ߦ"骺ή Fɒ2ԌO7JNSA`O4xpsߑ of7i#㷺vds&8dlN $X}յT3GJYT"-r@~1b)mvv0@IgPmۂ*K"SBb"͒NNG_19^G 9?Ɏ+R n1 8폯S3H!DA+g( AvAӦ\6"$ڹ u G4iuuZ\脚m# ]~%b"f*\ Ioee r/Z[Uv۪߸;GceSKA.UhL͊O<+ɍ@fGSÈr%o|'B3,P#0y__Db|OӸd20 VgO 5 /nCEQuWΊ# Jזzz:P,4CjJuM ]I4~XSܖepNYV0ZuEU̸VL#a"A&dZᐗ6C !W:C~U+|egzPN|p?&ر`1g%)MCL4p@=@OrV1J(Iޓz}xZF 15Gk vi HL Pry!LVT6(b(U,g>]:KI.J3e#Ko]*iRi5QH'v"5bQ2s=%r[5Hm˭'2Nc*ʨ"˗'%ʝ-܂ O98 wP9#οhO_SS?st`>oP)bĘԲ#\:Ԗmtԟ>5dE8H+$=eդRR@gŒ ~WR0I e++  FI8dPM~}9f98g0r*9jTгSKOO495R!$ÍxYLJ5ү^BӮu 6MjRjJ UjPI%өTʵnjg'`fФb0 uQO:q$5qX (u`<+_#K@$GDքm:ٵ1yo!d9 p NqҎrN)uǹҬq>5H+-))aa-E-طq -,AjxN+ }9uu- "p|S ͼ7i/[xvY֭jU.nX4QB⫽bufbԐ*۽J]VRڛX.APe]Km$uxqRD.?C 7.wv\1_1 PORa _[@G٘HXe*YC{u(Y"hRttbXN](]RklH&qN3Ȟސ?ߦV\ e)\ |8#%QkROXVXIdv"8bFX`7d,$vH M;xa6 Lo+ҎOʸ2S8mQZ"WU[1k"I3:3D&OjV<>U'U  @, 60gO+u/jz~klhj>mU]ZZ֖JLHPu UE6y +)i!1 n-u t*ĨbpF`7mSG:F*3ģ}IgV@d$)*p@4r[ܩ9$u>H=_%`fq?3zG˗-ɺmxYy?'t" C`tpeSRAjn ;9Vcep~ XS|^)U[5ʧJ~C^uG-lP'kW  }ڸuvyH\cG(75jωZk6]ƳRՅ֓> Q pjP0Ku|pGIWlK<&Xe4XlMT,ں6D&58dџ-9yR̤>`n?ܼ.Gg0tDS[(Mo.i%BD ]tTwf X݉PP!@ asD[֩@a L9Xk&ZGPrQ ͠R'5(T-FzTjSu( @:hP$ȅ$ԣV2r$` ~)7.W_ǺSgr˻Ym[E\]R:nttgzzJ DyB1J 6rNXk9'[)謟~emQ׸d„kSSV:TN(. =jI,3iUa]h᧶Fuiz%7Rqk-½{-酩niwz1A*쌥H+}s-*&@`!mmLji䃔d.$l(pKk 0,T"g @VdTF7_--ʼnjH8?M8ZnujOt²WpJPOZ ;Jd+)qv#ʨFJJQ©$v8ǹT<Z+ƮޚN ]v  a-H ,UHd, ek{sbL*#ѣQ`*Q 2eĺ}{P,/,+%/-6ԩ[jTT,U}?LRTlI mA3aTJǝ̥N*q N_*4e'd2E ̸BʎXI+{)W؀ `gMFtޕ/V#iz|8cj*j8M7⧬X&vdqYAZeSJM2g^y6'E!oF*kWA%1V!j{$dZ%I)m S >s !Cʺe!\ 萕_Gi$˩`Cx8r,.&>>[i.kE5EfaJAtq]ia8A8em̌ufRISy`} $\R|4 jJ}­z7LQE.hh-5I#yu2BnR"S!LG @>'QIuMeݔq:lݢJL(˜6$` ycvso蠫1\+1` a)BT,[#)D@Y7Y.l*cXqdjڣ81>H0iMg0bp ?S.~(ll*+UJ<%ȕt.R9"waNy/ Yn)_@PdݩEW:S*adGl>Z8oG}LX J'uHn.RUuߨ/ -HK$ܥ-Gdϩ,Pt9,>.Cx_p@H8xίLJaSY[Qg ~^O6 nԂz4#*j$y31* e?y#vx X+2v9 v*qI,^Wl!a$ >K|@m) RXvLUS"[_ r~!N3 Z#?~;'p!W9 0VP# *HA*ێ'I[wQ٘EҦ6bŝAP# bF:uܱK>?w ]Y1bKgƈTEfjC7a.re,@m2p0/t]4ho#ƯoWbI]Xc)BUe ,W*tTFN2 K#s@IePl`' &Y/0RJ%@l(a GK :K+fkUr?>0<LyXOOllP x/a+E_SLsem rI8lf/t6xfK\;K$?JvHF=߷F~!S90%IN<*2 A>YhK^[6A$3L]I!0,NHo,kOkbEzb@48σ[2Je%j\\*#3C!1p6׬Zvfr|2͒PvFy}7y glIu-k%,*֎grq ]\k~f/}@Kp5DB!VF$ybB7ˏMEj>nC;6" v ہ yS)XDAT =AX#":YCSN3P gR@ DoYN FJR{#I *˸r%OHVx(NĺaJlH#!s@_+F!CL`G=9d^˞ƒ9,zB(_V\Uc(,W]Np^T[Gm7 Kl5bx8)#%2gbYWS[ݺY,3MN^fe7r 2(o?ޫumxhQTTU)"KYWQO -]6}}^u^k %KgiZccr8 +Ji?)!Yd@a93=?93I}ud2LdOe%SuF3 q~|ͻ30@LyGZ%EowuDX1w)Č-*ΦNdF8RԦrH U*TNY~篚dIq#C.*әEEǷL% o 褃'dg$D[|11UAc*grJX%m䧁gt* |M7Lf)#`VFC0YrH V"1N q^RJ`H=~/꽲z,Q^-Pۦ"jpN$uDB7,(7ھCuޮW+*nUSiUJ;v,ƺ /pWVT2Ʌ %& 9#ggW|vtv*c5 fMə"^ƾ1.aCΓ[Z]p=7C@F+^omh(( O uu;>Ib +:IU@;utCE͸?'j:(ofd,r~3)Ԣ1l*+#X$pɠ,rJysC]|˼WkeIr2T+>!X!jbfԩ^X^л.ijJդ ilZlQ4 N Aܞ!qZ/rC\_ɮ4–% Qabmz=fu'r]AGTմwut "`пoD_ >GNCչR[h8[(a%].u\e_=f.̼vL}Ap4U;y I=aVesgKɵk[ֶKNZ4S>mYZeA^G:JZس;bK`Nf3ӴNͦ Ƌ]Pۃ4>~se3<@U_[PDglA8'*v'v̾3d!?WRǸr,Fyr< T@ 'q>F~doLvNz&YD)UYUB$ RIa~:uvmTjxCIAhz^(hLԲFR5+EU[bS (_1u ABg5WBRƚK5RΒJ ʤ F;SV@ZZلMxZ镫\UkTiU*SZFIfrSiU͕WWqRҹ]TFjY(I'nRDи- f$;a5,6b?*v JFCgdb[$ *UZaIIӖ@»$uN_2QZoxiXR,emy W!|2JMP#U8P ~\|Wt^nsq.m2r-HiUKM u5b* o\J+ƱGjpǨp3l+(#PP MNRx4[3TS=8iFI^JIU"ȬTS_RQvKTuU;nFH-$ K* D}u GU@6u [IQ54!!c@b_|xzVP0cv8PNDfd!U `ARADSDڄSAR܁]dW|K;lT `$%PY| 1Q1@KhiBWy y=Rc_ EҠ@]^8rcԾXd$fb* H\R *>VզdKS| H!F*8S=_a[T߷$1i6l$Is~Ly•E:[]t\{-]q\M=%{llw ;w1DT0dӓ#mJ܅8GmYQSJ΄C&Xe'ejʬƅ]Si]H;[c`L * $`D0r%p N"HJ@1\̀g*ߖsډ=" B[zG,2 8!T ѱU͜{jrF9p*bZdt LUVbX,OZ\9h1$ _aA@;8~)wZzU2,@T2`WUP~-ߨint +{t@* 1'׏f,c|Foj,-یgnj ̑dUbfV',J(=Zځс@#83LJJVR[ONU]ATu܂1,UjTw5e@|YTSR[L,}b|ةVP ARPU<{Ue*ԆZMD+]k-];YSp FnLkߧl4LFvginVmNΖ:M $d%؍p3bhyM$ B TD0J{!*l ﵲBYF#2)@\'\|PKxT%y6u;RjGP"8-S+OO#,S*Z*ĖZQM3U&) $*wG HA/d镯QpNZ@9Q5'^u]C(RٌLkvPrc UVąB/$+0%NngRCo\AT\fp敆_!O!wX9 >5 @C|Q22쪫 Y+Zjw1 #08~UU'i&$bHxa7!fXfP}Cġ ,ؖ-d띰KYLv dREpČ*}]j0S>mՙ7Jm#5K -Irw@H2@qjxW*'d]VTE-Dֺ٨gHJHrІ0(Kŕ- ftFX-Ag$+ T*` vHzi)>̃3IGX߹݅$m$21$ |h:Mӊ8nqb>CHbLzZॅ-`\; 2Zb]u(ߒ%0eb,M:MԾ=vJzm7~i鮶iH6ƃO*vԻFOWTѯi}='Rg4 {LjGD66`A#rkέToWuVEU^$W!H蠐P :䫂|1hJU<yr뒛`8lwP2݈],㢳oru (d$=Ҩye,ʄ 0b1.$ LĈa<ɑힶ&GgSTF:}IA*U" >ڨRlLZ1H |2 ꤀ppVX%pAXX0Åvc E$*XI ?'"<ݵmd8 'y KLTV]\@#s{Atj 44@ p929aOWeƦl#%q*u'l):YϙEy:{JdlRte,?ŗ'1QA)ynrǹ&![!dݼyeV;3HĴ,kd%'*ꭏlpMD *7q#0GzuڕS_ߤ(Tc5\X$ `!̘  RR\wĊ-!bPOME:nłhV$~+/W!N d|]N]`yB;! grʟo%]P>R\OZ5Ho^vOb>uhv*QKK2+OtVc5b5Ep=ąT2 >febl9ePXچ (l[K'wR~7aB%Fb 1gAbI}e!6TU٥_YC.Đ3)'|Kio#%ҍ:n h2[wpOXߍm~^(T3q%a 2:DC*F1 *˶C~p$P (՝gV`U> T *Ƞ 2G `PldFG%U4i:bk 0*<鴙<| /N}צJV2qc/ !vdԲ3l"md$t)+]ZF`KZ?LSn!%>J?8bbI% xԚ sТE4A;љufƒ dnH\:j~<;/>PtmdK|MhhήU#T+%C58e:A}9_8Uw!rMEoka+֎0zWtS!>h_E?=w RuasPoSOM-w+^x'[u Q$|~Өjy&[O5ˑꉻo]WMnyfH"ݛ7MwnrՖ7-%Mre昻ȬUEo_ ڸ̷lյD5\ ji;QUK X5MS7e2#i$bI,%.Iad` T>Q!I *d̗}sRLASNإA0zo2IN9L1V2) q`K\)#_ 1®qzԕ,kYdc n\,jŒ hR{L0#Rp([*Đ][C IZ+]4(l!'$pe:d³vTzMRުE=W4TmgzT&s[Xīyop6#XWY{{Gb̀ĐAŐ xΙ4c-UGw ,>a yJ)ݖ`YJH$* >qP |wۮm(BvbBqR6%N,s}.n!T3?pA}b@bņ@V0ˌ!dc#h ,)RJ!فVff213u $98uzyI:WQ*r>/2Ur9.TbTfk)đ"\H,W,IuoT+N:ڬ }Z*ݑR ~tqLvXz nSS!#`Y06hfp"6!W9 &$+ADEX7BYі'$΍i*iN"llv8MO'a:D;c #>m NIװ"3_TDQc9g«= qp@`b@$v'h14 R$*SrX1}c_a5b{r'}1}~Zt2PAE c1Ok>tO_Rp~9;sHbAǔsG䨨4FF`YYJzm0+OG]' F6 !s9 T9 o U{/ [9 q=0aOzY8ԥ[\ OHij:gig&6>uiFTHR R^ 9ܲnJ5FM JV<*RJ2P갎 !>ŸP6]`vȘZR<)bON? CD@ ,A>Hdl+V*1p `q>NOA?*@!>Y&OǷ˧+k/yK: $;3Seb,&?@T77 կҘ(Z*5Xev!<B/ɴ2 U@Af!?.FՅ[uD< DW(_ 0>`i0#{!UhSJȤ,$:c\l{|(,AA>r=.4ՊqW6 +r]rģ?m3D̃ Ⴐ`d8:1pwcY}\!1>]Xt>? 6(vv`G #u['L \?0_ʀ20IP0K w-$L 5TCgG*$ ]AW: ] URrv28`Cߪ57$>?Jr Ѿ[ū*yEuUqs)ZyOn)H3ce vV }ov׎#åL:[M?vPE+jषSehA a#y$gzw2ڨ|" c%KeXd׺zW&"z&rvrvЭiSMkWRU U6q;GʡsrH {G`7[x,B܆.C76d5yT(rFc`699a`H؞TGT ފ8)`P0l@d|HWCdLW/DWLJϮPoNˤ"bYO}brpH0 _BMţ BucDyCأo?m ֙ q   Y1Ui-#h3QHS,LJT녍AY y8UO:w,O)*RlMBL0 :KU8z.T `f"=L"4acWB>A 8%Bڹ}"ǩ|.u:zV+$dq0AيV QNdVHcF/Ϋ6@T,`-ETSڗV+l#&^ w <RFϭWHXZIi?(k= ZUC&6A)v/i^oo7u7Wq;%Q}9i6 DR<+Ʊ@ ~rN}p[:X)lP^*h*(UOYnI4j"q=3v]FuC漫i\tRĴj˽LQ&7dYCSjU+]&֐6&t?|ҕ4tJm` Յq D;&$A08= S#0%-/X T8Їď 29=Cvr$.dOjaX3[2w Fˮ *KCjXe{U;y/w"IuRmOiUO(\@wu;ꄪB+mzthSUޣj[T9 R%1.ʠn u!-^VF=V "P;2#'f%4X;R.[! /e(6'hdRfAQ@¯rԫ3OTi"+>cl2$ {Kq#M^ҕ,#Σ]?3طSf%c+rXN#'''e(ڨ/=S |i'4r@-^Rv2$b138QP F1;qՇQ =Z#p yHmWi{PNpV,SyFF2Q]e* B+8ΑW:twF r*/*p$\cOxv(L`*3\Ƙ# ~y/m, +zGrwb}}*/93N%E"ͲȖbPYBHX T%h8AXYWP1eEP=A' : Sfnqڒ++5<2d83y ʬheP5{0qw2O9_PIϹ=tk0{,HRڍ@SB岒SL0 R,(8VSc'R|\t+4ak#a ),T*|0’5`bu>AW`N%oof%l6ڎ=}%ִ\Vz#W"GXӷx6fQoQѴcShiu]Zu*VQJhıE6R*Csp8Y"NW,hHX(6C[!AH`qM(:a1 HlJoo{\-ndj()MR]颬J;S!AIK#Ho,!6)*'C1Omno4kot*(K:wGoԂi){7Jw J4몒$Ӫ%&7~eH ţ#)nY3U$F<$HU ?7)KG*O %pvMN`xWb+v!pEx$QF `* *N P=eE cv)Db1~:ikq=8tbUZ3k78䐥!J-7q_(r`iTjY (v|;U8],u=n"tGFXDTyPF1*@ܓuY82ݷ$h@8mB*I L0O*c%r|X[*ѿ`Ic,WIkdDw u *  kFSxB֕4Du1Rƥ+[ju(ֵ-|ֆ7mՅ3nT^ ;g>liEnYism-kISV1Jf`")cbduԏ, {4 D[WvuU[qsFQBJԅ@THW  uyoR`4<Ne/dX aw 0P8"nPGbKʠ 5m$7֪*LR%qS\kБH$ 2Ȯt|cʹWPx, I1A!1rX @j֗JRK =-ިT4HcbF6~p  j)DB-DZ' q>ǧ׎OlGP!I{ȷhk)+-UXd2oD5 $3K,]AgKMW4O ؅d$X1+)_]AiB8q d̒Oe vkZVjiOc]Ymջ{T7鋚bڛUw**]Y4PTF𻖧|h!0,r(`]O87(⎖[ݪUZj *KEhRZ**J;VoC.QʕdjCb|?AzC:Z]: 5=,5Uw "tIdVE +ڝGWM$J5-VWzTս!YJLE5\Vgu:+(UcNDl!TtwAZ1;7A\J_w DݢL'I`"g "G~YxݏZګrgUMMuQ>E ˦fLLX+4mo_o7vV򚫉yyTo]f!q˗z}FJ7z/iZ%+ [Smp$3U<8hYSVJ:ԸM>h-W%'9a>Jcp0ؗyԣ:MfEd>bA %@BXB5f@(C@-MWc.AF@e}oqP[vo H`PRVJȕ58 qȒO}6P؅R YH(=.̧%d<6\l1{ +el,)Ngir/.bcmVe,*smB%T8t.!S, ϐI$K kTuj&%|% 6eHh&x"`1fIpA`''9]W-qRPVwo\0`v& LZM7bӷ`Q9unK'+;.qW,A9f=K 8wbIaqN#S`j# |V$1(8{o%%f+G$#4$o,8(@grP<Nje;13n_gonHRGf~1YK<4}43ۜJƭ&LKtW%K BF.n]T]eNW!}UT8 ~heJY `YU$V݀eE#@F\2ˮw Շ"ՙr(lO E~CJ|3D}#&>C_L~(rXx#$ :0~unIbpTl5a{N=W],Up FH ~glCe !,u_;0UjQfx[ ĈLt}hyeh' fzfct $9,3΀\ӎ:~U\ߐr18S婆Pr=U'f r8s*(޳AޭŭU G+*L WO*i`jn০ıCOKp+J+D>eSyG'p:yRIˡP,6g |-|v gcco[3;zEjMJDKgsOC:x˽Cp`"ԪQ.$QQ`uY}Yã(tlɕfFܨ'=)WW(6 / V&$YKZ1h}U+ܭP$r$lw!aq3_=|Ϲazshk/5B(2w R >GΩs\#sT57p& $@ R yto O ȨZ MOQj\!WYTʮfʫnCI$`7mE/iS{ 0%YRH5Z΢RukpEApD0O`kǃeke}X,T`2} i݋'20;bHS =|F O[n^V=e_,4tv(a zhI2)ˆPec~?rGDT hK\רTk-cҡYV,RGҬ!X9SR@TJmP'ԍ1>SN, aTTa%R |eقa4o$аAtLmՈs'XJ b9I9,Ơ(,;%ov녚yLUIUKWbHX%EH >1$3Y20%e5 ځd hcrE|n44XLqHVh',cfm1(pZ:{QžmѫgdذR:[ͣzKIۥ[-Ф4$DBR>VI# T ѭƣzT)I R ,Vz+Utf*T3+1HQ/tH71Vf_rvq*0G0bU+o*_Mh8wQ#]FO Qu_ Yޞsܤp'}"/%ݪbmRI’UA 7Pm.)ZL89$' >vj\ (\ %QsߨI$9cp5l9@«ITSȷ%+ޫ%-ˌ*PIW_ ?wQ:cWpInUhI-w+EDСU/ \!C,Q+&<8+SEe,APX2˩\eӬj'uQc~}NH)}r٧^U5`{W?GVu:xisռY]XX2 @TR$մI_E[5ŽaނT !|~[Wnvq)P~ī#g־El4P1g5԰Ʊ^SGZ`MGKYB bJXiT4P?6Gi%N&FGO^}L+%qQ ѐ!jOm+@xd*\toT: ]t6BF\3_N7ZE:P7))ȕbJ %ˠrjoUʘU lI!R>J?h_*Pž6M#b#XzvB!EĵwtDNOBA.ܫ *deL,XaccZ& 7Oxb:MKjB9+.SQUy竨YfzIYfxVITv90J@H֍e¶v@_PZM^*ьD̹!!#e?A $o!WVI ]`C>ce`;dJFF#m/%zƍ#P}TU]X* #n5Ÿݖ(l$$NG:^h2YM@G"-JXhà/Nٛ[K'l60PBpH꠺v\礝U r3KԼ5ڎJHZY(WV8ttmEgDα:GhÃh:a/q?0nS,,PeIUj`Zz}>|J8jURfIUTf 9*4!2zFOEL"O~-ȩqk=O.wUSYj-&Be4vg8`+u \h%ņioVVǐQ*0ᕕXPAUZW~kJU)5U" $$`Jvpuw a|f8.B9brA6/V̠˫6 WPʱV?;(\yq:Wʃ@o-#̪<)Q3Ρ\ ymԇ` l=@}@ 1^:amS%gt4e!-(4D;+?4'MqUBЇpT0Y];YvcrDj$t;NjbF@5L2guTV`UÔk9=.nM(%lҢYLcߴ,W嗌~hv }cwmg tׅ)v n&Ie@@$=IYo3-8LF p e(pV8aOCo1)CYf9O?`I?1,죷$gbPYS Hz(S-s#F&0 `d`8,Tc*$`APd H${r_ԫګ~ߨ.\>uKpl@$ 2q>/VV#Dú "U>AVLj~r`>_\zHF@`?2٪)fnc;p`0(R0}Ш/aNa&c^)<s:HnGʶ>?,_|↣Hs5LWIb2\EW8 cWIDx*I.Haͅ/b@(@y[K4]ԚxBα\ rPQf.$ʃ>T0IY@*6CW\hF>hd}&h_28 |Q>)ڸȩg1Ec큎<&جK7iՙYT(` [,Ĩ$obvV$CĩTHsup 12~{Nɖ2fv cM`*Ec$cUSߒImPx\; uU?^.@QjECbFXƠ?V\ 5-b}\\`) <C @ppnA;$ O 6,$yIPS꺱n2scR ;cu:=Wc|wϊ[|^ KA J8܀FPGӺ׌3|_]'>1R\.LEirNԉLOSOK~aՠd]ܣ􋦋+{}#q {zcv"UœNm 퀇b_!؏T&̒'> l!]X4 9*e!8 2TƎ!Z_] *6Ya!Xc,1vfֈ@1b`rT`Lzou錄s=g}9?g[/Z^?br [8RTI-e}@;NrXE-mt[|X)-_n)E MP.ŢJ'$%?ЮsSݓZJ3e;-⮊ǚ %}hU5*4oEWۜV]5UuS4UI-L0f-$K;,ى9^ceWTL#@YC'` \f:]\TQ >ߣ]5-ݥhRڊ `w=ZX ?31` 3{.?*fgF 0(21 f9$E?Wm˥VJIZQ'}u}mGгDg\ľJr ̯Ym0I|T$z68ЮJ RNsq:%>tj^e=ZA]$T4h"g])ZUE?jfjܹDu<-i~rJ^ u|rXmb@#c)U.O%2(OZvEuޕVw{÷uEKG00a Ddp!YV?ϫ1+DOߖRse#P(bxQcf/4֔ƕUoK3: = mnҋ=1CWPw`۲$F^~k֙_WZS=[)%('W-JđU=idR7id^rFш*`1C Fr6lJbL.}+~WnVtuHԴh) H-T ,QR *,+L,# {σhb.Hd k+w"=?-JڝeN0I*IK:_̃fzY]\ZB;{AsfXp}0s?I_ 1l|Nkz/uuiMmN/AFU٤vJ\0TŤ ݁smp/ʀ> m4t5PVg>މLH [9~9$x$ՎLFɕVBhYfCĪW .} (j bL8 z]2$3_egWAI=+,OL$-JD{;]I qNNQ@i-`V1(G 5;H$ĕ?OdQ%,gɐ% 0_S\3ɇ97؉oWXou7-;\QIPHqF-NIQ$s#͘leI"x F*v 8Wᅚ}8\:upu[jo0Ŷz{R:?$Fi bbVC**L"6%I 0$=ϵZv+SfWr0;Иd2=:=6眣dO{AklKNMuUA^)4L,mCY`lo*`f!Ix}zʺ!n*t977jSk?v+YkzuRI;<ILAJYB`c9ԲĂXƿ;~QL1bV91j6jZTN.UlQ 1ΡhFSbA3ٰDi2Hl ƷJI9 3NFP3 6 iy'D-URUU窬HWWi:l#dc#KM 5AGSs >$BS ?H_s|*[÷AcLRcZ$BN=R( (gJg$H[8%o(K*m$r$p2N=B(JaF:UN# V8NrIت(|0v>YA!Z5V!• o{ZI&{"2F8 LovI *'-njY9.9vSCD,4OU(j{AS|s+S3ʇoW57mq({|Bkhh᧪%>RkE=IuK_w:t7i,. ҫ55c f+-IO{ Zzۗ b*Ui*"W,sԮE{2frѭg#Қz AmY/MO h!yZhϭtMBAAN+ձ,k Y bCNDZAVbBJ( *$AHӨRٙ=,C0)t%HUa<2D,^RYwrVePuM#7sp--:ч™C)b\{1*n78UO Uc̸>9dBC: dѐC1 }Ñ XF 9m]B(-F'ȚZ.AFޠNI`KYd k 3=vC(ɜՏ`Hȃ(+UӄleV YwTP"(.4m1Jf4(*EJ_P*d!KsLq+ DJu1ɦ'uʨc7cɕg7#^ET2Ge} Y *B 6K"0:o°O3tDr8 O1LhSPBgP6R̨*  nYMORРLbGNG d3iaBZy#-ұUaU` v?T4JK&yGbbp"' %jI7z,v=qz(d dnb8h8S<glb_?#>eθL;ҴqƄofi>$LJ1_1Wm@MrI.3 9by̩GX`a@e󀁂c,#.y픺x̂Bhf$ou|գ;K`;uQ`6I4u,p6.kPc( yu Ur5؀bd߫Tm0`SPӪ+1/h YʁA-2st6u@* X)9\Ю(psVT=erhzHuY2@b[l%u[6<\`W B(Lh+;ce+b## ©' 9G?tָnUU#gIeUHEO9eX YһU +FUo8X~I|XU%]eh#$޺V,[OA8g5tr)l.kv1sSW30p\cD+k+֥E]Қ=jIC5.ҨfhTAb0&1&0:׍IU\:а rJGrRN,v]GR!˺C:zq>pU╷jǎ'z)mUhzh)J**s6S"% 8Um0p0%+uK-F +Zw+TOAiUX52ӫM*)#5]d(.WxO)'_Rv7@@*(v3QRe!؊@{ġL@뒪P PU6zxO)*:I.łqj? [ h(9s;bgzkhr*:#9L*d99ΰfw){jJP-. <Ʒl6[}uLv.w: |:}j$ƨݑLeVڢ{]Eme1QLYeRK'ʀy@OˊVJM֓*B1Lszivw76gmݽ Uj۱%v֦M)VVJ!h !'Pgqp)QքQmD1Ow ހR#*Kr*:>ygl( p9Jº89ZRqUs* 5\ՔmY"0g@rI5Z>׮TJi:R =YРnlz)$KDL#f\O?I%K$a$M,$uf5+L(,HB#Ʉ!7ePHax Pq~jRخyLԲRA@`UUqb E'q 1rW~*o\qBA=$YK0\K ձlMS9w@?!kȮ"O,O4*)_WnɩTMSjՕ;i$@l1u*^KVWQ(%g\(G;1)++%VYgy%fXY1?UQo,9V p+&gqB5m -@'$?ՕHq ;QQw، $!\aV bďRH'Fsϰ>T@$UA8$ti.]zM|]FdeЮ r/F[,.=xڞ"X/Yn,eM,:^*uM'!2Oj>[8Quk-wU}w#QCE4E32IjCͅUi=L(WBu7yҾQxы[MIm_訅"eYg"(rMGvK=BH7S;ڙJuӰF/PTm#h,.YP%JֿzZĕܒPR,AM\BFȭqʯH쾡 !!@@l_Z9+_H0\a2:%2)뚓tq_l{j\Oٙ(%+kH6$ y3=DsJɢU_bۨ$ hUtO*ѤET=4`JLL܊6M" 0Dz+MسrHX.L:=,̠ul]v&̌vRT,T9 P> TZ88PdhVʮ m˶B:hr n:69[RF&#ݓ*U۴om5Juig*I_1=RچQ*S )B9v;WV.IX"GΪu4 qiԳ4TQd55Zjc%'cUQˑy5edUBC+09N'q` ZrJC~H*a4)(D4P$r#İW.2fݨ艸bI;%I`jQ7#*D jڽ{ ޖbTKauRիҩOzuM2A02cm9݈RRO¶Qtpu`@l0e&]tMӆ[i,\Qrĩ-Q8#?xLDWУ]\h1iv5`$1 1 rAKyoo߮SOOtU53GըfW%1RUTgWfj&apv%&˩' 3)VIa lڒA0= `&3xvłQv. DG'?$KxWUܖZSM&U¡M:Zb' SH_ԫW*鿳_KoZUX1u0P;h&7m\QGPA`vx #D|QHDtP `1ಹ> .A   `x9 #c؂u$|ZE '.ObF#]A;aXZKDl.{gf@)p?&Pf5Gz%Jx`cٌQ"?s!O˪UB.2܂ Ĭd XGؽpmutX.I$Iڢ y }$WF LpA @%MB,&F$ua 1ÏFꠁLD /lb#(*5FP;Bю|yH$F8 @g $oRYdBO= n{D#4{>GWh 3w XQTI$1m)/ozE/+]/0< .1}^(Z [s=-zDHhtR8z%/;O R\fh!\TMraD`ўΝ[Y@veP"ep}hKY_ZiuսQJj_[e{p:3Q@\u ĵ5jL*JYzE TNN陎i6Z]sccWtM&ɺ5Ke8&0E*JUVযuQ<7r$5,Up7 pe2K9#`9Cxe 1҅`i6Ԍ4 ?r3TlIH;vF=BuCƥ- SgE4eo4\1=n7mlNGG]aU]SEU RT]6.1%Fh E+"2GRm>@oU@c_! @a! 5>P 27]+}'#:Ӛ& Zt#D 7YZ9"kQj%;KMeuIۺ@eԨѭyeFe*ZdwM]q.ݑ9p2Yl$?V$l ̱1#TV%]F 3 )d}↪]t]cj1 +[r"iK.dm+ͩF4PVgC*9Ƕ.ѨԘzne0{n9gt[j%E2$3=#z_#ܪ.U\jvjj-2U#D"*sV<ۘO*7K ^wѕ!WR* NM ߧ,qY64^j)i3WR(RchK*.MƹiqZ5H H 5)x+jn?NJ]&*J`5B\(3~)h>HkԴM]D C]O'wBSIU{eLe_p2S_i)sQ.*G)Vu.I`4C,uPU,U+4l lG(ht!",i߰2* >!n V#Ҭe'ܰR!ԐT0q]6]*(|7z~Ik1SEyqNSM>Z#mB( 1,6$lBBHe\?BκTaݾ+-8\Zy߷ h[T(f5sAu$# 2WROu>rGvurN 1%6hu`|њ[UJ6햃&ޕ4N\NLlw0{;Jlz}Έ+WtOZsHi笫bt"5UCīVV\85<,T*ݒ(ev jo9jlzjZZtdJdHI<:iecUHLӨkWKJ:(2wIjlM=k1V $OVWFܽ'"A)Loa bQO|*:iTJա(8{k %f0W^Yy<*,H ŻjL} vO ةp|0J8IIǦRLƬB Tt}Q5^;^yi;ODhaFeU,)3l%({KiS0]`IDh3ukjV e Y#.Q)NN%G_hb=é'D,U\bDiUU#I s>/N*Wn_x-+[d!K~nUPHq()iXpDy._  ry1 .d Al(ZZc#L&^"i]yA鲑2A# -EotK mS=j!\4aߦw"u3B'jI5=D.Rh&WRnj(G_$|kO ܠ|nز19ʫ 2!躖ahduYvHԜӍEW+p]fJ+H )}%'fKKF7"V X"`J+ t6v5G HU탆rhN_R {tLd+:eSa Ց/GoK,UXChƶ'lCAӟH$d,/nnGVpN zg9N`OIF#%(S`w+0C*TȭunVR@w)P S!̅Zf>Hx±).)2xFv20~df\++Ub pWEVG"Od~Pi-77s"1P }< ERU*\eTT}] VIYRjZݺ)fRG 9 Q R}ť:*\ֶ~fbCS%Qr6}+ .v(u!ԓ0,6E'%~Z7Y8:23d_|u !,Q .J{g sh-?F~(0 ϓ?&_a;)ME2(brasA 1/Ԟ5+%X/ r̄V9X()⍵yrdU30y |xMe@Khw|7׬V?3۞oGRH#QsmkC$6IHN3w%L%*,|G' 1`\b(Dٰ;e*P@* eOpKY\n^U2jS9]V8$|2P[bvQ캹c6B[,5թ_WB [F L;W":MU4Ƒ? DoɌoxKDTafA}`JB|WRT]@'>ږ>wU%S| D"F;*͑%*#Pr 9Z6ջͲ2oS*#crxtX$kSP=mǓv]*Ȱ8BXF\T&-BrX8 @ m ey T5 +[A _!C5KT n>ǦJ*fY]Y~Z+ܫgnZKUhMCyYZHb0<I餎^S{h&VS#Hq]Yv_'M[2] jAU`Yԉ\PxpHĩ,8=pÓL,>ӞS'$ C]Kǰ`P\6_$6ӫRRVǶ[$;`ꤏΚ 3Vt1TS+e*RTKRq˅h~OuQG5m,50E/ ux][PIM$tQX%`BfZCgsGVz} =K6;^/]S%~GrN)=L5O:TGؒzg1S]Bq;rIQ[SWVE1WO"eeT tu <提qKf6o#x疎T.Ѵk_GnLVKNQ[)*2 ]ˍS pWTHIM!Yr X]Ѧ( I+ #|l.n*괅UKQ3J m%I]4Lv0-e\?6*^qz>IlFFHFZTfHԸŘL0lΪ{1y̥eG 6]I5u $uB jĽ &51q@k#c >螺#ЮURu S Ӫ:vzԀ^,T!zdeHSA\2&>r H$'a: jΣi i8cofUb0T {H9?npXo26>{3X n dQc&x=i}#4(`| Lp9}"mǠҞ&#< 7mYZ89#%P+;jm oJ%cSA T+:U64qq\P 2N rH`PXH(Ā̧}b}(] `$O[SRoi`X/:'P\\/ȖhUJA Qѣ [\Ε'+J:ʫ ޯgNXguWxp͛/~}E%u>m+ٮW ?ҽe3MjGsD?uDNw]N߾_>YyIj {)QWЬp5q w4PZTSur*J.f P&It E:N[)O㹂& O=g4Ns򋼕"EƤ8a$4#X^$I`QfD_ ᱮpa԰UP Wb?h}zԾq*i(!,¦i*(Y4 EQ^iڪHvTdF oۦG(,8)J( ;.jӐ{!H3:*GFFj# B;HeR Ñ VOèfV7r#. R\8;_*چ*$$h~JΡ'0+.XI 6#$UzTRR#0A3UBIh3Nc;uy"[yq>P_O=:'"P͌1ec@B!vY,DMa{q.xykfyj^"; p)=9 6gomGE%{KcN?N{;˷NA{D"7ɬQZeU==kPljx$ZI^F{RWՁCP0LaQ (zӋCzd c*Yš!Q̢Ya55vv([Hx=gͽͭ!kZieVHq42&"p/uo:׾/m^j;W꒮]VS$SRL>v%#,e( P8ՉPT01VԌ-oc_I?DziCn"U\KLu:oRSMG UOܪ1ݖ5wTKFCJf8* Q,ߖD"U $3UGmH`9V;d@]pNdq j6oNJ Uj)Sk8H+ZKNrJ{XF+!Vu*_*8c%녳PkqP[j20JHDo%80&E ,ݳ;%Ó,;v**)e`cP=^>rCEC`F =tCB v_w) `%}I_&dі!X+e6_B+X1/e\nCNs'Ԑ>4ئ&FX5BUU#ٰrȧ h0]+2$%˩hc\S u#`Z٥E_b n15"L$iCdGO'=:2 9W>UY22V8 d*x'8%h̨GLlFVC=O ȃ,]sLTf@TA?[[}G׋T5:4TT#>Cmk5nJ{\jb Z:zGmKC7o$25Rpejhҫ ԣ}V*[!1U?PĮ%M R̤ggaUr@RUG*`_uoۭua( YUD`*|tz*RuzU)1 (?>ZV*Ib ɓSlo7-CpUV*ό^Wp!ĨJ!l8ê铆)IETUAT<3d  +:YVF*hh , % ʭE+=0Թvp&L;vց["e(\рFs1"ೳ"4iw [ctލ 'h#9jc,!JĮX޾6bI3]A)`EY'mUfIE+(SVE[xD&ye(mRiYe£-$A5{E9 !q* &;Z$|$,c| `T$, 0qF:'TGa / ްO3xP[ !#ou]iZ3hBF.C`Fa 'V}P"MNs 垚=B);)M@0ƻ,j3ĶHP8 \yi'$![$Ls:&_m   FLHǩtC祖}Hbqk&ԅIH|ĤN;6A%u$zHXտ߾3ۮq<:wH,VH3wi#fX٘jq̗u{RHxq.8H T1,俱*|gb,?~6 #g=EJBVլI#1#8zjok4#;ٗ@rT 'qrLjKڜ;HeVVRT;05cQau}N]Ljѳkd#( O}\ :ADg 0dȞ 3T'Ru;( }/IMJ4!0#:+eLtSJSL?p Jσr(=(FaL)m x ƳIoIyWf Pc@T-5RKw$\:?ϪЋ=Ⓡh[ dO=0 4SJL1odW4-"Z-7}':D5d! c=ztҕ5d: @ʅ$+.WOUGR%*9g$czvq4ı5IAP8_/ikxgM"ZE.5: U`&s8c4Ws w+mfUikiiҺص rބ: ihJթwS̔QEjgDF@+,m<͒Uږ Tx1 9Y7FXdjc3$h舊QXH/,.hI[?{:ij{+Gp5'@5E3,Y  $ 3`Td Oƹ"SvzI;ٛ-I,q18 BB8QHA*:'h)*:Bq̳Ҵj"TYPţ^55^ӧVLEbЖYL VHں*2mXRrI#M?.!rlȩOY"'>!}H:u'VAKdPwU_g΍[:~'ӛβA'KeȞ9H5fʡ?ߐND֯6z]k뺪N zΩL5GaNBSVv0 Te5EhS_WB/$ VEK[\h hٌخ2̥KA+3*7H\ :"*`g喎OgSh8#r*Mo%m`"8s"'r_IYYL=#dBiš$zi7DuxXRD/Ȏvѽ3EOӫ,;/-EIXlQKf);OP Cv[mZ{-ם"n-8W72xU5lV+[Dʈ2(iZպkfwR+ʥcNTP7i% yj%$ ̛ặwTڑT{E+ eH[xLuMNXA &PYHL G?.~g[\Ĵ܊Z#@dq0eJ5R#(",F4*3pT-$2pL*iw,Bڵf5 E74ԪV1 ~:!dC]l[ 2YTޛ &%e_M{r=Xn6' }mn7I[jq-Omܯt54ZQSih)$3N4,4M$ʠPU>XOz)}N@ ڡOĠ"ZIz/.k٥ښF55bj"ylLtIX#Hm6U( U=cUOy0#$gDwatP :(gdSc!(a\ *&>Od8uޱx.w$YbV K?`C#^xu]wsv4މ\fiR7*(tYSO]JڲT_1h:A.OHNm=LWtBAHK$ ]UH]TCitA@LZ)pPnlH2-e/NRsqn'S:cd5N?]LTڋQ[tVU3iQR=ZMmU,T;,l`3xvPJǐ;{?jZbiZit4Ž u*-` WWP ӰDn)yDd$$ZeN-Mʊ5tQF˨] W u,ԾiDSΌUcqpe(C0uz0G* :' M,GvYɪqR[ݲ3,TϒF@ @b ÈbIzm&sVUn3 09_l3.c+Tx{d3;d<Ŋʪ˅drIQ[_;Ligr~\fbK@h &nM3%DurDզ$\L8C i XEmSGـ)-+\fʮu3'_RUZ@̈d(rS=Q_WUkX6ժFN+NѺC@T(*SbIMTM xRV <>9;:[{eV¨؞ޣmЮsQ,Y#"6es zU̫]>7mVNѡ6Wz{UE|efHѨҧ?uR8(A1s/n_ĵMkQESv*UmEz`TFv+DSۍB! Vʅ%#m_ķ LLZY H+";$KcYru݌5vRQFF@ NB*wL ?'` OxmӃ23pO&ܺUT%"@wrĄ;F_m%ؽ=5Tyc,FFʻ!B?:>0dڤhm,9 c;2N<9]58̜">)SѤEB' ocv.|ξ>to[}>WM5[_*}cRyZKT4R8ٺlRL5x@̄`D=hU%\Ot4=z#Jo\[\$]70ڣi-ܺ$Tv*vi^Q\~ G#q ?Zy(u>#]-T]Zin2(䊦1Q4BFf/ ͨ&JiGje۶A%ϔqq*䜚ud0SI4hUK 0'.']>xm3]:N4mJ;˒u򚚝t]6) ey﫳RAHoz` mEDBݫ42Z/{cV]WKD;LzCƵ45 N8H3\Ku,jH$g̛>|k`WTlwzR}rhcP21#WB`ASj4|*ň X:3̻ j @';qV0cx#N '׋ʒpҤS,sҭⱽ妨gmC2J" \)䧮C]I)zZ$u09 mq [$׼C^TqgI$$/r[NfufhĒI'[}( vuQ`Uᙘp@(G˛ִ()4Lض\-b:<ok!kW_zTR:jFSEQi=7溛aQNdX ʲfd HE]WAz[О~mwKe䎎*i%i`*kP՘+1=H5`SrAQUkB08 F`J(ǮkZߴ2ŰzӖ!a\1! QK]JO*[`ӭI6צNSѩN64Ҩ YYwcp0D@㞥WX>_7/"pUߥgIW)++&=JIS'!ZIpz7޸Z.kM=ECqJ8ZmКaU-D̔q:t "GItz[1 (, 7o$!XVt0uLXM]q,KTc\G?N@ReaVƵz7W4lnڵZgimf+* xգTݨV LL^쬦Pͳ0, H*;Ww-۲eB~FW1j6T` 1Sf8H% IPG$dnaruVr0+MR'0jOϨVc'qāg#+%,aP1Ό̯q'R+++j暴 $==BB# ۔˳E1:p)̂"YJ3U0䪅Fݿ$o"N:ūlw\PTM1ťLtR,5 t5wy~a]-}T+!69N&N`5+>{54۵MSz"ؗZ5SA:p̬ 2Ł V$aTedS=3d.pXm_k ʪ3%3b951FzrIM%FW1!I:荫"4Jn]X+("}貁C+ea@H#"G~"KtY:f:EqYg{U!.5/ Um{Ŷ$vll/qY.Qr!%JUUIM6 XmO tTSkDyg&U9OAp F=*zV2lt1xa(=L+Q;%_gn/.^\иSOwt6qr)V*TQB qd):z)c#7Ȑ 9z^Ch/,\/{<ݮS\굊*k*]j%c8!ۼ%T3 $EUAQ7b B H aU ς-K0EhV]UJUj$.Im%U}$Do.E\DEMRUUPU~g3)c,Le:u#eRYI ms#egdrS~ڨҵ4 VI##le(K5˶G(TL@10 g `.bv]٢->;`jLa(W9Rs1|7FRNUY\R*@&#1.Zk[ kz:ՔTVjui܎?D Xw9ZZyFϬ9Xf;lFDed ՊJEU `4uU \P6otuSQVq0- i^ 5Sk%=%Ҥ 1Aļ ''*NUfObw*J.`B-.?k4TÔ}lUTFvdl4e>$1'ZZIpĽCATV@(S)t<@!a#pGLZ;SqTMdIs]RTTuXj!Sݖ݅D E* wx4s'j`Tzy#VdF`%Fι%clmpK%R1&B,rѹRvP#sM]:.7[[-|Q!rT2IeYg%DF8F^Zwj.7pE&L~f`<ӺET{kT:S抛DՉZxuVXM1O_Ѽp}E\Rl㜂g唱ۯTVɝQDtFD웕U|m enHV'vP@-\ nXh wW%2F\*6ʋ'b_[sjF,4d.iy4 ztڝjkZQQ*yJo(ro[UjRCV !@' 0ۧN>5]xH켖ceBS$N(ɗ w_rQIm)\i^eeTtKZJ6;)I Yo V["5ΪH,1=jYRQW 4x,wk*g@؟S2gɔ;H jgi52ܔ3h q&U`ux {+/=-U%)*ɞ;pU4K20+rpn[8#mq{g[^XHx%ȒIiNAlib-NһZܭ45Vz,m˝-*|ՊFe`5*;6,Ilnݸ&K^1AlN%=r>tѩ`Hj)nR[᭢FTne);)JV pc(T]adUʒÆ*66@6pUղ)nEtԎ \2p~Bn q9*̑ƒu1ʚqSTV;;6ѷMoI]WͤL`Q5(_[oM-jT YկXNQȂ?ckAȁ6" A bB8)3DI)Wb˟@OPnpr3-8U[R xhնQ u$)UuNPi#Oo*=YH䪅 *:}HQd| &ϟnMJjF; ÜOs۳U_ZNS%M2\Ǿgb5[47cxx|nPFtfq*|U2µ̄Dej85]Y:F]LX-\omVtGdeeN4PFॠȥcy1ƈ• K- #8lq\`jq*/2V PPJ 4I PAb 0 ]H*fqUR;z"2 'Tʝw.eRIs~bM \}+28a9Uƪ%i*& ;@8L9ot 6 a0q>f+[9[)r ŔF IrS $)߲:Ev0-\]R89'5Kh2)!Iz.v OyYdSOGFQpboB YeDW|~{KKBD!!W`9'0{JlK"iFMC dž`Bh,X0X*S( <XΗj`G? M2.rH1VRhg$Y. EAQ59$ !.Z0żj@W:1 EcYLLXٲgiGn#<=4yoSQinUMAETQz)hjX+i樧)F׶\WJ*; 'h&=zQikZghz_bإPHT3Fڛ;:W"[h"%mUHD$C>YJ2(c*u6W9m5QbKO*JhVr:( ,IG܎INKߪ_b/ԛ1*c#6.9z?} 7I{6-‹GuH/ Y?UVM<; 1k`rQmTGKl_3a"¢H<?~kjt)=&Ewg\JUPP AQQXSNVVu7Rފ0HCttS#7?jS?H `bTԱ:1'#=朾YxkyI֛,֮ӽp̴$S$҇swE޷fdIh$q:n88Ah 8!!1?_Ǥ6NG/҃u&y_%ƴW.uEl}InT#ݪo+D5 UUsPѩLiMy %4T[RiU( Һj?sU`n6R<qAH;'waR:4f'f*7~A}ܐ(Oam?ؾ@9p,^)mvn%7DAkuXFX_{kzⱝ׷vl #dԤdi3%v̒ ,2{zһZŲզen20@uQ6P6 9sV]|ݪ\]D'd?(ed[P| 9F j̀6mXN߁;F@H~B F+>緒=Z"(|z81dbT jЦ?Ja#@߱s$qTƐG]}0gQv*cхªUzȜf%.އ o{z]gĵN-T@uPIvV}K+>EwdqH*Pv,8l^'5c>'$bO .[ I~L$ N3C҄1GdI Į27u yeU}*m3X 7QDW\dm׺7L8Fу(V.$VRYQaubaJUI'( ;?m1fP6%,wt-ld8"bs#PHB|秋I:3t-jiXoZJZj*M/iwswߧ4ZO:mSJ-K[Y4r:U` ?%*6@C ܢwXuG&XƎ1 l)'RK}Ĩ XDDz#R0W Iy߯0V=G4TOȬ, y _$vma &R`@+lj Z2ZxTt@R#z6 XeTP?-PT.IL'ʌA,Xu}DD솦N9szv8WzLC{ ?˺ibYcn8b@Xn[kn_:R:.eEYS,y[*2F*HJwQ_Q(g*s *URUBnۅp<=8\ j^^Y?Tn[-{jUꡒXXᜲiH5zC˦Q(D+ &-*j貁;0@ /L82u>o8P8|v Jl# mLGWAt~K%Alj@@2ȋ,ً*|Ή+:_[{5պIfRECJTnGDNk䨮STYH3W$OP,̪#0B*p*:-$]*UT%)J[`䬳H8't |bET]Wr5~-LXتx0 PRZ>} wFg1D, ?Ur | F)diHpFO'$d#)K.~H)IhLέێZG7o6n} WzfWP#GE&Պn`j` ('F:wٴb<c%vPʯǛ )YugPϩ gն+ #U_f/a*i@] @'#bvzUSTP>ƺUٍ݉-Y&@ \'$ ;g;?;wXM3R'BK+2* R "A [2j]mkBN8#52* 쀾Pj"+h$mB*]P ,1(H+6#ԫ۰Ddv9*@1L=wrHӉ=ho:-ޛu;uwWZk}m|z.Ū~ނI+,su£!/Wv9Kw>YyP4⺶cM|*™bg,6^_tK9?Ifzp"$\Ic%ELi$2pگ:վWƫf4[xIM SOLu, BI }YwbK FcE^3-`mi mo'U A;!6x\$ͫ>$[PŘgm2UJևqBKdG#ORcf,g_}bfF+@A p޹*i\䗷ʽD CMY]V<ɖp<)W*grF30?:O[H{$%i &2{r'SlYJ'B1+N] !UVN 6Ha R 1 FtB? ʅ )$ b?GH^Ĉ\̲R`Xl2[|*EƱ*S(IAe$0  `G]b6>~f:%*b ^8@=qֹ:ƆNuR5g8EKq8?Z{lnN %wnǮԨ:c=ʢ劽0غTw8 Hmʹg@N}Rޤ(h rDQvj²{b%@"}1k=, $KY#rj+HbJw B.:?E?ȝ O%3BQI?SM"o k!ETI+"LPBC䑞ԚQu&%Y((pJ`aPm##e7]Vebã+FĆU`#;?8:h*::C‚X6=iDnPTcۓ*6 鰾R=ڗb? 7XKJOMS[j^k#%T*n-[A  n[ c$QqS42pAR#kDt{wovFAB`G*T=8]\Bu_EB`h]Uox A\@gz/upcǚ#E? n"޴!WB(Q=ª5a J s [p5`H BSSMWI=T E4񲗎q,[$O.H!GϱD=AaZMH(TcBe ?̪^[WiZmVTe]#H$Z[M k)ҦI}E  `HhoX&*L1O\1Qc+Jdзe9_h _S#0:j=Hr2Q,eYJUUA;f)Ci'r~X ~i)wT%o+9],J%EKz5TT5G) s$2VrEͯ']RA^e:tU'XƁXk'ЕO[2^['˩L0H&w?*AJy6KʬH|2r9"Zav4D@y+$\*@1R2ˀ\)88mʏ 0YhRCG=]瞂YI#1U}$Fu,X~Ki5BU>K0Db0 WڍVv.3s߾o맖E v,%IY0*@ )~ul<2UOE$'ʺ9!vfc4AjnIᙕ;-\B< SH9t[=ӫJ.ƴW..utIlX*+h)*`4F {kK7iڢKtk۩₢X DXE3tXH"HEc4kZ4cFJtDCB27yl?[hnO ao+=0$.vZjSSE2.\Ȣ|[U/;U7:ze\çL:,&#$v>ZPNBT>G# 1Zmc2 !HÅfIu\`,3圮U˜߫e"KO8D /#(2HGh:}zYt0T0{ݫ$_ ""HX8U)"Mrd(3G V_[ZJ-rZYJ52I`4qQ{'UZSj1R :ME6P FA Y@A0p_+H@ qjxkIǪKcYL/BH'V "o44uV,kU%m,Sg Z ɱ+F9VkG.Ɗ$xj =] W[+jn2TQV'69wgmzRnIFZ4W+uZbť8<:Z~[MJ(;bD ę@^ؤY1Ep{lYr `: ;0d7d'f8%Hd" 'NTV[EANipM>Kh2Wn$AH l -\3x?'+oi9 {U-[yTr]5cErܪ$P3f3aЭek[usZYjvJ](jn))}j垞gMaEa:r"0m-3!`$~YZ*: @}zZUw0`|^lfr ,g y~3mƪE`ucH!l$lS@e ~:GShTۨV^*ce 4$MOqH Zf U:H X⊿T*J~KK\*p?Lq' BWrUJ6v$1RweB(d ,A4i'*=2.כn`y )Ӡe -raq >Z>'9u+zGt,${Yn^Kԩ08Yla j d %g:6P'cWi,p_I$)|#DX] j2! iv};{Zzyb5->zƝlnЊ4jm+ԭ:X\yJ ml$4L`@L|]#rU8TJ9 {Eq2MoSV'Lƒ4+_T%VU98Sl~sڳCWHBme`$%s'!pwceGP c;uKFl `GGot7yw3gEfȯr(isAt( 꿹\OkI],|sk/6O't4vUh)IlG_]Y$5TTb#BW92E+SK"#̡7t@;`/U|QhhrPvUp,2,k{w@5Tu]T]n =] uVCuTLTXj K%79!@(J ~ ~!ʀT[jpR|OH`fkTZ7ԑL1l.}'(Yї[ #ѕR c$;mTbLu 9k!NƂWnIHL5-L0,OOi'Ӫ[B Ȳ}Bԡ; IMh'=}jiIUX2T~:J( U?l9(/uV l,?OJ4Ӫ|. 5zA%-+򫷤M4Ԕp@ICJr 55rTTKDDYR4l$#h:WIZ[{5h2ba  P+zzQ[e?w{e@*b2ČfTw]43HRwwST }I;^#߰+O Eg[bO#OǨG[%T!ts޹ ziVIG7ڲn!±Pz_|VTP%]}P2( NU$;0gQBOq[xލJ5E:\bٴ]:^:@ mH[9WswJncUmYu\zSnJk]DU5+tJQY4x%%*2ʒ9Ui|QDR@)j,i^bK4hI7;O EKBPö`nh̸d,bb[ Z]}C("Or5_ub >H$${7iXKR,PE*+2X)UKT,0|O#ToP9yWN#39hb*B9Wbщ ($%fFPFFbĞό3s43G;hRHPI`K*d/tqS' E]pD UWT?. 5۫+n꿈_P283$I]Z2B@ TRr~X g}z-筷Wuc펆(#.\1Iuq&"Xs,ЖM9dZY#"XPQ=<uؑ\IR%s+!?%u%=#X-ѬN%E2,4*~ƻ$=Xh`A2 cei`X௣}hoJ_W^\KZ +WX4̐Wb:=.V5 iT %~$' 4s[_%l5/XoUPK$*ԏ3VIC/V- ]*!"r) b<47,i)ǐVA( *rg`uq¡:TΊ{mՎ de?m&\TAQR:lN YR𘞡?.1SMz] DX)$GKsduNr([2C7ji諡_zI.G3$Cbbr:TʰK ؕ(`VRQF3_: ߧ2)ÉVSTrK}<1AÏp C=+#)49("*^:6sqsaF[:8kIMZSi b)/}Bʝ+En(ḨN:IW/t~ $GZAR.H F|*J3_iRW#, r1ʂ}XOC9;9et-FH \bePD2F#wvY2b0Č Fv{Vl@<qևQ:[SQ`@mBj:Q%vby JIF?,2ΐK(Xԣɂu*\BBN|>ƦM9wmi 9*9RYue#:$6yq.#FZFEwՙvUe_4jGT4n.GTp;-Ah6%c D z KU,NӠi=3jRp_*2 *}:)v NIgs$H.۴VfU8 ?{edeJZOu/}(ǩRJ&:i0`x"dO"GSQù 'i^|9!(XM2RdR0 B3ښA*a)I.Q-DrFjT$e9R W@~y*70ib*jg6w1=m?g $O{y=PjYٜD4,M#2]I(U2k4qX-KT4{`HmF=V`hw  .T9a# F~t3Kĸ|аU%T1ӑn@;T3HN.s-dFQژ ZUua&FDtWo@d t۶JդAgQN=ܪ`W+rŀ8T'%;x \ ]X tܒ.VbAsƸ"o"jAvfF ~5r\ .܁w&WdAubHN. A`VB?uN?"A$ ɖ-C)!؝6<\P\aj::`yhB#ngv<QZ 1Pm5!U%'%M! F[o: Aby}Cy3U98zX_n=R^9)U/7zea2KS8%uƫ A\d=<:*nSAT,Y@cEӢ\Nz!ȫȹ]nЧmK- ]RK0( ,IAf j5_yOjUҫ [<Ӹ pyi |b3UGW"Tzh t? ^봫VsimNU ]TLSTeX\#'OYZ BzkqzH]IkUcU6Y> epcu IT#%ٝPȅRԱPX7p"'Y#eĥ%TȠmH +ד+7+ZO1 .+fhK^ ʯ\fȹ@* GP5KLN_WOO>Y减IЎrPjTqx(c:$) lWڢJZ/mMH!)A" RV!P4jZөѯNEj-uQRuh4{e]-bjZ#,]++-DSFίथH*rS|7:xjdW?XvhE*(Sg{D1#{0rҲ1!aϥ!aԕ#箺mg#c?N[+M4ӱ8 HĪLP sx%4 KŤmfٰu T#<0P!Պ Ru>SPTr`=&ȻLNU[@+L"I6e1$c;* a$Q Oq>~}^-W~=5Rr~WQVxRjZǦcW,ehYIvԚ;7JhE1=eLtyάGD5u \NPW#TwxUVҾ i4F<`)}[J/RҊ`Te)0dC CLQ \Qi-'jiLToe0"1'< &tEʡ FH%u KgE93*H Lx5n1*E2٣Ρىeug#-BTVG3."  f^έMЂ1d>2z1]!2""~\y#} z)H"ǵ -,} sR kW¢,Pv֡E]d՘R FV*J+8U.F9GnK=V풬h!9*l~IB*$H!U? $Á`2~,u}GlVTrD&8<`4B^٘:yUa?WDK)&6?ԕգRovdb2ؘ؅ƮT Yٙ5HݞUo F8 .dE.{O?!ܱXH][RF @+ֱ;A5 jj2 s8#]y*`)Ui|Oq\uFWӖ)J)% pN.Uk2 T4ɀrb7W8_Kx.<~hpC*7x!Q4dmLa$J}3sLfUFy\:`B\~#&c^WTUx@(Yc}ːF@԰`C R# [#'dCq 01p_ifO`B*sv6j\P8+k!] ı1a s[u/WQfU m/P<{{u+NM; @5gАOU{]hꥯݦZmnM˥ui8Z˃D=Kj(ԴfU.,*orq=UkE]=T~ўj7K#(\m-souKou+򾙚1[9-[D%MILd dTwb[_7xxb) %U^+>'kEDD7rc^MA-(Z/R*Ln+-Z*THS`Hz~r/n)R+mz4K-%wz Ys(H,21WI\BwU6#1QDE`BjŕYTɎt>tvjzMͣGEIx!oհ~Ve竐 WhnR*ɕ&&mTf"r!V  b~ykNxN֞:z_) lpMk5<5z3 iz."4[kZz>]Uw*R`nzIniJu $29$R ÿORK6JC2( bβyS)q8,҄ F .!ѐIEgCH]XI |Ԃ Tvl+njsr4*wWiK,e†]AsZ 02ªS""f*$t?~pB@%7Ī>}B+qѶGE' rWS>e?ٲ5m; @ H$"#9>07]D,clvn+Rpp د(xԩK HUu r!,T[Lmi]Ed܁V>-wMS$otF *U@=՞qky[z5m5ֺּTTk*aX&q s1 gGI+}tuPJqTK*P ބ.^8?r1ǢqJV'¹[c#~kQ)dDN-k='CD1ɅO¾tROAqn5,/vO\"x椢׉ޖRC$, HYRUr)r-VXTf+ 2`|jE-wQ[YPk yJ2GTd4rzY8%(Kukr/U5`TvJHѐpfn)wXFuuϛq ["TWн=}1HQ3Tnhpp+gZ?Q{ϜqKw#B x`+.uw9Y;M$beyTuOwjx^'^dxAiD_ajޚZ^>Cy͆ jbpDmMFMMQ~n^+n$>"f,g؎K_TFQtG<ێm-u^GPIY "rQF/ wxyg wwp˽fzz+9*J* E4b)PSnEzAϰ+Cշnq;Mk[cڬW SoAP3SN2_WelXT c C!-z[,@ĀA0=[@"\D#0=fcۓՠծ15dtb*` 9K=Жui)V?⦒$.)QT#?B)jV5#^,MgX`exfفc m!brTrQUܙUEo1'5eQ\:5/*W#Sk1-`I(%$\ہ=)TKPBF3+;4V= F|jF 5m:2<&XU#ĸB??q'=@:â}v W$FupgESzJؐUp02@mQȟhϿz[*@$N 'Ny1bWS1қ_i;\DuA&UpVBFȌ|>5u ~N ~dz[GSWIK#p^מIT@Y"6dO-!\>#ƿ+O#~h-r05i%߹H$ƋYTQU쮾IHIdH|;2 D+I#+&AlH9wPM-SSGL#3ӆ@nӇ2E`';ھxosDԕ|)PZK.ԤyjAU`K@dUr!P*,X)lɪ eUp?%pw,I 0 ެHl>}ѵvM܊J:hFDh RNUptes$HmY? Ub̧aA ȳL"0"gxzԥF|JZdW~nozydSwT,#AYv.TE @nmAˁ--H|QdZh`wĈRCKxUEAf [ʽJ. Q ߂'ev#f@TdFƮ$=~>V bcw?AM{oo64uE2OI߉VGdpѷ2`ꋀNV+OLU[.og/{EX^c,|Jy;1T 50"+I۲4qƕV ̬O|1w!`!4?wYY6*]KLJnۭ} L;XLLuݽ*cI,- ʶ*@=ztt|nmo=0y¡j!.ܤ筓<+εۭ9=Mw(D=%#ZZHq<T"YoAXw(%0!5 qB9H4k1e 3mP0rkzwh;Svƙzh'5Jƍ_6:"REpk0z'qLTLތ8/dONTTf cn ªePI`(*b6t--D2$p2+*3aja%{e mhPieؒG/"ȌSˡUL0`ʭƭ_bC=\5k$_Y엫c*X)+APQI YB] qޢMUxkPN(XY h$|:$2H: ,1e#g.Ѓ PeWc"x,FIۉ+4*Ȥr*pp 6߻7Su*g?YvYzn2VqHD:!-& $$xl6 PK; .6A9nYŢJ~AmQ KX'A豭E;`wc,j=E)fWx{1Pj?=C[kiuҙ5oZ[H $1TzR)UbCTQ$cc1+<32FlŀS"6/ȹ{%nDqbT)5ޭ!"Ry/B$krn_\+{31[ZJ95H"iUX V ]fA).D}L}Gq.ݴbO"@@^)>I6QPޚZ'gdghȏ 2!PK3p3P]'pA'Wcc{TwKcCGab́RĎ$m؉N2`%T` x.*׫5Zf&vEV-R* ?ZyJ)vZ=Z#2v@ F&o$ r7 c:ᔳ7U)v,$PUhK /UyT=TH` YF*^0$i!흃 |X%mEe[prLjXN*bdgVՁf]W [Jb6$bIemgxQ2 䐬2X.0 Q![r(+lgXd`@ZBKE ꡘ霖n-#D3w +*6 UcC\)"A dm3Lf:q"Qxv̞7{Jw 19@ `Y~9d*TE,û(X ϬOj;MAfQvc ^XX$R9 & jy"bhд4uC"Meـjk( DT1$fOV U> *e=ԦwT,sx՚wQWvEm*@I@%:E#I0eF=ܴGw`X\V,.#v) \HBYNi_,>cDi+.U %K)`E·#uR?tX!sL:hI,03 c!@ ۿI1WBLS%JH:-LL5!@@ O_Sl=%[1Gi;FRFZpvfv).V@vopb?ϐtP1,3 d'*pȬo$aȿ#iWtEU֪M` ʑ-mNSyVőv1#`DGVTMMI3##4rM]JjV@IUqW\՗Jʆަ]S=]eeFR6yjs3drvT*w4VAȮc3"9` Y]Dj6p 8zTP_Yz;vQpЂ`0gvk\T_ծ:1 I;R7ms:-;@``2c i \9a.3 He-]J J38Jg+?ľN@UX*aj.TeZ,YbbX.;d$4mLx⣌֭e*nN-NHP,>He`KkxRrա^>ZWiyBC6[h;A<۽qmH+U!8%L`#8 D˛OrFE5S4q*F D¬`j2 @ r1mX8P>vFXNH PV]#vdE8 D.Bpߪ\m$T\͖u3$#.UbSXbCzڷ֊lYvnPQ$2+;HX/ Qµ?(Ad&H GiI _qPCyvյ`U*KOFb p@Rb"el|v]G._.}7n`,ዻ&)-zU4 C.lѴ &Ke?|MWg[\܌m $;L4D"$m#̎`f`KMkzWȤrFq@Վ\~W EeU%$ATNʝcqadwQE-])91{C42Y$(@I1WYnTr*)-pHv"@GqY^c$p^%u2 .G²ФFRTX~6];ݯk ^Xt4@)0g5f $, iend=i|$ڒwKW>W2 ' ă9: TB rgƼ CN " ٌv)(UbfTRXjhT'iKlͤle+bO!@C,4 H%d]8TCF4#M;& 啊Pǐ|7I*:cd!Hhĩ 1p$PN! , BveRpʠ航rg~KBG?hO?55 $T-eFe@.˅,I!&䗚Xݤ#%J̠ebѢ8uQ#=A %L(U~}1\`pP,5fɓ\|QY!s}2NN>y'GcֽTaY .drf Ln&&juUp E^FSp5S#>H+ġVT;6Ci|WؕV*XϿH K`xyFO 1L`WF  5d1~ m)e@*#hJbW)jPdmꄡ8Gp.V-H:8pZ@HUZA zS,GF>(w:u(#%3?1q&\/! - l*FI\(Ua$/|m )dŽj`/彜,1R D>^Dg>矗_i X{C)M0ʉDm(Q3!q9\?%…Ln;l \aAُ ;q8fI`bFͣ+CaΡ!HBS9 f(C(e$Hl+JD 7P+;v*eJ9$[i=XRȌ8ň, ERH. pbKĨJ$Y\ &TΤi$>YAeds?N@ lB8p_ eWK~r0ep1 i(ڀCvnjuP2H{ZڌLceT zU*F=BC&@^bٶb x/ >Wߙ$R1͉VdU\їPanh.A(f6 TPFّ]wdR:=L#cS#b=^T,K[# Eɘ,gp33fnMN8 L@ϝr<H|~#U`6$.HL@`I7N=L3PCylWBPvRWG%xJl@YXIʩdUa1x a,Gppwi;QU K \GzArʤ#U8#1ùًPL zgK1o_nS] V!B9PO 0,A(FT3|3F@,^ !H )$3_8#m!uvo20,H _#e,:R{uA93 O^5*@mY|bT.1e}d% XA3$&N5\ `Oc\aI_KM$I!';eTpX6  )8!g?:ԛǕo!U#,1PFXӫl xCeERu Ƕ!I f)fUe,P,.TkJallvtS#[ץ OFztCry$d8: dy>*R bE6HDwg'*F}e0$`+ˢ FA`Hc@C(l4b@ $XTr2b'sxH ?3p06u;o*J!}X#h|lHDW3IXdHC+( +e8#c #D$\ PXE?ox'>'w=b{tYEUxΎKjTB &YC@܊HX`75pN\F"Ӊ d]8C7Eǫ'jn5kzY5j* gBd =e▻GmvHii#P!?Q23I(P@ Ƶ+>Ki U!!vimiXVmŔA 8KKS , #H*!i2JU`JZ[$xS1K*gWfvd)HȦKxb/ٌY#SYgdw!3B]F 8$USI,d!$eL @8Weʂ1f~gn 1,ӡaE8.2dU1.j7f J{hJ,VU' ~ޅGg}aǼnέ#%1U͹eFW\k"TT ؍vuX*X 9 9%s.GۥT3}z_̕uXYzOKxJy]դ*XQ+q;jG^ WWױ S]3<)'bQϲ-ȸU:M3.+ǬSwžO4/r@j4gomj)ȗмZ:^ Bɱf .#xˢp,2I2P+654yz9E.öNb,0w*}e-l"75uR?`%؅9]]wW _{t@W0x!b`G+o12Lr:IܬO[NFt%3եpTH]G*;֫=:J]9#ܠf=|F(jS*,.5JZ@QU٣@1VPM얻 vS\)8)妞 &IoU¾[fTO,:6w^P ZE-jfg b]P5KJ:[ZLBJ$+dCA+z4U굎xI((bQ;lχ!݁\Kl2ƫP0|3lP2A?+CFA6£.H*?3OMO~R˜"ʫFl(Rj@^挠 B * }[-ݾqY]RL;q*26rsپt@X"7#π,[!| %A(V1J#B{IId4A,BO13&]Y``.@! A>̤F*'H$pvv' plw` Y:`2q|81ܑ:s~{m\$zxdS>x$x8%&TFcoU`BUe2S#' NPK0RT`j5dUQO@YTB3+F&άTKj}HeT [2 ȍFyޝ| ?˷B0Es3om$pel9 +̈́c $.X`7ψJ $i%0\K5$l2&W!;`@ٲCl@qX2x`1xGϮjFTTf'_*I%X ת2Tf\ue3rC*a2VChi P4,geoVM2AvĂ\%w}(,A"=>_/b @|4$F4NC 0%U];|Q+R6f:C ,8Sl;3xm2ıbT($ՎTUR*0lYhTPzH"g~|Pz~ V&\1#!gf!cH*]Uqj#ϾYj9w!;36.jɀG(=c*IDvg2,G+;.Ć6 ~YȽp$ [l:ɅճaUA$Nw&2=_Q,B wS$[fplluOH}B)$*S؃(,bAcSH (]uelsC0fe@P=5][XF >u_|Ę (Y\ 13u8V^+ȪP1D$.Ox_9!A pWeP,H` >p*UA22 clGϕK=#)p'@*6@#W ?ٓ(դ![7]U43̤1%cV$8ٗ>[RBFSP0H\"4G Fe!ͥ`}O>z F9PX 3jKu9 e*t A*(XI,jb#3dmW,(@qv*2=:Ć=`6beb$T`$2 :w>*> '\˧(9v9 {G]1I mT4?? CA$Rm Ti T'ivA]RC;g)pBPH$~{Ո%l25`IlnI N;ԀH=6=&<g+`zJ<,Q׸NH$lH~>{$/eVb`FH-]2*9#_e'"8¤ 0==}]S4qdV%ò+u 0aؖUSxC3q U%s@Ω2Q4j#lrXj2f,BV_ C4I@#^O߷\CljXlppIn_# FblWQJB;e %C6rHQFv< Uw!j@]ʐT6RfLz?^Ol~\w҉7-!QՉ S As!t:'Lee*NC S m~$C u2ƖQ/q&RU D,T'\gDvIxg8*r&"y~>-ϓpH8g)2Qo6 Sm({uDS"!2:(I$0*GLy`HRS`x1vkS0\Щ+9ī|%ZY׺ӫŝjN匉SBʴ9궽5*%1*}#3VEɸښ [J6l2;HTѤl厡uu@=C U {Sf٭w\ٚYGOSK$e ߈)-g1"uuZ+mVJ rYT&AGYm"bXAhWI470" SRB}UT%Fʊ a$YUJ:d/6CPȪ 0Of9GnYl]ޠ -/V=WOmL_;[Ӷ[,y$ VXBA.{WO Plpq)PCpYmO*"VJm#{_-kWj7m0@VAyƪ 3*++z8 Iخ/dh{N[=FABFs]r7|=/3Hh2#~ –P\*;aȹuF"JZY eGFdP6'&!IEV+jV 20G$9"xeD9R~{ 24eF̨Y)\t$2N5q~ei<cbH#%KX7K7qTgc>dF&I!!DI9 |PcQb PEY+˾J 2c Kbev=}:3p@:KP aU32U!R05U%Ar2k ]  (ӈtu: Y3_%|dhHeOj8™Qe(P,Wb>s quM7hƠ#rT1$/oɌDąg+ub5r I6˂֛eRL;oet_PGm #MOH-F >ǁUԠseQrN> 1bWb~{Va>@RlYJ̾]Wm،~ 0ϯm#v{2# zYC3% kԪC Hق#|;+ 6A s5d $O#3`b0`Ĝ8-oy926w >25MWI NH0Gt|G'1srц,8]C1 U#O * P|~9BVBu1 c%Nک>_cgc6%eoPVU@9ce*wg .+zi}gN TJrL Tts=BL$ A`2l7+Jjh%Eo(s&PT>uvL9T =#  T@p g0Fx11^C0F۸u*7g}ˀ}Ƙ\KdC)9 $~< @ #R/d*H+ gQPU&*f'ӏ;uAבܩ+&KlI;2eԗ!l 0 $>TK8~?xVQ+l `5w3xX.N]H2qEqr)1\˰O7-p #?A}]kseY##LႻB8@ kϣ/ܣ*"!^gfBavܐ txEYi^W܌tMb I{`T;S0>^B&$d~_r:32Ib$BlSn9W&)X4#ʻ# o33 uԂC|^#9%5?j1!4P X١yK:3#?oңߪrh5$ޝ{!1v &T`0" N3c#uIV%YZ>T"@ P;h 9,{cIImCNu[Nm`]8? Ax=)hi=w U&j;E-/eU&5VG$P+J*J+GΐKQߨLbRX-&l 3 Fv(UDpg'崀38sH&30F?wS-i@F<<pT|[MQ4q4p t\DAWr,GkR(*,]_e@ uTf2b$Xذ%Rd @ (-\~L0 }ZYM {8X!>K$Uv𠁆6YMɢjzj#S.U;nT+daBNGX)dP越f5"%;`se i~ʫ,̜vQтkKV@W+ISwd3u9@3/z^8Q#8hIJ?)ΪlW (?UF$*%R@\A fʀ1 gUtRj?Ҝ TAEe]`.:-_N:p`YI>B"KTRR9 |'?1}2O=uK[+=}zEUJUXjt]B"D2 0K;d.jzvJ|(SB6o`I_Az$꤂SBtז0Y0S`|r]VJnZ*`TJT6&OԊCf㱾"&A'ָ>fE?:DӨM3ٕVWV,6NDs̎HJjGr=?ӧ[MU\K:Sܦ񑜀g]᜖8x*, HLBb~II?|]2`dzyڸs^BV k!#I&QWxҏd5<ѳȃh9 C),M6,r 끏?|mIǯs*¼u%[b)l7yoMb'biIP$yP^)yo*T>ԩhlnFW)~@8]|NMh|+߰tPKã?a1t/V 8ϟ_9HHCb[fm01#3}GRR?:vo&L4MC:RBSOHu 0AKM›\iOG'WqB>@ca|2cJG+48YzZ1e%>FEA\_EGHҐeW+ 3Yp3ȣǀ< jDU>_~ZO4iҚk]A@8ɨV>A<3(7*:V 2[-lI'$ ||zy=sR)(v?H*3'P}_|Ps|ǟ>*)?@&b?횞,#IEKLTN$CM6 (sc9Vͫo@qB"?o[h䄓#*TZdl%rI:?Eꅹ: E^*N0?bdI'=,R hEP}lJt2@ cb4'U}FzЊpt:0000̠`x?|v' ?F{t)YӘ1<#cؾ0eMu Q/X|I?8UA_06)F1 Yl~44 I<~]Hb8UG@}z?|?|?|tilem-2.0/data/skins/ti83p.skn000066400000000000000000010563341220200411600162110ustar00rootroot00000000000000TiEmu v2.00jti83+Duponchelle Thibault & Empoor1."TI-83+R\`P1Bj\xAZ@[B<YI?Y.iy%n+oa.b5hz2hx<M3"iCz#D"F$<EK&C4WluzWwWwU=wNVu5jy<L3k{;L6h y < L 6n=z>=;<L@JFIFHHCC"   `!"#123ABCQa Sq$Rcbrs4%DT&5d'(7EtUf R!"1A#2BQaRq3bCrS$c4sDTҳd%t ?5ep#wj- 5\! ͎OsROq3eP2K<2b fF'!8abS,)le|fxFv@:pϑK?^ΣmHjzu؞ӡ{aD`YF`#y韧( yFHe̵e?7 aHs|͵mF]Q$MGKMFƱ*4+,AGVǚ l faoO%N*IZDSMR"<́;'bWQM)AG+9#38tO }b5g{i[XSPK?o)tZignw+$S|k\^`4eGO/ - 3Ġ 㽎8%æS,G;&FJkϗ> zTS Sڊdvq[b{wgԾbL@_mYlS2.2dc_r|)P%hV6+*#WQ]iV0Θ`髾Tfi/EK- ^ isH,L'm[ݐȓlYމeQ:iǴ"<}D_#?SWܭoVd3=zPcG!gJzL?O/dWjQo#Ɯs 6K,krh ^ mHH]"u6RœJOGvycWWmYve0 WGLahE|ROeXa$rM@fGh*[e7Novb³xmj7~\+,΃#O Gd;{nژsXfR" gS]醯ΒotUB"V$%9DS@:^[|BEf WsFs;>Z],4v\aݗpƈ;$Tc{[WZul ݢăjIGW w:}| ߕ; Hw{m󶬭6A3"SFz!Žj5!O!cPQg+T^dČqc0fZ-oMwJ+:*HHRnƠcxҬg{ޮ'=12\Ɲ+gDAMC川i=I0챆0-1:RZL2zh.yES_ 7MZcKL!4mceM҅h̜Aϋ.0X >&7ON-kU).edYD| Jd0gUN;ŅD:oV޲6'"{{9S,i{JU&Dtb!P+k*^—ZLcP9WNXoXS`eV0c fS4<"ҐXjB!lRΒDY4o𝰋qIƬ! =Nud'g7m.X ;#me] > KM_`1 Rf<'jIgiA{B4ks$ِ,ăknS7Z{lS[ w0ĩHuus(Hu%TzJrh]6⍅H &u 9͊nqf;bVD"7ƮvssC$6:K!xoOɉ/dUku0؟ֳ4DW%Pd5#OֻMO&E.Yl밝=ɛ)0`tzOj4$WNT f0`w-~xԙcj H*iR#.Xs98ܽF\>5k"gxN-NeRoIV16 gY([6Ia׳,Dlal랞vtj1HYqD8+Drd.pd۲vovpy/ yVZZ]X]\T8Dmyŵ"Ϲd5њPB^clb͌z_{)Mi)^#$[@WP5<볿eTA~yzA;j ()0DƩɘ8?96<\^0F$%,)3Dz(`TCzY%.:llX-ضXĘL#Ep8@|? {"8^#GW5[k 2AU}7r zSZLMf̲0s~bIM[(HPoB{CdYTn5y!ST@ j0<ŧv\YX|&I 3>I<5:k?vط]y%&s,Dt jgatKٴYx"pѯ5<՞ *bLV"8LÑ~f'AKMcͥj5$MŦy'zKly4UXۡLBLqs5?C:d5Xtݕ8K&HQŷz3k=IM ÷rqڴ([үKwMn((Rs<{c!2 f'$\30=Ȥv7m ,*}Kz V=P4ݦx|- /i4MHS-hY2ڪk+āpX7vkߐ&1F*PmrrƎ^]#iԥ?=ittg c)d<"ÊO7)#?yc676!WRފ4@ZeMP[nvJj69k꭫H%V;J-v]u=߿GjnIJMH&qA>y)FMz,_މ5cc|ݢqId(rF"<9VJGwy)Jlld(eKEjGן4IØ<&d6F&ÖBŐJ2O :&'ba Ek7QӶ##;gݪK@r2&Ŝ@g$Og 0HYƔ4Z Oc*dz/[+M 0%-\0A:SP~W˧ka4gȨ5ӌ㢾 𝒕wɥhAӲbB1>XExy5g85b LR3,K>M35?灥L>"~|'n&-Y7x%*o7"I+zSYNyL6ty68a5[#$JjOx/']KuMJ<#Kt \\P렢F9Xx _O;(Ԃ)l ,Ws>qݳ%Y#'z" 6%#imw=+2i3/5GŠ1m@"\Ɣ̜K{>|'O%ioN^#gZN6 㤔QtsRk;WʀUց(Leac$*^0s+ `|Hw߳ >'yKfU|^fPCbSϒ_fZӲ-(G1J !驥 |1rﵷ'v;@* P`g5;3ӕ/&m!(5N>Dɓ i[=? W0DLlIJ.99۰q{<1߻њЎ@Z m(9.e`|aLlC O33j{>\|L%kZ:+y:9~X"HH@9y?~mpƬtDen|9%E3Fy)+he߫3nwl\*f7DznWmM̱D%:\gKx|-Uo͎@klIҲ5.R ls5>zء(Q4*ß\rGM `Mc,@QDBBbuo1ϏEԪJxDe=oO˖ڦ8:flbLsF|a=7&X Zu#BGcqI!5nHذ(f&gGGybSCy+S)55ugvY)BM9'y''GUMC,G:G&Lᩥߥb-OjiBW9_lj_XA F:bDV #&lx+wz+Mzμ̝/߶Ut6edIr1FO~_D\I;D!`"= a#M9~)vkPnM;H %y4~}?IV;>06H|EcGz z|>-3%UMhRskvi:)Z"@bgzkzwm/9c$Il̑g?#QL?+߰9}.9r~4c[q0\?N η_z]Ef?.]Ja8əԨŅ|׎©ERvyK˚{#=SbSIe`2L/3AU.QLiIʺ';rsWacUUhFZC'ɐN dS^}VT׆\6ŧ0G8hI Z0 pv1f䘹G HvO D?.[PMv$qʂϦ~-7d!]zwlF TH zY]l8fV:Nӛ{TT6ljqu;YԖ<IzQ4h!ؕ{Rmn,՘V tK'fZ,ĤVKJW"KOq;n^ ׺QJ!?.{fi0@HܘHԪe#oڲPNbֲ2_Y!?>ttX5O`ѢDq2.c_'`֩_8wl(kh[K0]#鳓K2yBrdžEbcpbw"5[K \_J Hmf! #|w[J_3MX$VHyI3Dk2pϧߩ3t5**KJцU=eLMMjNimp}{#\ y;Ű-zӪвZɠt7$ӒM&vk"e*͡HFWEGMFK)_iU|\r,q8[Ku趿8NK?y +d"᧪UBR[ֹ;3_E}Ӿ%fGm]!:H_{.Û鴋5s&vM(2L4uvAb .> >`j H D9p۟c-{vmR|q&KQyB6^bи8pƹ7.9nhQ"K0d暍з3&@æVD:2F쥦2KUD, VF]1>\K-*~tSQKpmOy>>WfvNAȰ1x@xg0wö܂IF!?3TkVule1&th@һP}6cӌR{kTɘօ0L|E*( u7Ȏր!sa,=, FS#<0{@|)"E?x~1;7\>GB7F^?+! v2c!@m~/orF"#%5\[5\Ɏ ?v#죻Zʽ[9gn6OQYT^^xb4D ^ϻmwef2fSʞ> vb{:M'x*#?oÛcnX҃/WԾ԰dYɿ|7Y?O2{x}!c?eb_;DL|a#yFB~g2"(9 { ;$VS|D9x 6doKγ,Dx,)BR>򊫲4NfHU~Etjsڣ쟲wξ+3X$&TC Acnd[ľa Y6F##iCffIq͈q?]8X9DwA$a8Ipjx09#khtUU̹8;IMd5aW=ˉ0ǽL=cJ$r䞧'WŸc.*}^კC!gVCD'鵬E0̊') WOAj.H8^w vʃ8:5kD8$m,CBO/;Aٶ&*tЃ' O->ڨ'ȹ&+80#+Fl!RX'^aG` S~vf^|з3u-<֒C*t1V٠8^O.E,G( >fF2i)|ᨍƴ}nlg՝d%8dR.T[>2'ojЃ9f"˪r,ɐҐHs}@rhL' //:k ]ZԒ!z534 :q0ጉc19y?oIa2#`|14wGqX Or7rq{Hk$N"}/jh13ĵ4ӱF*,K1Fop̙ lZ2ƒ+.%Fs z}%黎*D 09r"Y;x즕`Ռ  9^O=vF 3a3e"X̂Izf3_Ԡшw Rjڝlъlj0 z1ldh6(4XGDS۩Ӿc!dEDD!!e,87lOͻx$qCxwK2mxYNnb{?o^jucS3]G3>]6=Up&wWjSse ݻVK@՟\{ꕴ%#E `FRQ~ p1I(0 6HVN;8N{Ix?ټhIur6zOȲ@)M_:/SAA:m +^O*6 9+'8j`Ρ%|2Bֆg&Uß)n*l:&MMgV{mGS2bZgτɺ\ԫN-]ܹ@7#Ǵx#5ɼy{DUx;^^sۖT%(b"g69NNF'LL%Ĝv~e|tjv{n<CLh9%9cWzlJ|`C]lQ3O&)MXwt|߉ #w$p/*CTx̒0 g񿚾lLQc8>vc9*H`Τi?ÎhvhfV ˀ/`4u)sN3؇5[v 1BQLI,߮|JOGlE\FDSp"\f^qmzJM]wi95 3_tg7{s٨=Bv';ؓ:kZJkV?)ML1igÉ)^(lehm[KGk%Q c1N`A75Zyuv(()P*jvoZiCϬSښtԟ7e)s Z2 ;=϶ kԂeeӟ:GFAZ^v,il< |IdM+5ʝ(d/oCχ#btȮF"r281M |Ტٶl[v[OmgӢz QCiTXOFZlmjLXDjNY&B#>!34WteO3k2bzs:ڝEpgAx%D8teEe5KYdeA'^#nMFR˴0A"5|{t}--ߦj3H džC>vCq{(Q6(lګ(+3Zʹ( `y!]E/\S=llČB,%\q8uXM>I/hח2洺׮ĉMne1*_o(G8fg/MF8G3Kÿ緶_(hss&/Nz7͇*3L,Aqø8mx&dm;qRPϜ 7a|nk*Nɰr@z~_㨾~9/mQhdѫ$X)ɃV/lLimc:U~PFՕUBk&1 HL'F`ߔ|%P3%L+Z͚&Xdϭ0Tj;%o2+ˊk f 3/P2$cjϤL-fndS@yF@Ҍxvfă Ң=J(ڊ1TO\qPVHğN+OMtwbSSSX6R2^ZtÎ\v#J8W=Q'*?cU;nֻ7*]mmSYYIi9+6&5ٗ[CbLK! % ,iWYPiL0qC=i# ~{O-v}j;bZu*TٶOeU$)ȒaLk~|hdוW黷v˵dמu#TiT\|Z}Jv6MƚWҽ]%AYсڴ ]&{{i{J /,4٩ :j`ԩxk*Zz~O ͇& n>$9ZlOs,v& *U8hc5Fwv`^"ZζIr;Fqyi>x@=L&nkR}nPYU 'iO?̏bj-ԅ2.Ž_bٵ0')mJS>z|%>vW׼W6Z@6xZU_h@V:|=/iLF;Ww\,H%|B#K#wkR<VcĘ"vNv=<>6wczUe]m]Kj15 >ɷ(+b=L4)dg S$~Q.!h{7Y-se\ 6ΦQXmZ iɩ *=6QLΦ[p`ͷn6$uw6U)\~ .4Vtv'B>: Z&.t1ҀF_jpdK@;4 '9lC  qf2&E9?lNBFHdșwGWuNZ}}w]YS϶ {yTeS{1WJ-'WFz.u;-+cXD37:K=Sܪo/ "<baKÏݽvT\jEgnߦ{o5,85`UAMꪣڤ?gwEzlw Աg\Hi,jĖ V2M=},jȖpBPc1 eyf(~crfPrs>nhKd[6uݴ2ٶDɲBZu ̠qVn~+!fK#=L`|Oc#vyg^ZH,$4am8ijl;H_+~ް;v޻7riJ.e3E0#IT9mNC;3Gj=ip%ͼ[I$hc1Ԡ|ApߤhΛXJ'6"$ |b]ɏ;_.l213 E1ws~^jwuhZϭז &߫:Wae+*)hY68Mt'UxoMn&,+n˛Jݧ5=wSj)Z)WN.e,G jUs q89nc[h만-uKR ɚs4HdS<8Gx}p2B$%}8O͜0>s eEخmM~l]J dmimbd() c;&nkX7^1viSZ}eN}xVY:t髨kj))=Vбp"_1ΒQi>?(]61~>)u3cC4HF|10fg ft䍣.yNww-ʊWX ٔhMP[LkjX4e^ζt>[4ߦe̼u}}j⍛Qg[K`R}%hVުvWH ZGHGO)MB]$*m!x^3_U;HE.x鶁xć0x c)އjZ sv%³6uU6mɈMgM0{t_}޻t.ZoXE6~ԄSZOM_Q*Z`Y8uGl&3epM;F *kU-<h:KGhi܆ f8ˌDd2a.2~f_W~zX32Xqhg}7K:[u۟F.ɳJevcELbM8+b@+K6ۗԻ7۴mJ6!YG[MGUP-mIW YHe8i8Mz߇hZWFlnΦkRnM5Jvkmlڥ)MWIҖ`9/ڸvw{mشWYw\M^djbv[t|r#1$NN ^J{SO]E#J|Izc,Ҷ{C FL#0?mr$'Ib>W_ئǩZ\DOHN$NaB&dİR9_OϨ#3rĐԒ!s&xcb\'L(6j@+ds c?cy0SL`2eM8~og{Esk:Ҿ@"·ꯚTK4V4AիQ],ݥ:^T6z*-5t6mhSS: ~.a WO l3>LBK{%L<;ӽbRsVIx2Gd:j4;MD0HDD4I>3`aD @x#8pͿ-ʼL~nY5~P\Ѡs=.@w@+_/zWzϺmeMϴ*e_9hZ1;#@_jϙwM$pV.{dƦmaPs1%fLϏz-&1𔎤cQݴ,k~+SּUճmчZY[FuWL8Zkw{l{/Med_}+զMMn03TPUMÿ :,BI+ rť|]֕3ne[7Dfj;a 7ٌ j X~Kiq1z h2@sx},HV8PDמ 23g% 9.L u8iɛ^ͧKpi9&5l0rN21:n 6ͳ iSR4ǩgl55q0|9q2$%+.$Ϟ{OK/ \i,n;ҟ$qG+0V]ar,mŋ"^;z !U=s!aSۉt[osg0:6"5yT6{宴^G5m\M[a2tehˮB2" Á 92qx|e)k@iC#0eBZ~[z:Ҭghdtyr29|cBqUV"`HA|ͩ8" Hs.oHs! 4_4vlTdTn&1ڌ ziE\5,PA!n!91vJ*wGh֕;p2OZ|V $`FD|.d[B >`PF#OmvS3UAz F 5w+#{`>v ]>ZZ&P@090n!=rԓDd?i|q:!s3" :PM#bW,-t6.LdA}d@ZCUcˬ j7-1LJE&:A}}^m؃"L#4w ]:T&iND%F'?hWPjʗ=R%kTu  90 _0$ xT;+hݺ4!޷[D\4fR5gU6¶ݨ}+;RZ 93džɻ4%8~O̕ʷ^EFvz^L씎aF߇-^eJ F &`Ι du4N}E,qHTjeB2L3Mm,pꌽx,ŵ͙)fPx8σlu'U^;glqp.&C>5eMŜHCKx5Ի<1cnb<>|FU~{u`@ ָZLX9" ɟԬ>q`]aU]HNȩq+S\RYϦ`nac :fc`ff~>ٵ,gz*ٔ񘫭Zj:Q h!?;U&K43<) #v~u~\͇49Nc-sn|S~Fh.3vl:C>E|ʋ>½*:c]RʴZ[n.ã{bi{B__h/uUKF 1L,|ų^e)E~d8$e$c3N)SpRaJos#V.E7/rhSƟ'jvxD#wFj V9cK1G3[:{԰Oek"IJib4hR O&s?1Ƴ?w7EW沮]㠚Y(Jse0Mta1lϵdg2 ZSPUZ0t8=O+` ԪLSԥ"tձ75K^{UuT ZEewtҰ ;*q'JOΎzGmʸ,&:e L` Y1%rz^[|$ޭ XVJk,n DᏗGw;~!!kU@y쯅Vl&$5ú^VʦT鲾n׽;ݮkYwU;5ˬCXJ4jKY1kPj˯_TR[65j gZSYL3~S=p\z"eֲRX58YS%֩]1`k0W/{kvaI~gc]X ^|eQJmnǿ#DX`In9bxiul"6('L6>B$xfHW7$@^ۊP!w0HiI{Gcjո{`Ve{rmUftz̪k1Y$nmMKvh&ƾVEiA);6VuS*՝f])#e!ϝ k}Y?K;lv`&gsA0JMdd֍//aBW *9\Ȍ#Gm}-v!n}1IziVe%=N쭼fĪv. C-WRuQߣX)e71Z/ݡwQ;Q1T|y<4_TG7fEIޥH%T`d%ȼ ԌX {OIG8KȍVk|k{uQͼŗC#$;‚2ZxWoe{~-!jۿwoxKu> 6ѤVESWH+|껼borrѲlM΁`R 4 TTbNϭDvCczO$H1ՕA,t`l`jWw 6ھ]z#{2@3d9bAd\!|v<2@,c0IxŒ( fq .9";+ySSTnNJME`Z9P'A67Moěݵ쾣mYݵmj]ݷm+JļV+L)BКf~b[cv{bh>{8S 1~ '|+SzT!XKPc!t0 9%%,]ӽ3!qڻ\R[cz,I\z?88>Ln0/"DwTvo@2-4\Hy@ρ%{m#QD HDŽ?.-w.:-1Wbה@Sg+UYq351MGVm+ٺo2]/3veKIlv[ũPgcL]OIZ<:9OX^.eκKbTbCa8/Eh ƺ" ty,ti2g/ܘI$ĹHlLGWmE¾RA2IzSX9Ol&[Vڲ}bY͖u%u"A%j֩=3{2ֽݮ7yv,]⮕EeOAYQb- զ~>.SqNeKK!Dy鰱*riD^ Ȉ u"36ǢgA٧x:Y#XX/3r]=F.!Vh%(FKŏ ]<9oKv!n%x+/x+nIU0 U*Fk'VTҴS_K}ͻwPn݅c]&]j BZU3qLƷMv J{) vf3a gf.`8>'o+vՐW FC ja8~>S=ڻ o+.*PQK9IuZ5X_ʀlb&1n,'ۇ"cʿo6[Wsעǰֵ|.:ckJC&LY>dDs[}kX76ʼs`Ֆ,΀v|<ᣩKg]=&TI'Sguf3; [%3<2h85,߇[`W"lհث ~̳Hgc] {Pq*W{Gڏ/1SkB0R:c.wdMi ^xpß巶N ^"3E8N><;~/?-nzg~W-UFlS?<"1jy}_,h ,ĭ yjR䙹)?7,JҞCPXɄٕ&&DF"1gX6Ouq6C; AeU zԬ{Ye}׾8gFdM74|:^]h>y=JlLȸˑ9v0R [/tlvmH+FEr5+ ^ٸW`1a 5(<կ+ Ϙ-|?_g?M]Q\lƪ5R#`f4+OӺ$k # d~Wq{/-V۩(SPgqk>O4c4+rjͽso#20,D ln"y۽I~fXK4Y,QŽE2:_[Mb THȆ1,Unp97`wtCHaL:PvC$\FG%-tYALU !Ϝ53ӛQ܍T,gC(:crdWt@,xZ%g{ɦWNdhB9 TNZ S[jlR 4߀X-2JL>F%4jgOeHq*tA,;0#8jӄiEp5PZMjN]=<鄷Xaݫzaf:3,Ϝ$#vYݘC74 ΀I;AA&Aԭx 6 ~Z<{V_jZ,40܃$yHYݑ w9N v4nfNC7GV ,tue:]^ꋂ> AN P-NnTFG$g? 4_GAlHxhG\h~0*]`>N/һRf R^dC%C'0038&?!XfXלA; NSk^㮛Hv})@ӭk! L=w; ݐӐJ28> ˝@<~XFC7t#|]K =MKzZ \f_ᝣΝB hI56hC*lY7O;3*XiQP$XUH+04ĥxG f.gIv}AcB1ߎכ=cI$0`y/iϓL^}/&WŤj!H X x:X͘}tAO݁b"q(0Κ]mIU@PP^Gt0(4=6)el ЃQ'.a`'>Nv|%v@bJ0ss>xi_mz;$TF3쩂`=>CwKo۞:S!5sljUL>iO5%12$%!|g0᷏8JMkQ?nkㆷ vW cS߷<7K)crO(-XVbE#6SUDm5b03 :̢iij1\v6[EMk *e&,y^uNn肊h'D =0`|CBvEaNI°#0zK'gt E%#GWCuE>Kl(uq[@cwQnrr̢(m!{8w]Uy2958V5Ep1H,KMqȴ\`?lcՃ ) y0&`\8$[ hGQ$xe0׭K5lv -d ju%~᪼M.6-2Uᓨ-[b2 !e-6jM9s7"3G 7wW  p\ N}_mv{dIӔf+&Oqԍwjnm6&, fU>.Q%</=-%2>vg<aO&\m2'j8';^vx 4ӐgQ;;JR"s+XEa3?|m9\H{xܛ<5^@WͿfTU$c^ &ڑ&ecl%@g}^p߷ћ\b`mqpl8@NG3>W-u:[]WgЖA&~dE,fK8y|0gNuq =. lG'?姳ݑ`g^ؤxE`Dj0ؑ$,Z2) Y)^Egvt<@ʑV z~* ]vX7 6J$$wZT};T3"9PkTa 2|5glo-(XKJ3%X0Ry96Cu,1:H X#1O;?:SRr`T6u 5rN0h)sTwSQ{tTlcj,94z+nK~o "bDѨH (٥5xRr k,f6#3ҙà < PYP2SxiXMD d Ҫk Z=-(H$%r2R9~LD>H{@Sx춒0."IczI)hX$n\4 HF­s<۞ּ^2@jXa :Ҕ>vh#1% 0<L:]od*qL ,8YYə\:j/R:%ԊK% [|z FevYM pE'<<52G92ލ(ƳpDv:r}/1Tꡚ %RlXRd8$gcZv!TL^SݷV#- + NjVjd3 aq^&6壷PR*R.9>szMTqoqVesog#\FFlu|7[ʛfe!_wS=5/g˰2veѧVԂ]PJrKu0Uڀ[ pk#XdxgfǚGnhM3|ߵ&}$39+ &3'ҕ?m6)!#1q&s;o1 ! c`?j/JnWBlQHn@W!Mmlٜ%#<,TOnijM*gXO,596~gX`@Vx tbmӧK0ȨL%a0 0~ %fĤL {/ߴ,R;G.Ν+T|\';RSFbbcO\qNXBȴO?EgA b2C+ xK"Zm`(NfJq1#4wl)`qfx\lrm\{2(ylȌ%z+Q؝T++2S29=CNoUr#F gOG7?NOfq"8ğ>9ߏ'^Z'8!L1y~ۦH A"z'A`yg )+{d,Μt:uM$ $HˈH 3} $NNK|&0RpN?뷘!!0K;||{wv,$D%F*F?]K)APp㟮KQ#iqa0 E+)>>匙y/&=-"A(Jc`q`H=m2S`8> /^C05QYh j魵fX 'O8 bBAeafY rdrXwmCc9G 3bg2yCC}i%J0N%9<0CO.gx-|ioRvib$Z#O~[fD,D逑jg?>ElyWCL@Fsr9?2F1fI2f2$>>OXH1,dYx)S6x2F(mcrw CFf#6"rDϧ!(3J'[Nd3f2by<׻}83!͈,D}KigIJ\Ѣ~ӈ(y"5T1e/u?6\e$dL,`Ą3Sӿ 3^&\&xeώ0\+ݏٱY03"319>L?mG$Q yy;=RvTؗtXǛ mKbC~ϦrWؠ,aYJD`Q!W*ɣ8L(O?&=OG4DA@%%|q8)ئ ז0Lٞ0R@ ^ca%J$V2uJeבOEc]|؆yFLg(C_M|ÞpFD$"<`x~pzL}~& T,U4r@i2Vs/.߻:fWdK{,ȵhVgVǪi[U~W5p):eMl&c!Wp_? 7UR+nK ݀]QSf`r5~ wL^3w&$x4wozkR[ 9gZːN(6Ȕ2Hf=E{^PȫN2 eg!Ր>aY$F_'ϋb{o\[ɦ9*iNr3$S'ezRY|A3-.5t}^kF -"`uMGb".)Y6aCj*C>LlϏjTݬɪʼn9L錴>paˍPv"5"@S9Yfl|ݭ.!,V 2b $ 'wE1a X١ ~[MݻB3T{uZl LDg#{{bճL1 #,c˟v>"}?h=zϻ\voRFFįaϢg=7|^{aު~_nfr*4m}( ޺uAbWRA` 29|ms-]j,JdRUUFxr2/Q̅+GD샰{T[<Ξ?+m[g=@v(Mq埭QWiiUDS[!#Xs,>wɮSCGձ6yǠYz`yܳ+Oj;W쌐}عNt4l#&|[3;6ԏ+yNUQ!F r}QE0C2]w"dg}ʶ'ŵ&CePz\hmZXߕ-1Ҵ $3|kX pYM^Ov}Q$Is- 0d\鱫^~6wT"G49SO5x6ݒ鍽78D^zrS[ϐq^FLp# , g~OM}/o[vwx\R67/Mkvt~-a5V1IaǏoI_iN!˲zUٷ<'#(Q xj0,#"ycDxYx? ڐ>Ҙ0̈́%WmQH sϝfFyZp`pl>%첣.II5o=΁4l 2#|G[iplYT* EfbŊrOXv}$Be1gǚ,y|'m&E2y`5 q&޸9SӐ )("is6X1&FVe` >y-LDqañz~Zc^}9So wuKO/_M"!/?&p~vRXeŒRbK<ؗGvn$&%,r~DaHyKfؙlK:ҡ? <&Ur@&9gg\R+3Uۼ}= 9s:6&9G&B3$8< &\'L&?tm%!0gD<~aG`F9\d8j{- hk&;,?\EXVϗ/gY嘕2.v, Crr78Js+ Zq2D2g(ydcq>>]L?|!^?N՘ꏈ0 Y#4߆ŞٚbH"VPy=paU l`#)M1VYv42.ɕPdiK|@٠?*Lߗ] %31P)˗7$zG FV@V&rgv"JrQϟ(HjpcCW&L9ϔfFV}|Izl$\,f7Ex}2dĪW"T@Yg9'<3V1!8;S8Tes `MPL]Nsc39u͒Mi֜_ܗ3YAG^m52 =roRMHxY6 - ,(p69?oD*g &$u 0~dgӿvFp#H{HzQ_, 7N&TG9璹ɤ8Hsy>p14Lu#RD[f=Q:Mm?frs `XR9HB"0d|Fp\vֈAƞ>~o/&9˃7a8˄g,L9?G S T"P,0B<2|L58a|/Dr$Iq"2WWfnHy'SغXBQ&'#| ?OY8 PA[Y Df.C3DeL6@Ӥ&\O6ZKfg;gw{oK!O1{ rlE?}}6~_|fn]9jG )/Aj3I'I^f;rUWWJ&0]\ ^@ R7M{hS\ XENAFkq_8ۗ4뾶e:گ`Z.32NtL0?5j;;9das"D.j A˕+ݡM!9?_aXd;"z3< @#?8,ֹ>WHŽR~#SPKTB%Xy mo6賻g^7V)3bʱ,Zd<0UuOgx+SZ詇TˁD# O&oqv1"me޲ad5UWrnځbU,iYzֺ;1^SO;MƴKºq  ,NڪSWhOE,+P+63g(!%)f;N"۹XJ7D&ߴga~a.l<݇2O"S[aޗОjbipy]tt>:u3ۣ0dt"GEp9ݵ %͹55?rӦ^0FTmy`S38`]O~gsM: d_RX>&LOajUvxbs{i H=N`S2'VD InV 1:ʤ&g7DcM<%"Eʼ`s)x,.ꈊʤ{0 8SnP5Pzn2@&}ON;LJiInY2y,VNF:Tl^1Y% bW9rg30IJBL%rH?8pÎu"x@ 9 kdXg7?1wزY X4&rjd(#3i$gù*3[~]:ҹe?Q2bL2&B#BHH L$Yq?Yص*(,F@1\D@g0`wO92zwݲ, k`>JgʹmȪV;Z>\{{HBqB/ ;붘2ŸȀ0!!/sslcLHŔYsfqԈy @W2LLY>φZxkPSq>9FΓ-!$ q-3Ϛ (/Qb |9>ǧ6Ugpy0dg,xa1ha2Q#9<|8G($p~s<۳0ާWAJM^[L%rf"qѓ p'޻Q "s+0?ď;Iljr;ׇ+5d1G(\}6}棥+ɫ+鱉$s%8 |0M0ff`L9Ds{dX{<0Pqgd2~_W`"CS 2dONqLJd4NIyzuucy2^)gg8yfsp65<`J< !`g$\N2~99HHi'zzw˨22sF$ 3'I?TKT Lf<:\w0@E##?rHR<|>AȌ Y2^I5 e30@XF<?{-2\1XPD vTq\uxvSѺQ$Jz1mo!2 S;ߎm0flg?2a̖FHDG8Ns3GK48ħ y9Î<6L$[U8KrO=3vl„f("hvy簆k $*@r͘<ʏIvPʡX O^3&`03 )! , Y+8DY_\ 5[+ 3 & c Dqw)%yK]UÐĹoDCez/}yb 2%sqz@Olo6Ae`ᕶ\.fi?[ӻg\- iFs~@1Ʌg$N\8@p|,pD:sP acU$}uڲ(o]:Mnɒl]vy Ʈ=V2ݺ^e@yb6!ONsww|枛" QM>{lw@6+ _KᎋMSWOeTYTD"2£<0ή9xb؝>#v&xs=$>+Vj\=\K`A7߇J>ν.jE:dZZؖ2JhSΎp<3KSMVթb$TÂo=5-@W]3FMէ6NRbbx(Q jAI_ a%aj5d tWσtz68c@ x#h%ȧUmkEܰ-#h͙N]ur̉9MH;PB$p`i?X'  {i(;ysUaspxqݰX2ڕfVIʦca+q捉xVCsbi&R'<swoHyO,iIK]Zf[k$t:(^}*6r{6b7C[99cƞ lW#Q!" I&&LL&*_1>595,PҦvtY]yypz\]B )NvdE0&ٯh&|F#MʚW,kg@)Bxdĸ,q_t_ߟE3K0.I!ۆ`"\$a!›Y8pB..@Q֞?n *r?؏oCw7M"e*bΙbvsqg5eRkt'Qٵ"]N4YPaRjض۪Zzʖ q K2Ч6:aj:=9۔֕gW{l*bԴ&zMbՉNgeCS͍0[Nŧ#I[|`X\;~B?dOk~MJFRU0)|qNUTԀ&w?MD&jkJ350ylԖ:Jave[udɠA0\inIg=>ۦ;E6-FB.yA4V'QɒaR/xmu$p%+GkŖp# {誦Z.Z*L$}tQ&UnVʍ_S7޵id!r>!0XCSI 2lKI𨊅agm^Lά,fGFDij2ϓ<M^}X>bd^gDwXxW?L]ܱi/$G>"I-YQsMXoX/{CWӢ *q>" ^_sS?mAi#Z]$3E$Xny2+ōTƝvꎼvλ.oPd9NY%?TnIS G6x !k q0fM]8`Ff#( 8矾? ^ R 5O/O>_BӹisHYfz1lIWҬyЙ睋bbH Rr.a-(X4Y9LHyb'PWVzL圥xw0Ɍd!BE0ݲe%#!FDg 'a>dslPH599shJ^YG=\f8!#?'?O綆!G3% ?>AlߧaHx/~'ztme$M"s:簒C%)}kM~zS-E4Ϩ z[""dp_`! G0Dr|t㤙Aq8(.NsLd8 J` gbxx1I$293RN){_ywuh?̏,@/PD" c .|SGD,G8ςy:sݰv2&2%1x0s9Sk3ZL9e?ސyf# ǟy\מTUϘNU.u_ěL-c2DA:*3?MA.XbG%(f^vxyK}v-<ڰp9Dp>EtB/&L`Ҟ~;(PXU_S Bh4i@G'b9YH8rq?7?lLN9`xb1Dus🇎@idg &!8Lz<>$#?t/b09 >˝vր& JdDgg?O?m/t LF1,eÌc\IJ$qU DŽ g _9333,#r:>py%{3$~ǝfzSePbNta `q,cy?S`D3$ c[&L3q&HƘH&&|O@-BLb1<DŽa}ËJ; QGNk%ǗO[ UϏ>8mL(NPQ~~s)=(䄂"" -ϤWڳN@%1pHٳ,a*[N);)bz#P ZH$Q'^J6 HLyOS ?lJbd2$! xC'O~" gPaÎ%PHϘ$xic޾-xg8 i~@n; O|ҫ\1)Ց,R&IO IkY&F/L? ذ#tDF L} |8Op1'8e! BOURp\L =FJ@zylq&BP8I<jiMV\YCXGb6d")>M0CgI8僈3x;8okiy9Rȋ;/O'> $HQ"A,0K/Fu8?טL5fcy TF$'DΞn{6,5?r_\j"%'g2 i#:fâcN' 8=1fX!8>=gĪj Ndewj:\zqm}?ѝ>D1x6THɭ ^c8:e_uj" Li& Ч[D% Cc'HĶgnrEZ mi]ŅS8s%? '֕.߂Ul+d-k@p=cdf =. w~,gQ2Pv5$,gC8|9:Kzh=%,e=sg O[ј>ϯ@(/$L#t_\ne0Z8z{jfݐk%㯉+)h 89[]eqs,s#潨ETS߻f‰ eK&guM6*LVz6է#Z0FBZf#)<<ԏ+. Zظm L$Kkg :=N{.9}v\isifm hÌL͊ξH~.ܛbP5apKG&b*ԟ>Lsmն7oj_hh&G"*S0'LnHrkڂ  ʪ֨vsJғѻ-4Dk>ܾN퍢iٷh!$}-a,~kQTbkJS2YZѭϜYhJI n{4A8cs՝&gR~ckBKLUb5^ !YY솵`y@>:v1Sܗ9&'#u5@#gN͋6$IÆgd1û;,Dh0gͧgyhu}WeSs98X3klί *;ĪI5N}^:lNMkB7![U857Gq/DB #(hNH{~grB04qݬ_>F[V:@MNsl\ ӒsGxdet5;VsYc7f9XH}^@d F2y|0NsﴂLJLsnHl4uA%*|hf O!w '{PO@!%l1hضxaݧϪyWp#`LLNHGV:޾u=쬅wH#ϵi'3;p)ȔL51$eSϽ)rs0V%,& *Xƥ|g_3{? d@$c39#.|8pcAÒS~9cRX)J3^CJ4U,΄_^atm%NdJa3,dlbb0X('8,? ꭙόL,RYu9gq6P!1'1(isfE!9 g,r=O]BD./N]29URD(#h;/>md)N p ' fR"Df@xf/<kq@ḧ̖́LyxLhndžd2+lJqc<벚9/, ':?- 20IBGK8#\RRQ0 hY\1ALLI@g <Ɂz-=&Mb cW?/l+ʥ{$k4]fU\vpFg `xi|N\yIa X$eQNh ÆlJcU1. O#>r.N9ɧ34g&2>ϯ 8TGνؕx:rN-S%rJg#ѯ̈́ W  Oǿ`Q,ܾ "3p;kG V/8) 6 ID3@sD t`%XӉ ZU^A,tm9o\eӁ<=>q|@30̏)wC5_O;Q0 O4ssoE"1dMS3^m"(21( Ԍ_XKL.nb)VIZéoؑiJsJȱbǼssӎ$vtp$ʵ[z9—gl2~G1rnX,2sGr_|[h\S֜rd%96& @DfV+)9?pŌ< lU ZbA$Yg9ϋgM_t|mĦTTx4sK|<-96h$ ˃3~'|/ݷp*#Sϓ$>'Rq95P`Qf``%!ɟl=Cp1)9 #f8zG|RH`"60D#s3ߜ?vū('DEd"`2<$ϩ?bbdYf8/z;'aQK9q8ǻol(* z{}Y濻Ϡdo܁y:$8pK`|38ǿnRGzbdˌʲE0|I\$0ZlzKEHE@d3 Nc[ jه6䫴$G)PἅHs%g'xϥvл1ۆv?Z $?6=[!u?zBl~<%åbeޟS*m.ѲʳɕIM6gΕ4GMr~ӤgyX3|EL9 2c>-p5YQlwnM.fOlr@g1ᥫj%%@Ա&i  55qw[vu$ [pH)he5[vK1́nryol7Ĩ-v饭HB%#"%9 oZ٫MKY" 5܉Ifɛ)[)YJɫ{ƈ <cM QMOSw ٍdѼ&Jf7O#Z޶fc40QyLFOuya&|/ܷgèn4wi r@ ɼGj6{,=8Kw)*BYe,/JJ-9)bHJ"B\8|N'<x!ȼX$ >|3ԏߴzjC6SS@y陁{vT̋1!!x2`}i|sxǑyP ,GіgGnHbTؑaAh Jrӆ3.$ Bc<=O@l@@Ho~S߷9\-Psș|rax6S#`o[YݡϗTr)eG*Ls)^"`HLH93$F*_+Y,|X:~)\\ 'XC8ȳ[g>9|0;m g?e1$B4{ l.#_5:rmaL1PL=H>xQ-܀~d9 O˩<6D7`O?&H Ǐe͘Kp㰂lcs0E~\pûObJK(emD69 3sr Œ5#g%(QFu$ 1!s,a_]JY01Ϙ f~ 5 <8%tY"sjk;/N)Lt <6d?VۉqHs[j|X,v7I+:9:W؃4 bdG# kKxᱞSdf& G&09riG|ᳵH_ X72D:\M:Hd)bq&2?r\7Ae ) Yn|I?̮L[*]A6gj[u1%Ftow٠ PBh&,wfϞXS[R7d /G)Ih"S:wnEyr*|;WX m>PNNdB_z.qfrz .] ]Q\kN{wYW-i8aW ۜ16*â3ޣGg5N]8\\{p#$bg5Nfy'*|xm+I ~-%`E V[vt0=}}j}]~sM-9a2L,KC$8*+jmE5m+XѦi̚{3~j;j;<АĖ,*B^lSxi%ǐ:StaZQDDNZ90o8ic".H$֏Hlҗ-Wi XFeHV+mv.zKLr605;vOS>_m$icZl8 #ڀ$k` ]tdh(ML;ӱ^ x`R&}+timj.Yoq!IƙH,͙aW1nOvҖHmak%b[fq}FB?8w q]`,Y.F]<]#n3* ވ8fj4yki4_~ P!hd7yffy n9ר6E :I=6Kﳦ؝/&ֿ`Ӝo/{o, RC =:_h |WN:ڦ)/IHf\[ C f}v/rw| +%y kD& #: ^UN&dwl3Lxs Avl(UjYYbgSurjS+FyN]DR:Y] "W \Jzg0ݍ=<3'?i 4\dCWqmb@XD0s2ijge "| Jda`rrHˎQ= +(3&j L'"1Վ?a1-)1~{uW nzi*F`W}IɒC^(_4,[Oݷp, r,b=Ÿ9(\Dyp9x{wK綌rI02xg!"bqbn˯G?b $J:t˨u FAG8e` wmfS Hs 睜MYzQmlrD2E+9)"dLm7&2.sW (]T!Мu"Ui^&>S PF`I@)%1X_8WCg9$td'jqFX(2`,Äz`C&J"Nk8a|DY;|XOWlgP 6t Yl+43d Y3;?绫س4Yʨ8ʱ=A' !Ԑux FPY2@N?6)?H^~L{[7MqVGZg:@iT l&9P&˭M6j l959d_GؙDL0dNY"L':dyMOgÒg)e<=?0a6-%OdAq'1ϖ]4]Wg`@ ˌlb2HHa3<9 qaD@. HdUySD h%9iM""7R+!~`g> : y_**S, ɞZz|H}p&2xa R~ҼE@.89pjE32̢ yY?:?ϻڡh!((K`DA,DW<ϩׁU{r K_6mo> b3$d@.qa|C W$s 90-N ep 3̘5k\`l|"ɀ3 pL)tdc@ RU(c+gsK Ӫ*jq$E,fs,~Z87efKf3`ȼݧ?ܩ6BD08ߩ;2[3* 2tn CǡHHGe]ޕWQOZ9M(a$d"ygbYĭG#gD"ߒ V_[.,u2|:FS~Ruaۡ;8+!nwɠY`Ko eI2X;k`."]{.wg ᒚMc5>[n. {ݳ2j=ژd6M79oiĸ| YmvR,v&<;wAa׍I2n 2gAp1٢%0fv ˜02'QYν4,b @勲;?haY PP O2uU,kwpۜ+=Uf+sI~ ^OFVƬ|9 fuq_E*nm@a}AO`z͋e{s[\Wf $ҶtVM:5GMDK mQHLtՆ6 .rEȹc%s'w;J:@1φ58HjN9 zcY$.\9@~և}+M0!jծzϓXO:<ߞבJ˙vjW~'>YYPӞ~<ppFԝPǃiJbyng<uP(F׮..wgj|~ūw/fTԹᶓV:5ǥnU[պ7*! dӵ#9Om'l;aI4LNQ^z%reV}9JVZxFܭ^UFnZ,$D)u}QPgƎj=qz`?Gф|J/\}e ᓼX2T|,Ri)fҺjrWqY41=OUNя @)b>q 5eQ?ÕN\1keeٵ(S]{(z)i5ZN[8p^[mZSQ +9ξsXۨ\`9yKM.mB:v7s4{::G%?gd_{٩IU4xdϞ4WvSf6dOR ;&|j)8G[SlR x:IqWȏ0x/K -J| NC!WbћWHΡah)?ߴS"20&5E3@\OŤC+`+KΦ]V(_!ICtrf~mgr"\H'7[G#18>A9mˈl2*d~8o1RfgƿI_TJa qO?OqB1^vnv8I@d%r0 {:|?vpFl |y9~wL~nfl K)dEgşӻmMaADN\'-%y9O%mH䈖%"ux>H/^yWL e8}&2ÞxVUmbtFy< 0 6@bpaO>=ޛf]B`L!<ъٌ@>]#V! |zPz 2CFŠngm 8ɏ DZɎ?-L(2L|&? r`˄̎{4Wnڵ`(I2 Gr2Ü$s&c`IQuw ;W>䳪c=MaD$yz[bRoNfa2G|aElš4䄠9x3;F,Dg|u?Qq?Wrɑ٢Ay)}+Vm(p#,vԃ$BLgV@8nH[#>'l  *#0?Ea) 9$Hs094r0Fwre}l?~ш? jӕi-DY"rq990cyӉ8q,Ny?jz"ǜL$w~À8D2Dq")|!}OTƚկ^K{?˘aU0J9z^L^L )(ψGe /~oq@ijLr>pO3xc ˞`Gs< o]23:sBc8qa>6ؑĒGiKn=aE٭}Ω]3F Ӂ+??8޸wm$R8nG,=0=D0p*^9rg^aLjwzmإ8t^.C1'`=sQWcF!QB*?7a9H!a#̃LJ.!%gKfcIQq>'̲D3H%!ǐMipy3όq0;k.h_ U/'ٕ%*CĦ\f~ϼ>{l(N9qdc?φ;b2YDqJDVe9C8=cU]IHƖ#  {X3ߴHDgV[%\6y1aIbxLMx*Frdt վnϥ !E܇ gZs;BeR訙$e]aᏕae=>KkH=H٨Tsl '/Q-J'xBZaɃjYuLiMjrv'-`-ǰ@/Rl}OaIvh᳛.iE_x0DvRkvWja%eoĤw 8mnzS&}BeZȞf6`Ua0ѭ oKmU%%# d ?Iqۦߴ &HּP˫Q)ihޫ/>NO2aV\AO8g9!0Ff8l;w"H>Fy̝=a& [ b$ʹIDV#: Jm2*)DtE bekL/v;Yjp?Hf5a0fEPB_>9'6S8svABFGg{6N.%hd4"SX~lM/nӛ |4vF<£]1aӻ(RQ>\7<ڄfEK!~ 987^ʝܗH7~yRTŜçߵzBI`K1=fQIzF|{.UMJ]ɦFb1&d9rmԆ4 i~4*r}:̔x%4n+o:[Nԗ:UXkZYr"3<ūKݙVкe\/vb ,YS:Χkj:** D]o6'QQ!P$6a6{S|ed:i'K%Oym]uiUS2z,Ҙǧ3^C e4},_;Q{kZ/ #v8|=oZSRPOQ{aCRm]$wim$R0חy{ѧ3Tئ*)+Ƒ㎦L9slT-QNycOŦKt}?;QCQ-T .kɮT80?j/\8m{k$(89Fx=ig'R5o< @ e ̞F<:lS0W>{EA T¤#:%^$AP;ov|?{{n<-#3Øg>sVޛJ*Wpd3s3vGrM%d%H8E,1c~/v3ҞC̄@f˓\~,Rɣ*w H@։ATyإYاg'/11T?0ԃxH6(a11ˉ9єGLgp&32PDx O+ӌعǏ0.RC>_L6TZf>WkzCw UHGcX~O1+eS@ ˌ0WJ(Q%`dey_s{z\09G)q( ˓4{`C|#,g> 1hǍ5y~ Qm_6FYI Ӊg_9`q|_w}v R'Iff|O_N3D4FLgOA,=?NIS'4LAp`{}㳅Jrz)'nPqbp ϦQ INvAxȇY?&$0!`$ )aaOq݇w~ރ"1f1$60S2#9H ){0/8mD>! 8>́3WFEhe)ffV^ld`偙d|2i:`r+Idx|6-eWĜHJ^/Cr%,bU4ld L&9OQa~W~$a3ϧsaqILIc`dV\53ΟLϿEgP dC !.Cw8“I:}>u4{tGkt# W4}>~}Y0$DG)w! 8;C1BgOMɄqFRHrj " 9Ed6jy;3I6Wϩ"_Z7/o"B8|N%>TT1s@_!wFr -&Bq&?0zp^l`Y!#(?>q<8lJG(.xwgpL[_xGQdK@mf%惌Fr~$F?-2a0"p,3f޼=6TqdK%UG"FYC첆ME/~c9jhbXai8|vs-(M%$as/\v :Ձi`|Wj|Ҝpe\,N \Q2ky08xOODb񓓌0`yߎyq\K㬂N(5Noo=UM MyslTexS鶳>Q VHHsM_SC=8.@_<51oeI-Q'$sF?fI_~dfd+RᖏtkMslBgg-}zY! , sK%31qǫta[Xs,]銿EƔt<|U$9v.߀ 6WVy6/-opaEdT 7=L3c]rJ :Ĭ!b|1X۩>*v^L@l][=>$ܲ\W?wgk2T$L/qlР6Z:}bGJx,vYh4ۋ4,\~F?Nҁw]eû% Q& :|]_Jv'IdATTY7Gn(6"H'.$ª2IekpgSKjKwTrMyEft,2s؛iIcbE[zm112:okqkgCҀΚPjdH0 d??bOg3q#m92dawL׿oz񜡩Gώ<;k A Kp|aʒP嬊2k閁D6ْ!`q0QCww+b"O(5w>{h)dFrL j{D9M(!!F08NXG#=u7ujmR /o?O] S\I9ٝxwG ,H0G.X 2~mlN32)nr\0>>6 H\*yY㑑$H'V¹ ^ܫw2*]N^ Z8c[Fq$q9^aaxa8|'OXU?Z޷.RUd'7q˘rl D eY#3p?GSW8pW7R#XO8"LW?tFڤVHL2'w~vBbg bx@,3O2'鲔ZnwfV?}"ũQӐ_ Lfb3,@Xgv`") 3J?WZq>#,3sTa"O iɩzS Iǒxuz2iڻUHf颏y?E,(<|a=6g@D0Gf.9dza9~XXXN'L)d<3 %|;NCG1AcO?o\>{,L&28y+ yI Q}<**I반p5!/'S83ߦڳC ɐ^,#ϗ<qߖ8K2D@s(rbgWg6qc&ys2s&Yq>?? ^K-q!GSΛ2;j3$FJ$fL~\I>L0b%ቆ8 s|g L2LG)Ifa =D*< &PQʙ32F99y;z36 %B3L#P՜y3o1\$qr9LJ` @fDHg35s WάȉЮRQ\q\@^6er4dEsg#*XbY/]gY@+ę<;/mpF&+0]GǓOwjHK$$ǛQϐ `Wǻg4PLo'p^#Zވ@-VWG['mq%Rpd6CN tOEpLFjڦ 2w:|#<Ϧ>|20bsdYd3G}6FCDa$ Ò?n.Nj4巙W"RefR?얒3+$r+̾$#鳟nAe12 5 <}޿mz&*e:O| S1L,̜59ګ+$AkC-O5>Gev[abQ+Pz*$ xI2<~IdgN'P0dv.xz],8}vIIDC1>NHZÆڵMaB\5DfϮVa 2'Xܑ':fGU `O'stɥv^s3Dt,bX-9n?QUM;8Q3OGYRy:4jKvͲ_5x aWN΢LQSN3?gR'˭#ۛ6/$ 4xlG_ U @S98y9šilOfm/ kFVZPYq3 JV nܪ(} H2Gid5ft\vIg-K$-*QOK'wB]bN$1^=qő|m@DO23=TOL~Ģ=膦Z)ec "7/”ԹXąZesҎSε4fܐ޽,6m<:p奣Ξplb}(Sgka']q E-TX4 SљÏ/G*bAzosqbGE%bCN<}.=_5| ļ tBk0\f2ˢ42g5U;v-C aL(C%wF.;ؾ&FӺXV<1Ϋ6&cÇMtml#]glz|~|vd8qt~Ak6y>ŧwȼ@ 9[wprd6ذ  yn)_ sSӚ%#AX5j:ubzQV0:s[v 6ME&6je^|235y1Wv7!eip(qD8(O[$ VF~pӦ[u3qm>]蚥{4KQQLKSGե]:sENo&-ub0-{D/Lhj,p<8E lZ5T~TgNsm#fiϒbOKW+Kj1$v7Uuk&Mf gqMnlf7):U7v:ڕí>l˳;1u֬5u~B_-vX<%&L0U,0 φu^+&:*Ra{ Vm.q6eIaVr-NḃɆuHy`0/6Tcr׼[x4=#=?组͉Dh"Li_to9sۘL:f5uۨZ]-XrrAjT㉃ m=?~cZAEn[$:"͖Y.;s]w*%gY[+l{!ǝrSTGvn|cU *ZHRG)FfjOc#i2eǮΞ :I!!CɓK|Yб&ccωF }L+ev]0NPԂAd =MB`9NG]6I@H0 Dq}vR3< f볇wQ>x=H7IDw!K' ׁ&xf'01eՒ8DmePE#|q%f<OYUrABK6p sW5.Rf`xII 8~0?q a魲FH=H+\dvzCN=rsa 9g 0&$ח)s&9z:j߇&0%TdW Xg=a6r05 DZ}<mK4IFyO+-sL;r4ZDW'#U$+X9929ϖ3iRx3l"X "5ȱ͐$?醫~A{,ΞF IW/"@8/nܕF"r]^kH" bz q^?S\ߚE\, 33(fc3wafr1p,5<{Ջ&,$u j|Nj;D]|eF=0pJ[8xc;#A]-dn{KBP^wQA}<\sF0Ã@9<.O|mjdXg:$5 4{> L%@b`g6q,J\b `_#d  Y{g&l"|K:z|8jin )!_! +so] ĚCO0G i L.h"igɮh2ZZ3طG$cBO@M9 DB&hN`gɧ^m8F02Qd3:ry8ήl։1!gO1,Lytv1X4Fp).,8F ZeETV4w u,X[5ѹ -o!`H)& r/:)cDG! ,9j/ɐs6uOpɘa &rs4vŕM@ekӒHq>~&O# \va ,ҖHѼrkqJo q'u"V@=JTgfcs91ϥtǦL Ȇb*H>N8Ow~3Ph1i.f !VZa?S9ҟN`U N )zXl\qH$ݹJg֞;>oLQVQ3c燑 jD 8Y(tt5ȌY ԓǓ'Ŝ{SgREɚPJ [D3C3jX`DI3>`|_ͼy}tCXَ ̅kXui[v le&FS)ǹޢΕ9Ȗ)rL/;#<2 ݆ ',P((IfyZ&rqw f#asN-%"K1wo,G h a_}6yG*m iZ{SUc@di%p3ь(CexΗ!T4TkiȮ|tj+i90ڐ2 d4XcKjS98R@+#185"y^wIK`M-ߊ`;:vMi_eN~vRA儭_f;^/f&#f>%3)VU8Vv;m7گ:Ǵw|,bc)BԵ.AeS{WQU ^ڪV{+p2tKɒE~`}] -D*H͆mdLh&SNM4ᎻI,3JG"#9%Hʿfl|*3{0w 1XQ_hkWxZ-j),YO>:aǮnk*wfWnK]uoeM]Y6⧧Щr )j.45JmAD5Xb P#tݎ/՗ i٠&ONeJ J}N3Iϋ$y%24 h -m|۾XWiċ#ýAn/y$2E __'hIKeުdS[ֵ V 4+GY+>ҦT.+&нo^ˡ7}%**_OeYUS;qQJgʚkAZL-7h/\KmCL[KkPVSL)0X̞l [w_c%e-N~Mߛ$7: МjZjȥ2fUG˛fœZh{t#!ɏOiku#cu}[,.% 87Ƥa44t3.N鷚iՠn$@"| ;LKSOxx!p%hReՀ敋<~>6So#J0;Ώcɯ6x;K!#Vt㇠O<}Tj[=8Raw`GX 5&kcfts`ghL-=셮{CYX|/S[]Jb ,@QQyr CJY̸ RLǢu^ow AgN2Dש>fb=Xrvvm4iuANןگtȠ.Җֵ+ ՖQ0 UH L bБMU2fdRă8V SJgI&\b3 9APZǎŢY9dR&8Fyx3~Q%30 zTy>vjMS{ -íoGOZr`4bdžsiEL͘3T̿֝R +>ws&\j_0y4nփҚ\U 0Hb,φH.& e,G1p؅*9 fv%9Z2;|D]#M4t?zʭ!+f4TkBK0qϽqȥ|oV:BMYR"/Q3St+ާ KCa C,.^{i+JaXN$Q%?\3n%!;J&<:.w|'B!-19i7+Ouj?gOh1^`@d@O8gK8xVxFS}Μ ^|(4ȯݵ<ȷ32>Be9vg$Zbc˽bqy)aF~i;:7fZ8Hlmf>}7j %-^2ۣ %*?j[( bo>R߬-|Sڔ( q>c3툵|cY, Sɞs &XeG&[i{xoRҒ|$U4hCzUXo6"r/ř4՚˞= 8{@5Eڎg2U->fT{KsԆ lZqM"RP.$Ӟ'oKȌ|'8O"/\6XD$d(;o;%{C5Y8 v/|6}{1Gi%PR-f k~|4kK. *kKQ9=)b`}-]j2D q,f3|B@b&=x:"vh 2P=vT{H?{"+|ۯtPx2?=ޣZ>Ф#},F[% `W`݇zqN_pIHv+Hy%״!ɭRitUўۄ gp/ւ0(fgM2/>񈬑GZG:#ٯ;n~;7oR8p|t7hbMMQzs7~ v^3mt #qJDs䃩3ZV|-r*f5#X Vg[)DKb[T$ }1V0 ŞlZˍ?N݀aS7q DEX3K<d[[Lu1ɥehPS1" ^DnEHC(2g.yΧl7U-5:xBW>^-}⪶;Ŀw Ehbص)gSAfSg[ZY>?Nd]2+5DažKJzy?X9hnWIcˌGy9|#`v/,L)aC}vjlDX8&*B9{?h1XxQq"? ١jR{ލ\]%y9@~1>ljÃ܊ҹaVrId3SjN qvwbqw:]nZ4lm`=GCTX.u)2bHΊS^-ڑhb&8zEE)=HgF\H}Pj}-؜ MʲDqNG#ZL|ګiyA2[ *šP)ݑ>L<)Z:|vO!2"f(Ԝ91Y?ګl|BS0Һ1>ı : z6ۻ>©߯3ӕY}}߯ﶋrS,o}N2޾"fYV&yڗPn&Tns8;AzVqD9٨]gx5b[uz>tEc_ֶT-GlIscJR֥Ҍvvh-*I-d%p gN{4uvOtVo!@ap %_&l ](f/XDiƦs+ҹ&ԇ6 5T\qY:lzb؂s3\ %H,.pLf1ɇ|*uPP%U 394WĄ@D1"ɄOorD#,KվfmGfBLίL1oA}iW#O}Ebkm!aW#/: *u|K- B֕dG1|fg&uߩm(C4g.I"Ï ,`V%%ӻn"dqǧٟZhO_ٱ 1Eriڕ癋-T 6cJ13:SxF=]8 mralV*_Sڀy➬đ|L~⢄i *I1fgq\6Fc?LYF@-42e[[ڢr­j0y L3S [l^2"b[lW.2 ~6 +QK$1O{'<+6Bǡ%`F<1~qfʥcr#?y^_^pAE\#soMe漙W3FRu1w{go{h `[2ɐ Ŝ<8رc0A>8f>'% f̬%ԑwGWo˄l|D=lØeD"uOe /]07e)ӏ bAyƲ?aLp _,&p|/㶌 DHO3S 81i-Wצ\6-Ihe^3"LLLoɗ'96aceoz?Z@oJ[* KWכQ8R9dC0׻;lS%sT3QVе:t+CZ{f+NuʿgwýRޞ9%j[r3Σ W+qsnb?{# ]D̕;c>Wvn8ƨps|`c큩m9̓d#5Gv̄di8beΝr9~ .2yeO ΜpG~Dlxϐɏ oo{m|b ceIy:]y[4AJfp)́rszmAG AczOwQ1AE(ZRRycG\ڜ.{=?~[Tth ~MiLUhGhkۇLW>kKl2O,qG082R $KpČ$o@e^ ݃7y~=G}€߶^\p:/밄v070ű%}L>Oja6zG`LF32'×i3;`"f"%3Xx?lDBaE:};т÷ɔi3HAHq+"p u}@ :9=Q G̒M83It|&<(D `אc?qDY>L'.41kexgJzPmû7{[ ?/rNmN՘`2Уf^x3S>] %Qk 4v,t?a ,4S12Ϊj2i=]c}aֺrazaNL&kgvо0')A}"ɏ)?L6$`BQedNZ!rB4Az'RYhkDiP H8sYe=߈M5R3o" ᤈraG6' 3J#)\y?Sة\y$0Q(ú8᳍EQ*D|; -kf4qJW#Q_NS#dw]1rӟ a N=58_"Bo5ͅpdu$ԍ08a Ǿ0%r,,1dK9!_/\vf<$d-/~^+_rۃr~:t뵄{ڲq6壟B1 W*CSr݅ӥ2dUQ[NzV}|wKQ^xVWGl`erR:qdf,>A^N8Gl7sw\!Pz(K30>,k|5+ųi3u&#;2p9ɇ:,X.(`!ٮ5rFo$ᜇH?_1 adg&is*'4ǎm`k :XД0jbcLWwU YUT!gN9<ߟKi)b5!FMG&\pډ&=׎>Pcd_ݵv.$qe̖貏4⣧t]bqq{B|b=1闧o}$)ʈu#Qee#VJ?K;{/  GPyL'S}^Ch鶢½0[╞iX}ӧj|̪fƤ$A Ue%ę$[[sy1MާcaB&M>I:Y3iz:ip!#zo$Xf w1}v7vȣoZT Nǧ[%}MiM c\&OSj:=P5VOT XN0L}^[Mգ[ f~,[&v MY9Z Mke2nv6]ltTfX-AdQ垗|sRPb0]zV)>dm]b;#"<:xѮWڸ86&f\kSy9sF&rD jx=:MEi0#@9*QE㘘aO"#a9#˕1w`YYd:Mi֞LJ.VחSi*:ĵYҬ@ZºEeOmSǬT}3z VJvKŭY/Ҽ)6G&լ:|jP_Rҹ5^a/iK|7)Gª.Ͼ޶ˍUvEi>~حg WN\5]vټen[ZRڰW`I5vmKCLhS}e4s[ #rMႂ}Jˆib]mrf =*}B>4۳V.rmVn{W+l %ESmU.ͳM4U}MJ*ژR[wdz..uid6-kZ6weۼ4\Vzk/7j6ԠԲM_WBM[^ YՃiJdZkVl2Ⱦ  !JSI.kz=]K#/R7OnngX͹vclYVǷi*ue[uQ)ă uƎ""$S~,ѮVcaIb:UxΤeZVrfnf_[C{@VuVJ-vKjݲhKJưk*kb٢_TtRgZz1^ ~eb]yvɼʮ/ϼ.h\鬦-ItxB{ӫ3f,v\;j˯h\=:ֱ?E[cU=J[&˪gJ)ӥhȿ꿖6,XBۉq,R++- 4:ijJM3I8Ӯvovo a?W|;kq+k J60F5iiϐoμe"BlT[V:m+Au5-jjB5' b׆wn֥}Z1uE!uɟ[Tŧ?षh݋uuIb/zJr[Iu4ޭm/u.[5tj?&0Lͦ93eҩ>:ߖ׼LxEdōN41ҡg? kuZIݲvd&.;ˤ\h~S)5ܻ,{d,ZxYԑ[hPY3PC jSQQUCXy̝YOc QZV5uklk) dU"55'y+**x:oituvcOJl&2#`f$gkn _ZmùaYWZ-](ec{a`QV5R07GEzڝq`0gts򴇂a)ܥNF ix>`C/|׿twv:D[R赕̦cRT)X6i9MOvGߊjl;9 NмՕ}틼ʊJCRpw, 7VZU껻c;r5V[7.M:Rű֭уg%7Fpjrϵ%շ[d_nгNշۍ$lˣh]6YKHU*PSUR>ʺ7arDDppc0VO5o#:fMوPeO3$PvDulW]"fY괫hojth] 0kUufejiBֽW`ZVj_fվ)멫֚mDYLQVS|iz[Nm[gvݱgZ+.^5e-ue5cK&(<ʊKQ):QlXAj@`:Õ #> NZЮ=wN#{ˈ?8+ʏY1 rlEG?q `(J}[N׽kQvm=-&=VSS-aQTJtn5[˳+X PVY)r:ϬMBARUOIse.f\h\yV[XPkpR}fvSTJj@O<~gG[(eu6]Oy-)FޣuF],*ˊћl(~3 ^8}o%j?\>u¤'<>o/-(G b1 3(˩}6﯎/n˱mUMWT:#eEKMLJ9 s6By d,ο~ yVVW{- <7+- e!Vm~Yf5fV[)"L6H/a#Te;Z(Nyk-OdUVmʋ6:ʪZJcjm&QFO`_UHj fݺkYv.:j6V ۴Օ7>bY㴪muXkwjJ+jY7Nm#PJ Gg+" -}kյ* ~4:q;P,wШ Qٮ7MOlrEtԪ8^o}=ۭ [4P rjSR䦡lnWo7IXv˺i+ulө+떺3iЧ?5Ӳ R\ *ڔVN//%Vjun > Vg| OL$o*hĕ!Q;@ bWEN'U?h ~{|oxJ߻i{wAU-5`S!&`a۟M/mIoݻ@jtj.c7H5xl}e-7ken% +)̍z+jWbGwu:aS-6-֌kuNWMË|UC.18Sʈ?nɘ[:o^WtG#8RwYY~7iVU}WSN@)LUXKS-_KO DISe$q'\cxMz(*kEV5SNMvjk+jXf,cyVV2GP%34̘D N|2.f~靉așU( 6F5OFr6sO` b죵MV^}[kRO=OsϿVEo{/Mb:ֵ[ӡSJ:44D:{R\[ĶQu߶wlQvmK,ZާdJNe:~VUr;~ey7Iz/R i>R:g5Ul&)Se?F[-CnwtEN2ǽ53iTaު{}Sbܗg-9ojS>ΤʪM7FݘÜ_;ޑ#'ĵRIGf»{eQ:~Bzמww{}o-m԰nm/0wK(YugAzD⦫6).ůaZ-&ұ*l^̬ܽ>Jj w~vNk)F½ԗFXɨԻSdim fusúihkBzߥ8lk9w0ݶͲq ֨VKg]m!3b7}4F Mأ `_Y[$]F~>5=)=Uef^8e6e۶)Lj?:é귽:&,-xD)ƣ)^nl<=#kUO Vv[ȵmkn]Y6l(Х֦ttq+XM DFki%ԏ}U>@ZKym%wnU[!,JԢ`?i:yX{Hw8c;-ZI$*f΍N5D20eLWn.ݗ7u;ţj.mY Cy+/Sj4:~aYt)YN:OU>YWbֹ廗7~c7o)IֲJ;hC,:ϻjs/nV&,NF%rHȌ(:G]h6HPȭA U{VmԶl5Z6e$t]dѥ55C#N~xÏbf5(BQ՜마s<Kھ,:?/E dCl I~7ShS Z]7 ۲ue:k,:VJV(jIh>f2S9s-F[DNIM%/U+n^ceԓ?rM^|**zɦm@K%g)Y0qݓ{x:S Ts-HIJÄg_7=[ui~/+imKNƨMvU- A #Rij5.YPLo=x+45LZj•6b}GjtPl-Ҫlj՛|,b'hc$~ dgZsڱލ>|؉0:grq5Gw*9<۫g32Q0$?$Ac4]q,5!F2p zbbF DGπ,Y&AExxq=3FGsÒ4oeF4iL 4/1קMef(XwyiNs# ¤9캊pO(b9p\3mݗJJzs RTBdE9DJfuudim2,R$yd5a*u#c& #ݖ8c֬]ZzUfn) U&B>`zԁE&(2ɈS2q3vGK~ZUE5%1eu>g`6ۘ+t2P( %OPySӫqvJ!q21%.`TSԘg< }vou2nbcGpg,ffYp@!uV⨵ʜ﵂lg8駿Z2g?tN$Sfg?]qiIsʺ8r *O;;?h=˩~`^ S)Q *O^ irDK&8+\n2vؤg]Gé_mEb_zYRDfPcLO#) gU] ݬvoROAӵ'_Os* | 1NI^[N_Ļ.?eKF<g9=6v7IV/e q *&lq҅CcSPrV)o=]j}IR,r$0\nmT?I|Os6nֲ߬]C>EP.Nʬ fuJ 2Jdk*y2q"u@8WMW.G4E11é-/`7/pp<|N2?K߇` "-vG}s3pDf%5."QCNAڇAGg|V'B.0"lƛ1wGCsJzVILò2 2LN|ݭl]_kv;rJ5ۧ654t)]A*UNT7k/caSt{ukv+,{(kw6g)UۯELz_eSiUuF#e~&8Nv0/ām{h/o_Y\P@yHs]wx J[g12D6]V2?&{""_eɰ+>Pl juT.#n/.Ƕ,]mYېuߢM.ͤjX]0W_9 a@ {`g>^n?-wgf;ZVnXV?,x@ z8E+i%N^wuk[CM^l Vv:ӫʳpQ>֦GmU:hdK;NL?]zXz8$D#LP+Q X>x~ς#qlmRB}by"C>O39Σ<;_I rv;ô<FfHe$ rlΞe׎v9e/N"KQyoa%E 86 NB793qrkpмNv}oUZo:h3SbI`.+akӒ DzG3oReկq6Ȱm*{Z+iYoձjY6c)uQޠjꘓVᬩF>; xG4[܄ҋ~@Ugj1Mٜi nՀ{\eR2Y)l|ZE3Ӌ*$|4K1mnW- azg1tONt[v;Vm[V]*G7d9lwn>v;xGXV}ES~vjjt˗zհQ}Fmռ4~ǤWMoXFͱjRLJmRR$hmǛF/G>8Lr >MYxy/Ct%hin=Fz/0HXX#`goJU?v'.Ǜ9} IX ϭҞa|mU񲭛Νw[ŷڎ]krVnhh}k\*ȚJceUUG|oI[7[;Qݛq7W׵c.m{G|(]e@j?,:RSZ.™ ĻB.]c\QhbӞϮޱƗg.'fz^IuO*ț(_[ l^j@5K+hž۳fӫ7VXuT+i,N'j۸uݟ,j^*;pjngCwnJT]7]*sx.gΊ\RSstnܥvj\-Uآh^ڽVkDW&]XTzM*-ޘNȆ :ag'wq3TYLDH2jtdt4 !Jy\8}p/LTbN|yN} <]kM9ւ>_dKbK-ګw+vM6{B!3:] hByg镜Uo I1.9E00> m>Wx.6v+^k+Tu)m6-ڡ¡ZY t~{g߭\;M׳=nFįgcmٶKihԪ 6]{Uvk q" i8S.iA1j77c$"J%1ƇBdԧ(qL[0TC(ME,=pfZ[.;oYACS!<IKmUͻwuu7y]k`Ӽa.2]j*jǏ)霭U7wM~oeM\} k]U77n[U n5WTх:Vp*ڽQIn ظ$@wiP7`nB,]vύ齉V:< u/.۔;|8/ F`,(Ze:r`ćKʞKDt8Jp&Q:!J-Hnygt{[{q[MK-YGsmiSYIp]T[6]C)iᥴV߶y{\S~l6e߲o[T[iM uQӫ:IN0\B9i cJ58)߇خϣ ѭES,kfѤ*7:kαi)RcWdf3wo#cY̊Z,*L,Žg)k׺Vrmtk_kq Azl^. OۧM_O_Wmge'pb7I$A#Bx?8>⋁ 9Kb(ُ +`I TR`Mֈ1&`HKtK!íX+o+vbr ݼ2keTxfcuhTE[W+ӰxգW-+v]ܖ窯Mҵv7cK1,zVrhz:.Z_Wd ݍ-l)Į.,`x}w\ky˥eeu sEUV#=P;9ľ+F2iyޡ8kǝ!huM'>ʛ]S~*![X,jn:II=]FCn7u:x/- ٹsVd;41j6ii&gz_η6uı,kNΪ@-COi\:ٿֺmU.Wt\UCkվߍVo˳M,(l(۔v?X:JRF5Vݕ;$DX>P~ %%7{n_7Wy`8dk=,@Ξ (9۔w=e%Ywze fэSG!OF固m_WjUm/Լb?$M+/qTm٧~o]{FU`$nv5 ]C*۩tTgZ+ܳäKozd``jf drqSp^&jJvrn'u`O%Ԣ&ϚgNn\Y$|DX;7U T:xt2XS/l`ϳ5ӉNt.OY,n؝(v7_ݼ~%}So[[,g3s,Z=](CYeYRR2&dYDxg/3oVH}>Vm1Z6vbjV2D3>.Ti7aSni;Gx۶>bG[6u` Fi?:Gp/]/kPvSe(ZFȲlzjiF3erǬ-}p.Fy0M@st[?Tul]Zvf,Js|FkoYn2rm**ʹ;팪))(=SuMMo/>{UfMnMM͝CnY7}v,@();֮U@SRRkNWj10,]կMq9Zm}Hc%"בr5\v^*&Ll5X4MfCWೆٮ w}WHR%dihI۫Kv߮(w#d݋`\K`܊ e}y楳[zK;6˪S47Eivmӏk>)u^.ud>:ްh&RTEM02ܕ{U.,H[4ʸ a~~2 sZ][s;,o]Xc$[]8CHXo@29_{0]j¬kzMZnkt :em5^Ozvc7VҰljKS*jYfZL(t<hKa=uvQMYuw;q, *=v˹Wc }M9kSJ6fSjF8m;{[[ŗr(nlR:Լr (E54ɼ 䦦֕BXf)m;)chƉ}DuӘv_P~ol+Pk40_PZٺӓmmm i 9(X L/?˜#X.}vSzoRM뷩V19RBѓ,Gmej)YΦ8s1 {|w~6lzU w[RYa&@S=+uMސHNꊺS,+JbSxi)q7#-z]'t# Ħb@AdZ}O6XE7U#wϼz g`>cxoiw15|.l#n\`\ s\?eoq=k"2YOwgx)Zq{, 70^4 F}C.ͬ͐ W'㊒Ӓ6EJAa8N\Z[qx-m(Ar8tqƦ{X%e$|I?)[hM^@ܱp#'6ıYY14\De_$xp<9g8mpiI?.OMq=?fw_|ϴI .82@h:9gΞӁaxϮr,E秞Nce%B@8dr-^P/'hNZdPH;k E*8Yڄ7pOh˃0Dd$Ȅd=vspL;4F8+̹(C3~X.{;WO$y_N4kr9tU۝yw~sOSMiWȲXT]OR֦'X=*7NvBԶΙ0*-A|3W#~KЮlhJY֣4ЭzՀl`t_5IK>;(Sa4\M0q3_QkXq_9 Mk,G6e喖omvY$ME_!Z-`_U_ݹs]ҩ mK$FҾХ6CJ\rw—!|OJ#ViC?Zg%KZzٵ*sy5BɸV1c£#!WbzZvm*+^}RRڨ+>_~ɝ]xYACQyUb2ϩ\Hu ~v]wE n͸EݿvmdU"YlȚOڛؐÏrvZР5ݥ hTd׍M-MӥոkۜpΤL;,6`3˔~|Clbre![hq8]=s &, 9:?;+PtEc"@򒅴]L܅vaw+{&#{ꪜ{,5Ξ-ʊǻ$-XM?s= pgu|lŰ[vn묫 ,R4@᤭6'WLmβ nZFUc9~<RueZc\qc:9=-@2XvywbNT<<}:22iڈ~_@^Ţ"aGRVډ1Ү*(<]d#džAU. rd /&lةzK[vnH὏"'8zzRNUЯh wښUPIPv :I>u:~ ]iOiگmf$YjT`p=@uUM"vLbe]S g ,K:MYR*0ދVYYiT第rԭJ=mF- }ZDaUNb}cϩ8㢣mʿ5)H ҬrMyΥ5K,6)Zdjg[g!c1ZpBKIxשݷGbfTc_gQvXF>ǽ y i%ҳggڶ0Vڕe*5 sZ%ctOvOkMzm;{e6ͫjTJօRe{%5>=:zJ<63Z{D@YI|_UwT$M=q\ Dk3:g^$`1L^v82$:$#"[Nva1FYqRNàYaˡEyH\Lf?1 HW3<,zݶpeʥ*KM#Ns;'O?4kbkV3{W,y?=e1!X'5?h r 2sEl+Ӗ¢ŴXp"&^~'Lv&nJ@#!/e8{#6yкxIPsذUq#N#\|mRt ;޷[˶,K~+EWh ^{eXu6SSE5B~j:R^޻;v-o6km#y6l_*zvաwiiézgOJVQѩ뮉MR(s܁/ &ʡyN *D#ϟ? =EmMyKrܙu>P{z^h褩1.V˖oEm»d-*fֽ$nX2Kyɤsn8"ϦmCKG/0Ȁ̒^tN3՞L"mn@U,Q[9_gߚ+`p&Ld HaPNW {˵r{c7Q/\f2 m?ɀa.($~I(dv Rv{Ѱ aY0EkHӮ|Z_㵢؛M㡻;ge ϵ,YMHͪ KX+>T >2`}ujӝ=KM[g5pF730:C9>Ϧx{4nC1V1̜@:|2әWZ˼|lECd^m[6Ӧ>o\jlhoeu-{VVsm0+U;()cTh%L5;Mª{~بCjjjJKv?^;jܵ(NЈI&fX3 =5;~`QķfI#H/t7fx;Aټ2[qڤ5Nl0,5@gbbjXz)2;cʑva50X5@3ɩ>߳IgRYAe 2DR לz獡7i{`-߇`/<׻Vt w~lMYnv*M|ep. Jؔ/Prg:<;cݢܵ絮e+m5TTS*kg}]W4҆NC!O|9oRܫ榞Mȭ0͛7C3wc=7, ',yW/;v{ae& r#m󿻣-{.з\qZ۹CYdP=UyљҬ:/ll/m;{iދlj{iv,U}j2Ts1 tcGib+b ׀H``Wwo^穀 g<јNz^v>&NΏgBQT\,Mmi\0QjT\-˺{aSUE :nTUTLeVŠtzTzWy)];RKb^ݺ5ݢl{OlX++kbYij<)BXArd95`p;7қVt V4 gXzOadƒK:!x MUsZ8`|\=gtt3^F۹mi67kVnn¼4}=U-]2lS1c RTl7E: ݧz Q}o/ӸE7:SSYmQY4#Qy +- ꔛ[ ? upj8VgzǦ-NMm-_&ݝE^F9IJ]^]$⽟􁇞 _bGue@g8UDWkmӳۻXLL,P(8`ͥHo **m]dUvUiMlc*g3ߩ :**ZEy2 4S e\)yiFA`93u5W|/#lk-%RM|+/@u>^ldY1FHujxHUxp] 䔠J9W@:PxW,=V҉"Sg0ɏ!k+6_Fr)! >\߇2{qٷ**S<<]I|~\ ؔa+`bS#> S~i.l|z1;&6SǮ0 uÐ3-c=ZÇkwcf  xd㙑/NX `$|MtK M~kﵒCV.Q˚.ni;{aeDDЧ{l+x~/>mXbj'lBSUJڗRD#+fDX%;֭?+wYE7#3_Ms+fT.,([VL ]3E+yg A*LSa%ܱ͐Տ˾S 1HDpq(8HKvG3c17ɨhZ*]c`Ve@Yr9Z\֩TmE?8g fͦ>M(VsVz6}مie b%+ nei{ʷJ–I?^ jЉ9 &8?SgT072pqx>O 5 f~.AP-+PIi0KAƋΔG.gGơ4KPډqtg :Sz˞"2I.&pχ!fϟ>9  pS9r??, Lሶb4A.Mq _Ẁ2K6J<9DH^Ilecc, Yy'zuEDt$i CțP(Ql*Ҝ? #=6)}=؏aֽ$-jOR8/+&Ike1q E00Xjz_㲹Q<(# eOp>j:qZ22DL i}?#Y0ݤ eQp!lb@%P]u5f^gA-&-D1e#(/oLα\U12LQ3t,ǻmq&հF&c=L~\6X&ŵ a% b2ifC0[2aaN&ê%K# *#y>^=O^3a%d>5gC';EIIg~LpDs4|Y1:8O9 ԏK$bsD}!<ݎ+.ql6bc4,a<$Ka'?:h{ C,,Yyû8p+PZǞ1 ~t;6FS4q&A$c4Qɐ 7KXIN? cSÎ?-jVF$)+4B9:vz.}᚜)P@E!ݓ+gZ6`$+,TC=ݢ1Oʕ[O,FmRyTԜ3]F*2,D3{:gjgT\@e2a>CفwAm*Ef̌'4 Ly2p1l\0X!хI0W~Lԅ]Yj,1Kx u@muk ʷVNn[;Z.oξi>}S9jCLsp=my~N?mӰ}[1P7Nn ]bUŠ)fB66~@IgG)*)UTĉ99_TW͘=,cAqYpì Yo.>M[} -Һv^US͏M_uإ+b,B `j-cDS k5VRvyW@ ZV"U=If|yV lN1itTKB!pY|mK.ZȆ νAri#bq dDi|> b*x'[W:T0Y}׵~eb.\*-Y#!B`$W[D 'ټaIڒq:H.M`=sZ0fȶ!-0)?\@*b c?&|r{*\Q+5t8HcN)φ}对6ںzl zY3o^{*B,RRL,Tb`wOf!4C 1H'g^ir~kqh%&u:y=/1Q U+k$ Y >x:> &h8/WguU}vd IĐv\g֪WɑdR%<0j֖utho0\mI.HZ >.1efĂ`ը6q._F>xm[ܤ$FLvV&Y^9izڼKK, PZ&g8Qz WXl"o=zfYtvnl.rL'۾mimLDAM=Hrp0Xs>ӑ!f3@0xo'&Os3>;d+ )Sy"J!xh Hǽ 94֩ⱼj~FH:D-7s-M"`bJMNyFAOGK@уwؼ U"M5Las 4/v1 ىx8,3a^3 ,K7$dwۘȥY;Ŝ81GĻ 7ygsQ֣lŶlH^I9i;,VW>N뢥FdS%gBϝ^8+X$D$g8;waD`lf lA=<\vp bÓȼ՟%9 |% 2<^_[tУR8tM].I *X)S~iOm2&LRj[bVj;g${ŷL0i7h{Q#ڲX_YeMkJ(XI$Lr@?]J>*N? js>/h9_o$wҠ.Ыm֊ ܡd7@TӢpg>(olJ<#|#,?wvښ$x|.\?Nיmu>bH%ɲK?cZ%Μ;ޔkOKu\JxP P{Byq=VO T۶ر[wi85Kkqw[P/x(M&`< `KKpcvbJ$Jy#ڷ=UWN3b7%iW.wT)םF|n7>o5 ^Y- N T:ʩzSjV--|#kڂ$ ]5I(BIi8ɟ ubk5M\_}٭ܕLC4-j}I~OUh0:[Rf״+ K;z;M,mXsNPYcp5]Ѕʕyv9t{4K'!rYM?h@J9 #7qO$ֳ8Ds"5f|p"H*@d28c{4 %###&d=l` x<)RAaDH#5IT&i{*h]\B2 ~~:^.e gϟ.<L4D*Ep%8Ir`ymZ)GzPs! 9?~b?.sqwt|XFDJwY.:]+^Qg ]__ǐ)swtmS& !11g80<{"t*-)Bt z<wmIfp%`,FLYa͜%YxpE[6.!͖~mD`H[LDD0||u:}dca!sgap}?,ȆaJiLd2<}3LJLuΦcp5:]-Y*:gGB{S&J/ uSk ':BBey\q_ûm 8rOjwvE tAԌHG9ǟ龠DN2frBKɀA\old|5j㠏Y@몙N]08 &qp4W,aaN7+Sf,a-y~;i2 5 ;l~[o.bLVax3q`ЧKR# MT#[ڈxUFoS?^|@Mp$x tra#lbJHefrLVmEP&jQ:i,̌r>hWsEf#SAla|?eb$H(FyBñ"<\,P}3:Ӗ˙˥)$V]I98.2|M?Ec8\<pđ!i/&9㩏g NARlll 8a<|a4D.Trj xf%IH۹iGUjGJf\P?̣=60ŀFaYdόzFj Ԁ"dXc@YM mU-HłF<éKz Qr@1^~\84aʏÎ:??FͳդIC_u55Uf r̆3u:Xk# %s> eʸP<#O߿~NNn=U-o+ 9Dtc~6}㋞qIM9fKk5M 1 |f2>{#^|Th_dA)=x;ǩ{Sn(IxҴsa LvtvtW2^T:ؼf"%N5'~/\UN83aI5Đjkjx~KMX6=zZ+`օm5ʣl.+*N:UkXf=^Wb+HRA4UZM@0졝θ֕eKӰk[Fv cuʉ"pxG>SCK>v~ebqXw7| 5GDm5f)j) [ÉY _W[ot2}cۻT-[7E o_$ݻ}x۳t5}OUAhQUShiA ;Z?H 2h(@2)0˗,ޜpv؞kz46HYczZ=]g(13cNngΕ2߽_=E{ŠXipvZ]JT溟wTҷsTgf.Hd^[>3ݰx6ANp1 H.sǬxÿpe*1 3O1~Sl2,bJf 鯟L|V4hho}8wd(kj Z~ߘK=<Nu ` +Ac8da9ג", &O(?9Ҝpsf0)9\Ĕ:~d=be3! D>N3屐y%XΐJQh6pTI>y3k8Ld4c3ȼ{/. 0c/6d\,y<6BP,sIg8~,,p) !e9=X7ӻaDV1$&EB^mfw8ip&)u(sWs'{|c+Ҟ>^.2sxF^_VZH+47~abBKfs -LVykSr*KUAj(oR2$94 3tt㽪Fw}# }>-Ph@@%`&g!|<:cmq7˘QI'Drz2ZGm{xVF٤7 j+Foa#r8UрV:cղ\ m=E,qWzCb6@pH'Z!ɦ3rCyfvߺ j/z;i,fҳܛ6}1oT-v3IoYŠi @ p_;m9mفď2L!bKl|Y]Mʎ0&ib\r Xar1Ё9fQ5gĚGfI!ʢgBiQiO-m2;c*ʩcAZM (LA%"X5LrҚdS.ct`{O۳\vӽ=%ؗ~SIG|uwf 3;+٫*iQizwZ=ܝX]30IcR64^YVzm+X-ad|I.^O_MCPDq0Iǃ?P킐!\ Ag \p94_˾?Kv)+(o џO:li #g;I 2 <,GG/m82}I<홤+v9Ld.vSX6ڝNˆan+2r^@y ϧT+`>M"16ma֧-߼7%}HAg˙~cMD(bk<Y`y#Gs1>q&Lm!7g~ݟ}z{,*0K&]a3iYgG(x\%PS#3&bl0 $xvwޘC#K- ôx4~8'029DP݅ز5ִKcYVhgipj=>yNp.-Ѹ};[0n+=wfOZStեj]OQJ֥SRe;i4L9f WI=]O^~՛.}n{Rض6UMSduelxY:xVӟNY6x^!*dAb1#3[CFq,(M ^־o\^]]vΤtuFR[Il:(gR5uUc7ڶ<ow6f79ٱ;*bWTŕrm Vң0U4hPi5sZm_uգrqku*,YK}:F I6o egK[t؞y]w .7z*Ul;*靧LuM%Ѣ]=vgX,޻Ԥqa0z({H[F|V T&;EVv&(e]*: %i=pSTWun^7MMnMXly"$bkalO,:1)>tL6 `Жi%uI$gy UfcFמ)ִ[b>_?&籔@I0 +69{,OL69i: 1ɩAɡɩ=6Ndq!\$Sj{|Ex#$agP$;<;aȝbA${ Nx2~Y]JTܪTE \݊.:h][pͿ6%GOzlj{IvUveXŚR|b[ufSx%]c&ǼV+iZѢZԬgd[YeGv+ߏh -~jl[b۫Q"6MuMFJʴ"˯sګ<(jN>#]$bFX|xi{Q([Ww$|Je|yZlTa^bжĶ-;2+"i]CT:c5tI2櫂-,)^ >+Ü?i<#}UUVu]Es]QPSYvms5uߖ.ӒTŔJbV0t'Sc8_h o%KK_vU*[‘^=*+)T DeH<OEdgS$0YLSx302 ;$RQmJcr3{8l^l)z`CVEbé% '^::p߈ʶre,~}GrF$iCR8ggf1Th.jOUL9FV}lG:_愳mT:Pb#&fʂgU$+Ye2fHy>?/ѱ1LR\ q z[NMQE5E@8Z8+H61HB8">u ,ّZedx㎧nf֞iX1xgs֖KB[PݸVcR-p05'SR]wvo~IgbÙD-VXnO81I$zݳ[nP M!!Z1<0+g|_ڨ$fX1hFf#>O$1vn+rU*6R)3mZJkvDa T+Nz]𤯼;(ifK_5&zsǦ9ʏ7kXp؜bÇ&?G¹6]r;[.,f @HD^;B&QWMija oYVHrMK/Pd)Xa j.Xl:*2JQܚ з03kz8i6v:jp>$S4VS7bِ26~w?鹲iKy=lRڢ4,FfSL㞢N`cf-v>bBR"#֦R 97j;?>Xg<|]sS@f$p")zyt@pocyԛ]EվVmU=%QbؖiF߳m* wyL]V5]ilmyJUeͷias/BS_N5G^U-GSJjM7lд)]LFHX,0h7i~{} # 6&>gE_*lͰߊ'<@JZ=y۴ܪJyU"ߘ9l ( 04v-1ۖNdKߨpY.n5**󄙅Hg7-:q4DֵC } _X-s+(lNgD"V})=#j] Y#xzrjxi\@' ege ޷-އ_请zӊҝ`hh(}?oSP R8 -E4v*cr2 !x3<<={=}wq`O]jƺ{.rj\nZWÃ[t܉WKi1[sa^Yd*I4K;4hŽ6N bƸLt$[:vݭgXujW14]kZ9HG8?yڳm mۗ kU/2:z^t{4;Ƚ[zؘ:v(.3 DkCJf3;noN+U0ں {6ZjkL9_![ggw&Xuˤ&Ѣi nm~V0b7Fd#DDG>2d9؍**jJfd1kHγ8x?+_g-&-: =L4bfq?jw[wv4]ײ_kk- NsK4SWޚF7΢l4L!lrϫǻi?臇޶c%$AwEhۘYՓ'sR3'$kVfi1#YCF E&?" j sL0"&43 [RĚ]jhNk)GՍ6:UBf3 " F tϯl{^˂l#G Dt@:^8w)K%5*vN(q@(4Ľ,L8YM_lC!B\JE_$ń`?u t:Y" ("3?;/(Z+PYbs,μsQr$r3kN*FɣK+)NE# RHr^[5♊K6 Ee~f=5񣥧wm1;"cPXrUN^A|jg tΒl6,t,[`s+39xisRX5lHFjy032[>G &%"Ce" #G l(FKQc'<(Cg3RцWmJ]w`=j8u„/,baY{Y8js09,8@Lf0l^.8ۭ8aUBIB0a$`K".pO}pf0aH@(a$3sCrwq!K"Ə"W57P-b8NA,n~Nwv;Wzl;\[}j{:MGl[v֔^}%+]1kԵk3RY1!?ڹź؞V9wTiWcSsEzz\b8*l"q338CGNߘ_yAHx␞8az7,J/e DUgJi~4&9l i19 BC1%y'|bnV߾TjδV ݅ն_|/EeVW˙vMYLl:aގa;7Hw]l=zٻð`vMMN@66W&<6=AnXϾU1ǏS _ jիnChŃ08a'HL;wH/m(gmE"K,+rMAAbQ"`2ȃ(3z>ߎ q&x .3xMSULqޝo\tJo$w{=eϳ-Z"ҷ/U2oFtTS%5 GV3݁;K7hCMӄ͇HI8gE,D9j{caC8p|*3k,-ݼm=eZeeuHkSRlI>L|fQo w4̻_cI Z+4 tQGZ\p۲3iPq"C1l5riܟJ D> aFKf 26콾7qˋmߊbd 9Hl(ɵ5yY- VwP t"G+|V6ŇtZR0ƿ߳wns`oMQV_3ixSɳm44\z!PaNSeXÊ'@@&\=A^B.l Au.lQ[5iVNwyԹkvX<Ca%ۮp{7v7#qp;o]Vue˫l]sb~eۿuZUTڬmft7dカl Ot;K`Qw% nꣶ,QAM`veN r}knL;"sb'ގ7]P-7졾mgE& _Z誛/^{rCeAg?!SsN-K@㗺y#߫l1b 73hJJ2:hu;gR/:QQGeUc= ꆣ8mobYٹ6p5KEx*T9*ke>zqg4 RG-Mߥ} Qh^LM{KQR!h㩧ͶS{j21-6 e!j0/p`n]dO8ȁafXdy'ٯmfLd[T|A:d;ۤGt-_ZEdXAɶ zD|0|[rVd*fHMϐ0pc婧 ۛ}+T+jʴ*+ lKZŽ<GhJƳ#ՏJG ,DLdG9ώٞbe04x2ACs3J&wkg"hkFFZ[DZҴZ 6E %/Z驫==:G[hKsfX9s9ݵo2Ko]ڐK~Zz^fY W+c'KSڨGSzf1&Q_|Ҏ7iFx=?g.JNlvֻ;L^8n GB3~`  r>ƚIJS һ7}5ܯlKnU]Ρ;T~読(69~Z|9)уbbX3 <ɟ><^ֲ)w/h=ȵqm{*ݒE9dGJbX~<&߻8!i1-miYjjcpxip2tůӠ- z$U!v@YtgLZb,y?JO-tzQ06Egk306;kȩݚHkĄp"1ܹrwW޺ +:S-Y45֗jj6ԺcVpk4.}HDؑws{u*0vЛɁ||ab$$hhE[v߫"b ;QYb"t@xa )2cq8"y3OP9Nֵ;F[;dSkm] QeF):'Dca^D:@y1՚z*Z.jiܓRg#dΣq{2}wо] y$#^+Gm>f{kz9 ' # i]Juj6Ri`gu %ݟ gv;]wu6GQWt=Ykg𶀻- Nc%i^< gF-)0 kjVwKkcSd&UCa¬UW X`bnk4K&raDdMFT+v頱D`"= d.~+n0#PM0FXbN, aa( 9. +,ΐϜݜ` DVɄbZp\s`yͪv<0;\v~g}\RݭBռ^޽Z˭{-Ϭr^?76:.cv1 |_yqcD4C5ڏAYËhI#>hwPήUԯp%1p¤ϭLd*tW⚋>ͩ*UiR3 t-*S&IUK<ppfK- lݧT[XΡMg7lSǸn&ß4!~i\ڶJŵS%lx̞%=t!e&2&"96AWQ|JhhLX(5@ d&dDLi3N|0Ο|\piJ`D"Hp<DF?#i\ ɈAf38EBTINJ|dl&FD,1yϒ! RLuZ3m3TE5yΠU(! cE}˻X b1Xڊ"*nUگn7w~sH3HI/[nK_Rk)< "R3pǎ8ppjh WzO0yUF0 tx!Tij,CS1,߄mcZ4rijĈ*hRR%MbA 僥? cŻ ἑpc!=msb#f(hN`/|>[XvʹWr̹v].»of[&eRwZuҔXa$cZ>ޔ5Ncn;ݯe[2\X.ީv‚_^ КeeUQMje/8,efM\ِsKࣖ3)5-*R5OVUuPƪ9i0hȪԥ(fq[Ԙb_C9TI$q蔾] ~F. Wxhz$hNOlK./n}}+KKmnǸ۵T}1bQr_xViBݢY+`vZ%v Ƿj^ u[UOQOS@_c޵GPT{+mPS[筸[55r cXW$ y4VldC#¡9c)B<|gLJ),S,LbuK+PBg]8xh(Y#ޮ@<.3zڛûfg[GkX#u+VϺV:])i]ᴬJIu>ƭ:zt)[R݊j1P `|IXzzeOf4 m2GmEZi;PӋ B^7e |gsŖ`:BDnc Q]YN\/jzC-] %2{=i&365*et D0}>}$kVm<ÐAY'? Q.퍘5Cd?Xi w;3){=qE9! 6zD??AdHUTS6|JLӏ߫Qjuҿ[E/ UԿ]to:hj,YR驳kUT쥬5U)9m㆛ܶEb,U^Ds\jԦ7)wsn{"ɤsgZ[P*ii&jNS4֪9]n9c2$u5q r]XQQGrS1FhG?mĪݎwxo=*Qm]{ en[;w-JagQsq{'Ja~˹w۟av,`6}ܲw;blJ?i߼eP RYXW;Tl-)$8scOѿX;!6pcF\%^E'ɼ1A4KYÓGIzB }jGN'_зqv]ϳ!x eE>ƽv}=UQ_^jJVӅMes02+h_k^Zvj[6mel JhVgV)45 J_rbƪFpddRL<.?SaB fg9D1F:MlDď̶͞\8D+#<'ݯy쨾UʪMnĈA?dsc V0R B!~|"kA_^RYɟs p6V3ļ:$A5-ߋU#T/z9ʟ{NﳭVioxeFEma9=dn&{nwu6tSv1o^YUE@KGJ>mڦr4l=M֪Slv(}fyS-kSO]: 7iuU/յKvm`lKH LzOfvԫV9?o.n8bKq:rJ =wl0 H~Jnx6[n~=nQl+bٙ$ei&أ b&1N)h lÔy3s Cj?_M<}j(}t),ݑwZʴ-Z`eZҨۓ7Y3֥{DM^fdgJ9>xtvkbf'{1"Ne_ :=i[8b8|? D)tB܌5DO PgH1$<$_知{P]} =X%js33U0gcCX⼁ H-֒>$iRt2Thoޛ`ȞK& =JQ(Wx$d`GPÑSw֒{DO.T#@NTF)qr&[5Obٴ쯵N'IJ&:ڛtum[eçTSUW\*Wu5lי|knE/]Um_ORqe9`DSu<U2vn6e}n]+CwwW]TUG%wʴ)Y/fjokNapɾ1; LI4buږQhS7+0G4E%/r[ 5y6x n۫-~ҹUՔ6x,2]QSWSW.2{/[V1qѳ7UyaeI,"Eu3 j%n'EuKEٹ"˭ťUhWjĺJڡMSR{JըK] Znk;El[=ާT@n,jEn՝Y6vj:ag<2;t1cuu[Ox;ʷ,ĺ]5=iTjz RTiݶωqÀ< =wD ކ֭ 6ݤJ5|Bց#N_z;RMԸ=˹݋[dؖ}:z6s3aѷVGTW;ڮ{^S7S>`ÞrΛR932|d 0 f?I2$,b 9LƢPh  iB8e᎗컧o06ipH*ĖCzQ?-ʁ^R |=m]훛Ms#%$^ϜXoNR֌^U"Y!~@.Xep@r+0SBsYc͞6f+ne*Vբťc_ʢOq:P tOS.CibaAP[5y_ԴÀP x6}|ǃߑ鵞.D+yGD~olZ.P1M8DF:FϿX >di_|l9^~>R.ZT/ 6Ӛq̐'&8. 4dAN uE8.K b@__Sâ/u4ۏ5TuqSa RuBBZŲ%sył%l؂(Ka 3 Y mcی* RI-sIOg͕F5f;y82 }yE6~yOA[{yJ+cE=S"UaӤ?gvdpn94-(Fu2հL]A&gNUp6~8im'.U5뻢k]2#*ĕ[0u3zmBtaF=Ӊ۶ak"& MBX2 gpTi'7Y_HB ebᐭq,mEN{MIsIJNd MYg.\ڦ3N,az&,< guvP0FȌrZ/5@q\ӓ6ᩞ0'$UNBpp~9<}vaär^+"z:&[]d:J}ixSϾ{;^]xlB˳ei Ͷ:H59Rtٱ7EX@x۷TPUZJLE,P`>[Kv7;qneӲn/ }=欼ھUjMMO[h@HWnYްi.]~ESe&٧Y*oҰٌߵB]ܼl:_N%^2D{{]PH[[`18wfŖ8Y $2Y;}5[+(*k>ѵYkgϰŇjڵ >F5ɃcvS^axwg;z6Eei6dzm[*ǼuOWNRT]Ed{K]f^zz- &-֭:*o"̹V5=UV E褫-ՕfSYILtR륭s0A;YvOb)N1XA ?@smPmݲp l(|N3-~vYRoLN߭+f^YԶoЩ$m+UX"s+VEh *f/ݾ3 lӮG' 'ǃAlR#,\BY OXXIpb8a߱EPl `L^`.g&o%I34B$b~aQlj3ș#~mcʍrM#8'Wb2>T=6Sn~v+R,c]eM9 !&D9l^u$ݾk}ۊꮠʘ)sWiS&诅=\jVZwn+U}GU^QQ覱YޮCznV^J}_>ۻɶyiSjUf͛wmUUNBޭWT3{C l2`10F@1Q NOH%MRNlB>)PmmZ%ޅ_j/;.%jѝ`9߆=xhY_lQdvpVXwȺ6oWKjqؖESRxZU5Ι]Tmn{]rFͻ쯲.Wf:ZՔ"à(*BϯBۧ&ڤK8+Ht]+۲ۤ6ek+}օE}NzdИYUCR>ӀjKA rQMFDZGEV4iSH֙_ikZݝJm"UULY& iH%Q `AN랗xPlFB3 Yf}r~/]}VT}8h$r)h邰ҽy]25t/.g:dm"T?p'[И"8H,fMwm":޼m q\8k#f}CbM EPfKMD#3;6Cpy\W{/du?*mnvI4+>ߗJ@:x'(w02ja>ThxoMw`Tym"b5_Ur4XM)ru{vE% Q ( 2fϧFˋ\y죡AwBز-M`RJ{R$5>9^ЀOc9$2ʗQMξ vbviʕϗ<Ϸź{˯"ۼ|^5Yzݚ;Bɩ?T)u)QM-wݽׂ}-{nuqk/%ˡ+.+{6ö*}]/*Tnm[dr u{޷[eu}7Ǭ_F4K[N}gdEevnU**,}[TǤj{z۫n:tkm: Jŷ+)4f˚MX7S:pLxpQ!q|d>& 0޽ sQ+RJJy,w>+yȵu^IllN6)]SFk:h&+y!&L oQ3a9ϫ᳄7ue8imU]L-qY::j)|j/ Hʫ`ZP]:K%j^HFM& we <+6gq#"ƑPxadAP_Ȥ?AxNe R '0SǓ;kDD>rH1)0(g=>s? ;X}=&htqhugǒ>OllӒ@5X7L--fpNOr? 釛 ᡍ)ŏMw<䶕-^We+m>t?-{7c}WQ imQ4u}oE֮J)3UOyMm!c~}vF:&)bK 3<_snGxHh:+r6觖gcRzsMi1[8~E{#XYn8 & sBd#JCZ:ymυؿW{2^+NŢvnPPGxlUS}^*UBhZKP8`\3 &]JTP #+&a9uz U?"[dDC )iG_Mxt1 W%Es`Weidql/|X8yg #_3s嶕ٜ3<1NRB<@/~[lAB'ıO?Gwvf=ؖe=-Uv%JYv`׭jk8N̽EkZwvϴ-BXՊlwVxz>@?8>bvWujʦ%DZv:-!f1/]) \D+ƺ)e& -!)ZfID~p鑳,tfH8Ȇ1f>xϦy7ݽj^4T"ԴOlW QSOTu4v%亵r*O0XH0RJl8˺eJgO'Vx`h1edB&л+aW?S:]o7UZVev%I⃇Wy nt;"SAnҶuZm;;ՋGc`I Rɗ;pzC+y5nՍeo۶2ĂU^ʎ4g0T*RWNVLԹcC=DfFs=GKf؏ cubpT> (t>R,0/iUd*̴>k{D dm*StBoxsn@͌ݸ( c|\_.>v#t? cnܾ{T੤z[5,V 88 |PUe9y'3$dȷm-;z beA S*s:S.w蟵P6bqc$(N XF^-}_bZ˂ 8[aRb1`$A _W[oK"3KtWfQXوb8Gpng[ R榥e1֍GsΟQ-3W꼃ӲJ>r;<}'ǦFz5#̲UxoyMcG;CQ( ^L2v!-%GȘ\F%}37f,pmƎY8b|Gt㾚O-v{D>:JqXT,O8LDO6\ܿ O߳MӃ!R 猘x4ۧ^mׁ0N3nY)e"NV"$;Ճ'$ķwpxo.*)<+*E WEs|ne~t  jA8_>CxqV4N>_z'N M@cLLU3Ɵ/ ^Ǝil'L1stPQ?-Ob$9S"ʞqqzL 2̿D㥪ZA"%C?,9QGݪX7x'x`둌FFy?/NyK/gc9!Hx#4p.| f҂9G{j/^]~B| ~^)*t&uy*<-%bfvTHis[=,Q0-HY&0,Yҁdn?KJ{ۡ#웴šbp !̺p, :gi6zjpVZȬՁd. E綥ٖ1mT:4qTlӊ9ooe,iXZ? ] oV&4ifUKM⨧Nt4U*=Vc&淭8( d! G*Яav]TiKb2g+N)Oha*"D`2E81`57OmFmϺyDgqC(5 fma_%()MP,VJcʙ l%$0'g~f@0|{Mp`c% bp<8gt_"m# N[ɩWU-')2$L ("!~34 U1U-z81DY#𪬎VE+kk5]Xpr k!ԝwa~}eҙvYLjb5R_gF*ХYUu:3[S]ub{bXE {=% gPSb0Z`1σ~^EuL<}6몞e2@t~OeWuw7^}q쀱i1+{-N:gBԨuyK%A +kK5Y}nI;qd`puA1Ŝ~JdҖRSLFS#jp\wv) P٨MrRauWrn j-eˑaZRXTtu):0t&WԃVnsv-U+ko2ZQA|ҕ]jX6kT~~GJglX\xE|5 wth^v]⛹K$㸦i!7=Jczm^u󈢊bh잧!p,QZdҤD8H/^=v{*Jtim{,SYT57^ڬzjN4UCjG8npɺ~ڡIt-+u + y/ Fygsud5RnxԨY)+ZyߴQ՚ANF2lTrĂ((Ǘ(UUiHfȮߎeM:*Z82|Eg?7 C; 5ui0pz4'k6d_ݵvwأ|l[Rݶ`\ذlsθQ_)S v dn߰iMgn7|wX[ڳnunE׹ު k+Kz>檧egiZupZm_GktãFwm5Khi>Yl!xI/LDq@^iu-mQBz~ΗJP3'ɝiU pA1dHSOG+0su;'Xۮݞ>w3{{߽ʳo]p;SM`ӱlnԴX544sOv2wgg[>./f]M{mEYW|Wc}}tμ jjǷ.jt֥:mOWaI0 ,xIRbU)wuٱHp̒]7}J[[W, ƥ}ecJP9&385|iK>OO m^v(|EZ`3Xdǎ1P̎ɇpz?-JQN5.B@ri&Irn4?aXaP##2X_&]] j-r!ry9 l GUE}ߩE} {vR+LdGCX@mS~&hZb@@4:te&@H)][Boж(1FΣM:š4t`tM:,<'x_Wcdz&;no~fvԽõ/^[ԱgũGJzt6gR()ΙZ=-e"XI"lwfJ&jUvcS K8Iϒ8ꇠ -8sV1"cP3)\-^gaEW[/XKB2PP^pɣ ?^}~m}o~{O[wvVweoowKiT[QD*^M}Výv}Agږ5/[aR֛;9Kgny;[Wy e=QgmO{i,66ݠ߽,`:_7E` ,F(wLrtt3Zr]br`$Qsqe^_ƧjL j,bڐX>iN)\U2,փ0Důǝ'8 #kegju[м[}ޑðwjXoU_AfJ)lu]955T~uzHvFܾgn[/n/kzk,::;6]zU-|TTQ0WL8$DfiUZԀm!_&W 0ĿJp,g>]ײuAjReJZϖ Śqٔ,q998d> 8No ]Il!`BLUU?99/ګ= i!9(ZVS 'xAO3աTMlx I_hPֆv?lb@Y2s)f,q<әIϲuѷ}|vm@/5 l{`.tթã`!+gG&| 5<3붲(Nx=q v'vo Vd뤋_UN-X"9pܑ!h\ǡA"Fٲ]ƵpU~[SBgL<[z*jgV[bRSTQ\lRԨrRsMg)-w[BM9Rಈ19if|_6Zpat[Vť˦zo5zOp.xW `^K`5)<)I}g8N]鵺oeնΜ!wTBZVnH;)Z&دd`+-l,8cñN hmnM`{W1;av <nG\ϕUD=bX7: "XԷvV@BS\~[fF8%Ry0T5OL Lj\B20FC29`lvxݝ,=][&׮ȴvmMM yl6+(# F5bSj3;&i$]2?*~;5Rs# , A\BZryՎ m*4`P$,3y~צI#sNm÷WB%lhd?1mZMvijh-bMsl6l-* HRu74JP}F::}]c6ĠKB;D-gE%-m)MnuM9%r ςj/2*8-@z-yܽyY6 ABکkS@<[,YΖ̸{·.G˯dDȱkk,V>GiTԱ(gMuR`Vֶ9Qņ\3.C|2n*1UJe+9 C_OXmU=qU0e=BDd ѩ\åuOjJ[aܴq4 HO(?d7IXz6B֖}5 o971cy0$|rQϿ]iAIP_IUQX;ZVjqJYj:xwݬCWw.bm-eBHs luV`-;&]g͎l>O3/ԴT [1L 1'IݨH'y#"+SYr{Q?+3p#^]/QKK5C:Z^aꫝ 6x u::)I 7q]?2eXe(FC?pl 8#0?&l0!aÄ퓙&1#%!#M~:8vo\b$\^6y1XdO""-~Gæ0"DV8>#$xelD Y3$AArd|᏿ 2%d-ek~8u0odF," Zy>C峊˦M3 9368,׉p0‘Ywx-w1~@2R(< Msu9v2tdjh e*Ζ?zYr3Sjpk_|cڢk^P$,3qkV^s^&ӧ~v3; c% r`MF鯿^;t=*MRцr943Ftt6x ږ٨M`/9a峔ꝚVxc18LQ6-<6e+!?<'Sk N\QF MR*ʍ:pcy.[%`|i^ݛmͻ\+e;T `_"L2y%x/~[-m'y$ TE6zεтn<<-ꩿҍ[L\G<)E@G?KG =vM2n%:3 R9CD.9 ZLK=ݷ_Xwƿvܷ:/ի`ܰlZ{ }`,봽_ Vl_]Q[{ܫ[I]}-M]kINs(QL V%6]{0 Jqek356C?RZUM߲2TՔ.iOs`|=~7z #$l?/I]IO%|JnbI{e:uJo^]swi" v諩e>zP{6I f=-^mql;Bټ鼁maXvjl{b nwB~ [Nm;er%3 U$a:aح{?8 Ie!EgNal/N.%YlIACThJh\}jF}NM'aNyE?[SfBK&@ȸ_;ƾeS $/+Vg}U~IB0JDY ݶwZEӫ)-GW]{d*sYSF` 0[{$,\R;ݿv z7u mT򟩤Z:Lǡ餀z>][s_ku-n.gokwn%]nx7tv~rnٵïjtKV(vV;n^{{^+jj][b\;5v%MgW{ z?Y=jCVNQ\cw`ZT Wwʵ=@dǀ4XD;*}H$;~J֟#aa94*Ӊ'zmjݝodz<\vo߽o+yGx[E[-* 7ۿiYU ,5bӬj.wƶ{>oOxvMJͽݠo%/ܧ*:WrխM>u5UJ4Ӫ43e}Dڔ-{I,ņܔWmTQE]9K5 O1d;OKq5Dxu;\rFJ+|qGp;Ʃˠ絛V^Avuux{M:mK_YU_^ une]Z Ql۪W[k ڛuK~[cRCx-tڴ=GAf]G@: :/ڦ}Cs)XȲ3,8<3p|؃A-K bZ>E1\v6l[Ic ENXžWjo a "K@9쏐+wX V})/oh8A~PdrK8"J7O}znhS^t"!++1ccJJN W#XFB'0l8%KP8rwy5dѳѪ-w*8tGӟ:{rƷE6m ,ZL9B3 sm~;?y.z}7{ɢefDZMmgYlrS5V]*P~-KU`6ïMx±f_KG_Yd&.ҳj*i:y**csYmG /M 0(m[6Eer\N}VOSSՎ[늞(N}DpҙS`%ňx+!AR[[uUz;lnZƴnx[^ zK>Dz]zՇnZVotj,tͨraٿY˯[{v%i]f8\(VULu-Z6vpVTPS^HE.˔GX@6||AQKL,K&\| cOŜ7$_mL-AЈQoZvnПhչjK޽5޳ٱ[bTmk~,;e%bͻmZ~mgJZ{եô-oj.]ܧuؤ]dvPS;45P o|_7CGZD]Ex/+f1Z`37ҎHeWXUNn%jlbp# )_ Ex뉖-̲,CaZxv=%"2 j^fO*KVr HmC>32 UEM0ufg Npx{< 6d)ÈgY Jm*2 ~ҜO?2 A@O0)TLC,,/xq0>l ڳ$8L?/q? nHA H+p 6\ȋljPDIQIo*~y5 UY=*9Q^nX۠t ]Ntt7kUj-S:򫡆@~ӆŀ>*?8awi/Þy#ӏ 6QK~7gi}j݋B,K(%03:Z5j~wblYv+ &+v8x.yT_:5 fkZhq ,my`\qZ܏;+jdpldI0 |̚M_1n?=FL|RJLidэ-l=D{t/|NТֻv3詩wfokrjw͖đTQפLi:c'ݻu-Ç@8OD=KP)d]KwNg}"db l˓^J z^oc/yAq ~AOSw*/e{jgُ̛w*1e.?hUk*yTܺZ;RJAnh0Y.y0ʧ`ݩ]U"-Jˬ1\tܼ4t?ǥSnk8Mx\ى ,̬|:j`^~G#EװL|L^ F'eSrijݗP#D0x5@v%ڇJxgBJVkEH>dȼ= #+ O3jsHP_y(s&z}u"&^̙ ;)"Gd/ay)Pa> B S$XNAţ,n%#D`3sXc}q1 0F$2~;7$e CwI>6/=>_{V8(s=N -0s hN9}!v/YWy(Q[fGXL]A@cx_Ǔ[<=aX+)^@yϥ8㵑v"Uݻ,ץBYʑkH@gY1v=$nƅ'|W[\"~u^Fݥya#w4®kyWӎbDg4L}Yͤ\L>9f+:oo^%{SvyDG\*uH o—-ZOB!¢iu4{ݷ5F1Nk՚5.)=cs0^aۥ/4 Q.[& SGLZkM:\9޽[j7v+OxB VwM,l߶٩)7ɍcCHJވkf&gM?A}s4!vgZb^XyL  ~ةdjL萈ic;*a~S,٣:6X*Q04t6b?#g_KQ95Uk ^ҞƖĸܘfu4Ys+s~vݵ^7$HrwU`f *q'U kB"ʾ$<@99߱*Eg)I1[<9|~yn=Fǖm%M!18dJOj! ?\SbʼnI c:"2KUA^ZM>]l$ jrl؛-ࠋf,z7Zu۶ZR4IJutoHvws{8a6ٴicj:`rY0T5鴨 gƻv{9n=7b:ΫE juj4l7+'%bՕUaZT5u:N|j}v{׆q*L,aD(ՙٗ*\ 4pRǺ4=Q;U]eKro }}=UKw+g+?9*gJg^t-vSWYEtm1iHT걍^}%aa7a{]`um`7ozˮh.ZbͩeOUeRZI7WI]]]䮵BT>&TUQv¡&kAԖmKVRhVz{{>#w& !6Q.B+.BJF"H8(/H"ж)sWQH9FRj%T,k+߰xBBLPa3:C>ߞ-}UCΡTT=^a8j8{g&xd>i w gt0#8aSTe^*R$\3AJ6H-e*#$[`Y !pP`B("![xa<1]p.ѽWϳ鬛๭M]|[kӠQT;ULjgWf]l,ҷJ+*f&u5I致M_Kot1/w{ӸU]jײkj6-:ς-4p:urGrc<,w~$y=+oZo6?Lq0WxpТQҎW)ww-7`3Ïl}|,]nűfSR6"˪PJz.9*㪜|݀[v6eVIj[VE5KED-_RiM8{>d\zY7 Or,]Xu{ޮTh]z: Vͱk+D.[EL U'ARݫ{3,|H\^<n ;~8EJ]˧i8dYS 0>p־xqt7WѽvE]1V[x-k:T99 c5t' 'al۱g-,"߁xһn﫷. ycîފdZ4*Yiv8SD[^q(pÉLޖ1=bJ;uOzc1|$b0&&t*͢Fvg׺Bͱjl6EgeZ-AmP'Քi`RߗWwWx]aV;26e#GGJKUi@`%J\+>ڋyy6+hU^ ˯vbƶ2nnmT{KkQuvX9Z֙wlmdvnz/-ݺuuU44V=4G)5ɲctO3|o)V0`ygB'%[Bv'yoMێ*9/`0Y$s2$GN4A%g"⦾֝^ϻteU.NGQMM W5u.”7%P#x6ױlêoTײcMmMJsGM3ck~]*][]4M JTSVX YM햂 j]*}=fa^Nϳiʸ7bߛzuˣu}g%P:+-Z^ZZu XwQ^;g0wr't2dM;aLzFI-,g :c*!s{:_[ERn޺ZVu(lP՞jX4TT乞Vo jU۸M0 7u,ꔂjkUP\vnzN[|y~_Ik*z Rӹ'LeGNڪ:E6*cZ]W,:ٗZCX%`1eGxk)6xP1[=nWEN`;q ?»yf|^Д1# !C,%ڸlކY RqQRx/ ղvu4:V*O&^>B y50șu p\s9鷑T\BZ 53O?;83>lRuvAՒhG'L2:Um-\G.tgn#VjO0y-w9eΞ_59gvnޅ-DZζUX~mc5}&PWԦv+SKW٫,:˴h_MSg6˩m?R.pTbd|nґsʹۛoF-=[jnwݛ^Ү_tk-~eV3JYSTǭkimZr_ZNjuædkTWY8"a#4'ӈ,ʨid7h7˾!, #Kk2Fbhb|KɹM^ЯnM6E@fQYj-'RVIKO||)ln zEiVԴi+U uj}LnʴV0T1Tz]MgZKܫ g_ Gq{ilݻ2ڵimZ5ZŖI (*ij@ehj]tyl٪n&ɶ) J{JͲt;Jl6{WR*v-MwnطoCGdDC<8N:*YUյYq!#qd JjghWٳ|4W=ƪXɠ رkRXS{5Scx[tlZLږz.vݸݟvb)OYgi[*OLٷҬjii} ޸up葉ݪUշ(z*zj *.أ-#ReJٍs?kEh^ ~ommSTRԘYu@ia)j֙FsHt 7İE"~$# lgmJ]W46~%Y$a>A6>[qF[z&sg^۱lZO4iXmV;4գ=&~FDg2`$l3wimER<d'O~mjt9htD٠3q4,ѽxzPқlm#Sh3ᶦĮ&B$ "Yx5}{6fPS BK ǿg㶢0duz1vbS$Q/71~ eoӮl՘$F̏-\lP$-pĄ}<iS0Q^M)^Ċ"t!),KS6q\. $X qÿfWsQ|bBytWְi͟ ~#OmQ2B"y6DGن2Fa|&*kuev"N}V} eO#IOub"]@\}?hYfs^Ho+ۘ)w`HJSbS]L Lj,qK[I]@=K #!Nf_%a Rwu]wm̿nڜL&TS6'ɫ<8w]nqbD %! Ynl}6G^Ae3 | u;Ы4؊5T)=Ic2~1SZ\{K0<^30INEVgxLc)%Y-D*F~X`kubt/ʄm d 4&p!:Yf Kg?mY]и啣w2$hhRRLϤ%ר5#[痵ʹMb `ढQ~V{=Ӊd#dO3 x#lkoF<;Ci01n2Ub`9odx GiNj-FgF13(R[QzSU}]jZjm\t4㨟hpM?)Jc ФTR21b 0}/0?,6yAiyom|z;:}X];TL[k[_ѭX _nOwŷUbPZ~6`PQڔ eU*oWJFmˆDeĮE $QIw"#u[)V`18a%7K>_Xw"ň1]MdJҬ9U `ɥa*ӌ6"eгhC=r߫jTשf1-;NvM7Ap@=sZJ_YGeih )M3b)⶙Zj]Ľ(,^ Gse[*ٯul-um\unV:z.l1#2(ӈӼ` [OE,,1F>O 2%JBZ3tX΅̺(%ԖuC&ݹdG"6Z'Ʃ3՝5HlD.ܶzi,;f[C-l[5 uMebSyS+WGKRNb]״՝K^/ w{[wcwQemXk/VQZI]1U}g֪GN]Ґdݸ/粲r qCTS=u݊urg{型A6VUeUb6"bIՒ?0<3_“G{"J*LBYL^ vY+3txloYgW^[7vQTiXŗXY C(,pEMB39<Ζ VE8 "kBsp$Ml6NH:H"9P˺EM6>9VND'FqΞ/@ȧhhJF2 ?!~s?lsrYWiVVX&î(hVWR : =P7FzZJ fd 9{/?l;.E@:.ԴJEiZVeK䁸iՅ6G=v|b8n,X<=$'8޾Nօak6n F!Iq/droav=pjK+iU2Elׁ;M175a=ؒBՆD -&Ss`Ȇu髤7#ly1y4Ž}]#vѩkՍóՠ]UMi-Z}SIW5[mOmٻb{-vm+ʵ-2ߋxoUfڄAYYultTcwY|`cv6aޓÿ=Z=WQ!Toʮ*{5:2Rv+D̢~3ԓ0iXwh˼㫴l%k,=(8.5˳%]*;^~{Fm-ۿuNȰi*w޼YثܳL [jf`պUfDƜl!`vF,fRߦ[޻f®0&90*Ga*oٮSyeIg$52K/zKo*ƥ*uT2kc ĿsH?. biPb# k%P&Np `\T.1k%9`V&Oq؅-EMR,kBi2Yc x Y8ݖY>q7̠]U\{,*"VRdGKмfU '%Ջ. ; VadžV>ѓ 3@&/=n+wWᄘpmиfYwwujؐ6l6ҵL5MU,_',qWE={N.e^oKV}Ӥʛ`.M`QA kжV3qÆfûA ^h, 021H|c?/1tT͵1&^S%:Ay,ёt_lfX0Vf)rO(ǣA\Lkﳵgd*=o ׮*U`ٶb !uϪiT:}:MjZƾw.+}ܧd]kxjӿ;x>_ i}j]`MKEXRj[NRx`7 ?ӼbK#(mʶ&}`&Vx>=YdYT-}v︮QAvp03:e9f_֖7lfٕ :zJZWLHau <7 n;[!7xQWvev;f V.o e깴cTVG5ꩯiXVY҅NiM=7ݚז[c[el&нȰz.‰evb-WEw@Y@8mwߛ3d"\hG,*=μ>|嫥vj+fSgDӋ$dǏw;-*ZHsDFcy+?6{`j{PN`KħM2+WnA%iRɍP@w&lcNV1I%#.h/T&U?,6ErΙZS/]-mHD2 P3Ը`[=h]AM'*SN`өbOBu|7ݺhRQilդ, mO|R/K ozk*lo546z- YYRq55-Ts[\;A&-9Jb#GQ:B3t~P\=̵^S3([QtP^؊NWŬWHDWFؙ+>ɰ];\D'0!_|<5_vV}ݨ,6d n[Mio ݖl&v?{1Rvofv)ܧ` o;JnsMQjעڼwlW&,vmT6U]XdAi$oGrBW̙qjGIRp,qMyВ]KiTw"YL!M+ۻr3K"K bg[4XӾN[y`em]IM uMYdbONN+VJ/R}mmnnvˠ8]LulYWР)kԞW_u],k3D\=|,99ag,xD>6p풯j i)8#20/ÎvSm*JϺYa1 .ld1\L}O3]j˛~-q-˽S^{Ι6oP3)j|p]2na YVEj0.3>E'J8pnИ10dG+wҾi]1/<;s@r2t3dDa2 K)B~| _]=֚xk _PNy&3+[;@d0B}ǜ6Rnز,vo֥5֓{y,3+*ӨllNspYT*zSz' L+b-^=gIt"? Vn‹nki w v3NtyvAw+E SJ6{C5i.9?_v?MֻZl_& YYkv^}./Uv dvbq>}*}~o6}aؗzʏfS+*Gx~jJ7ww] nqWrJYW~ZlP&3wVPT՘nCD+ƒdH$Nh=mTs9 +IrȘq$>;ض[ʈ:dIյIԱ!pCE2<\ zchz&fds~Vyl7:SWaݾ-_]ZWvuѼVRm37zʪMYK-MRV?7N_svs-+7[>ʱhk-+z:+M*t hݝmUDH8' ]b+%]veGiy^6UԽFf˯d%t8ds;]tP2)*HpAMéEχ-76{G{nɻ:\GzroEgKj]#clY5mRihwwݎӹM|Wġ6kQhػu&6S((դߋn Lq„\MMAUvVx,L%Rhtڿvhsдw/pK]=F;>kY@pEcZUIjOWp%s;Bky b;ݖlKmڽݳutr[vU5h6SVTR iEWh[ɥ]ԼXv%md‚ϩZAŨNE? 5;δ,a:B~S zaFD3}6F#y>!xGWX5ž!Ú7~%x< |C¿7Mb=g+m,vļάz[]iXmX%kCi_m\RqW}Gҟg[xwhڰQzֺ)nV&&Z.˥URDiꝫ5sZjim VX% :g&AӏKU"]ŒzF ^ ɟrg b=Jw|ءea$5(?!ol8;r*vtFW~$/xE,ڠ1瞗blC[܌DIY0uUtT+nٖ!azqw,B֧Rd1}\;Mt@eTUZugXeƌu/2KJtWؿD7xP𸆑h^5{_3NXkwnQٟ vͻ+jϳFڵghOGfj U..EM'=޹~Wsq6%7;GOe:.]krҶK[]*Aʵ Զ%K"FϬR0< 3 >805vM>NuB֩9Y QgXHŽo.~KeGXgyXGwG=Z9H vvEnu)rݴ{dnoSz[u۱֥n.NohJZVjMU Y_bS]Z:X+^PAVR;YjǶl ~˹v}xL+~MXW uʛG5u֩NSGlUd1ua0a0m=6(e< :Oȓ#Zp$%.dGSjhe,6x!IY [UVn؃? 8㌤H7xH@5voUܖp%wnޥG S۽;yb(Tƪ΍h.ʯyHSES&uK$3i:'Z6:BȆ9` F<q pIXOW};ճijܪfW) џǓNqYh⿊C;{ǽX_JRD u=i MU崆,N?8x*N .-hU`)b]Ty1|2lʽYw\62)IN)&H+ZYs2L}X5eh *%^:_u? `I*⤕\I4#sR9Pxz0]ĉPIaSO$T.yl*PJMb[0FgpN8^3]wwيv۸wl7oغvݦM,J;Mt1Jը~GT7jUs;6{-JRۖx 5fxT6t-|l+I]dVQFpC$LV^4ڞji v0d3f`26#܊Ҷ6vhqsa/ â۬{CAbvt{yc ] :{l{,bUEX_Bey=;_[v}5[3M{roj :]]KNj]mMo0tk6%АK0,=~[l*IFXXD r ~\WQ#*V2$ ez)3uą) GFnC.~+`?O纾6܅=ҳ^ոUnݷrn}cWVijh5ek; C\VW˷bBo>˻;|g7}i"Ȼ::n-89ww>!)X6`Eϊ35`:S;[m80G#ϓ?8+f޸xY?fI3ܨ,-Z8N' rwb'ɪ]~Vj)EmWgm1"\VB,E;3xlw.t,d R Ӡ\?'E_D5jDjx>[,"ذ8af .HkY'U:.]YjdyBXRTz6ӈ5[vrˮ,_ ƌӒ8ce9@~_S:q;vRryLL쥴TNUm3%/|U*YMb,^p&|SWwWл]Z'U" WzSAMSR5Q;[a% @px^%|UBO=gJCEvgg4 KG_{Eٺ/kaEͱoKSF.Ƕn%O4Ԛ=Mj]-gn׿geϳE;y_b2^mT]+oq.RީYGƗ}¥&m-$UȌT=TӵE̸i3ɐ<leMh$X2c9 /}ߎ%~-HM`,3KW;ZBPDo#OLQC Kj}jۥs_dsj\۱~Eþւo qm+j^K,kIYʨRZSGJ^[ڏ}O?l.67e[A8j;> b_;xnMcjeURȩ[tcu1{qL}·$[7v7_j󸛷yQN&͹z7i, JRSOm5ښ!3][ۇq s)S4rbaצ<鰺jI3(et).Fyo?Y&@,~*ʵf+)*#ɮNzQyln@£,aCg {|Ou B( ϟ/?8=bS&сsW@|/Nl[gV2tײm$I*Ӥ9c\8-Q'm"i9X#':|Xc1!E':!ӧ'/dv{[oF *b׺]MXXTzm+xlg0U{=UB}j*i џe//k]k}].~'{VþҾB kMfһS.H)nK*knm[l.j(UKX ,CvΨ;1VPR(|I{$gqf ”AC@d(eCeMZ3MuQ#4}G-_@ nۤ]B{Enu]AY;߲.}߭xs/]+l۱_gҳMKWHkr׷N_ref}.~W[al-fϳ~ukbFu?0Uu%~$`1*R,LYWI(%oƂ4: GiL^>˙x#xׂ2#o^,Žm]W[7(:+V_[z=w5m*ͲVT%st[n;2R_y{KnXҾfٖ=mauT >N.JcmW.Če(rfrf!,cBҦHA%YT҅B={`[M$F68"D&Z囘m݂0謲9Id-Ds#URSo9}^y(Ӛ:v6|ZK Nv7slrA1Ԙ!S0KVu3l`-/ /93|4s8lbh &bH# ruXϟҫdЇ* oiN_D|^m*%0a_r3MK4u|_Jl@))O uE a$C)Fy>nvy^Ze^naKB6'4?ڴj? _;15qک߷d($É kk~kzC[UUFU,!=e֕LȩZjC ^%YK-s[+v=oloJø,7eRٛ>שׂVϺv&aV=Iؔ%6 +m-cr H->ncCĒhLN4Kthmgm=NȃuS4R&eXR/?l_>/$Qo]%E䰑6:¢^ ]KM|1Ɇ:ZMmҲoMqmsû=dve]ZOXҀ4mJ65گ.&ޘt py0i.K.]h4;r-=@S`AGyo%%2aJ5,o`,5:}5KWGڜV0ދGS%э=Jid`M_Feu͑sZ 7muwTh&_RjnyRZjR?YqšUZQ7vҡՉfzKWFǬ"A*Wg?K~bpy3ġ7v  M|,y6V'fWŤ 7|3fڰب aVP&Ч uEh%~_Lu5 o*:}"n|[a+] K=#,]y-:}NrmKvmݱ-k~ԐuEM=GYlZGN=9 oSIQfٙu6'8?wiC6Ա|ݭf٪mVJz}"ꪕд"^-P)npėqɋ?h:J(ϊf󗳽wn^88@!x΃ifv׷nõ:Q-GnٵmSPdMJRz'޺-N-dL1"Y'p)&CdoMN:L]Q4FY1,_E YUw"4*ū P6]]Fc#뛻fjؕձ\p4"Ng-yٓ-5ǎ֤kúu4M̙V=۽SG)jWٵ=LҫUR`tnEe++f_K&ZεU%W؟uS TZ.6v yMḸGUg-la̪%B^>*grGjjX3[f>FHbjaMRfF*8;ŪLc|@bXlOÿgB^{gӾܼVըBЫ -1# 6LHgʼ W 1c|BheLG!6r=-2)=5/0vZ),G(,_;+noDҹwQ-ew+Jup99)q.عi6.KJj)XN3: [ ᴥݖn AlZނjwiotmE`Y Z+,'.:DN~ՈJVEJ4 Uc"wZmŵLk[.`Đ!~I(MZ+cʨQ ]={zo]3M߻ G'|iꥦ%54`T#26XY_xC &q,g?|W17r/%wjemgZ}j+.'MiPV%zڴR05P6񯭥rWg_:`ݚ[Bص:" jMMm-ez} [/mɊĬ/œac!n[:Wf+bljIˆR+S.;7AnYZȾܴ(nV+ԫEe=QNj7@_S[o;us:yJӉ/.~8}M\I Mu]eozK* [iz:JI2#KKZݘFJZb8%$2xÓ8vnC𸙱0axV8rY)ZJc^5/g=*,՗+e=ٳPN*l;<Ns񭞽Lv][nϢmˡyk* ^ҰZ *v9AOSSLfӧQz~jnհ\kJ&[wla[`Y wTJ@M<,;/f]xwt%l[v*հnZ5u";,֢:q* @DtO jg]?poۻ0߇bS{Æ!, 7bZ穖HiHl9&8~tz [h, ؼXQ6mMTɉ0p:_#LysO6w1~/u˽E ѼenjUeL׆JUjVێƶ# x',BnrOH86ɇx4ekևdL'Shѩ+uS]q Nu:iLȯ0٭e߳*aH#rC< 6[P[ɽ o6YV zг,ZJQYSu+U=b|:Fձ,i1:L)ˑ<ľ7b+SGZ; eުZ|.# +7zr 5L9dxq仿e<"ő8"aCalC?Kߙ9 P4ˉFQL?-MNO&wpa*N%%Ћ-_DyOtؔ2^/sGgRY 5OBQ9i!  gM~|[eF*$%i͝燗xyJׂowʑ6ʼn]e\Ъ`ږ QAY+uJGQ쵌R_%FYG5^DdrėZ-nUm*)C0u* GP'O䙇ROV'ID  IGqc8S;kݫbv/*U%6],&jԨeB)vQ8W2Â.H`{"iJ%$ϥB/KG]#g;1;1? 0rTIL-з#n{ҌF`FAg1]E(2Ĕ e,ټc>O*`q䃡8Gè 玢9f>n$S3ɇxahHRX'vٗ#܀ G*?dųuTQ+[w-Sغ[26TIrr /UQw|ݩm]VzZ g[3=( rh񾳵ƒhmצigXEC'~0mIh㋏,rHsn&/V } HE_%.l=e^:ԡ&֫AT92[T8RzJc6ϫ6[xwYYYkxuSjZ+f5GKWSj L3V[Nt hNh fNSNl+`t+HQ3 Tgv f rkn YNݖhĒXUZ)/J ֶoe+i9AGYu2 teѲ%x, ZR 2x0汹槏9M~:fTqkK `+ƪeǩMUɽehXͰZvBWjY+Yfӊ+(ΛiTeUBPj.gWinVQ/HoFR]!Z55gy/HXB/=Z}H Mg6b0ԎRg=6"Zв!m I4e59z3򛲙Hb<3 ? wFXK!DD9 0ǧHV#w~>*ۥv~43^ B$+c* !+ La$5edI?>3셻9tu,#[8{9qX{i#H`s3_$jqlwÉc1[ =v@WP@xteO˞Uh-^ѱ\@_b٬Kf:-O'ع}h7VtŰ"p%yVޭ߰wz2:KJkj8=Nج2o~u]V:%OKCJuMCѦJ@s1]:WóHPw`+#ȏ4~ 6Vxٔ?"$y>zZeb7PYο fh8zofY7S݆کlJ +-VV`Y=1,yy^wv[ƸL^16wwm\?AFf9C订vΩ!e5eμpvݵ wƦ'~w,ut`B-&$}h7rխ56ZbhSNZC ɳ]p!8H2@EOS?/F6g @ #>sÇ/iv`wnxWXUvm,zI=ɳ]EN l1,vk|k HBC BY4XϟLS$*zq1G |> *?~QэVm"EجXإoH/ ;B,r0d$$KQS=vpg1 6rQ0_F^|-[ mZ bSg<ᱥE. I61>5~?-dB͒4/kw i"p堂c{cWfI)*" 1OG:^bf⚋JZˬs-Z6ȭ`ζՎaU zSUǷ/»MܵmAxZJWVTY+ԺSFjI}]\S7_FjXEaY]Y}ϥbibҷTѩLb󞓛Ѓw=iGrZi]Ѱ8*53eu_iڪa/crHjM0d&LxXv˴-' UUk='ZVAb}~67KDno+|h!!HGcEHVxua tCzS$KCzlU`^T*OL?˧j9m%B VY]ßڷ##xn]_zveCp+G|EY4t M-*WJ~8[kfW]nx [ü 7V bX6T(-bsRtyWH5(T r2_G&eV5ȯ^订!4~Oh[OV5Ǜ$S&V!C:$,vZYd,Z8ZޜD˼UM+bեbpϐ M?-i QBlk4L38+qy&A|EtÓWmVfوH/!mآ(8.PHb,t=,ʧW"@2 fuϡ0\㨆,nS !3w<}' YS*2r-Z%Ӑ o]4{5g,0,` X:v5:\1aLXĹ)Z #1p̝_>U@,4u9&)` Z jvvlJ&%_×tZVu2ATpEx1f# qTZ`:,|)4 f Ӭɥb(˸3n`d``uLM"̬y3vӶ͎"{}_Xka=KXUJgJv{aj郂J'ٔur'l7VH %O3ɩ]'11l L pT ^}&a7gccYXc!yٝe~5k~~}*#NBjjA5Ln{fE޲^ne^@%>|,rnD'8fBǮ洨VQw$BJ~\t7sr=ՓDT0Lp3㑀#'U1 $D`b"!rG~",F\ \))1SHC4 ,[%Ζr=L^]Ga8k`#D/ir5 ljʙ\z= ~](JAfL@3.SШR8qVͤ @@Iy`w:]ZfiʬЅ, ~κ2fDwtv+IZtL5 pԹ6(['VZݝuFØB9, vmb'ʁD&Yy5ީlZl Ba# a#St>2ݻqf;~w9|{hMvذ]ewZUNoSj:٭+kR[[nn ]*ɼudYMtMamƔږi[J nSL[͕~[ogX{wOr(VV>ʹup¾ʻulo2vtuUإpjtDuR TM㇟p¶I {G[!%UhzWrwbviMxd]s/+NAbnҚz;wR~AX)2KV}7YK7KbҷnwUFѲm[nX6}BmT[ MUBUCS՘zU{/yȭ _mZOKHBԪeeKB4u oJJRE+RU{^E5 ,盛G>p?sOB #Ek@~,r;I (ԥ#Or>d!I4 < 9cY]dj6 Y8qC,B#^}3u?~"D]ZImE}n%L1O|gf=~CiG H)Vȗ[yccb2a),_R*2A& D2c^vshy4lnuAjS#ԆS!8NIS;5L㋤y??OkWUgKڈX}ԠbP/٤VE#Qow;EƸ;+xf[.cK_O_-W"6l!)DyD9d ' b=k]j߭}=ܛy+hQEwv+uX Ue1IѬRZ]廮E1z,s3tۇ/φevd7cr}CKx:ʡƦ6ЦR :EFLf |!Eq%}i} `f[Ť.;7Gpe*%KfGkN_z^+lۃ;n07V]Q}-IׅZR+5kkjڰ{MvuAA=n;fXT9ɻ{cHްQS-Unf,E!QEU^{l/%XYGՎt((=sUҍC>l[oxWF,Wզ/h]SfHLz}%5:Z*m넆Cx7;~ ;Z]MRI. %,,(Fі*R@HkaƧ_8 -AÌː)X*` B LZ$Nr8ؘ״d93P ya'bWy=Gס-2Dbp~0G.aEo`eBf`9=pݘ+>$N4H$2aaS}NT"a3u@0Ag~c{a>fӭx6PD+!tb~d\7  aGP1(iκ3.Y8c(p<[-/INiˢ4wIa-Og{}8(Nśxh)cp5n˪klr7UNtOKj %ٶՄ +g^RfQ*y󞋙WZvol;yn%Ჯ]ͼVѽ e=d[bԴ,KjǬK9fڶmJk(f'U^v[š&aq,GJܺ4mqIQzl5WӕT67n>v^{`nxwߣЪ=3-ڶ}_OuNPrdz- kLUcg=gAqxhG`(*{47 ɮ{5{?@vMX[Taz=V^;HS-o{ݳ]eE4 44XjWST׵(-N߻5WhJ("NBlgy,ښ/oY*t;MwM#<0GBbx4|ֱK"Y0y,,Kҏ77G~_f]+f ދ/p[Es7{}M(c}7&+شUTv-첂T5تU壪MUtvեMWn7=M5jĝMSŕ &-o߳O N%\c$wI$z&]Yɺb1#JDc4U-WUI !.X.dEXA?Dzmʫ 9+MӉg%4>+_vDʊ6Mp >b͆N}L/Á*u,*գeq k)PiIզ\j.s`tupLR>3ǝ}>?MY $/v /)K-Fb,x}"C^e {{]+ٺX2wjkr,Zx `&ު>Nػn [eVjӪɱ\ꊧKUs&ۋhN-ϸ۷CucKGS%YYYZҗ9>4jޱ\J %3dKs͙<])U+zᤷ~`^yd =xm9xhiTGGJ;dDptz*7^!iWYxw߻ow#QhbH+H8_=[32lbbD"91Z$C:<l<rM"$B;..DJٟ崉P?TT4Ϡ˟J0ʸ+3.p鲒`Z@'8 a <O1E1)710,= 0DAH!''ǂ'hb<4I' 9@l4-s=io3LBjpS%t 0It9g#v=4OZ+][cRԭ:zy3åꝪrUۜS Gg2 gAǴڥӪzJk[xC*c025T|loW8m\c P-#/`2+Wklǥ$;wzW:-YG=fWE=GolM_'_)&"i?O'WT&& 'n`[A j+h-b~ =`XLzM|[tRMj KFc+|03^+7jC.鷹l n Rfny'7!+yJoSҝˢ%@SCgJe3p]Fr灈K^WVhޭtW&Z\ ӫk"@ `ܸc0df| 3/t{l[Np7jcT B<4˫Reܨ]6e(9E`O;:~/7`0<{#2wpf|3=Fnf bB G:\)\נ%S̘ B bٟpÓRtl%ʀ-sQ#}Ox쿷p5cVj.Y%}Ll6@%ƚ D>)Gtt׏v9`y1|NXK~ZAm%¦)e/ DoPҲ-e;R, JbKPܗ;y6UYz%6=bZ)4+-Y'ٜΚ-R] ޻wxbVUE=vSm6rSNAzrj Jt<{GgMRnΗGyWT+nߛbW^ NZUAfԝ6CSXӄ*ն6ÄMՀwo6*Q)3cp)dw/['g$rHVhnJ 1oyfnXg$lG9^J|Ml7yʷQ:?\a%-oѿ-}]T&ңrMʍM8POgU=0Gs' 1 8K;R)6]JAl@.8de?O_z#jmMuirR[`y=>=\Ė̽0aMa$ٽ:x1:3[8LK [J\3̈́dלmQ iAHK9D>0؟ÿ ?w* s&"Y(ҋwӥulC!Ǚ/JY=|#NͧڕPPd$Y gǻlTAT DFL!9 iEA`!09ϩˎ'xܻwm]JߺU%VC x ju;%A5څ+Wf# m!~$H |DtB*֯)hxqXE.3 i4xH\|ɴQK!ֵf<YlN)-$)-V8 2$'*Y;͹VWSXЯ}i)l*\uBNiKQ?vqp+.^.zzB&omUKcv}1S]0%_eZ:*ڥO&\)L@ɼ42GR@SDOFl@8Qdc?+ hVK:6ڧMxvc$>"3h+Y8փ`J)\U gɜ>Mn^ tjVtvv`aSe'YAXL̘|@>=>7nգ:;gyZvMzLv{(-JZ ZX6N`^*6cijgWY*6{bjJٳVg9InU M㎂LX#{Reֆ事u+1,#hrITxk?b5sRG4,܀jLϮ=+`UVsv 5/&N@L 6 0YpX"$^VN^ *cXρxJ?_ 4%t}:HP!3*̵+sDPZx88™:,jȀ2G8p3<ƠV6WpR_yU -C3ʧTAI\5|NMTKl_AL遘&H)e">;|@Xg3ɤ,2I!t_)w׵RʰMz;zemUNwVZvP1+j,n9z' k3xFGYq2Mlk{J+#oQ闧Jz.#Z917H3}vB@m&=X6<(/ӻ;Y1*#S$Ϊ>*;rE곙j񫯥u"*SngٵKR~Cb"ʵaď7]^|K5dɭeڳڎ`p GyGl- ;52̀&3#3G{$ c59ɼːV0a"K+Ea\Tڑwݏk)TT>jTΨk)sJԷhtH$}9Nthl%(X㰠hCMESW-Y ;ܻ`L&*c"YRU3K vQ B7 Φ9=WxTFp M=Uj3tuv zgd0qC_&@8 ⫎+%l^`ţIcY Z`;!zUy:Zdq.Y OD`C~c"`Ɍ1ozIJi!Ѻw:8hV[Wm3uaP՝ƺʂ-p5#F/~l}U'u|9[\#]GUɴ BaϔX͞C!__mNh`"ZʥP r$-dp!R=-EuF"}GND.dd~ Lqڵ*E+{R'>sюZ&ymY‘$'ϯ_qn VOGr㮣zCWwS0ӾOe Tإ&P-g G:ܘ&u[ǨgXe(̺P5R,@0f;?[*.FrLNR6bQHh0i#J^Tm5l*Ij>h/JQ]ev+t}\vlj* Ҡui9,֐[)N5ee;4-[aDQٖ2#A0sM2oI׎MEHS]dRvK+hU5DWMay*S+aUv5($d bnXy{<./wyY$"9990=⠖UUh}t85eF iN37zB$ KٴH6~']ERX C990l=|3Uwd4 ae rsy:QWX͒R% B0!6gG.F5uuYDzQ `f gOU XR;A dg?! ˥1GI3:ړҵ NK/5t2գ/@z缋0 l:_O.im:j-E52)i7!|_ϋb_RV[{n鍕I5icn_uX'%_(ًj5& '?嶋SSChWYqT*4 pN,> bZ;MY+%|z5e]k\f`p*nq;M zm'c _6uYaնSJYi:3]SôQ76]]n^[ө7/-:jZ&tUU3V:?Fe\pMy `zF8Owxne.mP5vjW~I$*UO`$i=JjoU1.s{Dz& F I% |"'D0w=NR2MT7+%*&fA+quյ]LM(նmG,d vl1' !,y $aC>yN;wDl,&<+,Li2O:^4?U'+8aw8cP;OOGVR WRM37N1?[Zk)XSi!#bDy +F,5,:k*\ջ̬@@šȶx(2'SjNHv8ɜú6Sn{vмh-:'Y )h(+>6.(ݤTR$R8ЙU O)laȀ0xl4v;H8t>P0bVNuT՞0q cͅGyrI}N1|oV+jͩjVT᧠M-:ABjjz::u*Ttɤ jVض͝k$;>Ӧ0,ʪz|X{kgfWEMKSxȆFC&<4ӌlujQCC[]hLe{@٥aM#Ĝhh(,8ӆnZIoal&  6 iDD,T)_zlyN>ޫf^S6,etgWIjU 5ObmaVb*зj}NJ(q,204ܞ>8~u]w=w,~ۨ}e=o-=Ag&T=RQzՔ髪ݚ&#),[0y8g0qwlX<>O(2Q;/s*fffNI#q J'(Ϛt`}+2S0_&a\:xFj* SEZlk))_>Hc:qBBY1!O3׆΅~/s}dܻRު>Ǽΰݥl&ǬyZGQӬm8.QM$/(G[g xMzn#F¯T(s3w W#g2g9dm-[D:Ce1.,¾G#1*1[*Znsf$2B3̠mzL:'&hK: @Ȓ^Fk-C?H4n Mi|bku O:S` {p|,2ˇ#Cxe2xkٺcn6ږ e5oPMm--jٵ6pVVV64kv*=Nlږ*RS )ַ9ru nO=l,jz}Ħ_ dX MgũQu}{gSTUTavhni[#ٙIw-.Ҫ*Ոpk%:_Il['{kye%n] D,C; {זC(K;~L”2)ٷeMa+ 4""Gg Y<:~?̂9h"\ 9>@? g9R ^`zy]޸wa`1-C # #p,N;_XxϚwedn̳|/`M s 0 x\2 ! DG.¸/3JeW DThDNlfI%ܽ+nn{Ӳnm j6Y4u̠Ѫ71u4uj(+M^.>1;Uk<@*K`'5^24wc $hE^Q/ yҔ1GGHwF YKVV^VZAP>PS5t!@O]xɻlA]۱GPUT3ӤWbS[ ֲٟ[O&JK/"D2i&pߏW`EgHVCiڅ3"b=@p/~XL fIIQt:]\o,}׺7#  $F{ƁҶE+#1ysO>O|==ggVfٳlkٲoڷfXtמɯfz k=Ɨ.զm:N||5cVd`FX'AώvIӴ{?y;żtggnVbU[+kp=MjY7Y,Y7?g#pb`aq9GYdrGjwUi|4eHiHGTKe=#vlw_ZUºóS6m|ƛǧhҵ*Щ;UkZ 3m5W^6LzkPt$OKYxW)b@iSQ`\Wtjg}5hUQkodӳq~/#n!T|$y#g}( _{z*`' 2WlѥϕTvWH1rKj8GOÕ>ꊮ;l+, %[ES_7iY^8ZQDIㄯM\s32d\L
]%ܲaR`8b8UaxѐRkjW`L.IGxpѢҖY9yX oݿuoHH1dqgϩ釹|ۼ1rag>R$AkQ_5|CmkvŃwSt' ؑ%2E䃧쥡>H P˔p.|h,* BJ23Ĝ;(M "1\Lu#'#06)! !i]ǹB D{7 S;LaER*<G>giҀmb;R](HBu{8)T{^D؝M=E^{"el.@ ̞|󍙝G>1@)B<>KaԊ2`a8ǐ<'8Qvv:L.5qRGy_zF3|;{eBOq#뷶lM|wYk￷lM?N`y?~B##XC3Y@IQLU@GTr`5tQ=^.]YB2.v-̘PuNft[7UZ蹫QAknTچQ4EViD՚vM|+ $ÐXMN='o7(2Sb%xV`FƉ2o3je[njҙ*RTӕh|=|+oL2 e3g y|qٶW ZMjΙwvs=Hl4TqGOrޣsְk`, 1!5>L|gǭw #b2EyPd-[se4uNRgF gRkv#%߫ \RK +a}! }|.Exj+P 2X3 >gxoPiHשԌe}.@h$1v"'<P\Va`ωTx9&>,@xq"gW7i|G/?d{;o.]nnٗ>Mol[=nbi w"գjz(+-m-SkU [ޯ87}o[üօɧee=u]s*~MeSSfԝ;t':YgW Wȧ]RuX˶o.gݡm&OUy:QShL0Z""092ipȟ^GoTrሀG98y!d_cp%)DyǏE2?.q8@qϒ?=z+D=NXq&6|;ͼg9c<09r 1.RjZd%Kjaq"|g:S8LFJ8*e 8tK^Ŵumltm@Z\2)N&p5!Qk Z#<"xfiN*JHmw?#cmseXzsgː?v&bQ1Y[ϊ*99LC/R#~>fX2/FN "Tuɵ"*tB6Q[aY&Y4tiAf׎2/3) OwLٷPV޻6zGXTsuTbs=->>xq)k2;__YBD'bW7 ]fS5ml!u!Xʭo4|~C44A,+<%0p$K59xK{]oDog+ȣ;&fCjP{m>شV7ڛ]S(փd 3qi6.ؽjvZn7УuMmR&n}䲯 䥬;Z¦TJֹ.^tgY~๼["^PVL&,,ˊRSe$9ߢ_pm\610Bd3@Ԍ#< gB<ǐ;F9Qer-O{&8lbr,3Ǔ/'F?Ģ1/,u'>BZѕ:i*+QN{s;T(-Pu:)Y8a&-8 Fe;&꩘"f'ԮC 8G9g[ (,KZ&R{A&%y3l1I6W"*+d"cצ R}=Yjg_'SjoґʐnՉ#N|d}u[(i뷄dbT*V̀_Z~3eӜ@$b@Hxz}{cRTT1$\b<Ő G IeTR S#a>݃nbYۻ>jIJo/=u)jj~,fGZ4Ws Fg3@y5?0fW⨂h$ {xܟ5`NY{ٱSvL4{i蚐y9FB# Ü98zíA*" @k-C"i%NSt{5K,g4LprX?^{݆ՖiͧeO&5:ZhrڬSmN}) /WִsNʹ%ȚJpg\cSݲY,KVpB"{Qj3/QR\W‰Ck/,InyB=.Wm#3FZb>4 gfbsĽ۞mvlMaZ쯲l+ٵTMyٷnjiGMTj)=eӤ;p#xG:^E;iG$- N!=;-R֟htwr}\2٨/q:+eSZAFљ_#ӲEU X0XJ,# g ε68pl"%B3D͉MCg 8fRV\Xt7O`tnEbdayd9;34L%#Gc8:Oݠhȑu\c fU+agw~O7qC()Xa8a8|F迗֡HʱE!0F: `OVug3qIJf$v;/Oo&$[Yϧ}" 0ItB`p"DŽ9#SŞ9DRPy2O:b/;OcK?Q,W,<pvo,}ӊ$;_Go  dCKӻ'~;[tEm .DJeyiHr/ݨaxuA]PDLH`py0TzT)U qpy 8GW&xagڰu&ŷ>Sz¸;eo I8gWGOs[X suM 򈏇b#~{d)e{e~~n`}}ϹTc]}?~x6gIif1^Mm;вAh4cAU<Έj8yXV:g,&U5HDO?lkQLNfFG$惐<όm. FZdxS3ric/~c FuC9:߽&ʴlsӰ磖fγ3 KP[S5[bbT c29ѻL7inzH6Z8Aϧ \鵬^zZ-F <@D%9ץ8~WˎWgqF?ys=|D7=VqGh dAu,»,„ \ < :~\jOf~# h$1 aD};go׷fJ =u(ȿ3Վv4uTR0K `]ay+r3Ϳ5f+1J'xᣣ$[8EG }9Ѭ:Bd`#3r։)otUTYjF $~J+Unҳl:4TdAmVh_OYm-3ҫ'QfX̭0pώs7ohřV&i0!2CbѹoNC-U;Hf 7QZg-]}Jo^fӬñ`y?|$ۏ?KJSR= vD` Aj@KfQ^C 4B~}8ᶔ ,2` "\ӉUcsgTNz;ͭ}%[;h3:j1%8qQF^LE όt#s쩲,a4PAfP2qs9ić{ W+lJ$u VؓM3t_o5Ѻn"մ,cYUJpUšf=)0YKU vUDUbЗ.pGuLixD,nBƾEiݠxb$)0rp`G_~!^eVCrH1WGGGOTW2)[}Ju5c`78㱑4a dḎigV|Syi#E.Fάk"5hd%ʷ53voLlNا[VftfX~*t6m+fhoh#QgN8^ :uR 2c1| ß'r祱tԸ"`#bSRLSi{3x ˞V‰B:!e^}T>F^ CRSM>J0ܓmKvЩMR:` z7٭QV4rILf!Ols(b"̈́c߰حF4\Ly1"4q|"[}>ƉjoK5ƿʛmz\{U_x~y[LL;6a-K\a` ILNʜ-ͪ;вQTkyz͵MV]X*L)z֦j)^ӝ= [l_ctj RTSԝ}kMGL I00ĪȎ\/gI }gkp[p| daนp N?]#,L8[ RM'&\f8w^J"]C(( seipsc+ G*ZJX1sO#iGa*fϰ* SW-WlYV=EֳkIԇ_FJOR˪Iq731qY\&c]¤D8OnDa? 5@u\4oU--[[gR6J"eH/YljUZ8a:j*ЇNѳ#ީ r"&OC\IlT8_ pF 2@(2q?-g]E9#h0230Zl|),./F*V8¼D l7}.s*.Nni٥;ȞP4Ϫȁk4r&F>[6;F%evn2eڵf$=FcO64+AQ 2g-5w~}/5N:- P{ifdg Xl߾WcIUUGgPPguc,}8т,#]"99} 2}I}n^u^ae~۵m^INæ4ˍ+_NoT E%dVl\V=vctl,RA8y8btgT =\RdP3"<u2w|})8|LʠYF#BS>mc^)7Q~vlZգ+>ʹmphiS(-z@slZjɳ.6u"Dr2 <{=;=pvVSC}U7'*}t|&=ごɂH10=F!K=+aQ01*~ +OeLF+eRc<9sNDP@@b3ω+p; jRȨōf<<3q`11&Ci:"} ]֔{ެƜ[@Ed!3+e33٫K̄DZD1+g/?L:YB }nRI$GLɗ~TXR*Nb$Js+ds8dwa<WA[հPr=MJR.|VzKa]c巶 vtDWĹc~\qNyg?~cWaeڽR5Tg*DL&j.ݟD],'SLb3M1'ÇT:{U%/HMxIT:s͕P74Yϕxv|TۥNE{) 7dԓGSEz[|N,J#veLq pii?omlXYn!YnN@/;T i\Kee2`LY+naxzJ#ىSIefr*5sï:뵼:ݲ-6']cZMF]rhv(J3O+c]=Whkk;ǻ5V]EV-kf(cGUQUNUq1JScYmE}fZr -0@ 0K |͜:`oci9MqVY8Kx^?=|[@x\Do1#'ť+N?{Mv ghC,%~ǦnfwfԨ"- 2ҥXSPS L5-/GWgviʖڽҷmZ+Z4ѝ=U22-ߦW>_Ըͥ!2RP@",>Nx;n^7VQӖ~wz]ۮ%`{nV]࣢3- &[*߸F7vw#=h774Nejks$F4dq(AT ZzmU'ػvֲr޺7U ᩬru:ίX\5TY s ^VW:J[TI5Q%%3#{mnpc܀iJ֚qax}F}=0O|!]C+;yƺ]R+Hh.A0C v!i82#~SVXOߩW;E]hAl]x 6)Xiݨݺ1ohMR1I^訞0*SU6BZs8C4rZ=%ͺ_ Oow޻=5 A]jɷWP"ScVS.=S 1m©,V119d1͓">[5Mޝö(m* FH'$8f䎢.@q[Aa^G1HcȔ"My@rq h1I,|H2?)˨ۀ:sM2kns5>V3{`Bg:JOyn> \{ݻ.=7n&5ug98g@ƷS[[`4Md٬  gbЧ#**Շ |$BL;G4#EwXmumdUH%! 0p+gW*zm5>vX7*β.+Q`uU6;&ĠlvѧL\6onda氒ҁNiȆ560jHCtw[6U:)ӰFJʗV5uZ:v(.x,Cp[KapG2KF׺ PksugmX\^-g&!ZZܾo}d +|wqr%Ob+> y4<?i_a$,͈haśad0 F֕gX}]k4mgӺ4tSSURiJW6Rq`n?k{CrV7cxIT"l["YU6[1( }Sǫ>@3݄~w?0gYAMO,l4vZzV. bO0X51MiiN "ʳ**]^RrѝB :pT;-O~>ȌHD (<8?IÎ1NF& c7,O0 f1F#?̟m`(y E({(w;ޅߴ[Fu8lv̫,z=g3!fnei2jGJVL-f! wtPwwٞ^o-͏[{M)~M@u)lO+IGn}Q)d.lHhL/Qrq|p |cbt񛄲X2<':׮ X!|w5]^jZGfR=}+9E*i)BtUgՎ։٣ 뼗LۆvҶ-+}6QTkr-ObMٻ[vv) 65}TyDΕR@c[M`TջM%bٔ $ӡ|<sOi]ߺ#q8|4Db)VoPS)+a̴\Rb lDFը۞OEX1 ų#Ιæ-f>-#+L=DI,+M E10ɢᧆ2矋hc=oZGJYiן4h*^9)] Xs=jc6⟢Q9!9ߍ;yrwLiKnmsi]Wwow}QRǦӅSLf f?:ʝ\(V$1#87/ ~ I($xN($`~kSM&O*R L*S$u]N* "ٴf$s:CMmOܕ*WIڍ7Ż:ۻޭ%f+O_hWVR VAR`W|E9"8B yǏ ߷vwIh+ Tw>MDӱuSuxG=d "0^Go(LF*Xq釗IU5NSngЩ3M"q@B?ݳdoBY;{EUk^ VmMjElKY44픾V-MRԟS=mc!qE$Xd #봍ʍޛR=߹T'n[E+֧%i c9aU)}C5j1v . $rF Wj[m0m?v u24Og-N\E஦*ڕ0j^"ZR08-m`a;n~7zFs;|KqY#B ]sͧjT]ix!vYTΗfef ֿV)\tON~܋7"#"(X/8ja鏮Q2n#j関^Uz<=.pJKTDɵfP8XY1*|x>7g ]Ȯ68;t+ثeV)[u7lLX,1NÍgDehr>ݫu۾ 2N.mXӞ `&u>^tpX;Ͻ[/;6лwv"{,X5VRj,d6uMr᧌6~@ b;8~}6J޻co˭E=-ZJ$*R& UG ɍTxF xF҈b!+;pgr!VϘiA0. ~pǮ$2=.ʪ6UvKjRQvdclх}C6TԯYgߣp٦e(9g<nݻvH UDvjU%;:4SKbcI[2q> b8Nl8X#ghiFJ︩$+ZݶXMݻ\,8pH-uZec6 Rbr310$$́8P]|m d_.L2&|x2'v%8Xd1icygN3S`X^;6L B ger_COLJ}X+7 /輩c1=R.?U2tfj*e;Zb 58ʏ>0X3Hd2 1ɨp ͍I P$Di0W΅ Q0G:[͔+"aM2YJ8"R^fD6.R,l>QṞEi+gR}gz5xzt*{6B+rjh͔qq1Xq={aڌgI"M/_lPád/.̫% 4sϒ4ت BU# %E?7cZB-b%dPqlRJ5u`agdۆi9Zu "Ix*f,m^6Rl9LyUjre$=6.< <yZ&xlOG.,9ve'9ϛloCnDVyo+6_:eͶK~;S>kuctzw7pNOםkg}6.ݽ}(ª/%rk)c.UG>+Rguga''fһ~/fVtwɴwԵ,{ ӳYZ㶻[qۤwh鿫/ݵ^k*ģlz;mt튛w*K X|9N% _@hzHκg+ɎX%$8UqrcH<M}Nh cvp;9"ûV֩򥽉*kv:4i]KJR_?y/gn6k\M}}ޅǫtw3>?XhmWG)moק6 ]M\>{Ұ}`+w F6=m؎F֓`]Tt{Dv{ay[źKhVWo[y:waQѸ,˙S`ge0=Վ_Q;a09Pd4(NY6`ZA$$Hx> 2m4|"pr"]< mz5]rȸ ^|OpVq lr>Nlyϟ8GWdu fṔQƼp֏0>&(f [W!9B$J!b FNp?04jve ixK@,7|[lj5Z \`X%<gpQaeS0"^v%",짴7z `=62c[Yp 2 ]8tzdC<-Aѻ1Pk+)ˀϽf?38[ze r)+(ذ,|p5߯m$3J&0>qLJ`+83)wτaVAY-htt=BQ^To}w5`]{-Xh=^D[דNдYFTMf ^̺W5N^س엹+{Wix/e$pFZɧa9"2Sѫ i)=ن-F7O+smr(j"ڥՔ?WWOךDf,Kq'?ܘ 2{2 Hᆪ<̼H8/w]CQj`9m+54txJ؞xߍ3 ԧ/ڷ h] r}|:ÐGJ3I] 0!]@|jPZ:kv$0Z[$1eؚhTcQK]KMVZu\ -o?6C@9f6/Xy5: EjXDlG8)gKZ~{略X4Z7qVmx+U"A!ö*&)r޳]m#M(/`XwT(A[}n׺}c4y">R`vpSn2n+: JɵapQMG٧RlN#9U=?ٿW{6n7?3}FEa]4ԝ䴨4P8P{AEShZ_u\ B73ÿ( 7ֺMkyna#HgA{ɒ;446';.sJj4NlCHD%2˨G.aS8`XfOOτwYfٔTtӦEl<4Z@5r.~E=x˞Gy]OlXvcߜKG/nxdJb+OU`INA@,t)kﯓܗozKݥiԊC%"=Me)uCTn<8N=`"gUI 'E"_Z"g yl,c@}|Wo.ۏuNۼÎvj`$B 6a2}ďq]v.xmʴY)=UX0JFn>}0;BХ x}[\l-WFSwT` (#ǯDXu;Go 39GIP9F'{\)v7x]twjj] K1]WKNźD󲦥 jVU-O'DG,wqC2Zkb^Z[&X,Z~ƳΓWQ+0sUfǁuRAPs4ZC[dىkJ g1Mކ3Ew۶o pޥsN]5CiTTVISBpV[u{fм;l."ѵ5ִ8uuGSZG?ucZOgk}.n״h|%r2/E5԰m;tU_Yfѧ9TƝ]J̡l 6*E2QJMt˄@_MÆ-d7F  Sl'"WѬQjjݍG<̜3\{}jB1w*ux(0ųn0fyDssjdomeV+P+JߛMgPju\6]bZ8N}LkVW1"oD@e)`E8lN"G^ ʤri(4 @Wf3sx 6|Y'{S@Nʣ1L'4VTs覢+ nV:J̞Q0&|88}f z+AKQ@DΜqFRY1qVgW^ӢLvc y ^V}YמOԲ*F\ F 0VMʦ4IIHz, 5זl\FH՞&i<95Y>߰ʑ%4$-:ңagbgk-7kl2Bualt2byy&uU!S iKpPEڼUYe-E\ \~7,-?z.;#[ݿյVݎn՚nOݶ`S6It~TqwnOin.oŴh^w-hKOR=NjZ޳Y;Eqٟ糷mpn7Э*kY`WNl Z ^T{V_]ojoo xVZҢY /%}Kn{5OSv6]Xw1hqs$I7!_i,La \B$Sy佐e̫tL&FyBxKLkaǠ%@DfH@913>|0%&R,K9 !06O0S Q1SQ+y DW>xU-_=,4is@-8kƆGhX݅#:$gU^Cv/S@"I{ d ¡3dgVMQW#`f8gҙo&Eoee9CizfddD0sؾOP[|=J!sXsSqq;48w`CEKt֔sF n'/k%ˮǏ $`SUy#8e=H},7j؃3if[|Dv|yɫqH֐{-'N2DNOόy\z.L_[1!Yh30VP#[8|0=UaDcIdR 4\ I >)ԚM;\%^cMTXy򧯰,D$%/z0|4˄̲-Jw)T%иԥy y1wSL=,T RH,gξU 6Jj)MlZ)&Bg>}q'1"phɓR7nXh)C$\ɒtזc#L韊epJc}~~P[9c52a8=/0X:yGi~GkěUĐxfN&yߏbǦ:eFO3ɟ2zÿ+)Z|U@02Fc<ѓɓ$w>?v4Ŷ,'gќkp!`mhӑڲIV3E4^jIlDgҨ[KkRDBS/7ne.gM X4͘|q>B})y)+: yYGF| /8q՞]^!|rIjX$B95d_=ĩC2(p1]%)$qlrOֻQ{FJ4EGi/j%$98 8xUFH1XH&Ju8bsgfzu0"&N"%'NmxHպ 3>9Xw1ÇH(k^K]S jM}Su6\;b^E:?@9s,UM5f[FUZ5@U ǧV[5O&VRa[y^)-m]Kb)͵} i(3P>.:j;zmk۹E\VXjʸtg__G핚~e-:]U=WgSs;ֻw_R]V+0:ZJɪMeJjQmPEa 9}mv}wlK{' $_ O71L_ThnΆvn-PO"M.ws*Fh5dgK͉:0rW=ZoűWP䄳E؞п-tmUZhFǥEMHSZEf4% :2q4/{IriBuc%D|:z|n33|E9ໄegh9jۋ ui$`Q`kIa|ܽ3/V${LY+2SOMlW/ I1q,h1srW}/I9ӕP"f1 .\i"{n FsIQsYSOC. F&D)H|RЫ_uءcG.4})h=NXYdHK8g{Re݉b*CYRk1 cg .>ͭfXYR& ʅ*4-FQy?;%uIjeRĥn`wSGm)lesfcB _Í¢%Qom}ӻ7F"~ `7hx #Q!a B0VLIrNlfOo+nn{3SS+fҤ[+7uz+u4ڶMRU8CT>MƼe`7z6,~6z(HP{Jtn3K^*iu;Qns:{.˼V*R@:u:{IѫSVGtvh. $X\:cou @.2yS&xDbұ$1"zvޛ[*kw۴vIß#NaQU KU}*!5*%YūeɆN_N18nofQ3s7%]SteZʝ7Xfu)ZVMM{nzdᄎ.`B]Q[6M2zE`0N~"YāuY\b"2)D+_򛏯N9$`כ1g/$~Q b0͌Ď>]39?6>پڈ+UŏP#Q]M5l쒼kn z[s;쉺uP$y ›ŚY qT $Kƽv|n k$ȡgy2Σn.xSAuEAh33 ^ g8wcv3ۛ>N.⸻=uEIfأFB}J{.ngFoK/V7{IW8˶/U dѻ4 &iqvʾ6}ҼnE츗rRW׊֦ 6X-EMPZT++C)DhNkGq/bwj/{*^ʢCj 6[ >8Vg;a<U8)65}eXTU5Օ66̩6Rƶ|[mM Yj@cr1ix짽xmJKc'5`ݴ#cLu]MGU :KubM&Y7SU9&i*zhǬs=$]eO$<>b$ᚻ؈T?:s3|dE|;cd j-=]=v7YTW~oZ;yn:֛*ctzT_YA^!ډr\݉Qc^k1ѷ,kcVGl]JسjCMenK:xH;q v}p;D[.T&v>Ӽ1cBͦ+z5LTRS VD)+7k^7ĩzwOc[7rͼV%q7ym>PMGMwMaXVPc^n1x-\f/ 69dĭCrʲ]ىp^ HcLЧ rMMo϶&%3$fg|po%PXb(qȿnߵ#="Ho׷aE8Mw> bClOoWS/컩^{q51N4<մ{ZřuJryi;ZS1O$D@ɒ-Awؕs+#,~U}6p%0ccahO=oovx7~.ͲP9BNp:[ۏvӾjNW҂]CuSb\CaSv6ɧܯl bKv}yo y-g׶*V0Y^U]޻71u0eow/Nǹ؉YbU!hN['aؽs[]׊VRΪ vJؔ5 ׵T}=-\)ˆf28"f0Ϝ&:|Xynwj]֣d~/m jMOu*զf3*ŮMй\;'ȀR[ 9֭N@$pY5a~=&%ccL&whs,vvv)OW b̰F>8SEMWLS '-n 7)jÿk귇qnKm2BSXښ:ZzuPWiqݻmx%6[[jmj*7r}g6ֵnz1K('[ qdCjVkV]-~͛Zիx+Ip .ڷdzE]=RP]$e5_PU`}H;Yml'- /w4:@[Mh%e: OF[u vȊF_2.Er۶Trql=?cmNUe5H:&>w8''W}xqW[۶E %AH^I]ɒ]e&-+۽}o k{ߘB^zX1ʝCWrcr?bW[/0&Δ{,O]~7PW##RQÌ '{}he"x]kfR;Oi @YYDl埗WX >v};[o7٤;jwH]#eRSYR0!J)Zw[kBJEc&(ܓ+*fuia<[ȹVh)xmhkMFY[Dpd` 7 rpa`+fB*U^n<e?dˉ%lL=0xFe !#8209gmt;{o>M|TQT \3;M STjz8Nr ÕlDˈ8f1|X?F7rTZ[mgZ5vF-a 𴬻B4ѡ55^)jb=-E/x>0/7@ !G-딪ծk>%l3C$qI #뙦,vq-ŷ54ݴiYo9cr4/UJǧ=7{%LLf: >Lu@&l$ HNBc&LcP?S?j0Q,+^pa.ͽG<_]24,u.{@MMT/ q/ῂSڴMv2CJB^9V:.z{Iʜ!90^p0Ξx8h(1%"Y,C`aߗ4AE Y ÞO/>9=O~wW׾H߫0S%`tKEgŦgddH48؝ZNB̓cQOkfHX%LXa:^r:}Vu:ھnͭߥeEUfX4`3_Js@g`ωKsߴmG_La}=;tcZDI㊸KKu뤢/v}}EڼugQW+6N٢sKHO$i̵l ?K;x|X$Dk~ 0~`Z1~' LHa>-ۇ%Fj#ʊxnf"5Q9L9ΰ2l3meҌ+Zs ëUϤ)Uvk>}5;*k)'Vu"sc_fr&#fO> {ɉbR2ȢXd96u-6qc0p$k]c4SH6qN$.0>gnJUC&t[Q+ɀξEMncY t,0,b$g$ 0<"# CXj1o"zY#Ae%+W{ۨ.\xIG DϛoS-ɲPfR̤-6x;K RVR28 AN}O2}}vhDYD}$ ß0kgQ)1r.>jy8|EzfILʖݦ\2çFt& Sⱽz0~gPJFdf&F&cf1'F1%NY"Kxzq"?_eOk?e8!ka* 5N"'sF_w''&bԴ D C!t"9N992sy?'t,Hxxwgh{nD?cgZz{E?[Dg[`>PR ` э_In8m]ނKId@vy-rGe0%,ɘl>CgZ^ξ-^7ɾ,KE.L &`rbxOmUϴM;֎gH6-e2U uΔz^sNW|-ʠ&F!P#𙓿lZ)98J`_:fF23`f/?Y~7)ZI4UpG`dLVYXg 2~|~>- BFqppkd!ˬBUxAnOPeW Ciﴕݾ^*+!I{/}i*[uu vZzTk[轕l&{Լ#xhШb]SU2̣eef82-f}z&ϱ:bK&+s $tSh]H7w\Jꊚ1EPQcMρ;L||A2aD#j)7dPXIK+IhKzuk-Q8^c q$&kgs0c[k A hg02q}~d;LIP쓔Mn3&ynqnHyYIZq dXA> .3U WilR<" nD7[>LoCIF7 (?8rHi& DVjD`SNڢ8_Nl\wJ*HgٵX˂YNaf!:ębXfy<Ǜ&X~ eUHή˘{cF,R5߷eMC <tG~3ЉDTVe]$ j26z gդOAnRP"s*mnlMRb>Wg:]˷jv}u~v箼˲4?viFfg_Բg 'KR6IȪul0!vVe3d-驓=8lqUTٵ$ESD]HoYrg3sYxyX;L\_{ƩΦ}Mo{KtvxȤ^73ƈ%cѓxI6}շlDSڷn٥슳\BͬYj#1~apxL ` N L^ދ]eEdVđq?/~CM?K^b;SW%0*1ku:4YSf1(=SmKOFDqhBA#6md+(0/Y1?/il̋`ijxwy-6fiI?xODų2,{.R##o3eQQ!$Z;y|%75;6Uދy. jop.*@3U|[BD11B\wa߆G^=nݻcEXT:αbSLycu=qx0u$~Nx݁?C\˃8C-#ttWVUT$Q8 ,5Q3`|1T]j c{Pߴh"Eb4tbo \;Cuӿ z; 7M-զyacy_%(TJMc ZG;̟^N3518ycg|@<KI!<@_?u (B0(FCicӽv;.غ鳙hʲ,6̱鎎f1s?5tOx;2^y[ϻv}5OlUi  Svmc b Z֐ ӻL1S 8藼Gy@W#8]a3ë@rۍ_/;۩&g;TW暚sZU8T2xlt߶Tw' grdXWK#݆{SgC3%I^~jmS0$y 3qt }7XUr';p}[6%M}.ڬXJHM6 kH(² 6R.qN*ٍ%1 d@545Gju5lWJ0ۏ)!1,z =ޛUqxtLY56;kWzPcNw>a0FWbBOSM@U;mݍUWq-͵i(Ecڣ[GNTҨlٶX:fGWZux8 ;ofYiRSMy&dzlIZi,zjku2N£zE.-6_J:{e3+,;:Ҭ0=CO7ӿnݽ}AbRSP-i56) VO]7q<Ǝ$Eu-ɴјNoLdb`ᣍg#<3+Ӕ}}ì*MEcSR8PRmH>[V>ogژFmKd*,оs^}LΟ_ϩxn`"1R4kH`2s5!ݘxUð@QQqHG Lf:~+Q#&rXh}ۗJ4H[Uuܤ{?9_mfb*u-i[Su/0S\:Ǵ L)nv)[ L0p[Z8c، &'#M7:ΉH?^ʽj|Pbq<)Ϝ,gźtn(m6ٹmE4,ZJiԎuM eLgҪrt1|9Y  g"Xd~M{u,6g),3fEڦc8=ӈ4MX &C$pv76.}1BH7$D:u U2*#$pp;PɁte 1DVY>x?v֞Vʱhα՗m\/98>J|V%c݊-ٴPw)QT%|goЬc~HxBc^Vmځ0|p'")x-/VBޡpHICL|&9:>K==|A,{Em< $L2ܐ^kDYA͓c-GF#f4tO>gl(jh@U#cY+.4` "f!9^O.^4$ [cäwdRk\%3xJC#,K@9 ,Ŷ }mgȥů2ͨUcX' e.}_ҵVvϯ\{B.Ь Ӧui2BmD-Ͳ-JzH]zFaeYRAe VE !zmQy:_M]=Y:lYUVuL KN `T:lW|~|6Lf#y~0?'֥fh]{7).n)\IbdgHjV!R}H*VZVh2Ӯ+ >S?;Ѥ Q2B2Lrp8ɟ]5ﳫiXiX9HN|5?-#Ǖr9Xr_glG+$cJ$^?ڲAX0qaD1C*D#jP=mC*U 8ɑAf@(j~<}G~y !, ~~ӝkXJo6NC0k\dl'(YxZZ('dӐ S2Ég|/efv0#<(hNÆ:%}ځ;~ 9Ni'$k6x=Vւ<ܣ<88񝽱?7?m},Ff^xL#<`NVbSN ʂbWc㲖ň̔ 831|0~^yuM-<[ǝ f+Z|q~m?!Gy,t!rQ?^fTx2 ;ʊIt^{UYU}Dɧaɥ0J `Z-D܁7Ra5̋sT,S#Dz^Ҟ: #[Ͱ qX k8Qm*1$kEB'<9c[+m3"Z(F z](\Α?ʟ\מݤ0yZ y!Yɞs3aC?:4֢ʢ K(|/Æ{*@#'NsIi'b6jEc tA{C5r|᫶C|A#Ct/\KǖuLSU% GV^u\ lX[߰@bnB>ΣbOՕ4X30iTIS {Ek3ދW٬K7Bm'SRLhi+ZPݪO@`G?b`D%GO7Wa* \;#sFZ]j/{M{mkn`n\-gXhjk(l.S+s&/9^pH~vAKvV[eozpmoe7ܗ"ln̶fMz(5,(5\vZ`UT )4Ei蟘N{U 鯍!@{_>-ݒo'gx% "1n>-ik"j $FKPyX~8lyw&giIkq,Ib`f sjpC:9T,+nH!<{&64jS:C|uKlI4Juk㢎#C~#z}i7.aFKPdf+!fCHX]rKTtgOa ȀSꌀ/)-3g5pGWȄS!3h*z5ֶ;BP4HJ`09ZK9xڟEȅG4Zx?f3>u~]HV8^?O>{~@ўiSn*YcO7r ;a#Lqc-;au}n٣5Zݵʚeփ3Fϵ1df a@ce:Q}RvX A<: ^WX̱.P0 =cyib1<;ru;k*;6 o56 ֵGݴu6X^zZ^RKvyҸW腐WbW"Ug`$ّm٦i 50ړ7xjoqVd;,y+e;Ʊvl9v6%-3YFZJ|hu]9"\D.bѽ>-2,DhŠGL"XYB@Trwx];k`d͋m6 Բ↞(pd:ì¡lN\cEwJ>Q̇g}7sf*kf[u6JZܞЧa+$S ( 9 ݎ?nHU7}>S*Y+N2dVTUMl'][}K^ǴXVcc?Ө-YV ;tA"KALk=>=Z)nE멬p!IZLһ6[>s'_:) ӴJm5:#ąLtFp7.!4|ݫ#!CTarYOH(> WWk.b0%pE:TX7*h'fA|Dfl͵2|SEI~*۰;^ɊDzy9ۍԡ>.ET_;b[R B fu,Օ۱ܓE^^KGP"x2#?XKq_v];rtlY#zhV+ ɨ fÆ YJj|7/{ N87+# O^fmnnoӱU /mSa¦^55U2KURҹ1ۮ .*i)_Npz%u8Pa.{ɹ߾;?{&]}}6mߪgݩM5;E,IMV ˤ > HzAM:WL{jp٤o| ~GrsF"h$xMҞ zK8_ lr3!"'% Y?Pm.PK F ɘTgLI8n8̗"ywZdjMؚPh193cGLf*{ K'w[uYBU|1 g+BP2jGPN CS?,6^6u%L*o]-rE`z4}8>}&7MWIW##@#(@IA/^>~# 56ȖxlYBkYIqYDi98u[cp?Iq 8G!Ԥy/nE)†dx\GWב\Y/ʵ9sD .dxg0=,6Ds9Ĥ2dp'=; 7eaSLp),#(N}E瑌3G_S5D28GɴҼ!W.FZS=谑8q^$jT6|;5ЦDKzօ=BªIqo#Vzw:JC57;7i$@n3{,bC\0En;7΅trgK>Ծ6mCdSšʳ)p0)ZhҚQf[cqaN+uS9۹8 ϧWSsڽCfM ɏz"X>Aa}h[RT8qP1Guf>tܹxh:m_uT-e rh+hj(+EE-UTź3v+"|%:[R&4epQ.H@ZgGޛ^[j׷ f״!tai95))YT7WW-b*K`ӦcI0ltqxXC,%F`LcBy̩EH%4A8:sȅ]ՕiMLF&("WHYRLϽs,ᐱ1%Θ}Yԝ>xZ7"Dk#ȳȳ--NqOv@cPS &JH8˰xvcI3v{<(.2qVqw.LRt` Grſ?bsAfSJY"ċ#σǞ0/*#6=Ƌ"Ōjt>O=6xc{J$@3?&EZLve;nXEI@ȶgxrDstѫh[4+q c>N(Gz=yZ5> .1ݲRS&X(rSf'{:Vu6 024fs@p NgSfxala$yx>A-K%E~n(AR-#XA0-#E|QHAO99qg/ g "_o>g w'{PՊkd# ua Ȇ0R(2jIl@KLaak?'O0ӈbk\hK83+SO'8ˉDt}ƒGDi4E&YzlU{b Z!JXs֭8|V{qxпVb+9' 3evy4c_Quyix>?}4Đ5&.CBwtbTĸyʳO:F^LJ~akϯcg鈚Pgp Wfn"]D&˙e?OSgBYDHƑ k9'Q}Fga)zuBl̒ʲdy_6p)Ѧ%F8QoO eKmHQ-GYr5:-}!Ue[Te[eTdrig *Ԇ M5u5A{SCun3Sn5ӛvl4bwռzRO=GŤip{R\❆XkZ ;/ ekV=DF֕}zh**]Nw]o,I!JhX{;*ټOKjM!!}..[îjekdF{>g|!w>֖3-g) ϬꎚZneSz봻&ZTׅVV3m@ s!ZyҪ_;K>hpJ N 2XNtmbccwf?IDcZ Bڻ>KTpC쉶砪6=E Wp-.r=d}AhNj)IDd cϞON: h'Fc/RqY4`sNm$,<9v\u6hvF &D7!ƦHZ!?Ϗ峛w,7Q^CU,(tttgÆv^SmYRk:4 8X:SaX/Ѽ^ FKN£u өeO0IaTh㫣K6L{qHQx!ruݣݻ[lFqwL\B!o */m5">TA@ t'O 3ݵ]v{;=orUhWfNwNTYU}5 +*]-G2BU{S[7x.jזU&yji2䣧7ˁWxh ^ IuOV{ tljeK4-::u0;.vu, [Ig6k W"'A>'kV=w'3׮ş R-6ֲj5VP>3Kk3<{"eǻ2pwzn5ln/E6eX]P&b%e۵S_edr SVcj0I~_/m+i8KsjlKT(vj?Op *90آG! όK] .iĽ)gWo^}9(`$̔{$!3aO[sA^YVJ7REyTnK i>8XtuE^#{5Kr}w#-z;"WML |50;. HWJ6~ZJ\FˈUyhe*d &b1ѓH0#v텻k-g :wb"N-{BVK?i թJۙ}]MWBŲSeǦ rX9?ygM<a-wm;aPoV[mCmKFѫ f̩@uCBD7WY] ].&xOYu)%n/gJlfdV'(nw%nw*={-]~ە2nvi9ӚJ0|_3d) :X2g\ l??-M"οV߸T5byj\T[V4֭aZULZ Ow3rl r-זۋ=bSW e-ARn R,u1\,)y$:h[Bs yknҸ ݘ=O8""> MER3tTָ]ͼkAw;17V:ڨ dg*& eeYIeR٥ֳUfVљE;@JDOLO$yZ_;Vݪ ;j]e^YuM১FَMkTW1TMoF:gswsU_z^+6nVc;J*YAjg֤SuP]]-N'iw6'C+G{nƩJt*^zkRۻ 4C/ ۼh.h[^N,WRnr@D'0BN̟De.%9sy;0ۚ;iK{ja%SgJ+n kjҦ[io짽sQ)P;=\Jc4߫z/"O!Qjg3͈^< Dƹ\\LǓMj˸i+ʷIt= +\#sۢa04 bKe!ӂm쨧JJ"6*; r/0_˴ղ&xjFzːNն)KhIow/if}eT l:.!˓'ܗm6m)J.HʊàG~AV6Xܼ4>","$@\JkI~л`\[˹=^~/M%]ۼ6Z.Y5BkLէ7%M-Nƒ֟ъs am$z@<8\1YYw8_}TXTa\F/F^1\.MR:{U-%j%-,p"b)#b5rbN#,]d?_v[? iOf}ŭ5!ux7zcG/6O[\a !dDbȎj~o%OjEH)Q~|\6x1?따 9ّ-D301,3sN?vUKF+5({%gVѷxil}ST[,:jCcZ2[<}@H>~63;0ׇ8r|>Z|uλ2V@gGjHv!}ymצ7 Yw@R41ڕϒʦs% IC{ikKen6w]n*#Fج8OOӣfv)Pf+U[p7dwym U][Vԅ귭 ^WJ-p Tlz6*kuf\̓pe𧳮ڶ[B׳kllػV%0հҨ*©kƳI?< T#бe;!M~f8>?"6uոi\}SISbKb$j25^LȔFM&>Gpgp3 Meɚ|+Q/x:"D8vBxEl)IPHya?x+me622<vd ;kr.ɾ6Mf(]`6==*yҺ)Tfpx3|Exߴ .>91X "X[ݮ^+VeيD>;V$P2#99ɋ<ؙKK*I!w$d?}nO]+aqxtxtK5#li&fȀ"2K<?'9zD쿳L "&u#1,:Ra?m0mX:T>Lo/T˳xTkqف,g{ӽ8ޥ+;qffe&Yu30p%U2(h6̵$MQWGQayo y ݠ0'h8`sv%W H3lwݥ]13pU3:| ƘWe:[4mf1U.WH哐 ;| ()U$%^^@0$%]UrKu1tnڼX  $4z|'KUq$xc~;dX>"c3έ+<3KRқswsBZvE׽7f̼vҧ.QP&SV޴km-{;vX_]ncyT׹v]t{c^Nƶ-Z{zmeGfFnZ)WK-Rzjm.C+KE(zuLLS0cҐuWԉze!4'4ytpu~_)ɱ.7pGd I$r?1bÁL< LOiv܍UޥĠޕIAx-˪߫&۷-ضJk=ĠzJGS[޵WM`C;mTuOi&~nbA?Mо._.J9 {Nvzo8Z]U%m,S]5 ,?8_=/g7ˌyᢇ*x˚S4wKx@ؠuMw[i6XDqK"fϐS#8b>%J/.z+mKs1V9Z'4J惌ugSqϫ6,;)){: ͓߬ <{_;k C71KG fmh*5J.bxQW(1tY]zaC;?%Jբ+iuc+i> Q9?WOǻiݝ]&YwZnjtSF`Y3V&\NU5vED)bYjWeǼ.ֳm8SLW:)H -g F$mV"ԖZ;#wI7| _T=)tjVa@\K_roԾu-]MӶhjZhR_g{wb;Nͼ6ڥWǷ=j]wh SYCN5LQjN2rCȟб+w>p8_k ]7f´nܽw3w]zsоֲ|[gW;Kwǝ:bNFl\#9Ӑ3K}63x>Qw`xRY9x׻ѻv)w9yT\TXigچAL`$4Q߃餖̝ *- LӠ<|Y>.۸d)gضU2PV>gιWĈ}at418D%' 3xq`<:a#c>%84>ļżk@ur#JL;4vimyYgp.Ȕ3y3oRvV-S &HAVK^Os?W$+KwŔS3)e`s?G?-}gD`K T"ǟ?f Y$^=['{o"ᓗzfu;p=(LUeEkȺcRp_GK٨//ejʵjudJ* l7S{JNmoUzű@iljeEYNQ7n]MfU"ML!fGN}@?-UaI ;2^S'Jz GgxtoޑaTw gn9Y6eUTp꺶W)  ֩<3OǏ~ۅ{7}HJW*Ӥ 7Q\vCczpkpٿ׶۳m/NֻݧaZ25]SAR|Zq;yeJUL2GրWS<oXc|,rM@1KczT^.ziu5`@¤b`DZ+m()7x..ߋ׭AuYxJ@nRSƮQZ]U>wڛ{6^CpvhmtζTjM}v紪}M:IP#vCt5n_aZ;EC{-Gԧ9-:h)gEfӵTt_IZw 2( *APѓ @d!;7d\8i>3Oǘ{Fж8k(ewW8I,I9]sgn!;#EwÚg$?lpfjoFu< +U YeiR<lxqp41IIsQ'3I6B??7mE%,Hӄyc紱je߉:#%/Eʻ8w6#A\rۆ6 [1 h1 :5F /](uײi-NIERN*j&IDb҆Y;a$G׾4Uj-RYS$ OvYHĒGKOKG;Mzyo|g݃= MTGo`U܋bllٻ*훃vֱh)FtՖvSZMUԏ7fZDpF29ZɌ/?>;tqvg{e^iT Tc0U@D+[6G$lqɁ||3hYSpD/'sqջf 4xLb b :^gfcVwzwYeKDZ}g^YnlaGTV:Y>(gP?g~ot'ڣy?xԩZRö)u5bZeRꪔCJV}a:[6={*jn2O68溧)U5nfVvuz\9?ek% DeՕdGi bqPɂ)231X~YxclW/V?2?φga$FRC(1zQ{ӟ+{ [qQx> YmȅA²``Y@ -uy Fr'?s}-.n/[EQ6m3*Yϒ aWW@sFA`
SaA Fi)/(X?*nZ?GwLv=.xNc|9#ᄭ?>\in}{4&¯٨r]i]a6~Egٵ4ў)s5hS~7|ﭠm>ժR:jr]5-馳(2Hӧۿ:KBԶ)I[@ `_N;riv]ܿ7*Nj:]6vMi0$b TŴ8cuY,]Ɩ%? Gv+b{| ]:&8x*5`ZP-96UdL!"\)wouat]]ܳ (U(=(~e$'ꪘʥX^2Ҍ xħ4\!~qܶ-Zu %v2mJglaǤS|7jnb{'qoHܢ Dh!Av|i |.8#EHy/"J^~Hv_-ZVd+xV.*uղ Hm*٬McULV8>Zٱ]ķPʛ^:1v{46}]]c}FaG^*Z%R!_puw6}-ӳ uJMx4iᆧ=\f1dU LIYIqϥ1y[3 sgz&Dh֜;UcfhM%߼?yQ+Hf6^VW%klX`iI3)=8d0>r6lwsDR >af`C wvdvmnʡixj▱Ҳ dʘ0yCzٌަl;fɤ+&YYKg@S;|v_MIEüFޮEi:9w߸)MbH8w˜էEeϞ>Ӵ&Ҷm;H]_YVԬeIc >q%)LZr`jfʑzl[\9ݳd*,Ė s?W"8|gl%ReEɅo2ƸX# 4q,q$Gzl3S8Ny,? S@QGNQK69,v֤uplL%1Y?XwOMJlj*6LJw93geo/iňI\C,lX'o:6vx]5u!M &E* <:0 >,9:Udpc1}s'Р8 _-fPs^=>*3{|8D-昈-"8]={ibrPNkeۮZ1[2%2pD5|Lxq)tT80"A"swqlrU͔)&|eO1uR S(-_8tpMDr0?htuhXha?NѾ1p:a@ܞ~p oGv?%;ܽ%^ `W&+f$6By鎗SS>7GEAV.P ^w~CVd_kJ8Fp1dIrqpsǩ:CUZ=HvFax84⠐ce{+{jbcR5 y,r'@,@@)ZDZgQ.+z>W-@#Y2 V[d4i ՟tL쳸l\ fZ%d#:ByO:E+}NIu4Zsz])<6[q#G|;U =vpFu$kU5n/h]^"ږ6:.^JJݪ-[zQbϱZoZ+hJO,vq\w"I]i{Ė:ުEhB(Gt zWRZV/hyʧݽ{yYƸֵ-߷7OX²]+d)ѩu{.- u7uO`kD)7ջJZeeB驩K*uURӭV~[&v;wx買%{nY?gЖďm}X GZYW{n[ muݳj譋vijMeTb:FtN].W_uB@ŦWbc$Q5G#oyUxROec$e513.kEl_z˧qҡC{Mo*VoVͰ!_ZSr6|=n?b=~ZzX5ݴ555.g]*: B-5R'[K v߿ipg{ruubo*ʹxeenS9=Tt.ju[~Ggkof˶}ooxV嗍h[UWұޣI]BJU6]]Tsq(0|DO3D{CL+U7p"G"ؗYgMƭ7^^;b_; ҺĨV·ijlBy# M˝'w%خ{E8MNڐNR 3g8Dj?nߖoށϹ5γ)Oh_ BuFsJRvmT-t[-S7iTW MΨ OZF; p⋬#tc{*]V3?X%pEN~|7X" V=@rg9Igb?e4>mRS%MޭK<}ry(ǩ R5a]vTt"7@ `4O>Nub~hSPQޡ(xC{`}iTb1!+sqN ̙H263>AY8Acg<2eoԞ?'{#Ff#JH}HP{g'bpiucˣ޴#N}>zjf.3ڐV큻Vs7uA/C26#~'3BNZv+v7n7YV65[gZϧu@њ?i7_-AD9I =6Dܫf][ޢjfųlOz:zQ{=M*W$%Q9J`g,#yO<}p5L~?(9.[~_tf++{:YK R܍#t6ܭWTPunY)T-ˬã^'QGjm-Tpć,z{gӿ wj]nѪiY;ϳm;:гz::{n˧{}$ҷV`&UyFCF%q$>1V[3+9dKYҵ!NDmF;eqg-oV#v7|U]ծes&ãF(ӥ5jF ۧ,%3B`9pv]n״mZ;J{>yzѱ]kTX}MJn:5즯e+X0szX~4(B̈ c>f0Wg+LJH;i%^*-:"l6"HcIDI]wK:yn63 103S~N0ڃݤ\=ŶV$KubR<ĦXyÐتNXm}3.3gǿ8BnURj.r/M௅N|Lg:㭰;"Jx,`8-*P[BF>˜X9tysYdE:NZ`Uq*&`gSOiӆ&YyNGӇ;8c|~ul܍xÓU &@fM0rX;YC-c >Y|ќuzh$6$X6r4NyXȵ'뱝Ly 184RfQKIA }@}8wp {eR\)iG#J@9fU#z = mR%0m4Ň3s33_&>_>MW`Y֝ b˴(':\YؐX1 &I}<6 b}l MAP ݑjBA(+aα$w߮WOjk ;*Fe6lѦ˵5yQklUi(F/Moպ5Wթ 6~lpP}@vjէVi؋AӛFhܻBҤ%.˻}0W!R+і?iko{{ɥWbKf[dV2ʚlpSLa˫Ev~x8vwkrimiEΘ$x#Gqj6Đ˖ن?h-nrWfMS{),%+[Dys ??/MiA*$$2dYaݎ9"?g YJ D"2A94mCVH%eGa?T>㌩o!ʹ"$㎱&S\~{Y!^}8|{cȦ)Ģ E>CZ3:?a_>kiddZq"$Y9'Äw6Qj!%+"U#&2&N y0ٷ.Sޤ6VQv-Ҟy01V{DE-v)[H{xhʼnNxӣSt 1vțuzvnjI5Ըu59f%L5\MrI6>)_*Ek@#we%%J; ?FrxeqЮ8bMtU?/*KKNؤ\ (kj^a5TvFW֤k+(iyYYY1kkJ9)S ̮vb-Cl7s׆ōB`Lsd a`g_UO;4.a0pcŞ4 CM-N%RT+3l, Lˣπ-ڭ.Y9BeI1^ʔr$ 6*X{*SҥOXr>σ#8m2NH2Fr"qHsҕ8\*4Rd"ޯoKxy21pB h9}/_flsJ SQN_0Lcڦ\;Ouo-zYhZU^gMLe}zȚzϼ5m t[ڜsbYmfЩuU ZꚪJ@RWgw%jk7y}Jƿ*716}YRjR4}rյD.f<$ Fϙ)st6TVfn ^ ̧ɞq+,HLs2$8w6$1Æ|0~{s Orl;.*w7^ߺ~}tKc)y,dөf+KvwW텿]MVUivUF|+,GşSOGYL VͶɨjWRp9 ĢE8ڷNPI'ѧ{LF\GGc_^\e*\Ẑ& @Iuuq̴ܺȼ-m]M^tuUe5J9JL[y?b1QEpC!qeJs6xmӸÑ4lR44^56ycaލĉb::=)_jT'qzNwmvl~UJBԶa;fSZʨӉj腦gJf k)WEP&)M3`4lȯ^L{ V5U]5soE;)4ְS[Vut:kJĩZ}]Nk5]OvzoB͡B7w¾tASAi1߆ڍvǣ6nhl94߼R:*j ⋖*9)Q8gGxx4y\Ȉȉ fC' v$DS8D|FvܚiRvs$zpňO%m؎wWBymOjSٻT j9k:*ղ蚚D%ѷ;܍z³j ԵIGM4i# ԩiNs6r7gX7kϺr.}wmz[փk70j:}QJ[Cv7~޸x $G>lrG-yX^Mr*k%lS^vtAsr~@_oJg1۝-vŻa^}]wnm֩kRRY (驚+&;Z 36ڵwy 8!m==Nk}խҩ:v*TVr3}}?0LmwT]gP/xm]@Ӆt1hFS[HEѳ7òyΚϩ[Yi93i aA,ĎG/Y%5 Pn4VwKSfvz>*`]P&{=mrԨ(4:k-jIȷo^U}7%Mr-Es*OQsj=e|J&|](7ֿyZ4]x-:kSQg!hԛ\jpe&}t ǴnMM}`^R:ݱ5y," l*$UF7;6$9>uG-h5rT[%;xX4& @^; FwBЌne J3A~=|w۵h(\P[1:.ʞzkJUҡ:"ggܜ8wWbwkgUUXL`1_X=O5uC )q+:g_JVQH ]6 J˳I`&%y{GWK69h &.bj 3Wfu}NZ,Ibh[{Vp^ UԵ/`|Jg>_vRY?P,0 5ȑߧXU]MiD[)+wyo=ݘ+\vު[xֱlx+rkZTj;Iv5Mce[wseIvkt˷{6-ԵI,.o:\ghZUڭ.8iUMnRVlTTI L9kI¿f~o8;˽*BɣvIGČg';mv"Mq1ҢbV!yD0sDÔ10V`tB^SSq;Bn_}]g*U-p:nu5Yh:}MpBwumJ1"P+-M[ÊҨ0^VZ+٥`B#J&Rb:k %J!c Ü;VC7wvb>),뇍I aq&e3$q)L1dZ^h2P,y$|=3D[bJb0 Ác95'w 4u8^b-MԈ"Ϝgs&(NNI+QrdÝ?k>/3ņ-##b#$(VNk . HMd!sW3&ڼcR`? m%@s!83>ǶʶhbNζh1ҳǸ/&ÏvKxJMz)&ysx p1c GDWSŽYdyWgVrv>tFgwWnmWKFڈDC=zXSXˎJ˩nַ-;QlSQNcBeoti4Ǥ=K }ЩsNؓ8Q94sO?,=-sUOڻx^=(snδoFM5=ZK6+Vټ*bRl*a'Ṇ8X8gfi+<8h$xoW_Kôm{Խl.ḻWN;aud^ [jYMe /(꽏VzRz--koU-k`^jPR:x*Sj&aGnSonu -5c)7Q)ʱ 4VXi~[g*L7>FXM/09nSavq||<6;p&n.ҹW,'XhN"՟_M+rJ]؁ hk" $ YӸJe%)C?}]kZ:5EILL^rLȰcd ==+v>V12K>$p9pI@,X,\f*f8dE(3gU籵.l;ȻdTٻwLuXf ϻ@5XPjqV챵;SZX͡Z:ɼQ`eӵ*YUP7G}7gd(Q55B$*SAuf ?8Լpn:n7X`.ͪ6`y 4ćmuSFB%/7rqeWөGHk7\s*GB_ކ+kޥiZ6}UQShV٭P2>Humc5<]+tu6Ek4/GSaׅRԲ bҲȦrh^\⍤].7RKm]&bR̠AÒ?f9SuC!wdj`2/ Vхoc4! ea3&3O#{Taa<3k]EMͪPl6y+[,L.uMu5B54 rD^g50c"̦i6@ᅓL>?oTXPYc<лs2 -$Vfh|GJQPkzzgjQm\FdIqQ-=ouUY ^ RP&ː c +ˏۗ%e}9,g$*M2s )MKQAI2s~:~{w!>3#ltKZdGbט4E#SU3׮ƩEom=-R鷙Yi(mJjɎZZ a鍊Km0/C Ub!QRR5@ɢ Ɯ k[4@A-X[ Ri},XTɩZ]0%5'?W{vb`LhO8kPޑRBjM$Q;s&"`x|8}r+zR ΛQ)%QG SXڥpٴuU7u]yt5ץ,uץ=eI0U~vx[}~wa*["6Ml=au#+UuOOtgj1Xh$Ut$*GݳdxbwTbXڲ:;"# l32R6Vf+uzhVvwɩ =ugéMBFT./tumn[fۻe鲬gm}k&Nw[>egvf.ivnCڋ뽾XKvk/} {i OcS[*jR䳢!6j !kRbjNOSOgGY'Rx? 㣫>UxiqS+NQt[6 ]\`EKfMcxuz_՗J@5"kQID+,~3jlmtQ<:Oܴi嵦2rsh9~̡P&DcL$RH@?ʾoe֢[m;PBfv_F=PQͺvIHJ%q h wk^߫.ν+܀~SNZmOƞ5s|ۺs UۛQ}o ۯh[5?s%騝z]?VZuM_x6mes~:{A'LU7wN&k*U cE4LU8|HӣZc1+ Y}WMOmpKO4Lf))G)Q23`NL;?2;Wo;}7:Q .rlօe#j)UU=qcڝSTC$8qԮJq8Txy~_z ˗qEDNn':A1& y\@p#$0G#_ Y qQkJ+f! <}]wc{jBRTW-n/$O7 Pq8& L2Q=>g?ix7PDL@K TVS$2]G P!38L)^EaG˾^ފz>>S礒K6꡴nxk bqџ,egx×Uqmх}SRs5s/18yۅFǕ cN<2ڭGGTa=(ӌ-*, yO܏a.Ibցl4whLUg܊?AMjX6!EcY6Vs)8 izcڗr{ޕ򣠢E݇թMMcݛ6EulDԚ)T3ѵun5NXKj]װOx,kFsJsK*(ާ|}pcvfAnRw&ӱ/nm{&ج-Zeϯzڼh#,xB^3a괽 >rru7˺KDfsCƞ;m̴;ow޹u;ֱwe})lavۼoxLSX>ұ/$Y~T6Uɖ)-nνb Wx41#/b9yq?Ffio z񻋙Mw.-&/9]$(ܻw]:`ۖʩhVma"~x# ·Qg*x3 kq/(P-4ϑn`N 8qo~ =@Î_:x`1iYgv{]/?nTcreɆ?{Q6n Z*w @`SݻTkrNz?yu?#,3 Ybgҝ @bW}~E2$2:mBkX2SdG70/=>Yf;=)"Vj\48Ns9~,mY5"# MYr8wav~juH\3=u;#,N2kBT/oWkU0wz`:9p]WҺv#`0++rpK8 nUM8xZsf>X!- u-Iڧ,|b2|`œϪpuwynWigϲmx-]:ƕ?v k ʊ15^N@/Gw7t7.ؗڶ7`vY>hT0=i&=ju.WHޘFl4R$d4@=S^A*f 9 N*=n9CjzfDʞF+RG hwCu 90_(0qj,%n[iQ6l,dw0́2uǤvlBjHd/0iΜ#d8^üd2@" 㼳9X$d|ny/,=6#Ч`ÆɄ?3 an>v9T˒k UGn.F٠U:1L 짃cɯ nuaQ8ۥ;{>ݪsaSB&`SH{3swv3BeLDPFhv#kgUHĮKY[&:FFNJ <2gau08r+ƽA%CMN[40"!L=erҰ5HMn_COes?tM)d 9CFu4b93ɳ#2g9^*eQiּ@Nq#vBf0;KJPg rOk" _F_~z]?/`ȢyH$#rqO_jR KhYT֓^}1q,aQ,ᤦiUrpĤ:qdsS|}Mw})GiR͡JfdgF:c# fW:r8ס Z[7×Jlpϥ *!kx &`̚''iaJ_zrZL9ҰVf  ,ULcYt47b:Ɛq*,dt٧KF-[Jy<ŭr}?7OK{ݸ%ᮈXC=qH=]51rLz5R@ɴ3ebM]**lʕURHTĖ8!yb櫻ӀZv8Ʀ5Ge^֐ϐg"R ZU4ZF|05ig{-WW{v/WeT6)EGjP7䦙\+$؎ʻwBߚ;Uvy/ ]1gloR=5~>"ѿiڂ}}(j[y-`Ns3J?Ry%yyk)" qNX3l| JcG$%R[ºD!I@kT|reKgԺөmC(h**QEH5iљ(̍J 풗mKjuz":jV)7TE40'L6U}ȉnaU]ߐ3T>ޭ ޥaU@d-G'9LsCQ`18i! ]slS52g@tCsO?>8FNׁWTQ䠄K9Rk>*;SܨN,M4,ee[4fe? ‹ Íw,r.F".ݣ,w\ 2()ҙ] dRd"a̸0FkN\˛Y~wէ(lY[b.ʧm l.ˬiU{^,n/\O"DpW!O&kh&,6M\:RhU!ThA &'l-UϬcfc0c-HѦ,A/pEkcSч,Dv+k$'w'_{wYgTYb*JӜ?ɧN1}gI LNx؞h{~ے}}=MAd6o&P(KaoJ֕SS[ym/YiU#k?nx wTf\^zm9ͧ‚<|&ZXh3 ct\/I~zH3?u %;\Ub.m쩢8zvb)xՔv8v樘g6̲,J:>͡]=- 0RQ%<4!kR*ڤ(>ʅNܭ٭1v+5o%`laa5y>VjȮ7oTcu:}*f05t%'hllø2pk!5[ΛƌןJemחk\Le刌3{qs]\\r_fðz"sYP eAs56sʖi.K y_nVuuL[^-@KiaaԫWqڧw}{z1'Me1Ga1zƠk*(g6 4FH9wzcuɝ+;a% #<ӆJ_KSأ=oxъiе)9OJhсg 9T|]nv-͕hWY4;>[īRh\zjR/ͪ%%2Q>'kXT~*(eyZt-$.z5&D&‮6Ү#Σ_Nץzmg7#&nnE7ϲht% R¼4Z*]!R6QԬ mS͝!$'cEÄ ލݍE߹bh5β"IoYJXiT,`^Z~JQ\}Q2~;64v Kkzڻ\Pq gb9B0؇H5,˖2Zs:|H: _*t^Uۨ s0P3?w r9`3摙~L{;PE4/Wǯڴv!?[M_[!nI-,@,8[nN&8lRIBQ :GT7M}wF-K0de2Y}=?ЌN3F 7 HfFJ'7v|x|,xwm@Wų֗=HIBm+|%fDF |h|E-p9;cihLީ͞Gvivzv%z/}hQʻkRua5[)YR&0fX 3caÓԏݷi5ʹmjJЫdѨ:ʧK\luCg v,'urÜOL>T1XBdȷ#XUIb皀VS4V^b}=};FvT ]QMKw-T`ndͼPGĩM-O6]pV]wfދl+FlUY,Z-Tue6Rv5c+$I!,0"γɟ?bӔ# ig)Ӓ83wkk{[ ,f I]3YV=Dkm"϶yI]ԹpDʊ[y,3 Qp[pO YT#twR8'J{S`m-'-9eFy DLcm@x#><nlm{' ]S @.}oZNI ѓ->745ʤ rl[6r-*0#5fYl ם>{-ޞ7m{h^^"Pӵ Xku[)`sFy2{o&٨P:lTTI ZU mc0㥣V n޻vږYiѫO"d] Csa|m]{&?#LJ_|5Ū_ c+I{S"8ya,M>i(#az2:Eu[E>5bFl3_pU®# , ac|4C-y5PǶc^OsSt޻*l YxLDIe [}m(E0<G-oY&zrALWAiZXR0~#3hg*V5#^5gTj]&ē Ɂ×^p,ֹOsVB* Th<OPJe]W I1ICg_mMab% ^ჍF_ګ 4Hs8N;/MϢ5"=y&JgB. ̂(c1<{d DGGp)!?15'+sUe pT ZO!aV@0wl\ᓉ$ @&|1RXifþ3ᏹ?]9MleXM9gDx_+;ZC @dMy$L~{BM`G֤WZ엪hH QE !y>@N`5v}%zjl"Q^)]P-fNN8uPHG:d$Z1<},&vťQb+)eSO>cfAI~!_9UFO7l9[B$+N'ZtnSTnfwܼQJtmj, dZsON G3ϳ j[ e6,W~vg^#c;|np_{ ̗[F ff^2%Z:ڻQUۯ(ʝMBX!LI٭.|)7cjsAqY4Of98탪`"H Y+O0f4ҼZ$ ^SW^. 7@i?c5R'B*"Mq Y6%{)*HDC)aCW~`EP9ese'H'`#.1 9rfyg鰑|4Ob&W$J=jQc]$"[|C"ʕ#֓d' Иȶ2>ri)}'m@bG$.>O~᥉ULIɴp8tYbbt|l)"]K1rxIc_T4IH,+fQy ={':RF+g>>_cM&FZ2 rbE|L;{,J\8b1Oxߌp'P`cTD g>u ?Q~ }AQg¥r9ޔȊl$j$`rd*d#,L̄$8s 2OɞWS b"fH3k"-8 vdFpL_8/3y#Gx"|OLBYÈ]aʟޗ#Ee??`Umq 0\0DR%9xwAe%VE'~}nq'8Cg?Î4c,rgÚ7y|5!56CC7εL9#HffK/^qsm0JRG/N@p>=m; 2`K&cI?x;}2)"#0.~R3% x(_jmvP!hOHEP*z6R1gYc$2sb3G 1!LRfxdL dyr9=)\KXg 9gG?ty&~`D25FG(Ky-)́>|1rq&I tat JDM!%揗 ɜzp }~?|p㱰1ES8%Рd(m*Cev]k(,Yg:Q0,s\~[k̜%':cMNo vTb "[|^:a=^-L,b\A""S!iXKG91e:/Tl\MVB5Na$DTQ,Ɩcgi3Pk+ʱ? E9YL@tK(FLj2 yQl[9}6*KM]ha`kur` ,%rx}@tM$@<4p*Vn.T,G 9E?lmOQ8×92 g|tv5R$Q d!`C;JreL!朾g3O`S18Fx?~0 cF^#$qW+-?x9ePX0zT}ur1 BC8 Odd<|/8:đpd%dhcK7Sۍ3sgm3(,LKMZFXS2:A`㫋'P?j$#%gi%}Èǻ6IYd!EHQX WwS<xA)k$ Fy}NמUKQ,sM:r /_v6ҩe]2#b@Hsga.-뾕CdH$qV}c*[( J)5Nl`MI4T&~ \}6dNe%sA3[4Ǔ>xŌ])5$,D>09$rbgX ;Q}GoG*J|~y(h*QF2&>!!,$<OEj)6T#92adaS?S V5" WS Oӻgg: |ZxV?OP-dџqZL5c& bru%]u.c=A.#KN^'=6.ƛYZ+TJNsPh$jU10҄Sg&nb`0 _j*l*(E ,8NJ _^@ûjGcZ)QRp(id(| ~mby>x-.Q޷:(QGe$?!q^\Z"xI: tK} `8x?3WI)̉!a45vM9,# \{?~GNS#0& Π05O F_SOۜ$mUJXWhφO%*z EK,xx>{#&))3 yӐ'!tݲe hL\|<\} 8XB aO|9|c#٩ѺEJ˘*P yOT)(CQO Q Nv z(eSw}/e۵j^ΚVVk0;_.T`Q&S+riXy9%|.jneURR L~߆{>wZWbQ?[R||~K*l?Ķ3Ozy oSnr*˪y ͪ*y6)>M=V`̘¼wù3r*/Z6ue0:H} 5S~ =MnGcKûU;B dLȷu)8a[~eGyCTdZUԚ+H{`\wjqgGJtkx=Xx_ FUJ+ ?]4 (%0:T_=VhkDOY/6L~Cg?F9\0 EIg+kx/g+}ѸQRiEH:cTF L"1#|q9"e ;fF'ÒR"qm1-P?]kΙJB&!_1OOp0 b!&{ƞg}6 $J|aqm"!HׇRgmNA /;&CPO0sgݚO}pq?Þ$82qcMzY3k^Leʃ N]NؾGafuKYrΘbaӇ3ra? 2B>q-T< bsI͐Sd< %M&X|S0=(ۨI o^5e]S/#OL!d xFQ0^N] E "s"_/`i2hCwyaJB1d1S&}?xj h+b#I+ 2YfzmB!Fgdt"sW$bז '#.>Xq`LȞ@O>Lx:] NDc E\C=ǓSlۧ%009!S=8O"#F~[h>Zt)IҹrNłHNu54q{>b PIG`5cpsʮ"V5R@Le}ʇmLӬX0S<~+5)8p3)wc붒rL]31%T#e9#?ᆝPE8 1ZccarΦOjdFWAaLO=0a s?9'` 0 D@NQ/7? 4fBsNp)'×"q?=#׌>$iUyP_:^#[r:V_z팛 bP>\>\<>[|T612k &~IeM6Rq?=C .'3.՘WP=x| XG“2b$#:r/ַ [pq*ڗ[ye{r; jfY#21ɐ96$ ",yg3=}~YNfW #-[**Uk.%sB&2#Yq91v,A"RG;NM TNX@/\{vY1+d}t<\ %wF99eg og:Sl3Ckx;,#86^9XQ1326L?_SB,f' Y?M!3N^M ugB.i1g{n\DFRX Bc3i?Ō~!@ I2 aOtzWQ2"8JJH",u3A\dGD}ͦ=>{ۘa W2QƏ5z<V=?>m( @( L?'~£,YB$dܙG.@<:o$t`r _>~lNm861 3ϫ3?)Yő>Qmy&GN[u[dp\3 29?{?qP@Ȍ -\Aw)8I_ec <{J~}o(ҕ ,*ϲ!$|gwl/H&Ň q2M}r؄B,?{yk"پ*ˤc("PPy2}gnU*}ܻ"R)`ʳ{U]Cs df}/0v{ۓa4j _Rד'UC# v0 ~G leZiċε{3ڬMKLq 豆s+3W[@A#@.ǒI}^B^XUFmrIe ?dyfF:Dbad?4?]JΨS)Sf#QI@q9>8ᶦYeC $K0oCuhh! E3`-Oyٔ]f9+^ w?W /w}6`Tk9d>V2=Ep,3wlsOT@|X !WdȘZ0xt5?ŭօ(ad_3'çvH>.%Ì%$~a/d-1Z4~y>vС(եr,X0e$8||-累bjgۗYIk5FtvO:Vq٭*R,"^B[RkM᣺jm n =7*,"A"G!`'ժtU8DH$a0"X'{9 2a1b9 KL9ǻk.;~1bږq;*fۡ$=@kǫN`%'vL[l: xDͮmB*Ll3 nTaՉia? 34$Unj;& FV(.@ ^Fڽ  (2˜eמ?,Od&`HN %gyҲ죽K96%}'gdJ䉀7%v=6 f] Bm{nل#9ͩdRجW ΦVY#['N+/5ܥ*}6-7W,R:4\fP_>lc'1"1|8d` a -4H3⿋?2x,, D'!,9&;a4a h \$I$xüso OzlTaxjCF/ {ֿJ '@ z| >?Î;}_D\)=xmN(iq"fh,|u ~ٚrg0D1c Dg &?t̄f`HDs嶩Q)Y̔ &8gq5D FG?qf^aȑAg,[/Nz,ed*^*9eo01 38`SҍȚ*1#fc1 H8ԃ\/FO1;1ʤCoN3`4 Q=x^"sof H 9(k𘝱EYNp,>x>NN:?- $' DسG%!S$c;O]2RD"0×(&L;r"K蒦ODˇ |=fb91Q;m^02$0fG#L;߄X#Đ qFag'6 dH-Bsg Cdߧڢ1̄ Jd'p9f8"ce hӧ;g[Q]!ggiT_} D&0r͐3௅߆{ (=L5Oǟ~&V rş<{$8}jMjhcQa fD)0,5ԩ>uKd@9Y`e﷘81\ G±,ypj;i+L e|1ϧç>w~e(}P`K))!ϑ!p_rug׎敷 Һ=`/7X@^c&3zn65K_r"x5ᶞݳ-;zk\WpgE-4ׇy֒Jb`C\awfy3I~R֛sՍr{ť|j*t]p9LY3 irvYČ. ĐϓSFIm'*k @yae/-E4` )烈f 30ÇIډKh1-<g > *c@fvN buї 8O#9:`a?gLv,x!4r,Hd p|<˂FkK(2YW­u68t41Y~ ;*9˲m( aNP8T9<1,&D g`|SSI6HT8E*JpȾL?ci`>,#2G<k2d㐯Q}T͟ӣM(ɣxfã:{}vZ* '*DqF$L|=2Da0yjU `2eLYy@ÈIYri&l)JKh(aAɻYxw?v;24kcՍy^n]KAu]Fd1Μ>uʬm£s5b=xvv֨-[sY͞ŏw8L?O{TWj\ׯj *P/@`s31w,K ,8m(` IFى0 ˜ 8z?z zZsi1YH2L'1=-Org]jU0ȴ*a/sRL{HCŔz?.v"ګOJ[jdSA< TVH0&rmNd4p/>.Fd"Q@q4y&to a?>+gZ$zcoJ^uP9 p(zyCG{> de1 !(2@~kXӽZG,ބELS>xld 94.GN3g2@^^Pif /3L :A)+]NvSta4gcuxtOֵ6T6ådhL< ~Um"۩(#,HN21LS+^# f,y?mf0 4afv8dfxՏSHıs48cq%;1A^{ ,%8G湌>qóݑ* j yp2uDώc"E~m0};!K˟$r0';kѨZV08V>OL=?p,a+M|}v+inNsN|bI ґj$ '3>3?-VnK-2Ӧh0UI"(a#5&YB1 6s+\d-0T"\.%_I¬Fኄ9S,ǦxXVBاp7UE{0iwLhU}>[^53t#ѶfbH!i:Z>kk}0W&et"#"6.ayK$spxu>WtDkH}I3 7RV1~t=CjH۫ XK"8|.|f#-PRs挋1ia1G{_s{V՝zԵ> ԵBXi'r2Nz/۬FѲUFI,Xg uL=' X :*jˢRiKC2gIS:Q|vz":ƿ$y ]*Jgϭ6M50oi#B+Ḁs|'nJ}].Դ0v&wI9ǿk+B-;V*eN5db,Y-mnKn\ڡYYti&cDxz3t7Ѯv ~PT!VݤCG0 )ߋil?mtB'=yl\݄Y)G֟7=坫.eੑh nUEEC}!ՇFTiFOK[dW_{6i2XUU6}_fs1}BM:CWN]._/7_y,+6Զ,(i$h2G:k6aj)뫴sd\6 >$U~^LJ`dō+19HO܈zګ{Vo.w[K}Љv?e ]བlD՘DBys?Thj:nqUYpj@OfS-ɯs2yʦQȺ߲K|Ia"˷J"ƹx G"jMUR6ٕjQ5EPqLdXp?X=ݎbYH83Ɖbx5ޫvhVpR70OOQeECUd~-&))*NѝeLN mHx;c!S^ԺDa{O7OS-'+fa \iVBp3d142agS3l.yP9}LL PzhL[pѣ<#MDdM;z\.6.g7@;]n}Wopג!lܚ%rc ([~7ŝT^/)Sbj`#GxFe+:i5tōV 4ˑ{Yf\=@tp^WbCכKπɗݵPD@~rraoSIo DfL!㞲G1UE| ]%)lT7ޙS3:Wnn*Ҥj(kպH+Js&a`ST+{U%$&>ONvȚ]:/ZKohy^ˬ3f#$Xק7GCzWgm vRHkF:YK&xvx?O\KvMZSjI{Yc6*`{1% .ʬ=P|j|Of,7y{[11bqLHF :iluD"N\rVQ}!nt1ZaqRfB=޻4+\# N M*gHĜg_ufq]SCCKDXAD9yåy}-J.ǽk0^2v5ad)5_7e~[Kc:3JT~Iy:᫩!t,>L_,(U}^R1 >.f|㩑rx;uM#}H0Wp),}ؿf'hVqVbF15u`Lzuu[g"'ԻbL\RT4ihW#:ll<6 8i'YD|ZcRFΦpUGZIuWT伹YTZzz6elYsFc.Ւ,zNׇv~[8]{/RSxdzR+a'9 z&O[۩^n>HT[1x햬mf[v:u@4 "AdW8G# #RͷU۱iLH @Zx}=V]L6q8Iȿs&L5]lA%0<˻ i7621 )#J#_ϫOCun$;הuӥqee^a&|v/xdxqWdO$~+JÀH`GCW V?;];w(+h9D+z1eRR,t͕_>cXz,(&q̨?! ;H\(A8pLa&O}pc y‡Wps 5&|\P8vұ6Wv*9!|㰙-R5""WSL$T`L93+>p?O߸$0\.X$ٹ20>whih?1y{oŒ=MC}6!#dJX#7= 05z`y8FcFͤL5`6(T[Ly.0W͗2'刐pS'[f-mb $k3kX04; p//}W㱋FA+0@~ UWU0#%>6~N;KFZVXA<8ww)+D;2ϩ FSQbLdw/&wV(a:RkFu A`w~G+GSKJ='ߺ>ٜ&ZiZN.}s˖}=v#vHC@Ǚɏ:sWpGY% *vt2l6S@Vf6U4[ K5:gf~^69Kѧ0"N$H`}YS / ;4q+/[|O bPyz{T؜h)2;U JnLٹp0~^^WKGTъ6D`fyqZ?)(C b 4?2aU'b:0!fp^qx}=5,K)Tœ/vܑU_B,g #rJyqq[e뷶p7)GO\)ǭղ{i`1}<9zڼSJ\DIg7ǿ/|e5DL F'"dLz>[{omet~3Nl1(d_deC5 ">O omÛ[cRJ#212lMa4S$#ǁ|巶o-ԬtV|> z3 @-Ԥ+^,8Xw~᷶ɋdž?gا Vs`S&3#s}FF&ND3L sLg'No5E2~?-]^L{P7PE! /OM1d>)?~?oe!x˃# 8Z(a X>X,c,aq~*.hzL3 \omTit I@)`Q˗*ڄ $%=ݿvohlIvˏz1:񔥜`ylqd@rQ,!J\^{olQ6ݲPzQ#"9ehAF)N[5]!h11a+(K"#mv94P2HJC7:~SSJc9v"/Aɺ[qg'4€%9MUD1,$'?z Xz1gM1C>%rFSBf]%# (njGPŝ1Y78F$G(com3 ^LCr$y"8pNqWaɭv. Py^msg9bBYR?L1р9#d0s&iȾc^*ʩs'2*Cȷb}>NnLv44g>e#r&w[|~{om; ʯo.((WȿveTMVd+dFYfB1<緪ZVuUAD`cS3޸q# ~x|xȿcl/X83:ek&0XaߛiISKt۱rb|x{e[q<Ŗ{ -/xUQ i)Db(1)Ɯ(M[+S(j2Ԍ cwcB\tMx= (&'H~_/* s0BK9\~{ol8bk=@8C!Nu6"e}[q@l g 83׌=(BJ*&X҉984lpom~&\}{/ٯd&Jnd 2XQ}8l6 cHpg@tAomMgv,u=Hc$fN3Ȏ3"y E" `^0aMw*-NJ#; 2O6:jA3PBRҌ;?l ÕRFFN$gJpO|'=xG~f&AI'RPN;0k2і.`FLxsLϯy 5$g5vwW!קH) [{ol<$gevV01."TI-83+Ebe"PUgvgTvTxU=vDRy fl$j%g%h!fm$ d4l46=4H4%AgjmAiBfA>gJ@f%wdluws?Gs'co>E'dk>G%d9m 9 9 ?9F5'@eln?m>l>>oE@uJFIFCreated with GIMPCC"  a!1"AQa 2q#B $3Rbr%&CS45't67TUcsu(DFVgvwG!1AQa"q2#BR$3brC4S%s5Dc ?spq~{qs8'9c*o$I C8 I@K s>y}>]PcJy>9};~FgWjP/MzW\%[wO^d͈Ih eّ֖Zahu% mO)$׬TEWl=_r+L\P!̌ ,,!D!Q|!VIa$r=~F3o˟}S#䟯? 7+|)@i!Mr >gq}#މM*/WݕbOb/%*)>0[LoFaRwrқ?oyO'Ãs矧U#}{oD_i]]nKӺ%J@4 $L?HPW<~ϵr^aP"5J+|-)rfA H{k&Nj%zn֯خ= TRRA(A^c m (lKPV~JP{ĝD^ҩvA49PX@jj]sž6YfCTGyY '>38* @-.ξTÕIIRT64XTDFJ%)?8]f\6-괨q:Cx^b//7UkTRoF\SJVrxǤp=F+Z8+U)X*5Ƿg Qr2~Ƥ!Eu8y17Zr64+QmqjHW]pG|i4E+EO.[`ˆ0܅(^]k/ԫoDͭUW$`}qڨP[tqjly堑J#{U/<,cJL< "z+?5S*#GR+Ns&3R yHOh_C5ߧR䗒(}1Da g }XriahS2NR˪Py?,d=V0SEĕJ)\]P>xp7D>MӡThbn1PZ4zRtT I-w0\}ן W bQu7Fx'*;sE**OB(wH^Q~1SHcAf$Q l"=*KbqImc'ԅ9YIR{F;ceCF c}J*#O8FO81Z̢UPmj JO=cMu[-P%s<?>S8`ńS<VTtFzRվi1h֧e>t=* yK#?HB)4W#йն{6%H1wL/]qٍaD:zT;9g[զBJUBXXퟐʒ3HV!%=+S]7bk[t\uUwx<9Iiu+͉,!xK$HIH =}/̡X:gAp:A^<…k2 KsPIBK㬮`JTm#s3EgaC}޴gvŴPtB¥%r\Z|>'GGVrNP*/9@?^=@?y{N ?mS[z)$PZ8{֪+ X'8w I }5fAKX 4ShiQ=||bDwuB^-ێTQIBTn7! XL )(#rr~}lEn-v9i1$2.b8#@#Wv,n=%7yȭv D)>N16tgl(^cja!k0W&1}]eI/閞JQ"\@ˈRN;y玷66iUBYbR)RqQP%*G\O\ }.Q&A.H!7 J4Y:~ٮ8R,/&:8z@H gYJve3u ΏW%ƈH`Idž/\u6%#RJ͉gԥNI;v-;EOк{RA\Z79qؒs(E ̥aUrFf^l EA 8-iJ[)I$DTb)( JOZHG@qqGrXqGJW+A_R %E:HO`V $Ii?) ᫪R)8>rA17eiE"cag s~^XM˪RwG*Q$*gI9?.96kCަVXӻp^jHe!Cp`w<㡆A岷Nl$kw 9R'x lJzOR f٬gY{|&f4t62Gy>jdpZ@'sF!+NmHfNGS{9NWT "왶3,[6T3=yצD6%E6BTG|nl誺5w=vqU~Y+K8 ̫1u 1}7aĞ.-;EU~" 58#?OG|tv[5H$+{Q!gdq=PDMm.c+<J'?>B1g{y( 珻:8$=~'3xd7"2zW/Aʣ$6.O\zg'ڢR)ۤKm;|,#s؏J .+-iZP+ w-d2; f8.Emhs#Ӕx:JGWSj%֚ʒ@M$(s'sKJ(#pEE"EP<{yui_Hq}l. F=)%iH=xG呎#b?CjPm[5)N0Q8.2[gڏ~e3m8bUk풙Z_!E%I$9P0%b\ T@C,v#  I)H `rr@?^@8A_.:?]t;5kMۙKejP&/>ښNVQ# ~99*f^auJ%o*:wn~DJʨS$MFU޼ج <%+#{C hqK*:m@)8r3ڽZRJIiUZnӑ1wXc ~5zc.)VڣZ-U@j8H%<|@<2D'EBZݬ qZջ 8J jcKFbxdCjEGZOiiKjfIJq8- I ;6aAj>AH bMP琥S!O R;NYNSu,rnƼRRPؐi<@ M]*Fim ӡ6**da3~L[J} 7r 0s{t#Wġ5۽N9r_3T " JXSk c)9ҟnq jTqCQ0f5+fQ\2;?޻|UFQt:lj2@j;vDaKP)%Ԩ(0@ T*C|e98FWI8;cg-)Sq+NM?Mn/'p촽Qa%+sw ai{͠!'LT)#PdyAN2LCTE [@5c}vC8\=A B[IۨvfoV*EhHnLQN2{a7ޞњB?VЀTYqsE$p8G?10XZ[P жсeV*E jꤧԔ62Xr,)RQ$vbS*L-U ~)B U 1Jv4;q6d X;NhV~y瞛G򡺿7o)s)>PA$<7&E?Yh)ܦ[ $%^Sc͠F@>+YtIsKo3ϕ^RSi$('' W$rlW}ROgfQ~[bhٴJTK 4. PlAi\C[BޮS'0ʂ~XJ $c<֌li N䔔s@e'~]M?V^KkZLSڂB8$4vbA܋' 9sqG%[)]RŻiBH3r;YdB aBukng'L(n j .[yb>ˊS P_6y?tҹ{[%ŸRpNppH=t|4^CGH~c'hB(۞xq ^YlxwHW$cHʋ ,rҫ;t:vj7өԹ9^T5] K% 8ӎH= )*pT9PojI|7±m!^mZ*H;TqE#n[fNQ?R䲀1m'߮ҫˮ;@*\b=b ݍ@}҇$y_ۋZ |d%G':0'G#!qݓ7e.$ ڥc'>ߩW DÝγ]%Ó ' ‡ZH-LjpIE?$*RÅ n5`wvU˒lNwRi rލ|A=i9iU:|ReNcjFF BZ<ϰVM.)z1 ;BPqB9K](8֋Y ' & 䟦:_\q빥4,6CTgPSs 9P"ÚTuE PN"< Ķgj~IZ )~ 8n20FNg{Nj# QQE- Q{I? [i4/THh{Lex*L-H;Wzcz)$z*8{e,$ N}<= sDTH20 HH1;yM$Zw#HЅr!.[Td$8~#n;*nJJWNiS y1u!<8#Dk9ϡR?VRU'$w\,u1LI% "jJHՅ( ($8]̖JR_ŧP, `:bPV Uňq]E~cЪFTTniɆ9 U@QԱ2Pt0Vs 8 NvG{bʛ 8X43?eO*-Z;<~Ok;\,JV .JqR*J1|JA#ع2BAr5 yѿǼ3sЖҔ+-ぴ0ptRxNHuE5IL' =Fƿ5!>Թ*EyJRTwa/ $<` ;—4uHb^ P Kvz9?t@yuRފr|BH ]n 8{wҭW:NՄ4e!U-RpaYYOeZ۫lmo!TT6@RXցr~(40*pBBxثܼpA(R"ץi&3E@ V؎zސw)%*m ޑ<FGID9ctυR+tCI$%BF=3!ИaÒz3o'zV_ip54k}b;4ډ .$$-CHĉP\6”3qI)X@Mǭ7;sTPUEj#$q$mj VN[6$q\ j)di,kA3FDF$K>[ .;,5 8jřO)(EkpWv0JFOz)QuA0RIICص:a ``85b=$3}Vo<ӑ I3YmA_TCin `P%![ JK?wki +~ywZLQah8K:Rz Ưc)Tt$ |,xsCm hG]$c%DPJX)?y5p͡EHziVS&6@ݩV/zMwL*y<ѵ|T!!-jZN`omJN18>葔iBas!AMJ<$_Pݗ PtF8t)}2ʓJ%Dz4ø+Da$b=ҵ)(MR`Wz@<s >{l䃒o?:pᆀֽ-{b`}CANr ٺ zGZAZiL{e4!Gr2: ]ztmzo٧n oOZ]zqxc߬!jIr9H>Ze.JJ3 ܜUJc2؂K"UƌI1(J-ץ/wb-jWe֠Bܕy(+~В)_RF2xğq`t.렀p?enVy=== cD8i.! l:m׫BZj$(Q>)'RQ qt{]==]`ZZ/{SeDe'hJBS%YNA)=# ˂vDVAV֐( J vݱ7zz*R8A<|Y| A'+w1QֲG?p}Ԥa9?S<6Iؐ~iʎVTs7csкb$-09 A~(p65ߜ`}v*:v$=c*NN~]n“뫟/ؚr `Ml4Rv8Yg68''砣1dEC)#鑌r{g=lJT38'{?AۦZ}ŔH2}7GZtD%G)Cm$+?w y#?HZPN{NVs>\z988]A-Zx1PA@¿g\9 IO ZnS۫S Av+`IR}3բSk8c ~|q?ਰ Ez8^!d%ezKҷ E5 brFqlsʳŠ.;*;Rq\g; I`#F۪"ɠ 5QCEι忂M;}$ۆ0|OpTm޷[)>i…)csM))JԥBN ^գ  `Ē>dViP)I>C=ǝir)) .TWZyJ~;<աA@p 3 9?<1?"x„AM*-lԫa*TU76j+u˙srWwR օ!WUZI)JtI GTFA$ (!H !*pA%[PwGᓞk: B :J)d?(+JM@ԭ4pg&ۋzbDXҸ0]9/Bh*”똵IAqt vZYU-Dҭ)Rke5gḏi$ -- }А9 y޼J3+~Y P3Oi/.IP  7zLE4]TbKn, ۣz wFmƕRRKp4} 9QPRSZ J6X -iBqmX6oPܵ˖ -sUSTB|Pky(m M 3pR" Ҹ/'.f$QRN}UKWjizVӉ(Z8)ZIRO{:fSE*%DpqqB͋[i˳[M0̴Ӫs5JUiAMңZVEtZZgoj&̭[Qj_vRD֙! uj4 / 4PȌ)_0pfRzz36$%!CҞ-8qORH?ϯސ}IߦAYiuZW-aVRP&SUxdA~,O4ڤ۫vaS*J }@l:jTkRvϾ;!:7CbɭR"T6E _PR*`7q} kns(Wi '{YtҸ}׫Wmޕ@٥Y۔˶^Vݑ9rgsǗ -^gH4oZuvW&נ\X2H uiݠzXD6Q J^"z%IRj,M-{m#؃gpN}*9-Xn_TV*P&;cz[Тqf֩4!pHm.65 ӫ_ \wi n SV]Eu7 |WTZ瑜EdSz UVĵq"C E)AQ%٭VN8YʉwQ2g%J" Y4*7= mջ&C TJuQY0'JC|$9O1(eniJ^W@ϷTÌg^i>Nԛ "k?fdٳ}Зtƚ-ǣ><*q)WZbω Fi)QuO\.L !ռ HJㄩ`G=faa1Iz#ԠJvqsl_ .<}εjؓܮ[*GQ%8"^̭iKI¼ԒP7=6>&SsBz7 R>*"veqGb;Jy\u -42>K$ m!G2kWǃZRxp[_UcUj6gT4}5vivgpIn]z4R~.-Hײ(-;U5&-Ftѫ;לn{q@j+VašC{RGLZP]uRJM٤'@pCɥ"}n\V~36Le%!>bRd7X5Y닡tE:ԵW43NYN >yMUȜZV=  nաWY!JHϕ (ΩM=/ZOa)A@pQ.tޢ떍kM. 'D0gߍ1%ZZ5&CLۭD^!c]GYo*#H7.Q$!ڳʌ:K|si!>Z6dYFqょ}l KMV7P|DٳtպK,JP%N~C t3SD:@j&d塶cS [i7]Z./b㸩X6LybZŨ̬^h$.TɑEe [o 9j 6\V@WRVTRXϨ?B|VX5-_BwBP]J);!\Z{xGm_zsvqS X]S6ݗK\TiH;)Ke )AV8Cmر`DAA@ĸSF2-!*(yJ5 wj*q)_%9*>BPθ,4JZ֥( QQ';Q$% $$(ch0FqAD T%JAbY.!EII7n^ā|i(YL/Ԇ6z!ܖnIz\ⷾZ\xd r=G bԥ Y2[W;qc:w:VS/)A'; ))'=8x>uҮA%.mq>j!BpnO]͌yr!c^.ٽOj]̰G;"~Cb@ BkS厭Bs9*Cr;{eO@?^^5}0QB99U!? v?=t矗>: ^f&ơE=:MƸJ^X#:.071?!e NFr#"^QWň$82BFRujP$*KPY$;nWәKQVnX'Ow_ =+k2)-*Maޢ!KM֕Sh+J&j}-!eԒHΣ A~dRK.U*ҹRތj-]:+t E%=NɕFLTdᚤ9DzN[ 6!$oy &̄n[RT*u/seH*ʁ㮌/F4jr)Xb)6é,֯leRLiJH0)HTǶ-&BeInDI}o:~$/{(>Nd>wpu)߽Hq'pX+Q;N {`I "DM'=8iCOnSK]B/=#ZRVʩ7}i*UQVj,hG[C-dBVI}1jQW}^ J?t6щklԺ׈ 0]{ԭ Ӌn :ݴYb-kyz3>[qؖ[N8$- Umj&3mu|;UOxGnn#̔2j6)U%u5@d(CCKRZ)_y YmvIWBԫ9pU%B]`J(.jBy{޸2Bb7ѿLD&Rͤfy |h8zx~ Dr-TЯ}Mv YjwLq+uLFջ *ZCG iEUKz;V[TQqPǦ7Ij{\RLHȝ҅8g\Rp XnZ6|cy-<%jB|=y8dzw(9oxjF`b=_fN" M~A^:٥Ƽ]ʧ״PIZ˩^#)}"co55*|hԧ_T QS)JTK ڌ'oЌܠNOBTToP"9ے2<mŶ[X쵻6SĶ!#jBOsOV@LRqj^7P8.VXup愲]>Z[iZ@6 8Va%NE狀eޓ~+_Ƭ4Η!?VjUXb hj\d)Kdç%I N]PAoOYU]!PKNuO3Y̩Kp{RpIb8",6+pU5D oe|NHz٘q!kB*z韃?zrQki Bh(PfDEZIeԃ(*l4;|j{i."I|Eْ4=LV툪b+ˢ>Q?sGiLǪ̈ $\D^smlI( >{bʑ46rbɫS %b7Vz3RIpA5?Z#tES<[]9uoC t6Rm:һm zfRiҚnY6 [umˑ ɷO5kRb2%{xi:M2k*Sut@KT 5EB0BѰh[:\()瞒+^g|a$#OQN2Zim aXy-yޣJ%ΤXFW/ccJ G0LHa:g_xCNj_ R:ZZ4O2KkI,[bSMq.(G64HMISL:^m-V\[lr+h R@hmJZ( A7dힶݍaKHRTHٕwS=#DBx@vT?]sJ\A"nv`}]{қ[]u5mJ-CXo(qP:]m:WD!dVj|uV2tʫdUy[H[<߇ '*Je-*JH[-yH#vJfHBNQ_.*H%;H<#}PBA.]+݆ G=\U,~B\AjF%^"mCu~]D53[,]3ߺ`N2*h [|P![\(fV;?MQ/T4X&ҫNUzSI1M6IOy\%iS%CyLE0ҘlRiյ$v 6)|4HIDT~T (:TFU63KNz/;u`7b-\emWNIc*7Vզz\9Gtn4krQjM6f@jDHlj7Jgխ,CR.6a!5O2f6䖄dY#utSpSOl[ҷW)O oD,ڄRX HJC.Sh=] MW  Mv=E48hq{ۧS؁Q>wƱx)J>h\{df7.i"e56!KjFꮟwj\*5hz'd1Ł$Dcfdv^#hiai RqJzdv[^VŸi)@ O2Nb228>psí$Y! g{r3q—HqO9z$6%_èňqXXoϟ{ m R'Eu!MF]*!C=9QC:Qs_k[v>m)|3RIRN@ D ꈽo5%j\QIM^[*:%-m:;+t;aG9pT,q@'Uz3\|4E'v?֖JM䤁Qc9įZM[uʔa/ RuB\<4CgR)0y(SQ㦶V搄MOeG&vDqyv *b4uxȆE EXjנLДl7d4l9n3>ǿWw䴕e% Hti--DntTUK> ?<a(ިׄKX|zZݺJ )z(zo%pzԜ~{ZM2q!<Ig>9&M•M6vHZ4WT\^aD'yjNZSS$*?%y)${]#|M+QQ'w/-mhEڜ'~A-NiXp[48=h7_DW"[\tuZE}J >ys0_YpriÊ(y` n8@:mA,W 0´=R>\Rz3S۟Jo.7\QP /^@A|yQA^}2u);Rw!\eJO%CFSBЅ^zXӐJV /xyDҪ;/8\kiGN22c  @[S G8[9I89IAqBjiǗbG Pw7$R$B 6K 7WH)uIܴ -- g#'l;{a4KD%9”iRdweG^eҨѩU xABp=|֘⺥RI#%:wL=ϩ gâr=4غZFjÄ]mq(ç^j@Sh P=I*ե#P*``֒yRt b?pqwr^(͛=H4s.ԺJڔt;!9!GlGiy6?c[6t$pW}L3S$:\8y>eWGJnj zUմө:8+jޱrWP֏1g#9$}\KegV4-Cmq)$3Ni ZJKL]aٴҶ<+LcB_9)Jǹq+f{y驛Q̹zyߴxc1mOG5>dLdO@!zˠJZO-뎘h=M2x9ukASZˠ RKk#)zAI Iy,%A7}Nozo}ΐ>RS!zE 6)>c zL2q5fdI@+r9ZgP?H!k7<}x=m!6z 8ni)s̑:=i!W@mx Q#> RNR Zu@1|]6HR;F=&4h#?7bшBx}}=8|Z2+_)G ʍߎ}}jR3q( SBiHIV^N=#߸^c+it5M09)`~ ȴ#fj+hsP]€ E-8ԲS=5S3n?ˍ$iNma49⚋j0ƕ|ziy֣yUgruIq {r1cJpdx]C;v<8̙VUoBPڃKzʣ4 #9 0Fyr-oT^Jӻo.T3$Qex>sSL?%>pqr`3f Z.榍LzkQdZM<|Pwq2q;[,_ma*5JR;*YO{s,2T*R!5!N1MOD`xgN-!7z_ElxN9iDxe=tMM?K,CC٪Ĉ!zmB(曷qN2J5B֕5:o!6Y>aA :UgNHq*d7?zu$?p4=. qיmkc3~j3qMڮ%eL&)rqijmPuBTö.Zӡ26衟ώ>]'ŎIwr;Rdcл*@y8$ #q8* ˫愎|J nz~9el*n~S.QvW` `2z`ZʈHB(}r3IvrVT[`v%,o Qq\LR,`v@J()^rXٵ&mR݅ҾĎvCR)J!˜G  ]gdΈ;^wwAH'܃~P$G\f=ԝ$צm1g~?WO <#Z) vmq=cǮ''r[?XH;G;N<([ W <`uť[DA zۏ}K| u: 8⤍rYaYyS&8VK0s3O*M(I\o-qm+N#c(ZJXv mUCǘN1g|zWܢ-1vFr >nD,nqRxkJEkJpl*Zv,D#$ pUrrq B4 u$WQ+YQ#H֡PL)Uctr0\*s)H]9Ak30GG|[uM8*p8y#E/oHoCi JjVۀҙV ҎI$nI#8 Ŭ.4d{cLt8NcM.pa=dNs::R4b j`\_׊@jpWZͅnēKd3v#Gn$ hPʚGBRPrd`nrl '#voc?>6剂,0Ln'hca)gn6HI>?rD1=rH'gۣg'#c#'3dlps?<9LXif;;<laډ)9Dv˔~zʫ*Z!E*.39'`JRJT>X<}V(8زa_x=Buq׮L8 Өl&4rAO @`ۛUcZNplU( #1Oь399펳 8dQ?&amP0it <lkQ )N)W|>܎v:3, ='gy9~_oKkÁ0X-@JF11ߒƴF@sg=߿~珧U=Yw֪[\-#,KMl !*} 68U6-t=ǃNo9ǶI#SI8Z?9{q|G= ɶ-+1I^slq۬fȵUޛFGAXFsA{N{g=>i=#! V,F_ Jxf[ 9M>"N0JYHGb㞲̶!F$3C9;8O8=ws{|uoe'wCqO_G(A|?LmI*#v7*%%P`0[)!ߎzIAڮOe.'#shBC?L&϶v)%qDDZꨳm! =28ϗFH 0yێcn63?:x_G=f } ‚; 1QޢF3|$=$l`|cY+JrHVFИQd!䜓d:!$Hol]| >@}Oqly$9JTx8 ^9'<ǬdO</n߻R?נ Eߡ IU8ֲ`RiHH%$X?Em{=60Q8<#\yq+o_l:1R(lӧrcM+NV~ps#t Q?GHK(8?xǃ)N2pGs\;@8Zs/[]KE!D@T%Jr)g|6 ̠5G̠ JZaS8'(AW!=O5z5=Ze;:!Re7)^XsCiQHŽrzB XWPQ Ipyg  4>j[ub/ ZS(' H}^ABaH@ J(+D.֥뉛JnRpYJsp?z>, YV {}=9=Я5:a@{2 Q;)Jsny9 Ns= !iQ| E-EO*(tn#ҚS'+mE;w}㟩RQ- o]gqIsֽV#pNOQ(IszB%$r0}>x{و4@AkTDYyLtM MF^S*OvS y׿\f)lk>_y+?2qj>ݽV_? s k.4#P+EmD߮3󊣤6$(`s]h@oƊ2a8'(a=qŧ"r=dd,JHtsŸ E@9P)-µXPŲm/+qU*sju<}lڝ  !_ FBdwc=Yaj[xբ7)QZp g~KK(uzl(NNr FKB6 r}]-@BD(f`&+ 7Fۓ¥r[ɯe,K8R=Ւ}{g?ĝ4 7yv RV)Rߒ!M=ay H|{wF:EUů!DB˻ˆ' 'Gk#} k; 4 <4Vm\zA=8x B@RH>܎rMNHEW1 899?^tA #9 י˛V VnUy05r~r{:˴($㏮O$* ?.8GڈqGt1}K<2vgߜ_(RV6)D~d{ s'C|K S d/y]9>399g#|?>._9s;u{s2w~篂TH'3XXHQgq|c 8Oq=e?O=P>8mßϥd#>w~u@d>r~. Ky䑑0r>\8? ݑpx#~ߏK IO'81N;4 _q᠟pNߦS#Cߏ8Gac2G'>x9˫pxDqq|qz#Hqۓs|Q$8;dߎOR% r;rH8ϰjATH<8'RWIs#9OolgV{g?g> +R3GOw=ZNqr>T?=ʼn'<hxG` ~}VQId8ߥ9@>A0~'8\wzH  qa}8͸+Up?>tug|s=OnY.O {~ ی#zv>An?:D7>EIS8>}O{^B8$=l;Uӏ>{?n߿K ƶҼ;8 1<s#=lu{ua)?k>迓jX~c {}hQW#nìj('n d?DZҴc~矿=m;²H#1@'ߜ?ǡq€}yڰ=A@䑌g1?Xqu㍼ld,6p$n8'ߎ=#T~: cJ?aaEEXEXVl$~}KJU)M kׂg(ypGD%ƙT|:G)9'b~n;P|T S9s8g fRL J^DUmJ%ؖASҙЏY !H8ݝ+P(DX^SEsӒ:CV9O{@튕ʘJ@\y@<{G   $Uϙ|mM/[J2s8ۜaXOQ˩iSyJN19,?oVoZ&D_zꂛ9-$i3 ` uKRܔ(%JX ʸJrG$|1?_a卌5j H KW0f"mq!Na>S%فs'qWk/@`ux?^NZH A\i t7A* {]sz(0 {u jMyIAF9뮿#LCZO:u^ρGAx8둫MIH!.zHI*VJcO׷C& :A;!˛5b ȳT3uv,fKw8 U_>J0 g SMNe)YO$oi p=9PSmD>_ \uBJW #r;u-[OTFe_1*`}52Uӷw$玌M+(SUD 1{ba):\F>sU( 1pQ$fKloy›t{{Y5}b}ڒXKhpV\J[+##'rvOjߣDj%>}?6dNx,,e ϱ?ߞ':' vIP_:XXYrھkF^ࣂprpxoǬ@T,cS;½PyzXX |?U p{q?u@yYxq ~],,b)Y+Rq(?c=Sjdsc͞ q#|g鞩;}9v],,cRHI졑=A+<?~ìvWXB'SFy?)iNs=wbFߖy>N8Y93UF0?9tRNP}=G{c'6ys82.G矧Wm)'$8V۲y#˹8ac.yo3lD. )I?m$sg?Mq+`ؤn!@.J8ÿYUp|%%YH6YI }zXX VqgQ{cYm'ӟǹjpw\|Xbv㟺Gcָ*O<P+nIK , xt,( #ߞ/ǎ\9O OcYfprss. 0j g-E$eR@? #90nz;bĶʄ*|T'{E5[I 'ܿ?DK $*a$r>]KF;Bs^2ӅMpdF2@z'fHL&%Cv^AW4?q.;sDw%*yֿW8)I*Gi%#N*u rB}@펋{jAF(U1Nf,u::ғGLfGSQ QQ gj<@i65<_*q>#]Jsiaԭ|r1 65GuZShlmZshywԮTj]I4ȥ.3inTpwy =2F-A!+'nV~|}dٲTbUK;e%Ա`bv jtkW1'rHi8v`*C8#?\q[V9?߮D )_C#eK} s׮pFs{SB !A1&"c<H<<)*|\n6#y |zIT(c$co +i.@88*6q3nm% Y@qЙLk<"yŨ)'*>Aݽu)X- fWam[V ĶYf ZMÉ"; cr|0@xӞ㨣ǚfn]L&A7Tښ:@)%;JrBP# <쎮jg;־VR lŎ,z_9)AEAXK<mju)I<y !!/ՠWQOK𦱱ć j-` P1'TAS8Hcj^{nRMOM[$ 1B;֪5~遰" qqp툓s!TI G~ߓ)?M_G֔ߘ+o̕w0P@ wNWF?{8_H;a(&b z8oJ.`I$31?>6a pp;w#h8 =~l)JP)}9alM;oluE>Ƿ?ǯ1}>K $`w~`qx8}~G_Hx<'뎮8N}~XK y{$doϯ`qؑ=Q=?,,} Jq;ӿW$=g>_*`v:XXc*<|2ۯ0N~Y9sc}??owN랩yo۬Eŏtq?N;@FF##'>c8㪅 ]T$HXXƴm=Xslu/ǧ׫T1Ob3|  T@ӌ??ϫX~lޤ'~s߷N2Ŀ||ZSMH szXX{돗bos8A#'e $ ~Jژ@G`=$|{IRsW 9' |zV99yoOEl|q% ؂y7>JӎX0{g>Ha;i1Rz^ch}~?ֲ\P?%ֺ9'{sRC)+I˯8y>rH=YhϨn{{z#!'L`r?TBݞ~g:G8 Oc㌟~N%*#w$dv>ct1K%$ddc?@W PJ}C2~?/z j yCKZB8Ґ@9N7}:osQ(6^fL-Tj#ݖCekބ;JU` Ůu&д4~RX !@`oW ٢llԣRio2 j+2RiBl'i@9 PWz'gbBP4IIaGZ"O?m-=kYS$—AwDjcr<% X)*,Ѿ(׋PvLiMZ=!/%MGt=LL r*-. Lj/թӖ怕) @ VI==zkZmCq㬄jpK{H߭B)$ PpӜNPI&'¦ZHM32=5^`O L(lBz}@)+7,mq)ʉ=󞤃mAu^٫[2Y9MS+"X #ִq ? )ֆBv~16jXlC!3m]?z_2RDERgfϹy=vNsN_H,X$R1WGF(W)dԩ(~Nq.zz%HHZ)crHrpr=K/\R?6wҜO@Qv}xYR|珙@XyqB'$_ũj*I=BgRiE0w:ґKE?u`(6ۓޞ2t;)-T r nRj}IC~8e Xڢ`•BOpr10Tͷ4o"R mGcÜtame<I#ps>too雵@-\uPP|gÓup I~ۯ-pka'?}#єHO'G'n=ϰb}8sۭp3'~'\eܞG9_EW=|=8abB2譿nѕG~Op?߫ϸG?_=ğ,,fc_jH3G{s~c>!;r;8>g~,1XWg8ʉqlgT =?1<߷K NT3p@Ó|۷_nJ =dwq s#g \=P8ss?ssdG;~.gwd}~}<Sc}ߵ=,,\JR]| sǤ~> `q3ՠA?Lc#_l:XXȐR@!Qx?ň8<{}W!~@ 9?<Oӥ3sp~.*O9|ÿ<(F;gQ`O=,,`A:>_㞾sg=Tr9#9Gyƣ@ onyՙspAwa<ݽI D|>?˫vv~,'8ǷǬ }L㥷-Icyc`߁vU%)9]U瞭 d>r>>OC#q#h$d3@uFFH=2Co҈3~y?.t-XB>Pa٪͇_Q 'ˎOd[ 8-b{'~U<>Aӵ(A$l+B\ݩX~ݬЪƢTY:Ȕ0BTq䑒HR^Cv'jŪDR͡'nGDrG\ZCqN/. rz]: fEE%23_T6)BBCw+;NH֟_m0;+His]ۊ3;6iMbyakY~PakmU-PtugBnW 6[TuY38Nj!m%KR؜nVVPӫRC 4]8٥ݠ1S)C 8oOn ̮@ym Wa"ZXSS6jZ)RZ '(,80ZR!IA>%U2UsUVB/ }(q:$-P_4}cVNZn9P9h*;(=:w s`w@ ,toGM)m'ւ`9' %AYP `.IqՑԒ9$~RS${IsOĘ~>?9|C~6v].~/~å'w>PdB@8ÌἌ{uݒq qpp39aca uL)#*@c*0>׎z珢zT!XWI禩ZZpG_0ՎQ߿gT ?{cgm?t+PvbQےy+=]W Oa=տ8$gw_ï{{u,_O,ncHs03#,}_sXc׃#zXX´%ivrvү{un{dw ʖ\۷*#\gw?,,d>= ߪ6@P$mOl:js{ ~_=Ў>G$#p*9Ge)%*@$o'6灎`g?_Tޕp7d s~߇n/ JNIa@>}dsq'5~{TNFIw}a### Hya'v1x)?ӏ9cą9R s؎irupx~2$0y}b P'93(qdvx$܌c#RZ}1AW>g((CrO92z29) qO|o[)PzyAP*~g?C\+$5+9q15g@FN??H1=Շ'o<w~}5!waQJl\[8qs;:Hp{s!rIF98GC8#ۿ˿=˩4O×1rN2X{+G9bRSA϶~=loN;+!8Y=kN8$v!6Y(==1?1@̯@= RT; ~_@҉Z䨁Asz1j~f8G̍g8 (9=z_eZ52LXᚘL).%A x89%uS0uIqE{cӐ`߯@) @,OR۫שZDR .4$Y^.XV> 91\JeH4╻!'sяSuപh,67OaLl$4ُ G8:vVj2ލ9fc5"u('PFz!n܏WwD3:l.BYChi;A9*HN:%.V)VG,*)w`(}ˮ'Fۆ]]p= Ɠ9,YHNʌhMoꖒ &G}/:vC`m X<`TJŪnqQؐS5ZzqR#> =5@_480XϿwכg>Ž/]5bRt1H5vM1٨x5S rc Cux##v{B?p]pۏfi!`g~*nza]>1Vd$E[J~;EωaP,夤,9p~nyPGS!g)$c8r]hG#αY(3V)9: w$cxVHQq`{uZ@ww“pߟ,KQT5 5\_JEiԪRiUn<8\A+u8S|aIIgUt6+~Qi[\V^p}ԥ %$ 4{s1TT.,HC.=)[t###:CK5Ti1v?GݎHV[[a8B2zvQ(ZApsl+vg醢Rn9܏ɮ[url/cՅ6JUxIVIP)ܵjki!Ĥp,Ը @s8Ht=h_\Ɍ_1m) TAi>GI6x_Z zWw%fSeNqBn-/ BT(TXߣ۶ƄԚAq\ن%4rkAsvC2Ӻ;yؑF] #'WwMWLHfPU-/:^ g;Gsө.!~j{|`c?>?;j-1^]J1s@mbߠ8p{I?> HloEq1ca{wi۠ gG'/uplm3wq3%RXym&k,$k uQi|g'#J{?qD7-`v} X_ I>>w9OըHFIBǷ>r2lN0~YP\pvl,[²1,vGߪՏ3@NxC43_9~V%D Ӗ. yZń` x?r?zX3_6h9Ꮋžɿݱ42JA=>m>r{~FR =_)o 4~z?@*9sqǷb9t- P;xsG'g?3%[ $~1?woEZCP}jQ'p=0{}z>~9H{Oo<{tQQ눻Ң1[ 1?[)l㺳_Xہ!8ܮs|He0nX[|.vqpl6ob8I)9{}{'՜=l:q|u*l<z_zeJZЖ'p{o0 FG̐}<=ġ׌Svr~ChO3cY`qq~~Z1|scǷmqw3o}l~ dpfFm'y֪U'1rrN}~jV1 J?9zr>!8??AKPOB|8>Sncr:0x!T\IIQ+SnjR zF`^0$-YI!7c{1'ԽyLë_vR&J]CRA%Ilj)8ѻ2z^OafqH17:jK3իHάBg y$J AxPlRM-ysGi?d[:m 61IyIunU[0ӨFLP/WNw֤WL fԚ{l8xI@m!%x#uT4.Q (vʖ䁜GFTuIX$-A*DA۷K&єID-,FnVP9+^T;1+ѯN%Ti;X#N^a"g ChCV6!TI9ԖޞޞZiAIS_]dghlDzq~~^\g}8wOn4H72@Ǹ<~{gfN{ 鶢++|E%+!W7`ijHO(_r[  ??:Y@ %hA8î?Z ej2Qvc<͘B(!E@p c8p:+t'mk틲HBd ^yH< )],˦l O?OҎA!Y>xoq~xaߟ{߷9~l\{Zqi) }:́X_ {$XV?Oۨun}wPgFr|~}TO>~ߪ~ nI$p;v8a=fV|dcs?ČqP~8#,랤 oabӻq#~êc(ӷ|uTcOnr>:҄9zd^^FGnvsSN>p{I:[Poo~Op:TG$`{|cጏ^~ëF6쟗ost>ov\bIP9F1ۯqyG;9>VI؞??}:[{_gIpR9{},}8)ϧp{)pIߒߏ!DTXCc2P؏|w=fBܒ2sw?_|J!M@'pF89ŨJw~~Vd>zr{uA{cs眜n2GԐq`KI ܒW!AJI$8s:j6 Ru#=/~'q99P<T)G<_MA$$Ӟ 8go??Z * <6r7pc玬H0s=?ߩ1<$P}IHӷ$O*= ’?@S1ӑ_ŀ5=C 4V|4lNg >q}!r]40i5vD.=Pd2 !CjU<`W2yP6ne s1^MuJ+MQbMb"JSUu'uLDx[XpmR^Z `ݛ>wިE),#tmzbϫ7^LD0 uB 2O)J$TH:*_FeU*EdtُlI+/L,))I{.}BjH5hiUjP!y#!@c)nJ4*G!R޹k΍3-q X*I*9$> @i\dg g?p:c'۷s=p7>кJX9=XA| ? 8aB,Bv0J c%8Q1?P%sTA=?>ђAjZPxGocߟ)%I(I) I=tj.7’ T4Rn܁۟l.Ԫ(;ʜq-@%I۹(O=-}ueN)Km,*yV3cq*Oj=LMBTHOB 8O 6[wv_ݕ- ,mR;(I$F3ۭe‚;=HY/AO_:>I$ Gv MϹ+~SvK~ADdFK,I H S.( 8=$'J{EHeq)u%9,JLuD\JyQ\,ITXPb.B",NR~I VLLD$!a/7-rAPJpw$vT,T^ `@PO<,Aj Ll)M(бr$.#-ִٷx^` lA@!p8mY+HS~d sӦT#ה5or ^L 3~۞;O][Ӑx#YqHr9?HAVƕ->{~n3ǿ|zN>g_o_`$'ނ@^= ,^!#=s3|WOs`qXIR "8H>ܟ6X?ˬS6HH!^VH@?wucܧ|~k7Ͱ_w;ol:|pGs8?_Sj쏗S%h\ޔd4{~#8۟_zՇ~W#::5՞p2oվs#*wϯϷVsꃁ?P:X0Xw޾?oo2Ϡ?$3t9ʸq#ߎH@ukc?3?,}϶8㥅_?~@wǿ*wmN}$wϾ1ŸQx߯O߾A8n;>V>ʿE >xcsuN1 ~c,urz*Qm! ؐFG]a͆*.[ޮxӜtga>܎Z]nb~ĿH y"ޭdqۿϯs#^V{|~>2l<? \Czc {²B>>qsߎr {?]Ĕr9>cT>x~㯀<yьr>]z;ycO ?MW}> @v8qY$@?תmȏ~J@}u zm%@Qvk9le=yOs}ĜN~~ua ?2yvԈ 6?|z㱈%%; )q;g>t[偃39~\NQ;|;{YUG?ߩQ\I??A2CLWF;|ϱNZVj@b]iNK>jg--8`~=SQ JP AG?_l:WBo-STCn-GRIHNm.(do+'}J;*bRMA:~kj9+"*BI8躅gvLU.x.Z\-TLVBY2i)F{BjP/O)Ӧ3\B^TU}j,' rQ03K.C6HnSHamRP@{ JMY(p`Tv )OjIܦBV>eA.,k[r>{aII0{]?@޾-5mbڟT%) a{ZgZLԻpx1IGqbHcFm~ݲ, ]V-P#D[u$`\#|Bu<Мp;s{3Ł8 \եl1`#pR m1S^ew  $p;qS} Rqc3r>-c8<1|ϩCj <yq1ߡIb MxqSԑV6~]rVg iǞh nm)n'kzmuq(JmcR%9'qH {vM{ԘGi:eM7! ddtx9_muJZ!">5Paa<]I5_=%OZf I"}^:e@h1'8 Ym% [<(weC|Fxz[ZzOV*EKTG KX)i{$Jqիܔ.ʔyqK,XyFr0N@R?F7TBj{be6jD-Mix!m-Qcmp2QE.kZ,VT{-?W p)8 )gӖi wT3Mkey4&m-(+.*2!+);G6=g'=ywhO8*}Z\4 KzGO?>6\g8zB$`㷿zɓ?=YVpFy<}笈z ~>TvW?=Gac(dn~nU?gO?O#?ߥYy#~X9p=uv<ߟ;?X_ Jy#$?>q?3yz\^c՟>}Tq|8tdb>.埧_yԃjN[R-_qO鋊I nϱ$dq;ssńwA?ˏWq匏nc>g40O-_,W#uc玭q#_Ì|=ǶoR:X~/X$)99?ubAJa=q=;}qR}Wc<;<tQ#gD;{}ê~xs?7}1<{?vFO_w?#Ìds?{ui$>ݿy}r֟iI*>Ǔ>G/_ RҚN9(+ANqNzH $qG~.{XVIϥC?1'9R޿*PR0`O>￷gÏ+?:N9W#8 '*80GLUfn,]|Oo==$׭epN9G׃/c8R6C鎟}.XǼ' 93'TO?LA#Oopr:p9s|3I|LtMM)ks>X9#$8^I瑗 xqGY 䄌ǰ |z ڸwvi=-u %`Onx=*R FUA#+2F0>b;0}t (䨂1ǿ|CqbJRA Jaav(x_x>o÷/- V)BN2$)r4ԗT'z[{)Rߖ\ZSˀA98#K~ƻkh.Y&#j$%/ C` R'=oIm8r?W#Baە4Uqފ4raw|Gߙ,sBIꚱutnK1k2RBDVj+ 6aCRcw8Q-phʍ5JJbJD[-;SԔ-JAFK_0" ̵Zde[)=h# qֽ~{>W>g눤7mP.h՚v:oRẲTT+G}Qt_syd\N `p89ۿ8M|gEz:~urs1#KI)Kjq15Y%Gt+`I>/  zlA=F)W$z8v>*g[h@ۄ]W8({ߜJw`x8m%~\hn'N$+6G$k0{cHmA6O#r|GiS3nrO˟si$LRWc!@A;۞M:c)r!^G 4I>(eG٨k$#³wU+SR^p=$q0g>Sh˄9 (PuJ'P)j3VpOc8'8R nܵnzR䷛G[kRFi>2FxQ2? γVFk1jqa5d)~P *)pxnƫ[چ]5(ԙDnEqKRP8WR6;Zl!#)N1=c⡶+-! A^GG 8c'Jt< X J S"mc=ERSuR*RcG\q'%Dߎӟ˦cuIQ.* qGQ>'s翺y:(_bhl+* M.e@`z$#w_ϱqБ`s|#%XV{Ǥp>}sSjtm\?qh$Gn *>|Ca}}pw~YqpZJNpN( !XpoϞT=sIH ߓUn=OWGjF%NCz,Z \@{z}xE+'`Gl{cs>|>@8=H@bAӨX?{9DZpv??ޯQ<{}gFGO?>Cy?}30F3=9hJxr3zjH$gx?L*ufwo[S*}">!*=L 8*>\uV{U"| w{rq~xcg8{v=?Cv”7<}=^ǫF3onE12ryIY|Ȗ;r2q;d=?ꌅ,|}G7o yN8lr3I4XX`'x<9fx#8A篕”J* WP0 #c8  9cV/{>owIO`tQ'5|n=rA8*yzj\>%8@1³{d*؎׬n~ݽ>= +$5(o?A6 ׏s9093ϾO+=?~^q~XxԨjod_cUjRRI$s? #=MV;t3 Jc$n}RA6}qPڽ)%Aaݫ#~RAd2 ؒHWBr<;gMؕ b` PV)NIH ʸ9$~eRk9O_ŸөJPm[G8=ρB~-_jW>gwHlrk-YmIiaC!$8=$ :^J **H<|F`)ƭ+nIMDmZ783#99oZT dhKr1<6>5 N~ {=?n" I$ Q݇Ϗ5yMZ66K$9Fy<'ס'syK1MpbK 9^ C `IF -/?jVP H PPH8A=;-_'\*SPwąPaufKKF ')u 8Դݝ < F3dVQ7hV7PTICͣ/'֤ @9=Kj-ٮˤ%[RҜ V3ӳiRe@4)ԯ1!qD.g5ms.Ӧs,7*cCMIX,$YFA iR!mJӀJFN2OGX/b7`dmy"vAd'k o^9[N}DӎAO!V|%Ƽn6ъSF2r#Z!E$rr8p+s>giJ@X*W| J@Ybxzqb1u98 Y`r>\܃{s:G =I>yB7jۊzfPؓ8܆ߞ%9A?>;_$d]ˏ?^9~]~P$ ryqB xP,skUDJC$P&{”|I>ZHpO@d|09Ƿg3G G9:ᄠQSABSz#hpw:y#GCl yqF?ʘn3؜+9'1yXQZ Yys\u1Ҥgs@7<#'8Ͽ %C1>Rzr;H+ BBy9_5YVA9 s?ӎsU;YiM^ͩJKC-kkcsp1?Ǫ)c=uޒ~$|;~c=|#N;h?l TdggC>S9= |!62OӿV)xN@P2OZz(؊֞Xjw?{8SyAǷJG`pN01'߷[ K H# >;x+p@Q*}?[?uv3XxlL;)W8Ʀ9z.?cЯÎ sr G8#Ϧ&BX: SÄ5(P*p\w;Sh8 r?>O׫6{?sycj Lc܎=Vpv88w)'9;ۻf=]9!YرY^\Xp=uvČ$O|{`hGh8Q990AϷ_R06IJg=kv[#W%C!@]:ҸǃϷ?Z)$=[HeE[R8<ǟn?Y~{ #r}:rW ԁE$pl\z0Prvg'W sc۸<~=me$?.c=Yqn F=|BQV1KZa p1Lt2RpO=fH18#EHްRoGp9?_7($'p=㞞 AA`ƛ*xgٺ_ m~1Fx#H#olXHlH$`uyՆ9 Y9@H 9qQMx:j{I06v20;u@`{d?=nPqJdc>3C$g9sw*P*G%b޸xR4RF8wƩ@;>e$ \OB1$9'V2UqDZݪG4J(KuR޾q{~?NJ yxРcvBR E_#ǿ=iJ+A~SziI$g=@8?@(@?#oʨO%!$v2xN}vPJNxQ?!qd4]LŴ.\PгThkBSE; h#GUQa++j"AFII V؎A=JYDyOLmm꫱#̔!JՂ{"PPW, r3n# ԷԘh%]Li<'z/ ?h$pz(0XPD?oN_]W Ψ9R}- 8)B J*'uհhRUTZvCInC3B SIC@x8udo r?/è5y$cahW/OT*Ekw=~sl2˕JU'}F!J'=OS7N@()|{=VL!/-' À{w< \*b#c8v D/RN MO~˜I:kmh>*0Zuj JV-Ӕ~O8&q!I8wdsߨ!un Ri_(C~+Or-APϚJW18LhL:CK6O0MI>{`^;D8CiK>'ODMit;"e.R, \K t q`l@\ECg'諧ѤL%;I+-+BCYIB'$ӭ `8oͱ KU΃֤ ,AȐYɤr:e%T59P5 e:1R4G(Nv='T<$5Z*xVH Wsܴiԅ)DI<>I5FχK"@%1So yIQp ԇ!X&N;j$$s99oHn5X۟kIc^.xo·I)t(MZ@=Dt91ٿt'txg%H^Zj+Qf"V~ã?KaºB8C<у'o]VA? mwOWKs%@P,'/ KNC)CȏBrI(2F~ӌ@}U3.:0LO#cPBU!i}PO孇JRkqHJ8H*g?ƪf "`FDZ=hRSFrsdRpp VչaVGw%ٺt>1r|;xޓM[+WK߅>I#7CׅOnKi ܬ@ ʕsa_g&\i%yvV Ǥ㌃:?g?ٺ3 pC71m^{. } Y$W/e)8kWz', b 67dj#kMF @h݁U)P`xaڌ2#J<Ķš$-\$n^n${p=K 4 bԹTWSXP کIJP<~:*Z_gE EʍJs,KiGBԟ{r<'\Y)ijU}-$@?_ Gsns$wh"Î+,wew$ hŽzPHF׼6[ F峱^j^2!*=aFB|1j ԵvuD' gKlDVIm- i*#$F~k|<"UϿ:/6rI-XIG׌uyEݤJt:;ɼůZYK)Ԓ|LYN,| ]OWYԽRې MF;2VFp5jR:D"Z<p_wiBps+3\AbGjleE_*U,oQX=3'1 g?)PN\ɲ|r)kܻGRS]XFl@kz'WmTKjU7Ptjtw{J!pz7Dw<-;ϼkE_)VRUSg@9#T$PZLMvPˮQJxyQt5hA.+BK B\HNP.6 '`sՏ9R&QAEQzlZ6#$V Nk7ls3ĥOV5 t^he$^%I9G]/4O\H TϤD)IQF9?f ԭ ͩ8!q}'B@Yp1>ٕwy6~<+Z:6qZleD9*q-d~}1I @8&XbZZ|5"› 0N J^4Ց3gP'N/}𖐋M)!ACHW yQ)[4d6P۳mQَmm̨SSCRAQqXI$7n;1XCH)!~FiN%m m?'fF\doқ-Ķ#C(}V堣Ny䎺!cC΂)oډZS(yvd9}f*ԖrmOsZPFwۃӖ?>!;WoceJ҆@#Tu;o}] U^QR/NC N-{- h8acCZRTbF '>% NpBIx@Wٛp=K[Ttm%>ig!r!+d$#h'<lo~D~ IQIBSXۮ> akMI/)^^0y6R+/,CJU۫Pj))ciڄG$)HnĴҠ&e, R IBrR3#!\fԏ!X)o>=5o-o 6R2T6 aP<`J=ZOeImvZ;/RG;)JUw/"TFY`\$ },Hma^^Y_DB\Q@ؿNlGJju&xѨ?VRTr֩*-"Q}HM_&ÀCeoq$h$d>I۰[KiL;9RTJg>G9)RxPzSX<>j:"/gQ%)T[WN$N{۵R>pIUzgbH.Hf-P6'2Ms0CR'[/\ 딁G~QMU.E&N/,IcV[<`8 NxzU9u}NR*/Bf%3IV䨗R((R2ONkOx:1vyiNjvҔ{++b@nK*IK""a_*XKmG`s8/:Y$rFb@Grx- ZaJ >E1\iN)ÊiK+ش'qE[#:-1>RB2 @Qg۶.$oʒԦ u} 2v$m3Ӏ ) qۿ/u~"4]5Y֘`sRɫښk> H_ZS(pC#$cWDwV\ѐ^R |9;yѐS-Hު9 ܠqP jC*)r:Bϥ `qYlHDMJIaF:Z˒^=pk,M^)jtOB#~!y#iP B'jx}#ףݓߗuZ#xp\o8qdI>Dt ]*Ox 6/2 %|qmńӽJg 2~gۮ|-i Yy=rr~JG#$Ŭ{dg~$N '9ǹkRUJ"0ԴxX5|# $]e=)1ܟ˩|]QjYt8;x(OCЋڕ,!+$G?:f h%͡gH>㮅HM +4yR{PwqW\ϡ *“+w@ʸ9[OSaHy/8ڷmNs9H=nj@ʶǃ~@dtB 6ڠ㺕/rU{RBxHs[aŕ'zgIG"2S~r -sG<: NPcԂN;pUvӰ Kq~6յv|صd!1U[ Jy(ڡ}̖BH.vpO~} 0XJVVJI9<I< OPc@9)8|ॉ4 \rIO54hH ?OFֆd܀䅄ˈBؤ}Ss|$! %(@I=Gˎ=֌q"_} %=C\_S/֮~C  'x'sEw33*˦i9qa% 'GF6w`R}؀H89j|?Ee\Hv=|lDabs?}/RVvNJF#{d qPQVPJpcG;ap V69'>瞰ƓRu*(Rף7ћOcNSKu0% I<q:Ҫhn[hڕdd ~r3/RnCK-6'x=@RJҔ'q;Gc3i7> Ϯ+O>6>O'sКY Rr;p@=pn_olEnO`n e- # ѭ(Zp 8iE Pe6NJPrdc[K Cm$rqsߡd NG#JI crJRN9·8*?c [PJBp8X#m"a6@#p(`Ou5)^ (*i2~q=roaUJ ܤ;Ҿt&S- X J\#qL). =VAg |OUS$jtm Ki*;NI|ZZmN8 $ϷZk {wx=㎤K0spC<)Jybjtx_%\ JVUYcXԭ mĂϿ?3G[.͖_BAVFc dOo"Y@= {3)!,U=8[Hys-% ?2;cXHIdcZlHq#ym휐ߓG<K < {|O{0C>e8a UғH}щ5 0q髂te8ےH9zTmp*Q8)|wFqԺvVe %;~J~Xzʴ-kChJG q0p > 5S@I)8֤DX9JBJTF pp>u5ZV-ңBAI Z0 Az֥QA%d恜67q# ܫ=.+_k0T܆iIR€㍾|Q R} ZG# ;$f;AHx%Xckm#[Tp}(6Գsg9 #I~78岺ѩ~XݬϳBhgǿG T/R9TN$wOK?zGz0<֨7<6 :B#oe%G>ĞÌzRBIǹ# + (锔orvߟ8*$tja2O@ ez ֥(2qI?BOg,nmjSmXXp矼^m,1xD$Qx^wFͷOy 8ؤR* 2,%HSj;BTwU6& (3U7FҬi+Sؐ0Þf(eO|,@`z=*lF}0eR.qɫ(e )s$BQW?{O~KKSZIڙXWb go׌=zm:|jjϙRzz07\RBy1%;mzu\OqMɇ&:LٯG$J :Pfh" C0͸%鍼^ƂV5(EכmfaGiJpTC Q9(=9[JX 6`E;TA$`=!,JhS1#mU%:P4@ނyYjfS_M2Wd*v*RSQQ܇PqRFu'*AqR c#IQWr,ԫ tZ3'>{siE-[sGڬO? ;5+ j+n2cL}X9)R =.1j>B tqJ>J)JnԀ{x c&A<S %@;@ 6Ƨ` 1rx&40,S~$n09ϱ8\`'ӌxMeUނ+M~2("j*K FzئݼZ9Uz?Zל[3jMZ.@ԡUhz$*K q 彯!OIP-diaaw&G6Tb!Q1" R ~oX2 8Dk$`Y*dZTkp+KnN<)?#oߜO$GLM:Kqq:"![+qL_d'QYK>-> CJ˚Ky %*PWug u̿ĹL3 d ؽB/1J k5xC}6\O?ClsuMF;gd}zCרkqbJUm.&V1XK*9FOF:H.2\ecEB½@lև/dV1au,$0ޤάiW$[CҜUc-AM%K*܀;>H,{㡸 a J+ ~!K.,)prl SJyJ\!IB+X ZR*ܐB QGk{/lYqX(o '(Ymڂ}Gߜca !CjT~W}8yzrxHU<v''>H]\kS4QCSϭnmrcTZB-t%([m$λM'4TÊ*PHnzfmk2̡e-ED Z*,vf yAA[(rvc>x#CW9 N@|w?qH?Rvl#7P2q1ܘd>Fs%!Ü+ʞeya춷k CcK;9rO\i"]FACHG6]3-Pǂ3)aGSJNsG߰҆A->x8|3h;_7;4WZb\.*VA` >F$չ[z.1|TP]im0vJeoB-ʉ!NB=cf\^g),]$+6Q"Cj 1`C=YSl?0Y J Zޖ$Cel:m%jmߗMnWh\^fmƢ3)A~J5)Tb\< :ֹ4\VZUmeժnO܄;LG_;|,B zUʦg(q jJuiv*^b%ֲPF;?g ʷm " ٭u)Ɖ(=-8S͸T }*{%K>@T饱2uIl_k RK_䑳xb<%hp*XAHmY6YK`[)ZCJ)+89^;(۞ZTҶ^4FBfCێyb5筽A8/%8ZDWfܔQ*JT[q H#g!([BCY9_-1 Sui1/`41 2hZ"Jv ~LjkpzU6 ]&Ral_2rHqL6! mHYx${@ RKtUȐ1R%\=ՎAHAa*)g9$`ߞjO0;- jFHZRp-P^)Z:)Kƒ$Ǿ@;3֒gV;><|9ZCeաR1Š?ҵeWmj+Rw`(#j@ :O",aL = _/!Q+hI kno|zM9PCkL+;1Hz۔v*q}=뒜ĆHUj=mݫk8' h9mR@ۿNqxtnRuHJРҦM-Q ʬEBVv3Kc%u8 3灜 a\ASNڷ[8H|] ƇCQ?~+lnI{q+m_kmvy$Ρ(FCȄ8b|oBL(EO#Hը0qwOڔjU윪 ;?ק G,~l4z~< j=RpjOg:wD~q#OTRjoLK0TEψ?8BG҈*łPo_>1G\C<%g|Csn3HakG>{chy * {r3i"0b;VA 1Ďu16WH kipy;rx31d>̮2%)ZT^ KpF=2VB))${rA$`a=<@`w@s>{vciN:Iq(J <\.fR׌xLJtn]1ڧҲe\(|=qQWMMpJ.յTowfsW aeCӘj5AĥVʥIyYiƐܒdw IFdjǞX"̳Քdž*?Ł!$thRb*2,; 9u)SҜCNcrDh|>*rwd&e.z8TPnzA R 8˚NkvwZbƸ˼ +i}~@׫ևrmx5JhJV=6ܠ&S[֮Sh zm!2ٍ9O5,Wՠ"Ê@ñ[#%جqhJӖ@%ܳsSn"4RvWAi絧\k\hpʌ q9 wN>÷E{Q-]TmE v-R2.y95JC̖l?l!LVDRaR[i[JR=Tٙ At43VV/)Pč%v5Xq&Zi5>1u?L*Yʕ]fP+zXM ӹ*I1&^}YpKˎRZNF\r\SQqR+Y >Uz.R`'^5m pȻꔊRm%4hM5MiRـc>[UJKhzud5ӭj=>L9kAu*A:snYG&L'#S>`N,Hv3) r`jH,%Ңw8JWi@1,ArZ3tӋ}.q/6]h[+K(Qʶ# pvuoQ S[fR]iF|덡%NࣰnQے8o_,T6_@eڐPf+S^x4Cmyz%i QH=e!  ]ne]T,TH &㬚q[ VC+zڏu2D9ݹ]COUvpH=5n+Z;м2<]?18K H$i8ʊRBh}nj}b)tص &u#X;qfN,˦C'0IQ%Jz3} 龪zbډju6 4im4ʣDyԴJ76ҢA=dfp`"K1P bt/Z9r~ā%23 T?vHbYٯz@GUiKeҴ%hII!+ WE6d'1A"!FLYu/MMS%i m.!<ʉ=mV̛1#muvSP IRe., )>bX0Q:֫V/ WA Χ1Y鴫{PpuU%hoSbE9m_.bwp!ĘSBPA$r>ZzrF$J@]~b{ v_kue-q i\u4:bA \KOpIBNr:M,`FSi\]B][|qmڻLf)o=%*y ҡRAW ?VWڤ*j+5ҫ0U(;&ygGC凰R =ʙJJ!b[HUnDpZ{TP=vrj; DΜZzRf=oyZm~hY+#>ՙwd&׸ВAN P' x?NROe\x(j.*JU] CYe4K:P6*zR4[vE5`[/yM~Þ"-5NIcKi<Rѫ2.!B\R w 늋c\'fQX$;}q<KD.ѺP[-(UxR0 {t,g)sJ\T <GR ޸bCPT6J qokĞ/Xru۶Te1Ra5xm8v.$Pq=;$@l軐cWi!`Y};K)9Nnb3ZXѦ2@Õk:2QKl)huU(#pnڞ#tYʒ.趐%~i%(CJYStvRӊPOKz)2ν!⥵*[Ψ4T%AC彚ˡ& aTBp5>bmC *PƲN4w^4MCiTҧ̕%зa0B ƔT8:7ɬD,E">nn.G[J q%y9K; 990KRնn:` !"b?O1vř"4%4ę._KR/j]A[MQ+ס[:ѭ׭]pFZJPPjQCT 2SvZCmٌRe1 Ce8,Ҧ~q^kJf@qPُL4z馄o7dn6! _(JpϺi%t8&KN֣%娲g^!f\Q!3Ŝ*$F_v\W_eSrc!.yeeH`%Љ#ŠJDTHq:pIf6yC $ ʆjp Nw7S+Qt%ێv[t@TOO8t*J+k/iBHK(q |99kRo@1I{.Pm_ziR}c.ِZmT%qmZ\m.leiܢZq)PPJ^@HצX E,$#|tމq7J[BIj֮Aq@m%8=o e%5nC\Ӷ|z!t r뚝.DwLT]IH&KBC3V)59Rp ۧVCJPz2jbe)T:ITQJ0)H<)%J $b dq5ֈX *<=5aXwvFZ.&Ya)KK?t`?@ǻ֒ B)|sǷʬk8'Y|Z= Ltډt6̇#Y[LgsblV' "ZwDAuJw ԊwMm97QNZmAN]6sJDDpʊNXД!I}JSF)А,Wr0>E#MCY/j)pUصۦ;,`^0|6ڕ Js8)Uiӧb~ܭs> n+N)%I)'-jF&狩)Hj*Ș׍]M~9թIˁ1?EH:rcAp=x1_YJ $GTwƵֵNp.:j^iԗ3MSC⒈|Be91 ҲVRba\5I2X1%`<$ :lڑm\֥tCOV (IJ8qIVҡ ؞>Gl?;}[7_gLZe* W҃p&}).KDE78[a-\u%8gdG/(0Ă35J#/T7?ي "b!Oaΐ +yJqR$' OF>d.IJpAk+w<ЏQ#:LOP Tߙ e\zr>`u5m?WuTJ|bmϧc{/QCVp?.zu9^CAˇBqv'6(n]J a5$I<oQ:ôz;SaQZWxkdz|G|աy?8OF;CNXk$w={v-50N8ߩъ|KiX$W|sʎp_HV } D5]{։~ uH[ (}?F$֫ӔO2V%9ssr@pd$#~ˑ=U5OՋa3%@۞YJ>'iiJt2WG<|UHRJ9FmsϭfA ;|B®K$1mbj>0#}#Jv8H$-y iHRv&"6uf- J%IG󉒥!v+0#{îVo Vhqkp%h[#m@өR.\<ӓT5HqԡזIz2ʐrtB=J]#Y[ʘQ4K5"=rUmr55Gi BFrx삻z+xxuQvZ%\:LV[@Wȣb̋25&ޮ_Cz ?Q]=K:y9SA[ ~5ɒA-Imݥm2hP<,USRQA~}\bfdj] / +5Jr)ZvEBum m6oV&٦E/T g *v,Y!;9`1X$8<{հ>ֺc tȖ+L鵟OoJ2dĭ^>շTUKT RN/[%mj9T)dyhSl‚> /M]kT."6.{[;TZ߫W+UuY%ʌECm AŃuoQiuE4f@Ė]aZaHϙ¦GR@<.]"JႢin-F`n}W\<7YuM- Td)[y.%(a`n-Gdҩχ}Y0,M!isX*#Fo#߿nSkZ`PfOU|ԩ!3RߒIӎq.ύ}YU0.J c!27$q ۞I J].`88JTWj]#Q/ TSA4TMJbU.46 zLk}JqjL*qc)r>܄z-(Џ.|$ں-3Zr+^o_XɯTtNkn:nZSi5y3ͻMV[NHiĘt(K. )TnQ̶օSc,ﴯ^ѭnFߴZ`[Ow͹j۶̛Jb4|h6k֛So*mIaVbɢ$ ZJv$Y0 DH%B R>Zv |>v}:'~v.xG컷Vޞ4[TE]ZRb-\uT-~Ѣ~b5q"22BARɭoc{mÖnjω*}'UlΧ\ f5KjL=d&ظ} kQ|ݺyWOG}jm64.e1`&jJ%\+iw3KUdŒY֣;Qӭr~h˹hVå=6fԋH%^~Pny3~!&!Bl%QQN 1qwR?stP*iΛ5OV'nTKZǭEJjUNh ۦ-C<>i@xؐdjˑ M^VhWZ0OcQk~;tbv׻sPotˎR J\bS)^\bVbϩ64}h?vVޮ TPƣځh"Hn=+kTkŷPŽU9P9-\xz7J; J4;bѺ]*~Ͱn;fDR.urAr r\!3jn3MLDDC=(;>aPMف巩+G? _hw^iXƴ3@ڗI!VvZMEmFdkt3n,c_f*g5M3TImal%JPZIPBDw6nmnW2"T. <5X4HT7DH4 ZEC3yov-uZjDv<ͭJ-)AәnKu8XbFz ZF;*- `p}Y%eK\U֭RT3"\Jr3*'%}jSV$1ԕ&JҤLK. :ǫTh+S.tmMiM-JТ@$z#Ŗ]xuD;gH*u9tKSCSmW v*$tvtMSc}.R`xĀMs ,ljytF1pkڋ:!v}ҿi~i|wxW'^J#Ht{pVRu6p]2T%.KtBTvDڊeDuyAM7C48!yRI/Uc#i&I"C\tzDNmG#\mWŵ"-er!Œ ;ֱ>ͻݩh3i."ԁi_+fgM0"\/ @!UmŸP$P*iRQrI$6Y!:\NlH QSPX9-fX󎋼~Qel=#T:մK-* >{"ݩ9IBV{@}#:d~46:)rć^Mv*Z`.RRSҧp!j.``3­D`O%URb1P P$绥Ea|A Q!ۓcO=f O}Rvx62Xa-ǝ.A0'rOӾ*V^-gŃj#fgjt2R źgL<딕2++C^=Ql赺ZB_Zi:T9vZjȓYAjw$\%m۞ e&U,>ϭ(Wހxu]'XW[^ph.F+N[YjN28}cQ$Le"PrJN-BlRfTjmߊAVLFCRFurW. Qǩs:nKn^ZI~=&SJ*#i[ Tn*bC$M"I؊(٪?8RiC[M];7i=ZפԿ sU˛3gk}/Lҡ~v3)4EX2+Vm^`nJ"j_Z-qxIե+_Ə3?f|*WjM^[?N Qk`]5&xF&uNwe9T}?ǯeT$9!EJKHĕ`}V[ﻚʳ)ڍx^ x\Ӥ,n[jn.mLjsgfW\ N'ϩhD軤jtߚ׮ +[ԥ!#3͓"X C9i(RO2,a nt[tL BF$IKSjuJ>iX bJ"՟ lVU,#(UaT2P}2] %끴u|h [C4F$(xܒX ySPPӃZ NPeh=ZL1 `ʨ8C%P5:FjqѪyK(%nB T()'~}+'RoXS-yJ=:S7e+j i+Wڜ#JfTG>JprV~3xu?VȧY5VMn\Z̊er(jr^Ge^s[ %!DKTͯG~#"T/Dfp¨#WԸ+[)e)RսUoZukTW5ui AS=Y3X}kQgֽ}IP3Q*]FͻkKh?:R:w(-Qgnч]JoVu^{ߗ]j*E6ɫ.W"rKm3C!S!$b*cBhԀE w"ٝ ֦$nKRn:/e'St_rY}`LJ+CʁrvEr,njMN,)]NÝhQ].ډ_m6ߺMoiUGH-AOvihUrnǯEr]%4Wƚ^e~q=sRc^(wĎ.xͅwF{K[)Tˢz˕ѫkUOJmz"Ԙ\*2놛c*3765?PZ2%WSA+IuuݯJe[tӪ%Gn;Gz +d:jH,BA 7/'($?v'XhU~MMtEԿ]D7s|ٮC_Egߴ/ IN\:]f֥*BV(lǛ:j'\umf@zC3T3# bФQu3RW3*:]h_X]h]Z%RKTV!2vEsAEZ*;ny aJSscoK#%sVj& SmZ/tEo vǃ=L.D-fS"KR #YH1"E(J ?$fzlbZ:stԉv3q&# $iKB6 QRg~ȎBHAI#q!5uSJp\:ZCT򊄂~*K]q(u/4:;Nԍ@A W+*B.B8**(I,zz #y_RB+r|=玠v~7%JqƃiW hu8i]OcOm]JEVYg"&;Id)pF=PQ}E!VQoh=ߎYLY +,ΐX?)?\~zJQh,-4v 2^}l( 囦8֦RJj/nԂ6"x/~A"ӧC-J 3ߪT5%)g~] Y8цoNNg `|r>gj@ x v<=6mP麒 P#5'!9רly.8* PxQ=?Q* 9`'K*pʵjDgɎrq* Nsh сѨPII )=w;q:u:6or .Sd)&;< em |Z@Od$ttم8Z儸ĔYA*B(HoBr2=sчi>ЬR-<,MCMe)!)tm2 'EM_F`9\nm/Ԡ; 223 . ڄtϠD"˛tggS#ϱBZenjSұg)QsP}V9Qs=[J 98 ֎Aq֟xR./ >4m2&$ NCl<|2HQQl*M-$(ˢ*B$zxA­2] iO6(12*jqXʷ,f[.Te> m'wʮ!%I Q qa ܚ_.~(ćO.6y[?v^yXmRrwK@8J6}. 5 "-ϥZFre,(OSh1ҥ4U-IboqbuËBKsJP޽v8Q)6+Tؐ1d(=K#*#.j6AiaJ aIzH8?B ¬N4Ƥb,j 1s JS|:]3M2]"$dS('4RRypѡ qMԶw@Y?] ZۚV`JO GwkG[7Y_ţݭFxK>tS|;I8$A@rr\JSWTOauRJ=MuΌLu~dn[vC!UYRR䄂-:^j4$&ź P*R sİ `;Y#"??NjX#T%(yߐMo,rVbTT$T()$@R>,m"$#UFvBrH BNTvT. H,JU/eёIڵyy.Bx۩A uIKp6թHiAEH,o931LU^DلqrNOֿPUTu+).8)NACП$|i#9(ћBBPHnNNpY[C7(xSd()D% ypşH#L"z? o,؉M #"]F}QCMMͧDUE͒ v/J|cO>|b7 Pw cq `sNIQ#(ĜvXeK ' `#'HE_2oP党j}ZUܶҐR! {!EPpF0xC#•T隋eүs-DbT59 *$THH-KSh`B #p{uw;p9O`u'w!?  U8&܇uuNkUZ},SE 3 ;ʂUU#o)3r?t,Rʄkpr* uKjkimBSN9FYBP1sے;{a ВPK1"ķV.~( VbGRw#r⭿;%ZE\N]7Nڱ':gRMp(0rbg8V8>I<@ $+O9驅4HB%r(+O83) DҔ  zb(b$US lJ]bwgҢ*cpJAH'ghneXQC^sr^_Nj!G J!0'bRLq;u%y#G nRʐ'z6H hHNeDbP|#S cf AJ \&K_LHK2OAx N=B-mmHA3rq?.E|0'Oc#?,:i)d %EcY rϑP$2 Eh ~Vzke…k\ڿ{Eaj&Mv-{Z|Ti7% !Qˈ)Q^>)EP&^5Z#l ㌩џHiBG#e8THI{`(dJR_g9B*1b,:aɘ)+C*j,y38ȵci\N՗VB{e*Hk9Z 'a؎!ZwRK6T s IT8B8Kb#Xi%c}{u %X$IJ p$|1D>">+shwƎץ#?45pB’?ei*7 ')_bNDIak 1?dUV'㮚bۓiX@?pkd¢y˟ q>g1-r9;[LlIٕ!-6'|2rpzYJc`ZEvS+& +K8aO:l[ٱ :q膇OMdi] RwEJejyI[0u*wBp!呓O֋wPp3IQ-} pqsK(ܓTGa&]jQe|dTj JN\l( h8Ejz.L+_v\dɃV*qp|JKK$c J'ಅ]]-SNv=~SͭPO8#:FiPJ.pfS *Nv1H, ڿXR7?qc9r\M]MjR"+ϲ8)q`Hӯ Oi>,};Нtj@d6A9=<ƃ!D$)~l7!"u$(QWjj|F-#LIzOjJ1 <ׄMrKHݵ%) ujs$>MKj%_us9*-GA5@Ͽ9X}gT(KW$4M[&#/'(zuCm do(@#Z}>!)(tƽΧ[UqiΔvE%gRHc"Eoc}nLIZFEޢN\0XH@6}c( JS6~%D#??̍~m you6TzjRSBs{_yb}Q vc!f>V|Rt@*W=`Wۿᩙ fMA)R׍O i zUبmPEM2R:▕D*$2`*>awXHq Y!ƛ[5j?mၠQ+$+ˑ) 7N0{wGi{Aj?NS [3KR cH; T־M|$ٮJ*xԊ[W.3݊NP9?E1-e~4E\$~$$`( *J6\;bYϗLBͯDI 4Im 7ݱ/;-.%NAH))WKrW9J4e^ƣJuˊkE7eIӆ*䊊w!:!Wï yȎ"W5g7Fy@Y[Cd*FZuF~&MˬZ:N֭6ާٚ?e8QH(Rhl䫆mr$KSRpU8C :^) {™Oa$UZ'A\^{%]..!T,[=[9<~}e;G"Jc1!BTҺw$ռyb@%,L"_Q-\x50A;uEN^$lム@^Z FSAUa(m_)00=w>NVs2@At \o480`_SG 6_67M5'@Px==dg#{שE>)⥀/a`5w O#3J(/N^`($|v5DA0T .|7 @(rSwo[_۠Q%G󢾌:PHݧ(sgOu6ښ[nI#TqˉI)A;Rc8MOQߒ$8A< q{0ݒHd=f:RR,iaԭҨ#Ca`n9N1=*+NE"- ~ؕ,OuVI=,+*)C)# ?E``Nz]mJRT@) }E[;8!KK {KRV,Q)R%)14ri>_!NCT[ki/n0#X8+Q^y*'R^Y!Ʃ6c+- \(q ^szJA9>m)-g v'kd#pIJ#p~x(8H` >ȹqQy=);Mk冸/xNܾI+Z?en-#O Cd[MRVpA,{%*PpB+>)i< ۞T` Rlwq=J% N!MGx 4J0PWqopDBu녇XYMR{5O[,gB!7"lʫ֤Fe$zSeS-yRPPP{ Wo$9w ~DԾApl3+-t#J&ol .Kr$EJ݁]$#zjpӄ$% Cć#EA.;*ngv 0rp[u*N tdNR ÛA>X$gւGjyFOJABjz_z㩚OۇLqF؆zׯ'{"SI rVc5"\m OHSUNʃ-dВM-(.ɪGb SBҠ8D~.慐.m\V5EmZ@V#mNxJT-|?g3,)jSeda1ղ7~j*ݪS>ԯS۫hX ?>Rԅ*ETxIiի$ ~ӟ #n_ ~cϧJ`+$h8qT:⶟F"[R&S)f$:m?qrk݁8B[@_gѼ,w( 2ـUF69W4te1 H4$S˚ciGّT dž .:*VFS$8{K! v #^9V<{xod `Ȯݰ)iMʵ[ySx\*~}~8ԙ}mKHw%BXR}#NxmnHޤKK5XSk@o X*.gRPmZ>L,$YvR Ocx?fA :jqi?6^ p2S7ENԴW R#ZO% |8'=óW1tW/ZbH[A/.B2TzvȊˋ-vʃ= ڐɛO0=VWOoLX|$$9b(!|oOL;T$ s AC\+"Ma/yPCRt%iRqвIpTA;&LSDCY@QV\{TbaR8g]ZIP`4MZy,-IFŕ+鷘>x7ӊ%pJ2I!y8eupeJhq&QZ\w=1V 9@zT3jmC[ .wUT۪)ZRBG K"Y8؇mtNV ,hH]=o@ZhQiQj-^Ħ|*V*^+u* H6ʼ(ExZ1uَǣ4į1@.-b_ҁh)nyN(:fRby}MVy'%X$}: Lea)CB[ۂ2Z&>7AHcI$QQ/SSslU*U^Z Xi` !4~0/HvqxeX|2T9O=?RGiMI 'vx ;*:(j/LjKqzyH9[iC\ iuB兾η:K)܀6iiE[pOeQ:{Δ7b/:wMu- Kh,tK3f$e~"sR|s-3ؚ- )S;€4r-]B5JEN\s]fLM:U[W$eցpe8ӋFѮOTZ-Fv${Gl[t’DT#I:a.KaAK[!P\m!;>]Z@uj5AzZuBEZ쩸}+[q+ZXaJltWq*1YqFYeU(H@S~zGpȩ`&"Q gwfÜi!fǬ܌$L5\T wFi8 \Xn(?l*y<(%)2Td=eRۇUĤ׽HggyaRB]}Rxx9\lclN3S2c=yj xn)NK[n(>|ѲHTAݤ~yVﳝ@ZjДim&[9P %*x=z'Bht$slOו=,&B 0I9)8s.6!@#=Y<RJRP8QܞIpFe+-`bQ7rۿ0rzfmnn<Б<\qӡHBh J}zS~~X.{Q!PԄϦ\Ws R) A!mʆx >ykXJ`O#t.E8SB̥)=qMnwV (eo8HV|cvrJuF{+֠`d\+X ,N0 bH AXIV g9$\m  VFCHVs[9G @Rڻ™cM%%ID?.~g!jQ(ܭsFS#NcVqU6ύK)t۹mF~ROxd8TJ&mMv>mɭBIgMdi)5$$GX"quihMölj QEE@{p5-kx6(g|Ҡw`z9Vӷ8'6[- vGjBԤ(nK$%9 >Z?͝@jmUR۵G$RiO[F]61yi(tUFc ˜VUJ4E=֪j: q\Ӟ0eViwÃZDHb-#o^yժn D 1YlZ1vJu*ԊiFYx&P"8et$PYB.~}.yM$ u[]B)<nKDꗷ8iJҀ;-D19= J[mC(!K?zN%A@6VsUɯ)"#nTCeEbʸЏxbڗiSj!H,prSgf}’Hq+ #!YztqP,p6:=_XCuw%j )N\$  cVTUzg3&[6P̣rS a,+z)7:GZ眊j#6]5,<7xG%lwGTPҠU)b M*f@!X*t,P 򑑎zt[2 VԻ AXb+ZԗWXnÉ"^)%8.hJ$*n )XcA7L.JhtzQQr&V ⒪O6C3+ Ћjmpԛr%ɫ\̙ D`S+ub% I/3+ ['EQPyh! w^<ԧY󎜟wS5OJt@MeeJp=wCj 9"UL$˺J%VDj;B'(K(@TVAɫ0K91+ jJV$)F {PY|"gS|C7C<%= r߭kʌ%TP{fSF}8ƘCxjN!v1qxgiψx R[F5)ξč0f+LVқp.Hr=Pԇ[P^#6~d@п˳&8&LJU!2'$v}iؓtMF\ˍ*НO,*R]Dm0R봪kPn%FRmT LSPBң VP454%C0BjJhRk V!R* ș-8d=2kK%mRQI[t>;2;eڤYNh~-U zg7;iG <c NЅK6]VdQjky2Xbnt&c:"-A)}*B'"NR+FZC%p|J)=z@Z@`I5ڦÆv 0LGh"DBtn}\[hR*Wn"!U1iL.I^R A g4Ԅטe B\q:<22@V3}܆2[2|8BxqFJv;`z^( }ʀZKR2';3ߞ䉍)i-9.FLͯXP &լތNQ֠V$@؂saࡶ\eH zx%D?ν kuĀ]'vS2qo~OT%FDQB䆠Ɣ%ؒR\y"RrI*$' pIO$}3tu&Q2BAJWϤg={.(%{R}9)ح:iTTӄHngzvVja+E[HAkoզ!(DJHJ@j󆺨3FVRIP=#ꕦZ*= ) UCHR[m+Z nkOT56!)6!ڒ%% H>7Nu}kP&fǖJu:A7( ޔGT5ƘmBm *qI cov'x j7^wQ\ OPSq:}^<ҟ7-uӡmU =%O%oJrTT&ۗ5b2+>ˑcII hу0Q@1/ e)&mDneJA)pimĈW\d&WEDxsG{(!$wae eTu M@4z:~(.%Wb]ii4W_T y58ԇ7{)C.]R0OAԏMӅMDfbl/9eZYRţPt32< n(4hѤ߆w2g8.>YPrj|/ئHWO U6w kn( )ܡm2z@%jA^AG%!Y zLj@ חY*** ? }y0h.5ZuJK:U\rܩ_Rg|<S| Hmi)z.;khpgfZdyhKL[ %jaBIAXݙ)J>,̉NdڜKoQ_f7K\PLR/u:Eru1*; q+Pi2YjBJp]q3!zyiX'ˤ<(0""BPH$9)5KK i0E B(&/1qUMv"e)wDM)VCJTp .$Ei-eeCw]-䆖) F pOqomãSwJiNmَِWn{n4 *2rmUREסȎ8)]&%>nz] çJM"}ғѩaQ!B˧mjn;Kqܔlt5UVܬW+UJw]smiT.6C1>ilOyiX/6Bxwl۪%ӨT !hX]6QN[`-pTh)H=\È\W™SZ:&q)ky^kA#+\QzNFL~DIJ-JQRԨhR3 9zcUQ&51J|>#uT$TKCQ|]SN>SV-n52[7*7mBRxT9\/nѩ͋S}v+2Eb"UZ=B ƤGn v\Ĵ. >6'>TC/=f^Mh ]ි0B1E2?Yo*6 %BdLJ~.'"ejF@ERaO{/B J@kޠ\9 \ZSW&$T뵉d%IV&RUoBU_STCS@*èg̐VRo^udVbjɽaH $ 5u:r8uHsgni=-+A/btu5Z"D3e ͭ%\nԹT9mq`ܟh`L8$ )@MAa* k\E'P!)&K7>*"R$2);Y*Z!RTnBr2OI+JVӴϐ7+=êPbszjUYpSzIV]M!STG%>T(-]Q}SPPަJJNDx ,^DD%cQ88 tT8%xR|!fm&*kQm쓗}I)ê% '`Q$gPpԦκ&ݮ7r*wXʤK\x-4d6Z< %,6V( ǘNT^I)PU\ =U:if4Pq)+ISj)SdڌJ!A(`N,*v=s J$ˆT5^ëinFEN7-cj|FR<ȒkRT7PxU)IHi_[ZB3R7«C}$4McNdą%wBj졄ǒvZW,)pʔoԇN=!%mE*RǬSZ/L4@v=QJ@H2<ũԄ )FRJҸjÊ`z*z"*Qը0fz@eA*+iڒĥAJ{ Cү!&Db8 RmK;PPxؔ3SRm\}n :T2;!;lp!aJJ_}Vܚ4S]K]SәRwlJspNԧA43FGRSBf$BSB -zލ;2 IC4 TT$\@;V}Y#q]<spQr]iZ8Vzp NTVV G*CG5Ai@zYP9V9s#&_c@܀f-gp~FgbC¶\'eMp!J A.6AhA`-ҳI*HGs$e_) m~`I6c~3E{HR7$<2) [z+C #NmÅ)kK)*NGz;5s7(sZJܧ-,˜$æ.̚/ۅN8U8Kc'pὸ$;idKJ$BR\M!Iq*%(R A"-.oQK7.T_ Db/.ZM~+_nB˴m^6ج^V۵9r"[]Rydl_u)b> T?{U z[H4d7M6eOy*ƴSU"ʗrԪzזԚLMIMV4Ŷrvk%t}!<4Y2FWneJy޵y7~mPOЩ48\p~-|9/%?N,rֵ֨ŭ5^wZF֪'aʬ.<%{=G!.$iEI mLB]Nx&{$(X07(P:t7u.ۚA}?m9z ԍ\[M\o;N6꟤.2-*ebZIz6ơCuv4=8ضjץfBLգީA赶JHndGԿsL4k7%<+NfokU+5&kDhIԥ[GPfZ_hA#P4/KКطM"6M욵& STvħ<." ~E=4GR(c%£Lx(&;`$ 8lH*H R@ ECfujڵ~#4Y]8WSdVMcW5AOЫV2L uןM*-emO ۳G5 FCm8~E>bՠTc*nE!(mE sĤ%Жw~$N.H}@emix34Et*Tēa5\SWCVGYiQkZ2ۑ|3KV)?qƞ 2])QXq5IC ѵ}dsvu\0-hJRB,KxVD,LYnnRZo_v샵eʔ-7!J yIHڬF,6p#$^Z>DvTL矐І a>`VFr7dM1C*ZRVҮ P39LF*ԩTQ#ʴsBL&(+j_B ?+P%C*c9Qz2cɖ۲P/).2S%miVG@!kx-.x-M4G;wuo*tIkkқINTӧVƩTc$csS}ﺋ2c2VT(VT9*m />֍@ߥ tur|xUUySp]jθQB!\KJT*MG;) E+[)؂qp+ %tjQ5n}Q^Uo'f*%^TnaVKV;*5dEj߱D)ׅ?zŨvK- [ .a]WVHӵ_JeibѶ7.ӭLST˯f[O_]jׯD:nٗ[&Ƥ[7E&Pk:`UH:Q\rR4xl5=\CD]gVO-HpYKi[%Hi#0`6 <ӁU) Sn[ -)hN`tkCy6jSvІFЖH lzRw`އ&3n0YvB Ly -Gn%JA8g`jlmj}s 1P`@--!*P< J2A8^k1W-HiǘǓK %~l\ -K 0<{3yVĴ)&. )t+gFpo*M q.KDdN1jRWO6^mK!ǘQ J8R*R }*CH:UQÇ.ˊ)-4#nT8JR`9ۻ)n[ #( d‰X qWAI'DYuiSח(GIrCu<K}RS$]#TRZ›:c7d6rBNTPS N4̞d0-B].[R tMBxy8 mjPS\iI$FضBm6"D.Ɔ<X-*}_ ߱dyVI)8WQ vS}ŭ-O% B\k$\o;5W=Z3-4w^OgR$JY4:9n9*B\c%9a'nw5%RLk7<\0,yMMy+QԘ(CU\4gXfL\dPu쬮$̽.!|l7"CtTɎۏl+R#N*O'A)/ ;(tp؎ts9يCZyU@Be\ڛz]J!܍G\2,9-\e*TH RN]ӻ>㬩j֕ oTPU) A \ -3JBk|y*&yC+$=4N/." ÑwK?"˖9g.OZҭm  c8eFƊjtHy_o$zLG# BO=IF]/;>ERHL^˯ pķ:`#g9跦ŏ5Kܜ&δ qw9I@=} g}mOP _J PP;pwǙpf"r!!)[j.Mvm ҕOë*185%/ n-MA_4LPSvcj.a˕eԥ2Tq㥥|d&Jckv+pig|mr9zGdœCz#j7mFPkyd)/ G;91$*DXrp78 FˣÇ*cZI,Ik}Aza) ,6O}%*A*9)9xN~h[aoLT)F."]{[Jӷ'$OZ2*.GeIlw-IAҰ b/í qQ۵d;jSo+bE/kFe&qZ&c5fl)Jt[T*4L9mW5^J#T_(hH! V-R RRYޫ}7/Oe3QW?V'J1Y`zUVQ.?jkWE~m2Hq(9UC)X2l5Am\;`PhJj/KJJ[!Ij>申 HOꃄ&Dr{Le-lr:iq) RmQ,iyMj:N8[yKiNH)Ӵ'>N=j z`/kN[X y03G낫[[r,uW$ӎx{p:3iR֍ ;$ i4%>ϫPPrK=O TjЃ%iHe[VR[R_;gW e!\ A\8s~Ӟ[kmKpIe%XڷTwe98tp/2|т)JCA9**' r=|;W+ EĪ TZ=8#iF"*B8 g(MOkT_jBrd"4WKZH D8H+ Ei!(C)8B[#KWLZS۹oqzj x+uZWîGѫ|ey;2VI%Nq_u*=BM6ԴVc2Ժy. ybFxQ!i½w%u&J! QU#p1P1;]a+ݫvWe]1/IJ6am%)m1aK$`ȒI!1ʢ) *Z) %M&J W-M(ޜ5WO˷Ne)wEivZYyrS,p4+jA!Q>-gRt{Q45?FT뱭ʤ:]ia!M[M RyY򲹥B\$R"')e*w-I팬Dj4B?4=Xөk.ȉ6eȩ,3њ~ 79JR!J܀$$KsUktll)ҧ -n}Ie F⑎vܐU!N&QZDwʖJiC:IG#&W&4RF-JO)'ʁ*ǹ̦70Z0 `iR,Io\RH߇ N"&3(hynek>vE|ܺgV^1HԧH*(J^xڣb1zRYqkL&RIQsQ#$94j5Uk+u=XFs7dd$%吅"A:JH, kΑ73ee?SԊxrI~w<Nn.jDYkLPӏ1:C[ph(`7vIx qawtx$n>qIH'JmszpeW,vT❒Mi;>JׄO?Zqiе_EgeX'=S[~#(qa[>1effbbPb%*I-$RXP0rJj4RBpغt5Q6#8^C~ dmަ >{`ּ5BK!JB>Qi[HBCm$`)` u#+.Fҭ_\t̘>ƹԵ"nz}$|L4\nsaH(U0TBzrP΢YwpJWmAť-OKjC'i"^VvP%@(bxaw6иTb!_břj 3PQ|W?VZSKRrH0R8W|ןlf;,yj*˭B˃h+*XV9Y*Uhǿ+&l_|9f]Xa~I_U#;NsюTAkU{u==6pϸ)O%+f}TМxprȅ/J,H ,X35Jm*W%PێCd8qj3 (Qq-$${>O-![ŅïaKPJ~$)ҞsZL~U  P̀3cHlq5岀I$JRRJNzƲ.d(Pí c>:eiD(*Qԕˊv~k5QBY`]؇ƍJ˱1^*d4ڿ*bK '9j25n$IG[m:FXqE ?IiUHq m|d)J!99 @V] d9埾R W{:k!HL( < a@Kչ^iu)ДҮp_]q+m <"8#hu-l22g]R!0 @AKEcvop_ޟxSkmVƬöUۅs?E*MJ4y`M;w>FOZT'j~@۔pka7 !&#nCI-$Y(q^XI*ZNRP%!Y!=; o-@Jp<_S͔r:O׆]mѫ+Źi鯈@EZ/{]3$[/2R4{zǫD!L*bdypC|h5bm )RłJ!ciHVOlځMQ~|*qf/GDq)BUVTSIl#$DPŝ[&=Ja1"§bH>+PP&TsVhLui1q!6[K\eíJy֛ 9/9Mڦ·6(1ZUI!xˣƷR׋[Gh- zޛ'StUIm.4⤫[R)/ٗ9$ŵ6S B܉ >>Z4J6[*B!McTJsAh !!4`ŽƍJݟe9)b\r۵o~m-iԔ=qΝVF^~[(R}dl)cWUa*gQ.$%e(!3ִHt.IW.LVb>Ӓvϰ?3Ny`DʋjS %*RH€RU_7) 4m6]D̨ h]o j tĄgXQ[nnU!G-f3F,"D(>s3Eǧ[ޟ";.5|zrV}]tqG4\5KK7fZjrvMkZAn\f]J9'}K׍`*зt@?Ueҋ2 YINM ܤQJHk$zR}iˊg RK#Aj|T`%$0*{?$~ZҗRzDf^RDz)YRC$t Vn+E"P8#OcWYԪ3gqo?%9!: N{_"] iyؚΦ-Ub[D+ZdHӔdg`{3-)/5s𐴼S Ѐjt91j$$:YkW6$&E{y -kHVUpJ{ rT3n%Qj]$ԣ̧-Q\9>?0:o!.HRS_#uuǀ;9;ˆWI[޽nG)r]\^Zx;NJ^Z/ @$lWFr/ i!QXҵ N{frf"% NR%Adjtسb0ïujq aV+6M!'r{(r[6˸"Tf3f ˧4dy T4Hd4SBVBOFYP*mL6(JWmuCOS_(3_ e0 BU%A(YO 1*BA!4D,QUejcFiDɏ i!` |)*څuWz[[5% /nމ%.E+n¡ó+rrۖhG7QLDxtO1"sM1@<#2aiZR^ H!¶ӝJR@#X*N %IGP})]a]DwQ/:m{uKI=b-2-BCaEmӫ*BPT %[PHG$fP&,01G?]߭*ÔTa`Dq.:SKitI(RVUSJ9' 7ekێJBRdrG˷KTA#p~\R;eB8;;\ %§;׿Oj%Kpa xČXw9#,?њ5ߍ,=)^ZćkVdz <ԳBec`68=<]v0 \Qӭv,t1_YN߇7pHrVbC$ s<{\[ﶥ!@zrqۮers\ U<r@O7m88ldwt wlU@,hE ,*@v[s6FJc$J!J#$dDLh̺$TaDR1 ˈV[$p8.*\P  *mB':o,Ci(9$-=[*{tk&EDȋ K;G,(=co޶ڵRiهݧHebP4͊m-[)ܤXzOHgiYR\讙M>Cg PI!ҒyNPAUlTD mn)ne%:0֥(!,H}s\v  ~aedF!,6Z\;W:6) *ugߛaKҴSHuvoը391ic;ÑiP?Ua 2h)Gj^:jZSL[xm6-kkWQ,IEEvYOe*BqJd|2lzk6MmRfPna֒OS%Ą#|!:ru3TMÕL>|(D}mjhO[9M v>,Ujd.,ESEATu[צ #2CS!!fmK$0cݭyxҋңEc:tnmu50OW)m."4 -+Kj.Yim7N_73V]-acY*qnkز}Ia.)iVўJwTf+4ssFy`$@1L/`3cR&2e,8ȾuN5Mjw0ZsR>% Y8[Jg%BҲ6rCD14 x0Rң~M,Căf_0,oW&!qr2ڃjZz| >:2.,W4a iImLzi}^Θaj]6Rz)z5J$% wKL:r ceL(JA+>Ӑ"|aćש hT3;A31 Y[ DhHj:n~D^n HZiQFR7`) Ju9v(~IRK@V Y(!FZRҢjZŽ(7 z 4V-QZ6:lTdTcĉ ϝKjT7J^v3hzdω'Rk+ֻӬiۏJˋN44ׯ6TXT1gAjt SLVN]u&*qoӭ(Rv{m D ͹$>7-ֈQkZk.N ;D.)*h# 50)=m #J@SjB"s7Rt`>I-UC0xT j&$bX ,0Q9Xn_7ym%NyѤRGŜ9 Q%HڥYy*|C|fDŽ܁1iB@VWƿ-ɄSiχzlgqj˘TJRJ(:5N2:]h UU^3y5js70\%;c4!_JBPYui}Q*@3ܜ&$Jt%/%s BU+=H>7PzYLb! Bz I,㓃KH6Ly>.#MBYu[@2ڳZt LmS9+trU^ cR3sH@=SщqZִ?Bt'9G@CL+#R8U ʜ \Jx^P2ᎄ!mRO;W(Ǩ &q.ZEB/) >P6I! -8TSڬӻ~sxK2NFUՂHug;{xRQ,8vYD~s9"!֛ZŠRXC*Q@KJ }8Nâ]O~C&k-˚9QRʊHVF7:;UH A 5R-J[\%Jڲb%1Q)sZ˛Fٱ\) A@9q9%-q֦^PÌ-d g{tCgm7%(2{Fwx=XvD;ROABxm1[$! q!D: 9''=Ot3oݮW_ul Y$SiܕwJWTULHcE - ׫#_.34NYIS Cf.E|uXG]M,֩v:vzLō/ Ԓ!A F[ȶjC?qe!*)R(1%#_ yE2OXQ8Pܣt֞MB»Q&ŋ^Ƒ8S''i)QPYȎ-m[+zuWnLRi*o"BeS%y2jJZZRX!a=!:C5U"jLi-KB?S [R#i>1 @ŒS *I) 5RCOvŘѡ\0RX=NĆm1OC㨟9".S>[MCD@$_r !1*dE%% +=!zUAjSWkc))m2K ?Z^}M.0ao! COŒڞ1(ҢS jDCPC!ޕ=E^e \Tp"*^5ij\}nTf{HVZېT*ZH”`ֿԲU.aK!#ߤ6xC`!9 H N^wSX}+aAQsRʊ}@r$"4_C HPٜn †N~]ir,zU WP)'#o'@UMqx Yp(:( J1yS х ڒSn)'; =Byq> pci<ߑTiH\p$%dq~}$hF, Aխ)T$[ԃV<_:# r+A`dv}H1$yz5Nl߀:ڵBq*5 \sn 2}#RHFEi$-nE=<`աc*?G6-CjPTQ$BNFF׮Y(&L}R Ku@' y<{ҫxot̻#pFP [p Bm[‰ Y)'<onU/GX+ I[9lz|ZD,a^7yIq -ŝ .<Mp >'amF{n/o\x=qHϰ県Zpʢ>n[N5gOw)O(F-:-RrRC.4o2:CiX?둘)cRX)J,/}xH$=`޸xCT.6եI#t- Y4tVϬ|[)!rb4t%=9 ; ][۫i%ʣPt[nZj%2)bNNbE5O6U\Mѽ:{[E"{b*TV.΅nu P7RiGv:Wn_'9,fbZ uTT6ljZT &(!9)܃}0h!&n5R6}zMyJi5ZF]JUn߷_D T:c PRomD+Eآ=S5vݵpNZdMNđZ\[MתutR!Ov$c!Jmf%Y1@Н3?yj{j>e\Fٍ"rFj }%H16 #vf :/:Sj[֋~ǣ5~VNaPhnB\W-طa32%J7Ogd j$R@p&6+I#HzknR)UVuM_[Jԙֻ)r(]R)^l~2RǠnJAv>%h֬L,y\'H_*ehE ʵ2J.V|\Q5nnߦhɏdY/V(R:WşL-.BU=Z"*SpIjB*^򟐊txiYKMA%?]򢜑ckZ O,Z̪CbSQGr8zK{y>뜙gR蒤7yA+h8 Т jE^|YseL2ˎGn7l%KROm'K#L3z]t:)i$(T8sKj$*I4"/) [*pn`g8^F-PI:X1&?>q N. v !^T_vj|פ6,M. ^PjχTSH&ҵ|-kEbaT[BMuMhTkr\öZJm~M-FS!v\˩,2N!S!3ȻmYՏZTbꕽh{5r[CQ.VWKlQS;sKi2!b,Hю^:,7E*24,wnʶݨq^bꕫƥy?!mmNjHE*NvgJZ P{bL˹o8Tn,%?oo ө.yЮ@}RimO9F.sժuvT [˪ ٌbs<Ӽ.}8n]I*OsS46}cj *`xם>b< -]:ҖɓkUzzb2n6xl'J:+Y~U/K^tb(֘SlmnB~EJ}BuMըUQLq3HDJ2 b|mNq p(7~-ŏERT. #S܁k5|Wl[uLӍjY #VmIn"rQ:C'5]J2G4:.=[gN ٢ɭzr*p=RiM.6u&)̽&=O>hQC\|O>:ΌjwzzM+mƔieOѨD]]Zdמ^眶دL㲕q\M(GG8BBRFd")Hgg, .is!H.K@ q2 `8Z.F !(%@PVēx'N񼪵܈MCQVAZρJʖ6. nhޒ1Ը̡6a);Î׻/;ItۦE2c!1ʒْ /3;Zd+#TeҒ~ ۀ/zW( *X#چ@\ip7'+ֽzZ-l]7viXM^ۖFP(;)m1)R$y2[dϋZKHnO / .|vѭ~\"tI3b)uZ}V_,xWC3J"-C<^xzՋ|tQ H]pRݭržΩS-HU{exgtQ ɻuH/n{+/>:(ZeCz?켾9g[GV!EJhӕw.|Hj[De;BRZ4 )nq ޯlB-{"l/exiskQvӔݩ/sM)긭zUB3cDBݟg[g}ܱn;{Z5WOt=~Z=E\W|\3NVrӋ2f!IjY>ɽp-<>^'*iu6[P4kQowVA4.TiL6PmQim Tk32?m? QLaaxzk6zٺj5PY4j߭eӴfk5d4*EWaWQbCAPjrko|0|@V4~i6%~^隙a_Ylf,CUZ;L/fT5,6%2ڒdFyUDȎSZ/bsާ*/րH6d,&T؝lЭF;C#@9|AGӻI2vMZ V5˯ZSEfv\))+m{ #Ɖ NBnUAڻ$4ˀ!zG6PwyBU@bEu X;9 _mߦW=FgbCIr> 1\RY\dy a;φKn>9OyC v=jh+af|h-8A*BsG<e^ԷdԷVOҔЬsץh !'pMޕ'vS4A`C:w-%HQʓzj%-.jN3mB h-Y%i%Bϧr lŠjgƎ$#)kXHh%je@I*߁o;-t4];4Ɵ>dڨuKUgIZj\z5Qg[P!Eeiݔj OfJg؛Kt-cCU"%['ziRwCۻ_SE6Y.Zsb2bBT"X(Awv5Հ|L,0׬@If5>@m?FCG?"+j18cG@ITƒVbU:leM>s%.5-^'kkw#8LJe@nkfuqn9imK>1:e} iќP[v]MPcIM}fR59ovg.SL2#y [o𪘙roR ),@ml JH!*~\{zSm1ꍟ1RiE /L7R >!lx?R$&d7ꝌjkPZSR} 'U(e R\IZZA$d+]7T*ewJiROImŬ$rC'I/E)h.J Q~6`,6W$RU\ogNRHD6KNYi>q@9l: [k) Jw/yunެprv`4[6+uIn+c$iVa9=j&,mĂOڛKum@>0OӶ20,jR;ذƥ8%)TID5pRٰYqZ+Gn%i I8$sInNm)) >iDq2iMqTIQpH;E( =2]1> קhoVC%'fw`Hgi&!̘PVW ]V I` (YmP*R?p2j1ziZBtO6M` cח?Q,֏ss?q/Sjpt`vu`*3r@{Z Z+ oX߻6XFwl}?/)ڝܵNw~70RҨaRg @B I, ?sW¿PCf<Jr) O DZwj:VB7g i8<܎>t+RFJd6FA(I? y=5Pn2֤-N B#hv).9?t'DE)$r.:`6s"`a5wf#ڬc>Ҝ)R8V 2x[w ["04RZJPB䧞s%*\WmyGXN$>'!-: K6,²A?^F yT2T0jC[v/JcRh$ҢF9;1ϝ427UCFER!-y/Ö+m4Ĕ8d! $d~iQyhTd@:DY.(. 1Dxi 41Ahqu6ɈF26x]ʂݗVuEEԁTXܡ#dXJMh,J$35:t| *X4-dMބqe6 6Y?U>SW),Vy.%r\Rt%;VL' #:BFTl:SL򩐔;^|'pK 弞WN֏DIjAr asyP-*jKj=̙:CN.}JG)8ϥ/s;Q2RÎU9_Vk+.5 CNNO8XhqqRAqzU* z:rώu꓅R>~PlwYVM1%%-(!w2J@ Z yⴼUI Z8! V|ePɩ1oEZu!.#iZB)o|Kq%Q\!In_KJ/L@*B6%>Y63ӌ%q& Ty-M-{9ZZ @y ηw9O=1[ >eI \vTίr lW2CZXnn_9HZF5R> F.MSۍQ&}NBz2Lo_yrTs=+uvLgM2lY7 dT2֛Ti;`DT-_1tĘoSq\m@-8x'U!My4U捁َ\le%q goّJKԄtA͛SL9{rDdN54! 3!=3oy =QYBZ X^!p i;Zt@C., zNAHћ_~?VZZ!n6˅+QJn #BTQN'W2H>-Hsl9럳uClJE657.p+."@OW GRӢHh*}$EjZR\*!RJL5-8\TH+B9Jҗz_ !i%x U!躧kWFzSg6Qߙ0RHr#0%$7Rmyb_fdB\'JYH\aqK:1_>1Ԑ_[͸#ҥ!_u$vtFRXVCJ_; cJI89yR#(Z"[( TP1#P3fԊ4눇Qi/.-ȨI%%.%,09I ~b))-<aI}ϷFt[XD#F+.+'r+)( p=KJ%YR[5ĨM=-mc*m, Hy,c D5$j*+ B֕@;>r½ip,B}䜡AiNrp $qs TRdA8=9Gf5=4Z@K/.qÈKd`[p2IsPrJ [  u# lqסHʮ!)v1 7ߣm ffa+T2A5P4$VO0"!bH$Ո݋ZK,kuJB<`yzU-kU c1$He!G$$,$'qi\$ŹuQVw5DnjYaݎ`C)Bb1pJI߬< :8s\K*PBC4*m)SjT4=WQ*iS!HMƴtgA̘PST3X㬌cDzFꔷ`jv }䩊?ڔvo8B-BJIQt2&GŕFvW0X0Tc{`,f$H31Re%Ħ 5[ -МNëZyJ~)8LDG)k-گ)qZUWJ!R fKs)Z%M!Duki&Zd_YK2ʒڀT-@JRԼ68]}Z.yGKg KR݄C%)@$nYFҒjQ!sAլ9|n${K1 KPP)Ăq986vjpU-6-j^~nj2+jf]J׺+TR#dsjdWq)$g!{Lie\ YWJ~}RpknʗZ,ɨ*) OYJ ئ4z͸|3J5iNf;GPi$ 4qvoܥ QS0ǚBJpsjA쬰Z,l:@bޔf}E1Z9KW ՝]&%E9l8⫌6dŇ$ܤlXhZ mxkˤr=-O'SW%r+ԕJ୵ )Kr1-%VB7qHұAҫ!*v(dUHiNCO섵gւyNJ&,=0LE4K*l~M Bbowgvۚ` Rsp1*,< ) M@ZVTQg&NCrWwgܷ=^*0iYn$mu*%@2 F8~j^f:]E` nڜp'-1+"G¢@.eT)nF+[qm.) {-ɇ |WT7Iߐ }:.齴:礡w BTv#C7bv\ $(%#%;@،>]xiXN%JaFz]gvČ%JH*Po gp3e  ZJܻh ܅?vyz)bوEBO#M?ۯ-%Z}-n^vanʀ9 Seejnѓt: $ օe)#w`Y_M597mG4H߼~rcju᝵Y%?Lx s4>QH݈AO=rmW Yg◵i 9p(q1W.00(iIJԀ)@hzr?5TKͩ9*RQ cR[7=Iq/:SVdi-ehgiF<;6ęcl p/*RR *`r9GZrP&] PQ g6v.+kԴUAWn+{?<½]-5ůX-ߵ.*}IF~q!%lycIk}*ʎ66[ȱ:uU_r=bԛrj5j_{ gŚn2)*Dv${Z_]ݰ--ө,&J*,SmIRe/p2q*nOF_nTJ=^Wrܧ rT(?A6iNJS?%Ԁ%! .kvk7'%s!-%3^,]ÇSV 06N4%‰,Rj \}~Pm7 =^wnHbB%hj5FM &}:[{ 'JDIPA=4]z)zc5VihD*v땛%V[.8KHeC(v*H PO@_ԛ^EN;)/Պ+&Z2ST麂EY+4²78(ke]qj}\u FtɹsI$0%G<4 ` }3D"KOCQr"$&;`GXi_B .R Jh[KnǝR+ֹp]8IIKyJ jZa 8RcrrxGIc a<]ű:mZ$sМ$™u>c.[$eላ}KjRvq׭&S@4+(Qւ1bE 5 @k{M!?G-eSxCa$*)F;ONcI:UaU+5>TWQ)n])nb57&ޠ˯dr^1꟪!&9 ܥ4 թ:n-||渎:9Kp>' qSV[U(UzmW"-.lVgCy;J擲Q$C"CXR@ IjSdI>@"I% Y >JcNNjϋ)rMe7*ZTUBq- 躞9U{bܶe~ߩI EfNn5eR?d.ڍEڄ❒AinLIH~NgՏIOVQZArC6ޠjPB&cݷ*+QWECj#Í)J~z5Of}/DHY !-̪iY CA j1* z?&Ȗ%2rʽbij`v &h1Em/,+}ߌJ ħҕ5KN{ZxmuZuU-jɒt6qKRl)oWڕLԹzAR،%ɪ]FsIMMWRaU2!ǒ YR?hKsLmm 6^ѫ%fU!Si?AZL-hW⹟exW C()v*jAs~ҵE0CHQ,-~hYÔԭ J=.eӿO.*Ъ)hKHvZ3&sSRNIF$S~ a= !JA sr0|+'T5 &mU[ߎK6v\*ERk)Mp:CqHD@SFl;}D 破)CQ[O>،cʃ)Y”W KiV}6*С %Ғ+G1Z9bs$&JIhEaaiz*VJ%cIA>+{CHqhl}&(/kk --Da?C-N4Ժ,mKK)a%N-/(yB#9Z(`t 5&Rt-aض/5d4aF@Xqi8I#q1;%E'-$qR(e34 XaO7ҩ֍J՝iZ.ZeOHi3)-4In:|y@dq-q) 8^$HI(E~h(q e^UcnҪ?Gv )%Hg16T%!d)j}ڜ7þ-D)>56.zMY,ӭBUUAqV }EtK(9꣺_ޕ*iFMkXS[QtʧӪ7E>QfU)LңRy͕1.LWejHJEp-ռS(2&#ﶇ JChR 'r,OzrΠQ Tdq>+ d%)?VT O¨,ٟcX%sHearC+#K8AI Y%OVـ܂ ,vçhn!~fj.dvt:z@nSٰۯս9yuĩ)DޟVnb3biϗ*+ѧ."hU-zRRɬڠ@jِ&#P"UU*J-^B!TYV:&c]k;U!q_[e%:\yEǁ.;kB%s#Hb iQI)r X; ,9CJ)zsRx]FvVٴ(w-:]:Yԗ\rR܅ZLKkF:HG^QYyr"G ˉ <~G[r!)fj; jR-BP HtSE>(l}lԴs9eN@ױ]eRYtQ&IU(䦲陕̅ Y PbGq~vb:WR );*eߕC-%.ŰњDztgjrj._~J 6AfV)QIey*Pi YJ aIJ k8HBTkUs[ct%Y.փ*(ϢKԪ]uHmtY^܄LJ4yX0I""A )J)bl1`tgQFqPG ޵`-vhi\q$舕 ,pGdA *: m!ɍY@9ʛAږw3lN5 ꓑSkmX[dC)SWi9. m d$2oPFF@!H=bBCeW;o.G&-QH`Hf /KRʔCmAx Y)8o=(ʙQի4Ρ|^TE\4l6U!1dNhJ+E*ےs0a4^=SB=;jh[ '#cB_C$3+TJf Y·}H4w$?"3 #Oo:5 6JFN e9ZĮ2:Tr7ofjbj)z7e5pMb>kVZghcWj}R.۶2ӬS#AP+^:ų/*/(g='-]׭Vj)BVn |kAe &=*q3r SLyVQ1Xs aJRq)F57H_m "!L -ЩRีyXR󯐥+ 8tԑ4AP,"Tx. jBJ]IUTɥYEG ]<l[[6%^Ѹ^6zzV(s55FbIrܳӋ@}tX6/9]jjK4mv}^Ë[96UjL,N5FuӧSJVF AWMqTÞk J&E[umFf"S."Ly.ʒYڕᝄ)u"_͗VøfO"dȘQ|-/e>vw=nBl(BTjH7\Fc,Pdb( *PB -F/3c!":a+qQ*|?))D!9!('m {vB/TVM124 I[a!=9³3<Οj=:hEIDIFyNR&ɬReyU'lq k*)/ۋu{[ZpN3׹B$҄5˘f֧c)&!sQ=jlkY(IEV$ǖb?X)h#pUЃ5d=HZ2#f|҂ :ZMZhvJڃN!]CITr}sUI.SR-$b11IW민(eiCJXJ۪RE)(D$`㨧 QH8m*ύ9Jb17n8JҔF:DrXy-6Х{mKc$d@!SV網DXtF!Lv(}ZW(3HERZBd{sFN]PHSWRcFkq,vw2Ub6`ع'#sb\T%e2@Z{iIiJP=TfS u3[NT|}hG[kVpKIl=uLЈJj)_ O'WnUyu5+e9vEFe$`gX;O/ЊP!(5UXTs)j# 4W;jY*ya/w?r2?<ub;a Jyg BQ)8d%C>r0?|ht톝}J{dLTGp63T$FZ-"ٻ\uNzJ*Γ"W*I˦L~bmVIWl%]RRQd LF%bGk_j6Td五gcdrTObIx=2.TR jRU(* q㢣cQ-Yr3=QT>J%jRJyA +uVk ~( NsF:7i2e %+R*U8$u^Et9P rv|;lXOoPF * vdO ?{A{cM:.8' .m(1ҟsC.D*` $(|>Y#l}l$ˈgډ-7W`wp1שͼ.ߡ#G ",$)bY.ߠɡ: |i&VZ.P=1 Ca ;r2A<zӤboĥ Q'J*gI۞ЇJKw`R}Tv0Fu˅&BVTd#;8'3W" ^gؚ\BIK|Js[CpGA(N 8}5IHC7rPڛBJvnI׬;)#.mW`I8==2MSY3$yj !aJq0ώR*0b5R]`NpbJxEtcOkҘG)#)FҒ!N+'*+ tjf1&N(P,-)ʷa!6ԊF%TB)=1!ý8m (*A ǿLQn/ԩT& M!%!R;Y!ܵ HJVj\h%M ыA^qb lz[ VxvÒGA0FUY[ym-M;vKMCnӪ)k;A^nJZzDG2Pj<5cSafiGԷj c۟g/CõSF.5qj~M@owj9fXEP7 R5-nRgȢJ-.3my쫲4K>:ۤVg9j]5r S֝ƵȵJVw_ˎ}>­k.Lw PJ\wGq:|z?v.:ՋVW-ڳHB^tȬ[IslKoxEY*j2\)פf3%+p"MCTy 4TmgcmЕ#s+v;*)Z;d54Ғhf6+N$F($(@3zusH%Ln}>`*2c[v%RK1ceRLh.Ҿe~էLDG^H2)jHvW%RPK.4ہnC@%i$0[Sӭ3rvڶ5kKO]zWn4t5TBn~56N!dc4s\.)B0wk |Yh%d*&P9xgm2I61F 7EtǒǑqMXQHa|Ԇ*%ZM:9E=t걚V6My4eEaԜ͟ #xZnho?D<5kܿ]:Y^ &UuIך>*{ ~MJHm*ddvxFxƑ} $9aZx#lEEbfb9yum[SŬգnΫԚ6f\ܠODfj(JԢ]Nf,,XMJC8ݫS|A 2I-;T]Ee"="-s&^d*FndG$.rkjgM=ʼnS_ z5&ՊV=El)4b+JV6te鮞x ]xhiev%N5[FXti2-j-NU[h%k&Uy'L<[_M, #N4Z5jChVvi[d^gT.ŋbNzEF>P0&sZg"DY %}&Ÿ]Dřᤛ k# D Lg5WIVԊ{B\6ya9eKrT(!Uj鹨Ժ̨_cseK HR')qҙ[nrO)z+D)D|F[} Ry޴jaK\\qǟqK k)NTA8ݴt)Ù"j(k[)FH.!5 Mw#cmE*S7yhn J*NpR:KuF_[j,JEUagp"2T ˕F܄Zr0TꔇKSM|=[,+K\NNR'.*K│E28CC,szxmj 2J轅lZ] Qiũ |6w!Jve*|@vi~Yk6e\ӫW^ڶ~r=Lm%jW\x8uJ"GdžOJ}go]KM{}_ ^->Ώ^*M~iviYb5JMUКrͿt@몴iӆa1gQuQ&M Bb $>,†Kq%WSYfcU>re2"iFT:]1LQPBe6j^%|PRC Z+e$+Kc-JRͩ;$nEwOo:56M1 fԺjSR~Dt;o96OJdGokN\uLJv݌ޅVFF}^3WVT.+bZC\.¯gKbJbw$bI-s֡\å" V;W 9S\~R"< Gm(ZfeNcHA򛐀SxN®:\ݳi22XصJ7),>BɭIqO\ƕ&cп Ϗ#{G-O6[ pj.fÙ"⃮U{n)le|hm4zMH-VTMR[XG JRkp%%YuӜv4F/J)V,SqG"DÎHk3B0+m /\Lj֝RTڦcJܦNRy4Ug3 6%Lwy, )D$g>.V'T-jeכÊHS0/*QRFO @ceC~;mŠGS/jH!'G2P6dS d$"aHG! 0Pk+ӪwKP3-8י2f#Kjmʊ6(ujl-zu:1oEp]K{r STdȌ 4a[n\R86m@BKT*mcqwjY⢸*\W>snLGQY7: >xBZ!  H7bũ^zj~,Lr{WF{tNJӁJUXGԗ8o< n]5HbKG!uIq!Coei2A[I*H$ԵZcτ-f'O//g.xS}5xJ\U-Zwe+p[ʡNn"\ץn?cτadhxw!ŖDVS›.ԏdv@TlhMq$*54V‘pKmܷ qH4TЖXR[*_HSKTXTxl[EuR!(ն^!ǖe-!GJH.SuD"Vi6ûtd)J2T7:Iv>ZZSbc>ȟ v\R >2iʵᲱvvFU:3̹mfEjuU2'.Dv#QP$sVz 12~17v&r%(KZjK{.v (jIc'NR,io?$:*Z񘞸wjN-Jm) ).Nʐ۫[RA "JZ/hٹҕ?g$w礣AgQR:veBY'P[iN̈́200GJu{|R’9crHǿ}ԹFH/2i)NZi더a vʒ 힜5Ķ[-+hd #70HV7<~H*S%3;N>ywrv)y򣁎ԴIJmDdܞUqLQbIJE)cGMo׍+S5?;nD;dcuJNU)Olvט22ƤY% S}`pz?>}Vʢ(WvCy~ũI@`zο*p$#Qj)},V1KJ@'rI8??~kA:VIogd ~Ҹep9=?zRۥ䔭#) )Y=cМٿJRWؚYJz)Jz9[ N⤥))BD(yt5Yķ52PdXr'#=<&+P I6l@ Gn>:R@`6N *Rs{&HA?vڰڝk}#6K%+:HmX.,);VSP㞘>FVؓ!Rq)  Nra\(0GNŞ'x(%d8 Rp9u${ߦ9lV_+hajQ̔8 O[\)hl )jrJem3%m_򽣕RW)ڇoLyvt=FƠRI3.qZVg>m. _jUUZ=Kmobж/|[22ٓ3Ə]ɵ)ʻs=qfdN!&{UYp7/m^s +'O޳dt77,2rYfQb|\LO7 =w0'аN|Ij~hrQhn KGoo^(mDeS)[m5Rk/M|Nx;]<=6;wWJj:7GkR=.,FSfݺ2:$\<4F[YK (}/iQBJ–PпR}3ԂuZRP{q<}L=TcZ×b _zmZ+qUڅ:y"L hҨԉ̰UTTiṟcCi im6 YJIl#$ 穨+uEN. ()vsюUf54xK*B3T{!*tpsSARƤ~#{ЇG"H o<<;-´Zpėyd+ K@PХCquuߥ>ި+)0˨CriƝ4)6"D[d:$7 *"2mʹXP vt)UQ-(5 . >PlÙ&L~jZCptvl܂(ɢb)g؊=)iiY5mI6/9oҼA Wʦif޶:-C][PR(t{n p΁ b_. #ή9!\ gKO{Q֮ŷVzF]"H.ӥ[oOB&TQ =_Jٶd.P]&+5g:u4$4Hk4.e8ݐ&1TTJ)2d$IXgjJbNhaML%HmHyKJ* *$0)w5`vp%BMb9zxR}Q_RE ⇤h8Nj+VٴP[T(wbpӤ#Dmg?ZAm>"uCX}8]"Eb bmv| bPn/д*e"xC]u7X]3'%̄뚳^*LK~E6PS;bKolZq -) %KZژvDu6!ҕ2Hlx{;"I$9;VT9z>g\Ną-lS^_^dzHjfŔzJNFhהYo4X!js%I@9' V\QfѶ[l"S"j]YNv'Ҭ sJF[PS0IP\5ɸ𨤻= 4ḹ8R3!Ciڗ$2UK\_Wp)YWy'`}O-R? |$-:X%T\)PIBk-QT]@m >Yi)~bVAܞGόO.Iа7o;$B"$ 8p㭼|HuNx}[kO߃CjΓ|́ڗnZS(lS?LrTIH7UB"H[)>Vĕ׼3ZQ,{D苏xi͕~:Unӧj-Hm1L)[2xd;ޖCC$nB@ƫ׵ԡ@+{D8zB֢YNBVT'с Gk{҂,0E>olOSOƤx:}@/Y [Å x8:;T}|+Qw@h]W UJ-VqO7?R<x:ݹtJu;Sm;^moL.%\UR6Sm[JZgȴ5oz "۪ᨱKqn62 \?}e(H Y;{8@24Xu!QNRw**GG]5f=ٰ#;\yFu;Ƈ}]ԽXfix/TfT86 @!D2ԉNEnay(3 oMeREtτṳ8 68KoW- Ib#`9V@NRUP@#cfnWSlCjSN5% yS ]=)e:$),Qߗ`[w~Vä'mԤz{ekQ V )Jx]vCD%֖SZj0PvJz@IQ#=+~=oƤHy+[m0 7o:Rdd߭ʤ7&;МMNs$6Š8Iiґ2yS9lR% N\Œ6hi\S)g GÜ3 ol~XޠiLWT\I(B00s|b=8i߅K 2ӎyHP[4TG`T|YkK$yki, yŀ-K8Q #zGDq NAe6IJSI9|bDPpI]NB༬tB,$ [H<(U^$m+FzT4LXgoѵ.|i^%Yt*]Zjr㥥:/ڗ* u†ƍZ.hD`t.VtU{Ci QE\J W އxCLTjL?I@㌷-l ::T\/ӵ*wHZ/w_Zwb0!x@ :=JoyNDwn/O 3 澘 Nmj_|On}V>bXZ7I.P5&>Brf]V ke:dž8.Kr̉Q 4&Ԗk'.K\g[f#:- )B ،)CZUnˇ3Bߦ~NMkQԩK*%9mVSp *z͸vޛeX z[7qWmymyZAdkF럇=MZEy7SKrfd\QjTK+> PJ[jbMau*Bke\F,{X֎Vjy5JمWURHРAjͫU} z:lA3OPՆ&9%!#pB0U#pZݕR[uf(.0[@%%+;NKwdP h?r1T@kzst*4nϝ@?%_ ^+ZUE6Ԛc$dqZ* PNfD5S/y֍eO ҹXK]@ jxnʼnkҭ)TRD0"h%>)ː#8% m\e\^J[ޑz-rGzKNe->Ą]h佐Gzx6G|Ѻc*w~Lt9gw]/=2QL|Gݺ!6=uI!w p\׃ ;%Ti9VTOa1P]VJaF"27R^vwlH\?t!Nr-9 kokոҖVn IqT%iqBqh ۹56WaeQ)D2Zpˈ4*u^*^eo C$9'M9aQJC|>Wq=ݧ%KmQJ%)ץ}vmV261儧V~̒m%IaNN*3H*%`iJJ‰F(<[0ّ-7dn2uA [$XRڧ25$ ftz_!夥+HmX[FOxq9'k.yCI0 G99Ƿvϥ)SRAIW =}ڎ֙JKc8oqs7gǞv[a~~ ,4*Ln:gp7q>zzSM|?t#?iPѝD! I? dק;'7) `#'@ *1<>_kw{ gɺ2EǶo\]kJ}!o Nyu7є)hna\#ۑ z02@' ZVG =O9EM,(Cxې+Oq##m$܇Nޘ|Tww99~D{ LU]p9%N )) ;v[$pRVTUޜmNOk®侷T,6V-OTN@씾ZfŘA AH$ ij~0<9djIHۡv8lOvXz<~z S/KrmPvH9*.-$$$xZ@r u%Кn_>kn*7.6Tb1)ޕFi-8Դ㥶ѷRLɵiM/ODRjm}柩>. FWYN[?1''/A&F!%-DŽ茔vK( .|3$!i%ьʒϒ(Zy~I`_S*UԘU_=U(UMjSe).9 s!ޚqW˃sx}ŝ&nGiJk1KsdgjL\p?DKfrUqQ)Zb(92i^Jj;wLxFY\u-gk؄8&SHbs?gMA VH^[;F)MvD[qY'jswdB)O%O*͔h.L0Fq X8rRp~r n¢F XPGinIu4;O"\O9S,*!=:{dk{ 8ҡC -;VBUU樆XfH9z '܅פvRg%ϥfW1fSBxH RH錨 ^;pV t9tE}6BqrS+ 1PxeE0N4(.ШֻPJm}R!MU*AˊzJp%N`q„W[vBi mHڐ@t♿49W.-Mt%'Q%LG٬SJz֒U"\y߽hrvK(+n[XGͻwr)ը *:3GK4 p})놈R!HJe6eIt㎲@қR|B<ĥDw?"`pIBIH bjeDU/ԣ2%#<u)m (cwDR* UH6Zݝ*ԯ\{Abm> f#)I!Ѩ|$%CQ J-PIc$JAzQ;@tz-;^wZRV]̫ΈfGf,ň@+ J uLvkԱG6V QmI'*%#9"QaѪ|2bͽѨ6]QŭUFr0Q[KRa˱[Z( GDJߌK^էRwWe#@߉HQz j0-[ $358WkXF|.v{$XQ{8 UCCR\2.lc`Z,80Sݺ hjAgCyՂ[YDI?PToPn:RD@%Ȑ[]|ô:XU l)k`ϊVJ0o%*(V0K;7tj2쩵wj>ꙧI Ѩ˲.nJdUk 7}9N.l-cjnS|vɪT֙(6SSK9kb!.j73/Sr[J<|G ݢ@NCRN"#u%$S=lʢX$)*$ W&l1Q4J7)8;Yrtp_CI8 %  1T6wϧR KoVuRr N}c=3CJmV[e-<P!_S)좳H\#&ҋkq,TwPةr]mRI>! W K"JROJRHei]q\|$NBPk~rλn2LnCuTTYC7ܸ\uJȲ*yI3r)|)c*Q}SR) 9B7)*V Zng:?:HVR:S㵐^ Ku#*< Cͭ7)++m*THBhnǥQRs$!eU" r b&6bǏPu,Cmc@uG78YVQN:X=/տ"-.kR[~0<*Kn,gښ.{W~?Xu{pX5Rޏk*n]ն"½+hj})[]q-qK?GCnԻLi}Ri֕ΦKI~(onJLYihU!(qN) HePK'4A843r0' LP" CS#nu)oEwiQxYWsR#GR WS`E ԅ3> BOvK96E戏TZuZ]u3MXmώ ˔FeJRPFiݨ$rTnᶵ"ݨI F@iSiЩ0PM ; Q FbꪮnS,Z4^JM3Lo?_'Sty+y[VE2!Cg"d^4Hĝ [ւu EO<"/{vtP\}! e%fHJF\js'd4!r%V IZ)S1,q@JN͠,>^Gbe>\z.V&YZ|&bʟrM$RX|PfX(e$#Fcu^uJnkU]u+zL8^u__x({Jg+RROK$bMF%NJ)3>Ifcb*ov6."Rd)RR])H66tᑤЩSzmK0IZtKˆD0|tm=4d"l# VeVҥTc2Lͥ𴔟::v(%5oRy_K6oծ]AtZΤ;eE.&{+>K{OC@M;duFBtP/ sQFjsrXڕo}Uܗ&`iMB乺Gʱ咱R3QQ c!4ux^,6C<J T)P* y,n­eS7lلm]k)+|Ui@y*yQ5OcJr~U/AƏ$fj-uQ!d+RpE)JA]4ꤍ0ĸMf mWPR QI=ԍ/n:FxTJNE9Յ<arDM":֏(iQuAM]ڥ!!]>o˴4~ښX, ޷:Of[ Ĉ"&sRTx2֖Ir޿4wWwP-JCjPyt&r\SvRlM0t‘vQc;J JTzZp6"Z_L$O8p\eOV@ZUw|>jQJ[Y|M(HsC 6I #Wx_31wczgq9ە)jzYR^i%$NE8=^8Y>+6*fZ+%B҇UF}ۏ>>NBˎ%E IJ+Ne&U..2o͸ץj\t^lZMU8ƎbpCRPvʘL&"Rcw$}ocip!*"i^ Q؉^!~zE.EraT`iR)POE%oŝiж;OMƼBc-!r& CrVť @=5+.u@ꆵPOB]TCGMy5:wĴ+t"Y{jw%3iqc6.{y,8ϼgDe8 BHW^O#.1 A ST5ili4hH z;n-^YEJ5V۱n tg4om1گWUѭ E1_)xiǶ վ&@NKU=29$>d' Rf8\d ૧_nxr ivEڍ6Ѯkj͜t# 4ֺW0_StZX >`hynRQz#[9"JXLxְV^H IGʔ&T#G^ vp6%˵mj*PPPfJunՊeo[vȃ%HwR(+OTh*RaR?KO!5m)g>RziS \sR<;&m>vݤê&TV_jK1҉*Rq5۲MzUfO KR*HxJj}HZR7#~=jFƫnr]ߑlX]ئAԫfKĸΈuE[iqTN?sY(VT.!PQ vl`w#*`Ѫ("l1Dl$0MP}!!ƙ--I L yDpBN$hMS8a/I* ? .Il` ij.4ڂҏi.5{T.6ҐAԆ\u9sM>xKjVOu3sףe0PxVXJ\'UwKUBݗH0/[^"6gn3 P;TxI)x*OqƄY1R?O )>RGKkK.¹ǔ2HRͫsmܺJK[Te\ۃ<)dy)IcK)$iHH `HkDj%F /HtSi y6P:h:XyRT= T1Ozs!B>!%%YX$ }s~Ǘv=J oN&wǡD5ig~*i Q5HJuˡNR+203~]קe?u8|DqM$:u)F${^7S'PGXTKq%$!nFc|A'<Q%`&#![p;s B錤&B'i sdoMHQ/j+d' 'kIZiNƁ48|`=2gT?&<ĺܤP()ogzGSJ痿'A+$'n2]TNJBG)W 2rqp:{XiI!`2^!# 8|碽!S }GLP͔,R*Ӈf,~ !Bf",J]9Km'?4iZJVU`68jއd.+e1xZ)Ŕ 1os(GM:C @O !ITQ$S@ ($@** Uuؕ,;`bE^T4=G4)DBi-)ihDJc3=PH+G_AVʅA*W)ER&K9r4ʂⰏ6:2 s(!XgomItת \1YLXf!Af#,GB|IqHT@)h!( V9i8XN P=o^Ue!CAӻxM qB*0ĉZ([/s$4oR]\@*Rn-Uv!1[TdMŶjDvn;*4$JO؎uHn2\[ݕ e ENe*Fe&rT 2)H}Bm+SR$&RVܻn[f|# /qXᥩj^\uqeRd^J=oVK!^|3)s)T*{Qރ)Qq1EnFP BrD*4l&/JZ/"Cͬ (Ba\8/߁}?&H3SGYrJReHpC:OĠ֒iLzeH[H AVT;7 G;R y;dQk@b w Jtj,z9~F́$g )!qɐVg('\|W\2 ix^3QbS|.OqLwkqXÆK fӺ|s%>ISy!Ts$-@ A I|hUm/ILƕ5@ԦR!RNjeBnT j^^H ֖}cYf# m Y]IpU.%BVG*x 7͠(>#IEk#=EqN`œtKf;,8# ; CgᦼlB"THNJ e8ؑ32*J/ŏw"l}Wǻ^Yh <ϫ,+BFh&o=H~ߏ:-fsEᦒZ:SnV?mR-@i|-- ym'-̥FqO3Vp=jXu<\T ێ^QJi(.ۍ6~#@܄Azͫ+tx]7j6YM&ݼ^@Vh}6yjz2$7 r܅ԢQԦϮ)4%H>5fڕ/ z*0ݚh"ڪ֡+ȩB>.vH٤ $]Y90$<-C*}o0p` =/7mǜmZDڒv bJUA '7LתءI$蔤D: i̗+4yQ"RKi<6QuEu]1գ?ޯԻ~]Vڗj]Ev+vDgVʡԧ#. :-۩yB!(}n584Ɩí%U,f@$;$t4԰$ ih={j)V§nP':j=S TPG}%'s--*'ZRҼ%;*'wEmR!$ l /{HJBZsR錢NFq}ɋ-GChQAn(?AuEm8ڊҚ^mL,H$3D6'7/h_ ғǙBMX%TeNr3R>[,<%1g( 9*KȈFUB5ƅAyWOtt¤yKts2.2B6[~cr!vMjNT92i e2;yaQ(!ka12Q=&AulKb+';KPISaPpTRrb6a˥  şwښ^`C:8 { uV5թdTl4΀ 8PSSJ)ڴ1ʓ9ǖ牛DTHq i[OP$>??hި&nT4&Ƣꖛ. M3KU:XǦi͹kB_*jTaSS-1oDl/%+L46ܨ]hM=8[tL~;"n}:tJ*I\J TxJ') %8aSfX6&!K &O\"Ȥ> qE)7 }5iPPgSik՚MZxТ:FHQjNɥL"2TG!R&oSM˗$"ThL +87F'O¦LFn%~%VԘڒCEöSj]U_ P8cmFy˓3i5ӻϏ:\L͔z%@ d@%%)QjHRpTO'c' `:S\r+xCD+f$ңo#pt>TJ'pA$$ 翸SldRPQm@c)<{OC*Rv9|G@^:WcUeX rw8+ԋ9J]B@I#^F @ aq^az$_MeZdN87 =8IS/qA<z}0I@÷BAp6:AX$!ӈcEt(%%R sǿ}>)RT THB ֤$1;9-$+|ր|ҒT;y-mR}I; R>ZLZJNe*J1C u(nN{rKJmKjBIQVw4 V_zGgÿzn&jDoxzk&dXK@FkjK=GES_k[;)pE}p: (:ĸ%hC$!%e!)rzzvR,涬w`pp;uA]^;0ښmD?=v9kJSH?)HpVTq-h BAЦa,(o\*6Lj"S˨:hv⊔})ݴ!-8N0zڈc0-(uD!#.KiJ0R2N3aK49%+T6(Thӝʊ; jdn}PK CDGK%'YY_.tI/Nsc"L?EK(;tABqHuSQu𴡆U`,W![r;$mSn+ŚM.q[j!iV\aPB}ꤦ%4W؊2S+X(kSQhLvPˬKKRԒŤz@%CʱTDA%] p婲 ޠ UYٴFLPAЧ,GghԄ(3ȣz㤽Ym:yQx7Jk ս"JVje.;ƍn>](2b*W4`T-&:- k\(HRCYShmKG}+{bYr6-ZՕ-DJQ=1ST vj }l-L&?_LW8o%e#b֦ҕ')J>Yȓg̜SjZqHgvAd3OMfMzS>$*v$%[mC8JF6rt2$2ly2Kc<{$g .>q@H5PӍVJ۝:lCSԣc9!Q(bm,̺'EFiӉ)J܉KzPeƗ!I{ӬFfSП}l,!nR׿M+PIonIr,ʖˌ,m$Aw>ێs4.$(IR \=]nZR5qfҨm][WIӚ}iMԸT{勒/8`v)-Rikoӽ^k]i_Fr٧ _Qh%gRfҭ/U>Iș>R7]vسh8O"'Zlu5 ji-(q n r[f+r$%J J7Hv]THpwA!fN 6nkm_/O:K5z3'Zq[hx=c]`ux녥j4} .}ޗrЫQ*6X-b*l\go{j p=45vWVz?SMm˶V\$Gx3t7q\sd I%^%GgT~/Mm ) iԥ(NBS--u m-=MKq.yˋ.!ސ|v/!Z"co/؆>roo"MEނT/Ϗ\:G{TZ!m\0@cS/k,\[#ϫ[qͮ:&(1!)T/"Z5Or#6^JԆ[\¢^KEIq+xIx+rPRHܔD:Ji iR|yUF #R[^em->mI(?`ffq,ރ~4RQQCHP4 v4qv2g{^:MA~MJ:ݩjUS+zTZ@Z%f5O3$+ o w٤azz{kE 0(/ժ]Ymx:Uc! "rBTtf^-Ru:@BPqTۊVBP"DFl5J mYOn*J-Kv d+lzbnmI1S !۾~ǯkP-5~tk}\ֵb 9Uql]Xh*:9[E7u1F4oU4}:V^M]ce]"MmrgҠREVTzJԫZesa^V") X驽LҶO#zªbjҵ P[pzgT4AR܅ *2Li:>[JTqK-d eAbZ} H (=KW\R]Om&7HCRҟR]AYql;Kn{y-ldǨ--<t^548IC0p![(8?RTۙF֚TH%!iVN9J4`>|鄥xTA EKtTF$9/8cYSz{&!s~WlR֣;e)^>YaKh!-#~X$j`O$6Ե) IBТR4 SC 2QY ͋pKʤ:-[%+IۀXmm IJ@<$B:jAWۍRc)+JPZڟw ՂGȊЏpd2^ gnҷ8> ' !mD9Z֗׳k*Y$/bTbx["3hhu;en%K9Pg+B)m4SRI>=?!Z uUW.-PEkz5 ZJRA .ؚ~+÷+ w jƝPuFMN֥^+&TbQ-Ou)I+xjJПTz_K4ÇYIjZS''U*Z]|\ԟ_"\`[$zC ViƝ1ہ:*Jsqq)m.}%-դe;z \21%9**KPѕ=)m$Cb\F=(ֵ-(?ϟVZVVvԛ.֠2ֺ=.PC-n8-TT,f;%vVMnj7I-l)5n3-0,~!8NOXVMAQ^Z+nO%5HT4;~\wRВ]N-CfМt3F6 ADsePC%%Iܐ#eyZҲ01`e(K;7&尖HHRunAayډ"ݮ8!1>\}ڀ)0Jr9,܄B`(vݴ)% ` 4!^jrWs0$p2zV7a=y^.|:6ZV֭:;x)禐Gק*`ďvXDj{?ɁBlaMa}߳_ҩnvI\'ڱJ @ iب'wSH pFmFA)G>3 czT||wvI 8#s_19&Ѝ0"%Ë#w`%@:VGmP^pZ,Ae㐕$;{$5RrۉBsCNǾ>?=2PxRCjtöJ}!TZpDHq7zT[ $tK$8թwU(J pNv Z6VyHDw)j8[n0ccBI+}үiQ2ઙĩ$vs9Wc+p&Fi-6fFqRTK-d qܫ6>֮鎢W*/Ϡ&d%"4^RETpAX8SeY)=:ʙPU!Rj,C`u尀ΣgЧ "3` 9 )M>I*z;m\֔60-lr- ڞr*! yZK}h=)XݓGFNjUI)Q+TƬ!Uq0cJ:2Ӟr1.4j A(잾ƃv nj 8 ^u*ytY6\zXԖm*#dwcfIҢzE'iEksF:JT6AA;GHh6⚫"MkE'> 7&lm#0 1]zg E9)Ʃ.ZvSʼn&,З3 !Tq`7=GkR0r=L> 1_SJ7gYM=yq{!7wQ5k\G{Zyp2ڃФ6^RN|!D}' #=fFKXRwmuHV7*qrK q:~KaeuhIؾrmHFѹ"AP W=b$@Q}G6K$r%W #R1.,ۊ{WwdK1ìЧ+qqZ_a'K̬)hGܰdF2%ayܑqp 8^S8eE#Eiՠh+!SaY]>aVH=m%ǶXqAuxh˄ DX*C;K#$m p)P}L)SvfZOjXQ`݃ǫ 7CDǝuIƖO>me 5 YmN̂>[<,33-)@AJJTǖ@PAQҭEťh&TN֮ Ґd$JB)F 6814*-VZ#ItD&!AEHr0xv[ٵ)kJcAAIP$Zm"ve(hVC z> "lUIi-mn8ҐXB2%Iot+j-d}YZw5&ySPdUR$~ Tܽ2PB =_".I[V LJjLPZuu'krĸQێg fvB)oLL!ڵ+k:E U> Ԥ!!/ z ?%3/C0!%0ЧTvYfI,C[BQIO'P/վb*Z> *;);i︐O\^܈ Bckh͡J)a$()oOC8.<^OW䅥1D?+< ꎵ3]0hJu”QjQ޵>s{l9!T(lLm:KDmђ |;Eˇ!=~vo#/W:1).FoK;H2uҤ9I)eIYKeD/)Gq a4>%&CS:TԄ)m`:L8}g8ӐUv[])KLIyhULMYs!<䧞url8 Zb՗ܮ\4 cҎ!K<*րCZc1)k 9K+% 7wFL0uԷ5h-K|i0F@Q٫W)YPhR )ʔ[àyŸPGGHZ;(u+ =ЅE *44%z[ҍ\--pք-R]0Sx=RXX猜[ *TԔ 4ń(JOZqS֭f_]D>>E[aT+ZV|ʒ0(dR|$eDt}oMN2U) uqJB<}*Aq0L;9Poqn˵y2!\1;DARY9lzEJ@i \Gn`4Hp'v9^l "›+ mdH-UeŭJW0I8}&H 䒒@88ۙ#Qujm) HQ89v; Gp#}|M9p$ssI *(^}qDn€9c6w Xsy,֨2#чR\i!itnސN 8ۀA;)8w}vN'} Y l|!jV``c^[)OmSZYIt1 'e-0_JT;dqfFW-qqzzWF7C5c9&toWLB˦ljDHE%PT(*#1##j;$ ]0BԦ T* o}':ʒ!IP<,z/mv#*YJ duTCc5WBfGZM(l\q#Jlk˝pQj2~82dN uyWZ}@hmKNz«0tNQ Iy,N2R\BT#-%Jc)ڈCAZU,YX|EJFrAO#47 TaNf9/mFiTNjsT! K,0nӴI %[Xo( fURӎ$)&]Lp|Zp ePvQ=yԝ)TOSѵnBU¢?QօEB}>R"Wmڵ-.ⱔqٛfc٩:VRnP 5AaCa#n65w բyC;ZbCnz#w[m=^~UvԽEzW@]N9.CLʣ1/@ڲ pI]FRiYrk5-.e%ma4]yPY` [X4zu Mx6TERҧjQne|.¶TͥXh ନ}i5x`| HL2c Ԉ T4ףKh^$Oq/%|QJˡI)o8ө5~]b}&U5KR&- T`|VXѣVBgzj#!P7NХI$+$Z#:% 6[qEN)$ʉ`&U e%j% Skŷ ]5!*I;*#P%ڴpt^4jWK~Mݱv^Uֈ71GB[S`U7oY*zE"LA*E͔eZ)s<ɑZrDR}Ͷd/[ܮ1sfp *ΆR%ˆQ$)B̄=.9q%GuIZ ՚^ؖM'\xmUbR7TZs%oe(nZYDOH"HwZЭJ JAS41#r1K!Е'KL(C8VBY JSUEzJpxv-Ļ.9& ڴ6 TX~(H?}nq`u?PhŹ;/(o`vP%) @ 5{bei9riL0t7MLO<6OF W07PkOR{>m $FI.t+Viujlp3wJ)PC Bq[sqH?y^m)Am${ʀTo&4vf?$)8mЮZ:NZqSt!Օ>Bw%h J)X%i 8z>j3́QcGZjmy/8ݿCjP' kzi'bVjmIJ@ HmXf[ qU:m>5Z ۰Mٸ5 [CSث)K > R^kpJpsBm>6X/KMr =} PV\Ot*TZyq;=+Noho]JZV1nVJR-S e& 0)RUeZCJR䁐RtS(0.EU M/GsI8rHL8jB%isg%]~kdene-)dSE!ĭA)NwjQumsRܲ*-}[ԻF`e0fӕ,EH!SY,A7:ke^[XN TR Y *#ӞF~5ukN#2L=nعq]FkHc) qN&Y(~$E.jTE0ԥCmۆNORS]%J֢tzzc|JXi-2C[S+&:GA$b=R]K)6h XAWD5BQix4u؎eU uZ%E8+2tVFU0m-MV%zV~NaIOiV"DXcL-Z5.xv{64hɥ?-%%I)o̸o!|TQ-*FRzٔ) nRG*'891*&澷joZ3 |mi oO ^>w_NiM}8ҍ/"""-B[9ЕY9K")*FÙ6;QkU.? WfQɌ"ytŮ3GqmF-ȟL"9Ly 8::BHkWB}(j aѲy!%D4Q> "n-%EH z@e̬M<Եox5#JuqɈ嫨`@3*P>9N%4@pz+ֽfRPϐnvCJnـ$uݼԘ׵.ǽiv۴q+hF%:+H⢕ x @oX&*5* R3epؿ#!+L6$&BIWYS1h[RӸ ͡E\pQrz[u*}RRN!V%BP㰖$GURRBU iIz (| mUIu%)r> 2_y-(CtVjCXyVSj@rZ@RfaƖ$Yxb bX՞ud4 .K8)Z\=v]5^z⩳KN5wiEQ̆iZ%mBQ)P#03)2)|sR2ގ:n\ȔZ)z{~H>Rb1!>ZI#֡i)o2)ߗe\pvZ$ECKS-jmEcBJm-SCx{U?0Jp,6+LGiuJe'( "t1Q -˕(]5d!,ƙ.b !)/ާ #:uaڊ@"].Q1rZ;46╜EṖK]m/TZDr\JZZ[Jv# GjŌK-m$bK-ݬ%YNRJBpxXӏ65e tص\j]7 ٮtOVY4gԭ=NmKg0YEof=.tlD(}A5 ŰF&K! I$Jͬ[o 75)IrB@!B"SR.!xFqyXySN2c4Xf-.[f&6ҽ zA'QNZZyj ѧ[ZVzmj\!(5,y2)sIiIx4lU ѭiAbh:26@t؝kPz&ߚRw8дEViKNLnZ)Vc{@8.I- )YSp Q7PPا&4"M\p3 `4ܗI K$) *U"jaPeCBPY).b_-!b5H b*=>D-;BdCK)hl)+jUC2c܆?Q5|Iet«y\LC1@f"YWPb@h!)^A/5Wmo%%LJ}[TvO) V)@~}\ZEXZvH^EN9@]>$#`=h![iۓ-hN޴.,ҳ0y)qhdžS5 h,7'dz.i^.KdW7%.IR_" ZL8JӥJ%P_[adRqPE `&+W2΃8< ذRJz{m VIg4KM1UaИ—!8 n0p1=+Ro(z]UAS-D/VTm->X\*GӛmPYy>UfSIJܐli!^v ,j itGR2JGbC.2Am`O'!aHTX$-kI@:QN@:ƫt7"`u~Rt产EwtI}Հ-I֜GowZ_/TK **Z MVd[[6GH*ON4kurIN÷*Pg@n"'Ȓ#%>krUR@im°'7RD[w^Zv8n ~mnĉVhFCPYTCMyHIL[*3Ҩk.j|؅<&}JHT(e:CkgBL~u5h$R[X^w% Fv4ZÒߙ)a'b-eeHKY.0גpHtk&b_rd+ﰶG'5 S8IH7ۏ:Rp&A% T@'\)]BJ)M)LgBi(e;h)R ޚSo1A1^PP#[W2Z)Hu Boo9 9:mw)^cG'l[RrsU6jY;m%9I~Re,DI,jԹ{6yPaMր*l:(s;!!-KL )פ2ϯ8xXiHպ"RK% QAu2s(*qGUFTG%E_ڛ[f*`߆7l6\j ϭޣ`ZI`m5:c[j6f]BlV 2(҉@(2S!\IFR҂B]g H)B=9Blu*bfE:RhJf 9vh)Lݼ(jnZRmCY d䂄)YQZQw%)#ˌ(q"P \SmTQSi9Q8flg1Fy Q64PRQidܐY娩@p.UNBk{`NlR2cEԊ!DgcЧ-T*MU L8.T*<1>E)W%=ځ qW?;aD겪VK|cQ TI}^c! 0򔌸 J<`Hbt&D|BO*mK`}"!)k }=hnp$-{*YꔢItTSL/1kU߆R( !C$t!֩H5{2)f)LB*04m̸Xv_MRaJg%J ' r뭕K ؖ+lgEcӓNp9rb^RgCO(pʒʐBFpNvGӐU2C%M))iH V8, [wieL$iZt.jS ڢ\2,VT#Ҷ€$M}~A}Zw^lߗ]=Y|zehUB5&[tc†Der5 8u%W! BJJ0\BJ9 Ƈg(>{W|ߴ+ɤwڨjX~ecPvUE!!"%ĥRÎ)KKHqAz}z*:Jfb5i)ߍy1Ld(4;4_ZJԅ6N5Wu[ijĕ6RPWn:TvL 6(KpaUA;jQ$ ЙiN70 kiu)p%a@ޠ $,d`e 9a*"B5Uۯs JY81݈B?TI܇4 ${ǭ"z4Y)"Co/B^hB)'9 ƉӁLx2/Mƕ%Iܶ|̒Rt.Ko.8*+o{YqiV,(&rS$,ɥpa%ǎ!njpj:ˎ< u iֈϜ ; %?syU]waA!@YyõH /)2:r+  (jTTZy;%*\U-KwcrkߨJ"3IyTyJldc U<д$X>\W,j:Y"^~epdrMIu'b)pkܴ$-]=ow[4VSV[۷W+6HOBATTsz$(* î%Cd%$q~f,u|ƲS%aJB JN~`2Ġ)IH#vռݶ & "A^ f_h[[)h\O0'eȳ貜bTKkbLZi.b[;®J,D9!!qˠ6@x+QԔ/*!E @M>+os'OHh eʩiVit6%:S?Qb.OM~Z"$51ZxBeOMm˝ $=2 BXel6hK $:*!Y =W78I!%)=ll=gj3!CHKI[>d 9Q+̽;Nƞi‚Ч\ Y[m)M2S|hI NQ. EYm/%>G# p{瞫'BtKGhC> * S]ڥMڰVKOF"촣 -ĨA*.@nS1),6f":!ⶀJI2PRT[I 9t+G jXmFp(e AX0GnDS+  CRJG 8(@m.pTGm-B] H O|1*P.Yhz>jIR6cBq <АD8H9y"tya;k`GO> !##P_ n}ܥ88Ix^pA8+hGF-ZRTtn^IWĐT8`Y|DLjzp) (ƶW}j(3`O͊,+e5?-RzKY. )nVM^bs&SuN5GB! I .T *S O+@KPBDRǐTEcqpr@P8ӣm~;ލ'4-Nm%=)zލU5Ն2V;2g/(t\;e\fȥ.(5wK< 7fq$^:oUNn;W텢Z_ѩnV8WP֮V'Le֓sJsh☤yZ] y,i¢qĞxxt߬ZVXl24 ŅZLjѵFU 5Z&[BL{}:\dHTekYI{n')?"2[vs@[\4%d1  ;0p鵗1BalZ 'cdeyߨ2> S%c KAn%hqـT^!D.R ZG>.T|JR YY<r!PlC8О cm.U%U6j.-ؑ O0̖Olm2e^c#ֵ!DWDY3enzDcD%-ZJp$:DPuV8,lqo6>\!էSXPl|/ Weizݭ3 YZ39:{m%h^R9_;FuΤXZ_2k.ijf]4K]V2%~DKn"X";yKi$nfv! q`K2b>y,2e*q%0JT:ܣ]=)֥|YWuH~غl뢳e]VII~$F-Y%ُ7)Jz%-H&;Ř(JXRIjJk T@~28k 1Ҙ'}wvߺcy%?WmZ٫SM } cɫNtƞVcMogwU NCƉZv:&OHѽ-_zmOuϝ%&7GZӤRLʬQ2a/:f&XbxpviW}HڿCl8W&Wg ZRzUN38nRD]z 5K#@jUnK-XknRk&U>YfSbfCM5QfGv3!lf˅(B UDlv0 T]\}yLO4VB3!aN+ Q2$RnpY('ak$^'č&+XrcխҵbĔ4<qR$!4L4*0T 3/{1-i!>s%JI@mMZ)43f\ۉ )r\j2] ~;k-O:[aKNB! Yڊ`p u8$?>Iڣf՜61[m")SF?V @HɀǕ+hޣ#8AR2aImRi [oCX%PHpoBd68P P%M,*)q''0>@pz4RY+CM>)i*t9[ B2C') qd|qӞ@Ai*;RRX)S6ނLUC; >N"PeFFvpӸ1וv=~_6eH,i}7(zMi G3,6V9Z.n~N1:b32kw4݄Ŷn@9zI'o=?9Zҝ Ffܲa3Zb ,{QÖXH|BF4'Wc`?Wj0;e˯6*[ek)KkQMN#sDvn.r9:r^.8^gLYZǑ: MZ @-G @mϾ1ߴx w0VJTznƲ;YO /؍<D~'~Y b45$ STaN.5J>}R*W/GrFp0N8jEvvΑK6ʔӎ!)ay:!ܳ0D≃ jWfږd/-bé ̄`pV䜨MsR)8v SP)@wa8)<# A p*7u 5ҫ,Cxϟ0 #,w87ׅnN65N^-NrPU*ZLxuZtk8JU:xiߘpg5Q"JLN'0 TNn7vVh"CJMD!oGvb w\t)(l(s(ZJG֚$z[\D】z=I oՉ6k亯շ,vn=lb\ڥriX(*(-{([s^ܣ;[2%SHn i)}$a% !zBFGo ?U=Qevhk]>v]>|[Qu!u%$FCVses9kT,Bs2Gv*9 acS p)gRvwy5%A®. %C qq-(Y;$vNO$d7|tk3Z[fO|6焐j?NF[7jZY|rU[ ˒jK+Bѡ5 R@SZ>M>)blHbMeySpA=Òr=R:Ha$&(w\ip̢ p,8T|v5A))hMaE|R)r;.[w䔺ZZ֗>'qⱁ3tʋJC[X)'{r x9J@}D SS''G֍uڜA)PmEE-PBS}'r-GfHQyXD) ]=#g-iJgB؁?ς#^XJCl.Jm6š!ր.:M,8Hf@N5֔ aVI9W?xwsChzޜʑw"Dߗ,nqe. Fm4Eks)I4ܵK[e3Cp?t8!;w ܣ*$HhARuNB&)B޶>O)a<$ grv!U lHP x4k ')gvNZvAYwsARO yn/nʈK'JLHK;WM `C; #2Im ЩV,vĬ/U7_-[plSt,ԩtpE9,ԔIHQf@IKR,6p*\&BUK*Sxģ7gPANҔÎ'ԬGmnAgwS2q$%bC n(}Xز (8*z { ㇔lN-drJBNՂ:3zXwiŧzPtSŵ e&\1ֆ7PjJ[BѱPuʣeQf%f=}4x嘛; ?xaLI\REM.ABō8T-WS* bbCQy# m@@p$mHHG$d:jG68Z8!N6Y g<snxnepk13oEiӦj\T(w `j*-*cjͭHmF>%,WM [:վ{讣H_~304pT 0܋RpenҿFɘn rN/ŦeDKŠcjp<:3<%BA !؊.nCI$$:XIB@~XN=֑t]%rw]BTTBZITbIJ )-(%Օ<CFcrF8ASl qN!Hi y ((? ^Ҙ[JU.V|ñؙNTKsc;L02 6tW?H*T+m֗D*jlEm|LBU6v89݁WҪu5Re[imm}𠐜d'Ih ͓!@qQ<۹)QRr 50SiMCî ێeq `x ח%(N$-Cid*J܀9lv)oIfJ[}ܠ6YZХa* M}k9raiuA[CI /ijZUÊsԍűkOн+YW=Tvᑬz3޶nTHLvI: c%AbRu Onu:SL5NJ2ŠzhN1͌ACc=w(G3 nT;CWHݢ6.fb k1\ϖHトA]IIE>KIJR#XaK)h%so KZ5۽% IO=J;u{jfJP+t*˧U:ȼŝ$D};΅\(>.gr":tbծ+s{NC™=T*,H4:kkJP1l%yA$/AFq!JT'uRIѯ Uf_vR̠!tuhRP}uR*$Z[mm,NQMNL8*@jOj3i`X3xOC@@-EmDu1c2k >h* Z$prU#p S*) .!N`eHN=L*.*mLjm(:%A Z2"7l.$vNNW~&4h4B%6 um&R A;pM)f{ 't~0fIHF OO 67f8\q ![tR!dH#'52jZySm"0_8▔ Uz!XU!%_cO#mPdJ9Vrx=W`SqgĔ%6K q.B@†Gb~ӯ.e5Zf^26Qm4ϗvRҗqŲQQmAJڞ"? 㑳W>Mn`%e'쀆?>hic?u[$) mvHpgb@ g)6m)> .(7ZIIͯ--7rGBlk$xCi -t+EĜ)X6øcCp.5fpƧRN)1<7;}^ˡJ-lISPҥ8qitpH#Ga]nZ%uI?uL*"uTˁFPPCë 'l 6RT1ҥ,좑e +t/ }R$ñ.XN^ RỷůBPLVՐZ@t S)* K$$TсfsJޔҥ*YPݫ]:sT(r%\2:aHXa% )C7+Ytn]Fju>Xnrbm[̈Mxb*p4cP,+~ՑonB ̧OKL̒7@u6msaJLnJHRmV\P|Y^ICRC|4[|IH``Ewkf4ђ 3o:^/%0iZH&"I@Mnmn?j^w*~T u/rja~z3P[%5Fd-G8]*uRJ&T:!1hmFb,W]QR31a$`.|%Su$U;.IA޺,<RImXZ*×[E1)x1̝[B*ZbC%+si*i%AduS'// dað( H "<8\TMA" r֜L=XmIr8Lٷ# y`yu~T\;TQaMӑkJ x֖xa!#KtRL"7C"pWH .+6J@P鿇IqNj}q4+/•V1SdI'rzVӗ 7vY r Iȁ؊y!e<œN &YPY*{硚TtX G**i 6;N^.ifIqZ %LaDFIs i'tNa-QVRR<>t̖ӵn#$RpC8Uf # S@T19vVK-LӜLlEZjAHUofvK~ |Ǧ-|b]tk)LfWWP%J: P#ntfÐm*b:CfMVZ#H( fO(͕cR[0Ƨɕ) RAJ@**R)VJKlʳS)jDBP)"rEK>.×!DTᔒTg 7qC:!!ME/t(W$9ڊb9)d86!ųde8NH\ {"%]R \eJ@u!W)`!Xx=t \-we11!_Khݽ!'(8$ER+[Km8Pm?n-KBspb&1K>Uǁ+"Q.V$ Ikm5`=*4xp*qy $Sn%Li.s qG@ϷAu $|<[~႔$Ȗg|:TF:uۊ)|soqHRYP мu"k m9|gA.gsk-)Jy[VNo3ezN q@\ٛʕB pJUABv(t 6ɲ= B u4S|PsU ̤RtԧӪ1ucSISOŊ<򗱴:$H)[ yM7Rƭ6Ž ir, eJhh2;-LKu^h :{x0%IߨV*dĈ;plݔg p=sDeS o*0닫ˤ`Ayv B5JZ*çwXM:լҺͧMF3bm*yDz?GMWʹ o-:Qt[_Oׄ*h rmRXqN;L}AnVzj$ƙ]ZJ|ñ(_6bx߭[̧.+w0#M%LS27"IT6nTQQq!jմL7<_+?5[pir9k,I1'veDD/1ˡ.ydJJM%qyR SS[nz $M.Oulv<6;,ݍ%+ ,E ;׻;_oݷmF]@$V*պu$X)n>sCӆFI+nۂKJuRfi.EꚟY\#ަ\X1GНYǫh֑ v2]T-mRi5Q %?UjE7h:'Ye)KLN-I PZIF̰ vF.R|*AH%;za7_\uM(źמT:iIk$e@Qm9_twujPkFm8*x.[ܪPCFf5-iʳ%gnDD$@fS$d)o@HG>_%G cy#zIVԓʔ~rrwЄUKP PP=B̤a: @K  v8tz}om*d'p6r};;G|AhD}ߊ: sr>©mɐ$䔥$$u@rA 8StmGvL`P G|7ff'i,@aJ7wrxUAEDhHLJo g?(õ"RKoRB{wذIz>Q {+*e\[J m!;뼵ODTDER'Pr\ѯ~yijBIBMAw.Rl*>`1ӯ3o"|@j\~\A@r ZM{~}yxoV%Ȍ)H+ZQO=:G$ԠǩN"bZ/QL L_H0L)kpW}%5N)FAW;H2}8=^e8I0a VFBN~~WN}$%#)x|c=Y<$ěJ CYizͻG&\*tׯy R1,9Ky*Rh()q#*phL!.*|@Q̘i7Ad :tWaoI1!uImKM(Q@;$ eɷb:v!'% s"@H!/QR wapifJLXm43SJm`JVHI9z?cO_~~-|ej~mT_<8iӵʥcV.U2WZJa)S;۞ Cc˪aiUq=.7&u)tS-DPq*XjS(C %;nH婚|4#N<2e*Lҫzߩe}TjS~ݩSi$;[MTS~4:ӨPԖ=}]e>Xtmrvk{Hiۓkw}fN"ؠݮY}euN&Ϳ;NfeQCNe^&۩Vj ~ջnڶƨV5_mlif>~.q_wdͥgoڳŵG =]&[O=eqjvD:It-ѭgR![D_:ᲫOM=L;<ni߄"]"RfԻta5CQ@ 5ni\bĎu'XPm/bO@A鎋1?.;Skj6(VNƼإTKO"ԡAWCЙImjARR 3Q-v^F[IZ4! H(y,6ܖ'r<Я!Ghy֝Z wJF:YmϝT%\˴-.t&}2)1R6ӳSnH,!Q]E%uax*+$6X^FO;P%DPpHW]%=%^uZ=JNJ9>ocm)) JJVBw8a5C24#vKP~#$tNic|l[Nyh Ȑq XZ}p  .Ŕ2e->\t( HPܕFqעK(QMBrI-G&} T`MV"ЪiyTt8ӎ%X)^x|ZKJWIwIw'ߤ6Me!_Kyܒ77mGӨ,$;9 `=uLER j&cC R5kj$^+dhKaZ>Z–qywJm>c@J;SMû+P,'v*B㉕ZQK2%-yHm XH9@]e0o KO݅z?Pj=CҺUq‡eyj/UkpFK OD|Z6䖗QC!*Pp")@d35\>}JJh?91*cS|Re7T#ʎ\ Z2%-j!Gv`v#=!^k³"vߢ 7$VMFz`TYE)nCEvr`VFc36W)qĩCx[6`BuScp?L\IFM5=yoHQNnpAsQo*Er$ (JN+IW|F:(iDB]8.4HNFJ#8$:/"UV`8+Jҥm?N9VH#V@v;G6`Ĕ'0C0..K, Ӗ +oh0ߜP@@bS71dbJ =P7crC% Qp 8{?>sÊ2|n(ZC V 92{{gQB7'qsG)&T$SwMmvZڛBPq)slub z]CJJ\}Z[,l ''<zPبZ1"q9S.zkJO!!IP 8T@M@%pгȿ4I9e 8$T-5 euNu]z'ѬjUVEUFᾯ3cn8dZD7c$֊$!n[/%1P֊Ӯ}DBlZLѪ0t2d[C9t)LMN]KQMJw@#M}@-`ZۇNG\d?[ 4r*B7zDuֹJg;WpRvTFjqs[z;tW>?~WL;Ԗfտ/@\0 $@rk[9nE a1RV+p!$Tr08BFl(+$wO+#."6t|}^Y$[1jԙQm퐧QI(8 'AsT8'ٛV\nfT!!֍*͈uVhqF]I#* #Iؒ:?[$DB TĒ 9<(9zONojD)mP ۅY F\jBl(*ؒ)o3vTxסȩ?:-)zٙle(C*R"4VҾw|<;H،HT Xo%hh%@ZRl<-r}5V=a7lBB>~ HlPHa9:j=#$sߧ@T|)D8T6I?:L%HǞhpS?J\Vgo-&,'ў1 e j:ڏqꥵu{4Lzr*BFKO2SFbA]B c=>)tZU62;UVrHOːG8M#ԫSפun޹4KR˘=Tq&:֥(GTUs~/ Ђ H`ůqKC3R"UzrH[ quhW2ZɌR!K(6S ]4>tt).AXYSzs"㺼DjצS'*Wm2+bYȋ..1h(uiA;DŽiEf[Y[!,*Hp_SxHPNx9\*MHogcAB5w%vnj2%:ԀJm$( ) ų̸$R@ZzCRRW?Z;HI8Yk`OB% ),%*Q;Jګ˩n\"5FiMƝ:x-78%A'hmеoF d ѦHG$>B#IVs:Wt\5Z-D7MfեٶuYjULSK*7 +Ai@rD@҃Z;bґ*Y!,g$n?iٳu?OtfV[2@Jm:|T<$n݊^E3TvQߕ

 {i֤yܗ-6.b-gQMh(y\|!xџ:|xk[Z6}oHIT7FShS4٣SP쪶œ'MO (H*T@ -iH,b Wm8+V9rg%0؝:/>ښ{L6ٍQl`CAY#ۣ>iMfYCGyt6YJfM9Lv`![J]ZVTTHDzuC! ו<& T yìga͕ }!%˹d>,yȮFpQ ⇛m$8\Jr"%RȮ Bl1^faB)MFހb8K̿RBDt~kK 8S.8Jr8萖qPJ[u ,Y>vcW++;IǾ0y㑞9@I2$԰`~Tp0"3lԪ*~JGmQyrԅNvW\~]_ڭ2%>ꃍO 9'>bjRrwq# DQZ29?ȳ9uJMى4&:ˀL0I6z'N'ti_J6\ۅr;t'!_qikkQR!$R=vII矙˩,S"z0RP!;>cR ܘ2 XƋ' pX (_ߔ99>8=z?_(=y-/Pq* ׸g~t?Pہq|6Pɯ?K0 H3$Rx'=<s4)@ <~H GR?Vp_#==߭jیo#ߟD Ґ %,(Nvcs%A.Z> .ԩISDk! BN9t pAԷco HwAp^9m|(JJ)D3:@ UۖĐ3xi8([L%`CiO1R%jIJK$A> FFh65jUd-1dƜܦ"P6YzP2≮S.6 9*M Z:]N]y]w5*;ƵEaw{5Jri\Qe Y?J%n 6bj qH?ߝO#@ i`Q1ckih(krAIq JF<)I0JK` Xh\2HIFQ"=@|9$;i[-4į{:"gjMwjœW-Jk o zsn\J7):Ku "rt1ywmOҟ~.Dkwffh4Sm5Fhp |yٵ)A44Ȉ꟎(Z8p@3ր&Ly; yϚ!!vX+W==l` ߑ1*fBbbEJ JpAj,I1}iZ:1,?GlUՓ.cp%?Q.'qTShlVfZA)ݵǸ<3y*V zғ#,\`+9y61SC;j&L xL`b ;8pǢ. [Bjujlv(Pc;xH:e +-8}GZ[ݒ )%*:ku `ӚCEͯMRԈ$yRX ey)Jc>(8'qn+wZ1VZ|%I!t'rq]9*=ڰԃ$ʋtK KݙKH*0|\չq3!(m$gֵHܦ>{ۭ>M$R*%*;P: NXM$HEi^@*m2GK  @s@} vT\+5r P݁sM,?qBؑpa OxAHPj RM&w'mx L\lP[m* zU&w-qqǞCRPHR’R}TNxH ju%EZt2֕)< %Ib^/mZ$ v-N$j>kOS9q 8}8K9m鿈-;-i~\BT fNϝIlr̀ZKˎɕ W5DWKV]4RTo*jHR{%l! մ9|e4^i+[)Rí7B{FrZ0&ڡ!Yo21F,q#\3NŬ݁qhayecFeϘ(B@~qJxԺ]rʋ!o2›(a>Z)Cx$ {`u}jSCҙR7y&,6&tRRa#iX)>a;ze7zRNeH%cJL&KA+>a;tc'* YQa:CzP;ZMpԄ2T $;{ԋ t+Qg7>=ּ KTvv;+KJۑSGnKelW㐯RJZ[YCNŶc)cbRc nART;R.I2j]t;Z^cih :STm5'i>xr^_n٭- @pF_721&5E!s4),HxS҈Fʐߎ[J& PJU@$($`Ř[8ۉM"9QIi! '2[vlkoĠW#p6J[n3TvOu"g*t+S_4JIC'"+ I*?ug?`^X/k %yv08=c,$㝮J\1 m$ u,lPQQ>r%Fw.R'S BBMH&p5-Q+ڋV׭Qi}sjMFTiWUjn@һ~#h-JFBe.'˒FM7~ŭV޲֦Z .˒> )5|M5mUT%-ػ?nYjeUT8- !ڶL QXIm)7dgќpzƞ^9l7O$!Kq+.hZ]dn-cÀ@ Q%E` .P$p"bAL@$*Vz"x|:&uˆ6cuk`;@P+!My꥽>"FҒb3, 1n030H'&2d8ĪE5e)e)vY޲T@H +T KCXS ZKMMS$9 }ǛvpH JBh4K-JRJkXػ&VWĶ#qL'KIryH7J5%MDe7a%Iڿ|o'#9˟/ӡ;I |}5 RG8 @0mn%*^̜)ßs2bEIz^4cKCP|jJ'REOtx [%j8Ž8ÁiF$ow<߉ ip(:н`(<nHu#9Ӹ{`psoǯ({XrEqc$օBRTCaS'6ݬAcƎI@F@O$6suӦedBN8x8"̑,3wG#dss߯UwL{ #=SC‚x?WV1.`qWJq!jqA䝡qr;t_uJeXJJP PY-J+hN9+u((_3sD:#j* E/1.!pԥHʘB$ wrmS鄫D􂭭wJ޸+b@m s)Fi#[ ')-v%oF<1(U{6tm~Ij>^]OT;hUV܎uzY5WVaRi7=M,򗩷EXitڤ$ԩit+oEJX%O*HzZ2D) ӒT2Gi;i;ւvBw1ͦǛ'B`D.@M3rΔF.޶66\z>P$6-_N+)A5Ai(B O=7ʣ>YMgkMDU)XKhZ yo8\T:FeסQӵҜ[\Zy hg(.1de#PZ:mݵ(UrNzIOIJAP(D[(Ժү OLQZXQjKL]A[B[P(q1cV% Q݋Fmr]ډ.T"iY8 QUG#њfa)nJpw,xC ɎIS)Լ D2IP8ć% ֵbdzOԕRrCu(+!R%yK)HHBB@%W5=[m6e-Yy,\}% )6,iY$Ye*1R=-$B > p[kMZS+wWGlZ4چi꩑\rW޴zL}[iTPJJе+=1KPkQDV;gE=NF6pi#;osqBOCfUEЋ !NODRwz[R D#ԉ[f^URMgkpMq.:d,ʙ !-6Sr̛*4H TCmVbbOB dK($.7oVqꗞnʈڐN/R2rpI&-ז6-GmJWN~X3b/XRZu^Z$! JW9JWm*ٻ}1P cS9)7m% sJBTJ@˙ lLdAY58I &1p(N%CHGROi.@m1F Rbe*’\VRIIC+m RtB|2"e6d52[W=M|/GRiE٦)v8KΩێ-)F)/ay`G~?fnSr%Qn\ʔU-9)$=z{AI hXt ;#QPn hQ EqtUI )p~L6DS-{XܒPH '$ǜX#n0:¼w-O!',Ix+ߚ tI,Fҝap#*1;S6DYI[ \I3n8QTJuw_ yarB@ݻ e5Ď(J*Y:@%b&>SS30A%+N*zGKHZ!MK-d' zIo>rh-cxn״b;PlT).Q->U2\bJPEJQd[9=9M)*;GRڣQ\̝Ǘ rqVk;Ěreh;Kꊩ*#J$w!8ʲ|(`}fcFpM1ڥ *+PǍD2TC9aġ}"w<RrOz!^m^oQ2vr\jA L~f&eU>{y{%V(Ny B}O|jYIm`Js>/j)-7l>Riss/S(Kao=vK9tI@DH`%)+@sҵdb,\ERT* g\p䮷NZKhҢ]V_{pIL2)l>[Ҝ!Aa7)yN OHO?rNBKFrLXT5r$:wJOB 5uvS_.h^d0f-mR%0 $$rs`,,? kI% @|D8*#9"J{m+~d!!b;KcYmը%,!NIHcj2%^eiJʹ'WڎnuaHbBRʔ![CdzJoH' VT )[IX#kWDӦ[v L57 BjiƖۂC2W#׻iY9 \$% s|P@g0\mI,jQlEk̗!H\0J}W)}:ꕷϔ\pPFmw)zr^T]äyN[JpQ)Ťm BYP\[Ͻ2dD81Jc- ÎzNزP(.˚JLde)qk'rs1'L@LĄa@I+H݃2(wq5Gk͞H]|-G4PTB n!$1JXOΙ>Cv5_4~뿪u]m'"nTzؕbPk݋5+jK&UVEEPBN̜4$j#U*Ru"EDo0-;݌Tpi[$_y{U)ɩXY_>.dW@SUDGsNS1r̗9a,x1!iKUPeDه1Ru%Z6HH!رq{ ; A.;4[6[dYXR ‰mgVGZoi>cERۡ;!!+n"֠ʆ2csuU҃h9{,%t@$2lX2r:*۩S>b6TzkyADa4D-**x]n!ǩRYSc;qCqTkF\뒹=%^橼YyL&\.TKNA;8Ca")q;G)Ôܮ DBĨ mJ&`e$Ҹh` Y%kToWNܚ m xo־AJ(DduJe2*zB$u\b2T(OF7HmuzpRCNY6Nj^b܋" )_8*o9*} Óe~yM3˺%^q@m'n)a-HXB;D)ik)HYmPhX%ωRP`t;F2px|$ǁ==!RhV O% 0' 9dLU)N$ǜg>76V2\&YCspg,Y"R$Opio?I a%$~`^}8w?ۮ <똟AB4_* RW\THIN">Y?>wVsq2-dQ@ Xs_+Fq"]2IH +*2N=@ {x~eBcxJT::(1 $vϰrZ2<&ωdJDUjf}*Ӄ$͔K z}>7E^)!\r< >KW#qnn]N\HQs$1~]/7PYZJe q)8jTy?D/>c?c4ШD8<^zὶ[UEnU4ꊝKiy*m<*O 29YM ]r:StkV ILYKJ%4GNYg]Q]v,6dT[ )'ԯ x/5P qJi  Y큜{gh'cA ;05-4j5Pr޸S&G|F^}nبf:rNB[V87Ej'MR)orXwEK ,0͹*WM:E`̩Mi+e\i l ޤ TҤ}1ږH$?R1}Gex~TvhsƆFimSk+$rԵ61 8;4mS5ԣSn/oaxӏ5~$tfι4;B_p!/mÑpZjg\*ίS2qdGq VGÒ/::KQCR\U(!m~䨤uѾxUVٯC^dEV\4ju+M[XõR6dZ B*ilJS'Ƨ_G<5}~ [VTDqmz 6 ]ڣdU>.],CapVj떥V q*\ecNNC,#,/u5 Ԧ{0*=NG*3h\V4D6숈wyRӀp,#Neκ`4zūU2SNyzeSt9(S ÷HV2$8D V<ĝ[Jt/hzS4 {TZ睅RR}|}1%IrogfcX M Bx0Rw`E)ccOյlèjNjĤ"vlF&CaaOTI@! tˈi԰ݨQ/J^T6T-ŋ-$v:&KZInh-̆ԡ'b4+l6mQV HJմ yd9aJFd!m #i*IZ a'z2$HF:ɩETe(kG+/ᩐ5P؇/p~j%qoGmmR,shn(y-4d&SHl=$/iƘN\eCP[M0Qa@|K>RmEmB ݓ8Q ֤Rr#%F-\DlO.ZP I+y#G{ToCNٯ!;&۵S\ԸsE* \r2T {^6zqr%*Q:Y*&36>”ĒԵSyT1LĴ4ԐcP 9+mKjBuk\JD1cㄧBv@ (0_5uҕ8m~Ij2DLIcf3>۔斴4ېq[qi nZ- #qq H醘JSfߜ=yn]h) V܍˻aGIvVܫP"T5h2S!0[x:ED>D]=Fq ^),Z]RiT~4I ~(;i7 p2~yS6M4Y)0m p5GwۅpCkL%$r8*8:d#eAIy.302Eu4ZN~\-/\JZ}Е =iH*;r{e[4Ƨ_UtڔЛ~,؏18%(ʟ7)RAݐZU,%oGI,26A'KtoU]q GМ,*'2"JYpŹS-߈Ē0P uP>]uJD҈ ][2ϖr?%n-j.>@ǔՔ֬}L&<ϒۨal K>XIVd$1DwaT_ԗÌ,(^[Ǡu1t2VZiǞi%(TӄyRHPj!(0&䖹$1'vsmVx¡y7n8R3Np0d4AyL|vQ 40$-\&;6DtRa+%JQ%SؙYCA:Ev5͛uQ$E)hBed>-HfK@I۳aty*dY)u.}Aڥ(RpHtx^ԟ!ޚw֤ U.VhPv^ݶ*?MUD *3-g+^7DTEtԋ3OL2 |kXPxxBmEݣJEV{Xh̅G Hr,=qݍ B)0I$ /-]j m/NZeōh{Zo}VSBʋ`7oG<$~ȒJˁ֕Q_`' /Ğׅ@4b[6uUޗ`"™ު-¶"ɨȜ̔T/㩦\)PsRČ8(0d+"Nf$4Aa3.;hΠx2ԫɒKQ>xL41y/bi8iq[Jy}@fbĭqTuvD-*5(QaGr1.=\xMQ6[OU(.jm-/%"P7yhq*1X12 n=5C5xӦNhrڂZ uT\wS;R[I+^G Jg!D֯ń"<8Kv+Wv@keGKzFbvU꺌VBaثC B@p0%-OVA-_ED%ط6d#𩛀>lr\(I=X2UE>-e%)ؕ$d;p9cEӐV)IA-OU) XI)S^S)Nwwn'7J0i)RVpܑۜ3}YLXUPp'K1K-ztU<% +l5!Tw%[mH@H# 'z$M [v6MU]Dim%c*R!HI;n3ie͡QA `^Ɨ c;/K(3 mO6qу!)W0p `':<~=)I7{EuWFқzE,:hʗsҪUz4[UxʹmܫRh_f1!#N]̤4J#pyT, HB].2[)،m!E 줜p A.v kajXFbv|L-YO~]ѻM%~ +v@~0\3T=;#SWcv:|[24x>2fqo/jn7i I"j5> O iY6N[4Ky/R"*w=PT.aM&Õ]}ؔOb( s:Evry4)O)’Fzpc-]+ EA9DD$ ֻUGdm-GOҷnY%'9B(oH%| *;u2y xx'%)fVsgGFiθir)pB@[-IRhZĽV&&ѥA$]9fM /R!6L# {thdp*R-O! !aJ^;;exAnIXm9HmKe }'3ť]Aӈsm) #+m FOAiG.6II`|)!Tlc)1fRWTjI %fzӣ VFm J\jsmJ>,v *qӬMVtv-{x%%RHRKIKZ_-aD)p`Ge!z}}:q%v^ZK{jo)i(A!nwOcE)>Whڗ*2[\?Ȏd4-Y;Dm C$/iG$z/Zi[J\nuvot)(6`g*52 e'J-bTZ)%JQiېG] *JP-ŅKu!BA-VUzף1n;̢ۻd6LTCJV^JAEIIIR U؊*-e7 0V21펗X? i1d֨ֆ߅͋6-6OO1\v"F] ^l[$E+Yyi% ') Pi FzdPw#xQ .sE)wRr`"ERb.}6*,J&jH  /Mr#CLd e)@yyJXS@{T^9Nܞt(7#[TrҰr-JݷԬr~gZc vJ@*Ci2Q Bv R[-41ɜ&<@iۮC&ZHt"F;3*1IʎHZS2'֐p;:0SCiľDSRZyC(G#*+Vm)Wu Dӑ̨pȆGiPc71\ %9.0ʖ L<a[VZV83~07oIU1Jp A'Pmr?SoZyT 6׹w[s+eص>P jKȖRA*xWۦ_M Ũ *OT^Gܺ;K9d!=;(mR#ysSXd *M8o(%ȩkiX 8:a!+k-pmi;'' #؆tŋ\=ZM\ RU5 924f+(-y,6% $qF罇yHKA-A)#B9 H*'6m&}4$ԃo0`CC.c,/rS++I'ֽVѲ.5Vp-[rJY2 nHhh!..߀ziP2BpMȗ)7u`)fOiJZg Bq~2ؚ7yXnKP 8G' ;VJïT.K8Ғm*%NNDw鹷^qbR8I [ױ!I =o䈇%T*V?^q 4}h") 'nݩGB>ѓoT!Fqj̘oq橥0 8#؞NzxjDGTIp̦X c^U`\h:}X^q>c V_z3kaÁ>ʈ=K>)\K"t"&W)KB64.HHJ*l6Ž23Qee*ֈ|DUYa JuiJH%>;9η$8r1a66P:\RԢ+woX݀L{[l恫Vvi:Т"gs&S*QS>J=.)iq:xC!2-ߊdISU!Tө)V67WTĒ АRݏ$a%Bۊ+ hy':$4Av)0Z3#|(9zb%aEJ*`fO\4 ׎s5]9`YZJR'U)Ѥ"W)qcCR>IO10œSEP$%hNҁKJ[k+RӰs*UzBiasv@Zyw>ӭI mdRR@wEi8j:[+/)Mm%TBxþn 2) wK٩)E?6c**ah !HdRШ-Ԗeſ4DйJV(@7D}fH[XR*X*$0$:SugŮZ*.tKFBT٠8ېy=o@qݳFKqH#k4pKR?6=D1k*(Y+B Q".A}NѫITR.EOڅJg**[ISmBc>b)e+@RQQYjܝH )ʰA;= ˤψ)hmLFaCO K{}M^Rf\iSI 8Bp=CVԄÅݡZxuT8Q*βoYp(bTJR&sCn FYpA9EHBvЕzhOm)J삤 ={c\ӵ’N7*J|񜓞G^A(4K7sK,R:_šmpÍN .:⊎r*9]IdϷs1:U^wˇ@׮~z"v~"˶򭛆Ӏp201=E*0ýM}ysK)HJC7!HFiT$0{dgON{ghJ+ܓq8ԤsiHJB})8G&,CRs (II02S J%*$ 5 b?vl, _2$޲cj%2RT"^)i*+\!r@-bmW-+SiS($MC763 %Yuf)-[~1}Ϧވv{vع.=uڝ wC)J@Gˏ#i vӨ'5"kNi%7bXÏEJpԑ<6@)O kۈ1"ڤ% jH!Asarc.F(|$݀m`bkF\MF;K>ev~2;HUeCnPq܃5쯸R-G, jRYSm 0lڥUB օrZ n 6΋lIV4fiQ%Eq޿٨BB:JY6zEto-mWtɶKH"j[Ey) )mN6H9I?B}qeEC*(0N$L i&ֵw m`RtTr%&R)m܆qL8ι!E.$) j}A;)AE'lBl #ߥV8-ҨM[6k]0%[e l!)@;GDvhr5)d!_yO$8vp=D׹G$'Fzp,')z;PfSKR)T8H.R٘oJ[cNmŢQO2*e@(Z~G=[tDk]=3gwZfZbUݙS~;ԆյF9T5_BRdn)kօҧla)o% ޹,(-YIH-,h=K="Ѻ*=uQD?-m&=!)c\tJ-%kNQI%@AY)."\iB ;T$bCT\QaVnЪKK[ν&ڜc v<) P!CtTEW)ZaVe|8SChaBWj]^j֙:SԶCB{qYS,qH$)M\ VGZʨSo˧QKKaT5-``~Y\pH5!FGfqq4"5 E7`d^|n˴bU ҷb3$FLܬ~ꢝ0Fe։r0nZ}|v܍nW0ݫm m9eԤ!9A~jTU(wHgT*sN6e-BV؆mJ=NWG .䵧jI^SfrKW.Y+U˕T?G=re>mT#f;8ңh*!`2TJNKBQN=mf{>5k< 9t$CSE@:X-m"xm!CTjSɐ9RIQݑ(x&c'}hR*%e#Y9v7t#ív;To$JfQipym )Q)ڕzgm UR.~㡐RԬov z/,J{14'W(gff"OĀR9fzP64Jqm* RJmNm@Oqz}5ֿ=XTNᄥw)IJ=+ýƙ[i؄nCZ8 cW1J߃SJJ]b]*oHQ?t=x'`#'/R雄U*ƛ(Q)hKKi4EpܶijL4= @"%5@RJB\(T+-K@+e8ڊI\T((ZZ&jv(B0zv9tCԬquSo?8SW#-3cTPM.g]*Ԥ|5rǣŘۥE$[.2Vm*Z|8!Crq2hP`B jjpmHÍmc mLNRN#r,_/D i n*b\;$ǒXD!!hH`pkz+zHJ_J\mV3R*^=5Ye 딛rvkQ qa\ d7T,9u[.CZ7r9 +Z DJqI^%IHW5t%i!9=[%uD(MK|Gb&Kzċ>›ځ7VxфKWOGn{4jVx*prBԐ='p3/0TYaAhK:qZ)6$KϷ%luQ: q$\JQ'T4-ʷdDeAfĄ+?TN9*_-Uv_q迡bu;p=H(ʻiW)b()JQRAC`0?ͥBZR,v78|W#Jl߇ivhܶ!˭ؾ.*.\e;UJi+.DNBuix>ٶtW>oɦkQ_GKSaoIR&M0tX/B6))#;_2#[ąIUj锛*-12ަʠRcS%=($g%iW^jM}uw^Zro QSMvHDN h:r_fP#gSPD^[RI 9zi*D ғbX 3^u&m{WED")+G9;@$+G=eiۚn8%ВA!l-Cq_ wl~'x2ܔ^[H0'K0gz%r?*%!C Je{RWxW)"VקּٴP))V\m30`+QW[Iv: u,p:7`zf{D]Gw}Cgƃ+|DVޔz{kPROjd-- 3{>_wd"ZX2缑Kqj,dw =.GÕ\h\IZ #*-=Z/R?aq/ U2؍wjV1JPQޒSLU'dT+Kjt#*NqN$dGՅ]㟈 TD*0I)KcwޝZR£J, AԦ\&QVW!K yaALҠ11ZNl6!PXyҦVjjPmDlBGJ [@n"C9}hÜZ$! 31Xq0v`j&>Z%vW^R7l-%#҄ۡF_OF)a1 *ZuK6E Q.IK0zT׏gӭ(EӋULkLzLqGOͬEQq00J#$kkݛoͯ||3ݿ3!7D5>ƢƖNnqy @e&-Z5J pat&,Ҍ~Sqm%mZqFLiA;Dg%Gz8[\P)KCچ% 'qs%&dGVI`!No8ddI)b8)}A<{T}4ԍ7DYnޭSikmHn5"tf)3IU\2Y}i6wٵC/  >WZ= jM:դDvC*Nǔ':[[7]/E-U*ީV ׵ޭCcI`0j >p[u=!`y+rZ>y^azEv6ӱF*LGm( +WPf2㥕2 G2%%V3+*^)TN扳.nW `YּZ|d5L3+xJ m)F9$r{mm1ۂj>=ZW{r(JTSX}Re-(Ay`]? n,6ukޤ,.) : #z"!L5$n҃3R.bԾ Q&Ci+rbR}'jBP17=ErE5s .ۯLDMHJJm>h%ͧ)7eSiTLY(29 JOuV,")$2Ӆ جOt/9ˈJ1>dvwv!'=J@E˹;jW͋&ˍہ"= c[IR˭)AENnRdBV#KМy+I9({#z.HEeCImlJm`FЄ$NAei%͇9%W3|(r"CB Jb¾:N`)h*@$Qf$>gYiUg8I Zv#{59=nh};Psd(%O7HFԄ)p=AMg#-㲳䋚xk }D #w}\s&Q R.ffXӌw78f?e_&W O+ zG-xRjAH%m6xF;u9*<<t:SO 5?bbVMʫ'y?>!7=cЈ'!YApdo~~GzBqWZf0vN?U&o$, 6b (-/;ǎzL6-ԒZ( ݁;pxp *4R_,<*>ҒK(g&WQS^AN登p* 'FT4;?%B+#4^CQިpmI y9蕔AL0R[\[Lc1I/ >]^$pr;) z~"ecJ [[VkIZrChGh  %q❈(~6>! B ;oɛ*|ך ,F2Knjӏ̈~&wm?PѨlF|KXUAe|;E& _[56tU?EV :HκbX+H*)bC 7 %ȤH/qAՍN 3P$/Lz9n!YnBx8Ƥix4ޭx\TíUҘMCImhytC-um-rKiu% H W[՟^0Zqxmi׻̺ˤԍ1w ݡG>eR|:68mժ 5rf-8Q[b4R-SjqgѦQv~VO%I_daĕX9!K$ h¾sVNTM5 5;eUMh^Rz>%H[u$xJԀhƌ3)+$0 շsMm2r}t)mC,y-A-t>I>^F By_O,LjQl4IZFĐ8PV9{HrCL'#K}撔yps W( w~%m$&kI wH2F=8gnfSEV¡i}W02i =16<7.諮ڴi4mڜw7Ud=J jΐPbRV%1f;Ӳ-*0I2fTp)s i-jR &4Sh6ZR)BpX#)R}C'zZQ 9V2 PB#$:f?:RP;}Oӗ 5&'v@}%4zemN'+jP *62 9򑰂 :S;yeg7n@Hڜdse`O%;RH^͊JG*[@ l|@ZJzl OtӉGu:B_7dco:[畣%~^ *>]zbXy]+4w]ڍLI5=e @u)]RƐ,<$,8m+IWdԚ܈bneŐM>ZtҖT31sC{M_O-eڌN\MK-nmRRPJqŚ2FMwj+z'$ aG7o,5ydTD@ro[j٪o?- ~uսNL\x1SF+}hCn7[-u!t$›Xp2B@J0 :23X6+q#Ь3vʌPTT0 y( 8I30QJZu)Z%99Fe"E]ބ!HCBT )ڠyP|6xdNNM1 JQL2n8' +Pm %{9 I!]G]?%fZq*RR 3t|6>D4Ilj R'!JRQhAWAO=D=>5(@JJ7LT$@JQbBCurN5+O6cZ#"3 [}nզGf:T*h}ăZsЬ7YovŸ[]3-/T<]RS%)xi'!%{ɓ.R2hJRʔT+'*)ct"*k6 jPdo*+N#sqzĦmK5)Ke%EG;8"EzAG`[49Ttm[[)$)3*{d*-T}Ih`'G=dMKNc~F8KIChuLZ':*bA# &x.BűB~}&S%.MI1A"I6>%Ĩ'`JGX6MQEru.-T7!m*Km0[q(ʔfIgsX==)oT$&P\B"w-Zz}P0c 5_#p„؍.ARG+*9 ayƖj%1ZRn)iܶCV)ރ+R!^Կ(qdIi%%((BTZNv86iʘkXS)Sjgp@!`R8z& I,-S|8ZbjX^V4K`h@+MQ+tX*49u Du)A RBRN=nH]Rb8ʞf2FJ 6=JV yn8m/KK.` I#sQfwqw IsjJxc翢PRX ITu$&UQlggDLY%KJTuSK4 o;.<ˁT\\w\TBaRrycƍYYR-*)-TUBrK<[e~*."ʆu=CzBv۴qzY%C-^*ʛJTH9F15, B@3ٸdDˆ %* Yp.\8/4a6:ruĺjNOBK,6Zj!i_E_YmK~3`zlNԡFd)^Z*PfH/~i*HdK(6OJ J26$Šp1S52ଥ˝Ay{=yo)P0$"#OJ7êZazA⩔(u"EbFS*b[e\'%P3H޵*uzTJJRJmHڕo d1MփKq0d))h.YJ q5d+*'*pJ߫$ON9هeYq.)NU^CZn a8{'k'*u JKJV|ϗcm>H1[GE6->'55&#d( e-`6zn\q=M͟?PZTTrڜpqN:S)*O”ˎ-S!-mF4S*iIRR0Ɉ (%0P,)g6(I L5@$^l(ߛz6^v-4[S"cizYt8vQY>b\H[fЦ#HC{݂xִCuqiM)oRԓ]ZKˏ*;jԪHTȎ,Sq[ܒ'$8 _I_{i5:ɨW,>ӻ}w5>Iv]Vu>ԨL%542BL)Px0J61u81P*bhzhR C_k!r:(z)nߓ D:Q:ʢ̊MNJCJ jUQΨA:3SYR]n[4Tu/ַX1J!Ol_w~U >鱭gH鵫|WjWzMI鿤";eM(%I ?-6Wo-EMz_Ѫiå•9\Q$6УW~I2RTIZg2 P|;8$F0FL@T \@+Vx>&/mi15V(7-+X%!/[4j 8+jjӗ*hWp+ 8֩I(Fvԡȃ R:2md`uRNǣUyd|-nIì LKDHPq*u&Ъ,MB +OZq0&3-J]ZJyN"!ritѩPFQ,bJ( MMh,(NӓWCAuƫ4reqMBwu m_K7S)8iqdG&H`ɰ"D5Y:@N̒ :C//c.lCԧ:a*r m u.ynRFrRagk/rc)8܄*o(ǘ8>7Uq K-* $6IQ*ǖyT$H/Ax(jH$=(MKlmm E;S[,;NpmElT~\"m5HݯZؚC˦PaR|S\!+i']Tr6Ȣ5U.6X7(i_oFijZDJg[ShVEZױG[yZHUWObyKuQHeY9Mu=֖X@@GH 8l2mVfks^v<$<[-iv}g}SC4|mxlk-Kж]wӧEqNVT%-y{J&Z ĐԘҩiտƭvnx[ćqjium.oQtnţͦ ]LjfwATKh-:Wri)3!7 yu1O-P:[\PAqDd!) +W3:je@x6]mIBZr0Z) hS!)CfyUT l8UmÜr=#iPIO~*ƨUtC:|=X.V$6- 74tҗ.*HnVDlBRaʨ*t]o*pm%}psǷ?#DIʉ""Y_B@TT cn2Nw`U4=% !/ $Dg;uB)P\W VB"R k=n?QMa:}Jd r}~ڳrq8Kf)%)J u/ByHk RxH<$n-&u␇B^b A]ZtR$>-~gPYPlSckNA&XHoT,)lc*,oV-{b=7 3Uf˷ĘMCVظ! $Bq$ns˦xyVYilm80TT2Fq>uQbӣIoN APR[YXs%M?NZw).^!X !I}3&\(.}1$c&THKw/FnS‚]e z8I$~NjлLf#.r?MD*XFTg==8B]/+#?4($ =%:cC d=q9o\0Er$9-RD R~I @ }bI!qTK/CFm/4n9cMkъT>_7PpO=+ޑjRe-.-d-@7|)!iDQUQT( OzW#C$GcshI-g2Rmyǭ*B76 XFpuJ_ 6mYp~őHUl|{GYJJ@KEA$`c푎g j*E@yC%RT(Co-U 7TbА _@Y 9B}Ǥw3 8 mD2VT RI;VߤmDy-!-]K*'o`F=eabڕnِ:p0F&V6, RHVmFպ6bCP(1~rVUR6x=y"ĔȦǏ$(:BH.%m?=%mj}Z`Zթ$OsgI#8iqͪKCaT_{8 9+N8'' @(X }xRt97mZw%%jS0%*(VU#Qlr;䬡=@PZ9d}LnJK(VQHJrHQ q@'ߖAI_Qmo0(O╒=Gg;|AQ(K0!,a-B!iRm=k+{jYPR|);H9\01ӳ|`oҜCI iȌ$zoz : EsHq >jwI:~7V$8axR.~I)#q}f""Twm*qo<[TT䁼ԟ0L6 *I zc'IQ,`ZtzVLLDfĒzL=p1qJ# `uKn<ˎ./ZpPVHMwFtuN3S\5jOJBQ+yÎ8dj$+'~}@f 1TS-L.SТzO+8dt+$Æ5\Q|+tiԛvL"'sklrW =3MRl`Z<$1r1cϧ\DN 2ZTPQBJν!* OQk=AȲT)[P™Zb6J\qOr GпX+az_䲦@TiyŸh<bW op8}[=*\/j埬:e*:"ERi=1vVBki/0! kU*Q^eQpSksp%JRJpdc؃х:fy/&)FXmУ记a0yOC)H[UjQ܌h1'!gH.HRBz\d_.5?ݥ^zd)zCV3$DaTS㴈AjJZ}!tjTLTlD&hNZR.[vqTub M}]5ZN.2'M&˹C^5Dn*~iEQ*չ"S.گEe_Iy9nU[e0JamI0;OR٭nUnq*e.%D%a$Ky)][-6юRZ,X/cB.7~FC pC/@Ɨ'gfÑ>{u)WC O0N"#K.Jm)mCJ0cbK<) )(G41 2$XezB.-(i*K^a_al@%L2^›KRR S)zOE;V%)?C2c%m8\#-Ǟ$}JhpIujء #K$>tfs?,D %ԫ5*Y ֘ȌLE:1$!w[6Vַ2,1Ѧ{r)Pi8l<$=SIc2dOa oqH)ZՓF:=my+Cеyps`Ĉ'㣩JJ \ OVq{{^} e(ؕRt8ϹPo?Ya6q>5y\~v(_E%OCkN4:> 7E >˅ Ai\i`xDE_TTXBN0T ӎ11kVhuqpBWx79솗!{KaM-$NAD+ LC-Ig+<=H<\RD%E xZ|))B QP|tme[LUғ3ʅ`f6F'IQ*>=irA' UV;wJD18XQZl5떱QrΔK4:Rdǔ3 vޔ*-@#)z}Y&%|kISFb'ΓU1Ir| z[ P<)M5 KS$?ڌf[56Ӗ f ڞҁjr:sWV.<ݱf"4Rb&(R 'c [mʀ.Z[Q zTt;>3ʫ0J XBA/Frd&n8AP:g!ȡw5-Fv _buj&bWiiS۩?Ou)3c0)ے/;NT0/];XD}Ꜫm^ҪKϠM$}B_Ca.72$s)KiGs8H?L˪ܣ=եMM8&xjMbTka TyU9oSg@t)[5d` ],ѫvZmat2SCcJ5&]N?_*)#sN(kkre)u)I$k7ն#l)H&fU+I4 W5O e#Tu!!Q Bm¢KJӼn!|tW*3;M86 i +@Snԍ3#wzoZB Į<Ȕbq?% wPRA /:BTzڡQp6=Hyd&I)m"L*+J=EjP+U,)ȅ 0:HN8bS Ys u>f۬T`btFiho?U Ȃ+Al8iCRwOKESK.x~4U FثSttPaaZZٸ$:VtQ5Bfh91mR%fGT)M5"E*ĺV%0\ XZ[jR\j2_6]i,M"smT)T&,{Hl$!YGbv9,d葇+ު`UbpT@/^CbXSIL"*K,7E5P6JP=q;S\IRrqӷ|YMF:$Tw5O'jZ&>\.KLP d G岊l„uM8QHRA= x `u7b:?[$=bgYr&PO) jk8 spV) pg"ijͪF[Ltq[.܀=wA0{UsFXب"4 N#9<8'ΫԐe}^0'qdJ*'pՐaeln%,<;IJVWFGUOar8W7}p _jc%[Њ5ק0RmUuԶ>..N5){\l%a'p ^j_MQYm[*kޖY[S Z,TyOri"lĸZ[XU/8 HŠ3W[˅P@UChuiٙ ؎?N@*2:P 2"GUTWP&ގRz"t~p\7CڍZ{c5uzG||)kHdE;O!j$ :ԲԻ-`Y嚲}&jSV-"$ ļ`{=D52kDb}nc#3n!qr:X<8j Cu2uZÉ.uoLlrce` !idMYDďwi(J! IR Tܛ5TIl(CSg ,,7Mh&ڴ랱PXg%?ըLS_(Vr:*3*>Я8! X62r&4z4ڬ7kK'p"k<͆NY~;en PݏI$t~@$4^kS)6=M2r7g ?{s1Ƿ$99\Y)JH!΍$ Fs[*mC#q*Biʚ JH!8<pGbrՕ4\8А*R} RZ[4eKU9d,:-Ha[Dt}qi@r2aP#l۶n *\-GS)v9#=H!GT48{-hXW^A:u:]b*$ &TZKc I==J;!wm>@Ө<{G8R$֗KjЪXcKq` øW/qη*ڍσa|ԲZ"*^N[ >y7qINdƐJ)%͔,89XG~y]cTJڑ:m fmҜmRgTjnǘy]!:?TqslICԤKD2J׻rJ>Gu̯!AQ L%,% 5mff K5quJBBPJn un%;gԐNJǹ t"cq;Bf[2P􀢗n;Sg9 6U^֋6E]ڗ,AS. eKҴ%MF2ZnGSP!_cpY;sߩfDUқFA SnVA#$R8ԙxqE* #2)6o+ut1d"z Ԛ~ݝ->^g1M#J/S]zc52u 5$1 ԚYGm𴞷2;Wm!LטI9Y|䌌m$UJMڔo i ,o8 ?)II Xc\`tVuʸ"պbGe&@v5IqC~b9@y.JiMYLڨ̷A& |jգЙmsT8K&I. JSPDBTԀP=@kN1*PD@3D@} ^ִGz\xmJ5Y.2AerʌE-$Y!$aY:n/&6*^BTr34Zs*\CX/2U@@i䊑g@G44ËQ!KJJ)RvKJZ9e߆-bͯ[J -1 (qI jz9̠.$Q>egڍ{PƓ.#@Ң̕fbڶ?,mTcI+Z6+Ӟ:?ʔ@'zO#|ҩ5z&9P%VR`8sۣ;.&$'jox JdVHE$IRRIH w"a͘h=ZEX7[IYf) l)9)z@ :偟@|}GYή $wH<Hxۿ;Ԅ$YiJR<(}F-)q8۷Ԟ2L*%$Br\}#N:'G9ߏu+QZR)ʁyq$ # <V-`A +l:"jm|p[d{HFO|`{v :XS!ܸq@=vH# 9F+%+lPdډ)ځ<}ջݧFRV4ASTjS(ukΨQ8J m;JDfYu6b!~r]z~yRR%,W00ӁFXy%j)m>wLNr3FTzMMb J NcӋJHiX䬼y4EJK x}<2ФcD!g*ڄrxm THzs01TTZf@,|##6-&5^8c**RTTOA6j?jRn Tj`1)G mͶwdĶޖi.xD'IY{`.ﺪPҚ(1H~!ARSPbS1ڇwU,rmXnsL/[}m&e4ړlSeW(-QR9{w%Ϡ1Xd4()5ި;JE^PaVČ$6M*r-Vo[`bj>{۶))Fܔ)<Az>k-9ϊNRv%*>k,<4h2#BVi>Ԥk t>B LHPb; PV~jyF%ե'yبPq$/jNsOdkBe @9B3K ~PddΠ҉XSοeM)n-iHHA!(8sG_י`b2(Q9p9ֲZiĈ+(\ 76vH`(/]Dܶah }ݷ!WkwXn 4Ғyo! ?uIlT\mJތn7D4׌TH5JF f5!F*BYVkjeCl ZzhUH)8PkBM!9!xCj>ZL~>`%EH`)'ոzO瑕18)@JFX;16VuRȇyh>4%KRˆ نBvQqT>>ԮҶ3N[jJ[0Fz)V~q6;ތZQel㒣 C)P%MT9!!SVlFmM4ہ%(m ӓۤRX[ZB6E>+CB\Mj&[E+ ! 2=0ѵ2#Q\QBGyZDy*U6V'FBۙ'Ԡ)XtZ5RDH[ _JTXFԴwZHFNMb)\EֿjGZ#\Xm3.)f7 WR4Ij#QJT ̼ӿZRPA)$d ܌Ŧ5SLTxLJf~Jf !OeD}^FS{ nTRN6q8} $Hz jl˕pMapeEChK\HiRR !)8ەdo$#Pr)aG RI$qGKo* Ex7Liv79V1-) մvmҔ-_nI I<+TN3ֺNh&%d))@ Ƚ{d]jIBETY MbejQߓMB$v- eԒI^x$g]c}&`M*բ5MTc-C@Qimv yJ.&(Й!m*R-Bx>KP,<V .)r$m%(H 8 =fs Z`K օ\ "̬(Qe`i I(~+Uv=0ܸʖReѡ%(s܂:{QCl(qd|9ǥ'm(I%''RzP\i.n4jb1iJԪ_ 7NR !‚y@$sҡHԉrbDXILi+ld!%n KBZp$,ԶeT.]ެ7-^|j Q%UbAg ;eITަa]ezde)YJ =J$E`T:ĝINjNl*Czq]uiy8nPS b;u̺)RK!P II%.mEI%lMSm0dӜ(uI[N(J}NeF^wݾakD5Fz=?V|? QeO/Uh3)qRd . d6OCiREjFDڝ*i,4Aخ$8>[@Pt$uҕU(qSkQo!0)*AJvQi5=mrM:jt:Hl4hKǘ--kvg+RbTK קq!똂`R%;5EX1;[Gݺu]sYB,Pr$JfS~K-m(Rr0O tWFt#dVjr^OOz=ߟ>ݺ?nq՚īrۂTPae7,ɩhm?)TJyvZğh ZR(<[YrpOw \^8F/K(cHE"SЖ{ =RWIY VH<:ƎC:t4Y[4F-Rnlq)*tphJڰt6ЧTsoZ,+! 'uO)2Ɖ%d# ; S(vŒ -Ə%Je5"lVj@aRGYؓR2-$ .f!9zcO 'Rs@%Fn@wǸ^*OS,ԩmռ1(%R^'c:w%GnlwQ*s6 &8V2G}&+ @ 'X&,GV]8$;$N}r| m-#&2)2ZAȎQ[ƓۖĒ@ҝ 3=,\OZ֥i{M0-4i9rT]EVKHǓ%H1q^u7ٰ+ɡ5IqEBYӓo.*TC2 d]+)U =MN\%i~:ٛ"2z8U6;&[K1]mZm!T^WBj!iZP@KNg(  AKbk@=0dgYDߍdxE!^C9"S fP$<4TTF8 :2ZmhJH;ZJtT(w E6;Ux$,)mTI )mmԤ(LvUTl;a$A#LeI,Si`z{|)ECT(&!HzaQCb5%Q$2Z$CeR\65>> }=W\mjH;FA{ }=dfmB#a, vk2T2|@EA$SˁCXK$Ppǣٯxq< z՜}`|@Ӻ1ڜ74;c=xK>ݾ`{vQ),2Fdsq8PR;bSh+U:Q! 2RQFWGS_Or3s=߶($$3XC<$gFj>Ae@{RL8մ;!Xsf+D7uaE$|MCiq Ecq-n 2G~}. LWv*)Jqv9{K=RC|$PR '=0J1C+!%H8>'jO<sW*|UR^i$RjI892 -l–Kim ) Q>R~%N-y+u{0QԜ$~5 6)Sd7KB#Gq R颡"Dqp /Y c֤;>t'\5+wC~]s"Iֽ'<,X5B|зmeNm:T*7-#-tRTSC7DyVIPKw!j}n㩳4QUK!bD훆̬_-kùXW<fv)jm}όR(C;;4*9|uw_ VnO(V2T'g:jV?JUޢ:I`L=?-~&?e/u4'Je:D3P&l?6]bK[Y2R V4q V>lxtHXu7LCO,Y]`(SmrhAnRR&˨J4T|_xCj"*-Oo\vb.jT^KabS@^;6WcGa > FEM/NZ &u~D: Z*%+Bc)O`!:ˁiJRTO,$pӬَ7<!m%',TmIJBR{M6iXq(GY!E;?95A"TjrO {W )ǟ{q%d%TN*G9<<Mu"7SAR[(sxOIBߣ4Km-:r+ l$~%qD 6mX8@І]Ӊ!@H_$yőxUz1C\QoCZ w7d%g.pScӻVC2Bo הwGV8H a)Q*c#8ϳF#MVƆrGe3%tee^- S*mdG%wo\v5gPy%P+ШMS*.qšYq.3PAi+z W;~_<6HYJƤO75ιQc?M.K9oar6.okKy¥)*;sn͚DIa|ZV SxZU AH5ɹZuJʥW5"5GT*o-"lq-[Q @9jU%8zQ%ϰ yGPI)f6zfLN"0L'elj@6̧DTc<V`nrH QXMbr!hh}աD=#*'rLrD=Hɔ  OQ>Q\U6Lm:J\JЮJr{GE{?l(G=- BfxK$`q+1捸x8xudJiDe8*$Rd ,pR^J ـF99h+\gd%NZrNFт8 xHb~ϊCHAEtжZͪEE. -{#go97H/u!iBRsaqXs/V3O=h9Vrt!S#J rG[PS唩-# r -CV@4 R6$5jpBGVŞjΏ͵ƝJFSpt6]`ښh4Ljҕ'$6r[[|xsÞdgTuJ[}d6@NϤMԁT &O$Tt )+p9!Ԣ|)lԚYKAEEJTj\XIʊV H#jcsnv\I?-ڀ$9&*,CDŬhB6UNspH(\wzVf.m$fBE O-% k-.!)SXNyPc;`I9'ݍ){DKIR)Fg}Fzo4JS\l$34)R:3EaCiV  G>;(߀e~bbRTP` o2rD@jw "`Ng,LPJ $ 5^J2f_#z!D4BTTA=;ad<=%S8v"Z!~f$p W$g5Fj2>ҋ7 y$- (c<|R̓ eB)*#GG!jDb%p,T8PB tpSVğ/j} I!ԯLSU*4p[ [en);i! K`]lmZ_%Bޚ-[^+HFi) ̒qC΂Rqαi=ZUxZM6ؿzuVTS%ҥ.ZTl-zք>%V lU\($8iԘki)yQY SYZ㯗KA>a TusSኞ@P`f&;NΕ6گ?BߓRSkv*HC2Q\sp{en'::NΚbR*T;Fv)nIBd2TBGh*=4y/"sa.82NZKRZ8ϳrt:KS/ pl0̥L)THQMwvbRXQ=p M*Zo~1*fMjG~ZQܨ 8%͇A*!ӎBy2D~%y$:JR@<+)7 Zۛ<ۿ>K\Q$\2Y'%m^Q$0?vI1bPCp\XWXoNZ!u噝I?ӵO()R8n9sН1*bT!S[qI1R/8џ}Q(K*5RKix(cFrKJSJb(?'#IQc!1$C*Xݴ |<_܀%5, %Z?-~~1kkNBfڔ9XZo:QhU-jmKV.e*L#N~! ̹pѿDͿ#[WV4cj vZr~鎖Gvl6lU}j^I:~6PB>WI[_hW=8FuS|ȻmO ;XjiݏjٱzrjeFuLթ(vl_u1UXx=:g<6궓>3bիg}ƪ44խ,6i %B&Sk֖wMQR&̢u,%#RɅQ ~ Tx"~+<xL5nͰ:}oUӊgӭڋ58Sj,1K)mbXH}?AXn9- Z36%Z/ }`w&rVvgˬ1!&>$'[EWIgqȰB|.‰?~lV#sHS13cr> YJֆT) gZ=<xv2tZƙIp8ԄKj(;O@dH+n*Kdop--Vۜ`~}hJX8aVfk>&Xpw$վ,]-\t@[\vVrr35S Rvtt?.}(P%;0%*'7mp3i2[uwꑀmHHbI?61?Hk7+]cM>նǤ𭢱#TRG$G, MCWl&$6rp0>`w(x'{J 0P5ML\95Np>x~?OQS_%҂]"B' rG:c_5v׊8Nϫ4a;PHv;r=QQl<}V6Du ldQ0䉌cfĐ۷OL}M!4ٶީSQHTqlUHiA6 $z|lrjBHbvaB1LULÂj Kb,K8z1-q;rL֖Nv.8V8t4H ۍVmG)S`΃HD.IT_[+PZJR8*T7thWz ֜KC|I\|SmyhqmE*uT-f9&9 *ބW`fryH j&܍L0wB[VLVnK!z 9V9(SsЃ[ FIzZhv;|7&ĎyUHM'<ʊp,yKRZh9!2i3] 2C|жʏAFkP%Shk !m=<Jt~IrYu%/Ju)+hQNwgذ֒dđ vA9wNwo%FB{nĭL)0w3ڹgC̯ôJZA>PD[ȉ/f>( SȦ ӢP8p\5CbiHpԣ;7`phqm!D5o:G7JZ6ޣAfL98 u p3b}zp~ PE2*Ȕ#aKCm23ftn2v(qqgT>ΟJCN&2XzD|ZO鷻`LRܢm='(RH?tq@2ae(TʉÈL .`cWE'{3G`ėPԆIڎoA|T:bej 3RZxlq{F5@dIjn.On-%ԅ);ǹYR5РVT*|:HE-|Sb2"I!(`*܂(܂TNAwۍ6Vn0v#2䶷r zF6t.:0_bրc(r Qm{- Krk 0 K>־1(KpFNqZRnl[TbI ·Uy#=s|CxjДңSLR̖NT1p ^>]gPlc!Gu(G Rs;SFVt#ͬ:牑϶F;5p]:AimrVeczS*sQPTmZ)Iڞ@[N} WFOvvv B@+;7~|Z9hl0t\XU(4->A u\o`MYJ._ʃK}JҽA?x!8pF1avS;#\xIL4WPzW=$!RhJMLY1(ʡǓިEVPmr n孠F>GרLӊCyʂ)RNF; YAu vBSV ߎq\v9=EzJetTV 9sJG."!JSy ggg1HJS ABpR3)~cmyDGc'7$Pa%Ҧ+ >-AA(#E K6'v` H{nJ]aXv)a-POڶF +"4$$fW)aECQ~< 筶l$In,tL @qsZ Z--%)A;xH%i13 !#?\%I|zk鹮8&>-Q(% W\,(#-CGoFku03A ckwC_L9*&M!tD⼐ VOkj8Bн92$%%43ԝ y=eJtZrLmfI[P'Hd(( Tx cXzu FAu!%agci{ 8c*Z Hj6@S㟺p~6"LST\gہxLa-.4@>ZpU7Rq)KDJֿ%A$<1h6v=%[xO b;)@ %YY)?An7YS9Mx (w+TV[[\VyRRHv % 5-~?LqYVGXwk.vBǚe<ؠ[*RT@ Y$TRT1j »8( ƥSY4 BV *; D[G$UF *|F6*)Oyy+@ JfKb8ʉ4(Y C"Vo(e$HNy#sz_?PUrEGdypS(JpTG [J@~8 p>_VOW<^85ZЍ7.-KRANr'>|oWx ֦{Q\ {VN%"\"-ol0cKOb̎GJg>d":ԃD`iN1?eg{~Q)jIdAw?נkIw>L5vқV8#$+= c~\<`ԧ88,yWzjT,ˊ]b% 0gB0F cʱbT!tͪxB֗ߜv]}Ⅿ67̪Zϊ}¶*Z鏅w`*.(#\Pq)J@$ʒ=||A: {0# ֔jֆaEBcpqsD0K;܏; I#XC)x8A@MlڤѬyeĺeyjڤ`c #۩xzKqlm>"c2:Q*Vҝd'ă۞?k'"fc%έc7?Z`|7?.I׊j[J"RvIX')>a vi.ؚF0זd(yyaj8H+m(ԥOTgmgirFS{OzJ RV0XRVFV X>ZT=*N:'1P 8ݺifleb"ނ75mwhNTv!2IffSZr y)qV+É-VҒNaʥ l²|)RFx` 1?ҥ{!*ڷI竟:-_[үyp ee4)8!GxE] -N{}nߩ.MCU=I i8 ISGwjBR\!I`|uz,-^Y/% \`<À 2O95Sj@ԙSI4$жUХ$Rz7 .: #mN:ۮ31P{:[ʫLzKjXlRӇV;9?3"/ i%m!mfT3I94R!No/$d ,3-i5M.q i$ Y~zcb RfMif5E0@Wm)s%ˇ S%:Y7c)GsrqTB'eK.dp iWYSoGu)+CRd)/($+jUHUG[IwQo>eEYqMiA?p1)f Zp]5<|Z,$@; ڵ#̺o(p`R[{Dd)J-.@JwvTA?uXۗ8Ċoa)K 䡰d[Cc6*mq }Sg2UqUX*Q}t?N AJXN=9&`0L!ط:R)nέۣܦK@r3Z9 ar yV,j!!E%ZUIBR0TprBNr9(y3 %:f$?7"<Q`G[r294\mP.IX'=QNg2jQS&Mۓ@'MdAY47ԛ7Ei*RI/ AiLbRZLr4yJE-C XAAP?{ EֈbZ}Í$>߿*)JHNTށ֯0Z Pa YaIzgaVA ,6%O y'$YVRA@iG*qò%-׽,-^H RB`'8)~ BAtoSa*Zq>5{/zoo?|$Ĕjr^7841ZUV;v9sߌu;a%E@! +IQO+9ltoCtTɞ PlqZT_k Uc iĶ(y4x){dDsdgbn u];DÄY%Ɋ>\mHm;#?Av@;!6 qԒ-!R7s9$d(WR6@Xs02Gn*Qq ⭉PRG,<تYQܫq37ĩS;Y_Wt*\|,:רĭA${I?˭ib[e RF{st`ԙ#thJ}.`nAp8w=InqimiT2WhJAwULJ2T4ˍ6?-%* Mn|*:%56 ?-塅`ĖOs nOѸjM):6L-)))iG 3Jah[zqHnKjRH*mh}S7Am>댨?($ȒJRHI~}Q\_| An )}نI*-JaaKr_u`S`('p{eꔷY=@}֔!y%Dq’s N}#= -o +SHPy8<Ha1U&b&n2ɁJh7j:oMFm4SNy'?R~D[HTzS}@㣛ii{83 9%J+TA܄:7,sO#H+^(&,T7P_*b3az'@gn S4:i-½NJVr=sh6G% [qyc+#W%]Rڌ~0?~]jP+ln+>ܟcp ҉A٨axCn96.Y))VKp S D&%1ҁ`nv=u }r=:;(U_@q@ >Sm<ʲO_Ce-Pm}z[*L,tK)n m'b2TpVNq8>4%K0IJph#>ꂹE[lI}*^H$d眜:3%s BR \le O|du|ap .(C a]ݪ-M$sj)k=-W1MRy9~\/@=xSJf]]*TR *sopه"zUx-Β>b!@RZKlQ*ǰ'H_-ohYcnGC<8(SPD r+Y'g607BXafkc/HIS1`3Z֭'9~pUHy@E@|}p|OF?rg~_*9Sz_HM+PZ$%+uCNp#sn*@΋şK^]VENv2#v8.V^ӬA@ lx8>{Y>~-UhSG՛6$Є&ZqǨZ1TJڑˆ4g!)H1a@ = kUݬKA'J3ФS(\!O8 tdvH :PAF2FW#ujPeSg% \GN2g .m$ã-zd;I$ `ܞ3ϠP,.WP GSlw 億~q=((Zosp@81#Amۀڣ%gxV2>=fj:=DDCX(8wKzv=3KmHN))VG|cQR%NlbPpyO>Gc䥭 _NJy¸<fJХ/zHǿd:PYo: b6;`6Hf*`1^{ȧڑ6h mkar) J~pps~njtUeCqQ +>rO|XUF zcl C S*d2)IRVR>],;}ĤI%q6()#ژPcr)*B ( Ҷ0ⲥh0ǹDm'A #R#/A*Gb?OS 8<ʒBywGC # *+Ʈo)XenrFrIRI=:Lӥ*52KJ_쨝=o-e-LRq ؤz ::T m+R`H@v`im.:ʼqyRy;pQ8:? n Fᒝ9'Oĭ%O}ISQbJIZT2Pq!ЦR)TRV\.6Fr1ҀI]\\Rio Tb N(Pc)~:#XJq\)[6u=q&e:J\%ZJ1dSTKB–9ItzR#*BR Hj >j'%nY!N3s=2YqHqMH5n!*eO `@.Gzϟ RmJ)n(޶eCxG߭!ɍN,$({9O&ɥ6}JmI9g;*M M*DzsTܮ$>zZ0=`0N:A&4Y -.rg="]) ŏMІ˂tBr<q" %@ekqXO82=#6-2eGV<,A mo(RʲP$HzN0TG)% O H OdTe t0_)X+u^RZF9Q玶sVa _;TIVxI=t9uW(t),Z$UQkrR]nZyTTϾybD Xp _anipv ϸ$3?腄tԪ"c_v1)锇\Fԑde*F>]tV?3=iR鰩bS)ۍ-m%8 'n+8ItE!08Kv銥<OG.~@uT1z{gbN~ð}0:I׎˞w{s89~:XX9}=϶uaHZJVXڤ9Fy}d?^?SnqgxWǷߥȫ C1-]Xeˊ)js'xL!I QIJe$eJ=q/^z[-^%]j[n-I00D(q}‡ s'<{c'<@tżax?V/*3\M2MT#A-\ }܌yT]CUb4>=0#H#m-mJTNyǾ:Q B0B]BTFrp'qԣxB;KOa?PZ#x[ЛN򤧃 sfT%Rn5F.i}R@~~:rKR$~|bya44Qqrַp]zq/kQڧO##<ͼ6)B ʉ'@$M*z<_$p=#tîiioӜS )hceX,ͥC% VݛgpkG xr$=ف-O\F&ةԖy6OH۞aJ]<4)(C*Z2}鞕-RZQha猫#:Xo0%+rԜ$8 |PNLMCN"bu`ro;-+&$% @ 86 #:]YZw*+Wmڤ}ϬLi-yJZT )}sȄZDP!ґӒFI݂N92:V'T<ǒ~ ViC%K"m5fXrI,MX|ҥFu9X @(+g h U ʤ%*ܓ!--[;R g }y-Ai6\H*lgqQ6oI/ ,wsNE X1;?;򪀭 J 8,ZfU[Vԧ6Tԥ̧Z9 P){qA|i2-6>Ph֥d w=*:>BP)N!ЯNp2}lslbB4%]]J9q{ yy%.e""{,/LBAj#v.w4caWnBI JI{ VyI>,,DGeJ (6pnOMy1JC;H\)SN06$$r=[>=!JPt(rmds HP: "-,ļB?Zw5aEVJPYKdHʁۜn:M@Bg l3fs彻N !9`DRzE 9QjBBTI sup%9@P1€HoʬX4J'XJt𽉻qw~*0W,zu\KjIV;|}Cf_CRG '=ңRzB[wgrPFB-`3Y= iyyV0dϷkZH&SO+  3~_،'4מS.).wxljIyN66-+ڀʏr2lvSDvˣHJJ~d~X̏%J ہ*l ʎy2=xw~jP,c1-Ġ[sZRi\ }8!n6!iQYsg>$UT:X x6wjqc>8Z͙R[QVXJ>'=? T<\JBݰ&G*m^/q'vq890!2NB/jTNI+qap|<~9.7O;m*qJK{qV~1֋+U:r;Qׯ'd P`v-s07@RΔh@ u,p I۸ZO<-Oi.$*۸ ( SG#+-%e)JPHRI~tr涄]25b2bl0Tye8TX ;r -AD   ^xpC$^mVgijmI:dw%^K I҆W~{Jp,lZ݉$-9lH`ORgEP1y\+QBHzIO!wpxCa zNV|th~ĕqgz6weVHqPsiS"@Kj܄dHʱ@2i+e۹Ԓw=FX dF#c9 2VvTs!%AwR~c<=?2#b\ IG;rz|p$U(%dž)DpҦ Q 4#ZȖu!u1\`/؅l tPu).2W;!W<%<':r&[>kmKP#vA*pr=߇FtE H+aX^ B }dqϱa|}>&uhBT!}JW!-v8EOzI.Ry5{XެA"4X8␅${+9V}x0;"%0L2BZ!FI#n$<|@!POs$6˕S S4X-@8+-6jV6䎺 !ׇ{Z:1[T c He@"@21BQ,‚@pHJ@g\lEg*TU$ I .5Z߳'VuJe!N VaVձB(ЭrIGj,Hpme6m6(HNO^8#1 vČ%i!BR$%!#c +,{{4$ ݀ )!UX 6zs9<{>|gcuEa1?{lwac~Ib'c=Qd緷=U w|pGTP9O>Oaˎ?8~]c)9?Oaq9gdsG>?d q;ßOqnʽcۏK F?/OۏSw,v>=8U+>\ssI폺~GOFfCJfC-BuRTlL}>|KAeW 9JIa䅭M;}ԁc߷#*'Rp㠐\<[㌿`vTKUENBr4ܠܤ a8݀3',귄/=n&5K i)(*G[l!f%-O$g8c>t:o1hR:ʐHK}S߰4fIZh42UJʒRHR _CM q-Ӣ2 ZI#$w˩i*ZNQkVjS`eO,҅A]"]hUڊV1 mYIM6|x#bO9q#60fQK mkN.61T0QCz-ZnLd{-!$+<Gֵ2Tv lV8=$=%VT'i!+dL* lzJQe7 ?@s~v#gV;՟~łYgFcf,^vc;TҖӑ2Jˀ@T)%:PTڎ'<8?.ߥs9PaLs )ʊA$c 9R;[C' ^ JI1 R@3w}%wqZdnj}/*U6KJ[+ם![  du-e6\,n^R~c$}zQjVYZR=c1}zYC{o` \RA$>]FxU@ +AW^EmUQ%MN0m!ЊP)IS[K# q]m[(:\lAyF2}KH9OcBj.j"Q#o}+6&XZeFo6֣m- O N%+#r(OGsy=}*=vy'9}'*b.Ǩq垾#?Ͽc~n?.#ʻqq*oa;آ!8g㯀»=xwTP?~_=g < /ՠc^}~.zC'߷/|=>Gx9S՟o{tMMnPa,7ZNI) ?2;\qK -,RFJR@>A#~G w@?q?\]=P'ˢ7 V"0J wی`=|dEIl,'qu{‰8}z]Ezy~# x#~:>ǶˠU@ԡ*hZgbdq?!1O'8ö?87'_D>N'n=C_sq?{,\NG</WT?ӯP.F?:S{찱Pn?:mCjЕ\lZRy >^#cw}K }ӢzQz!ĶbRT*![\[<~ye[KK ‘ tʷKi'#2 {{c'ߞʻ1~Tkp%OR7j^\jjL6 er0e~ÝL'Q?r,S>|K#pH'Sy a=)s<6~a܈ %(52OZKRs儒m7R%(,TH My$vע {^T(’Dx"а$< <*?gKu+= 'r9Aݵ}8ODc ٿKۺr!p;9'<*k8~ܠͣzٸl?O?C/s㋪Toj|Sn. cr@;T]9Q}$ZrJK[#hBB[䑜RsfYi=K<|ߞ,4 N=\wՈRT%భO?+I YN)BғIE Y)N]W:ʖTAQi`GZI X*RPU!uѕ$;!_1oN^ʲmc W#'<~]x~cۢrKPP7V{tH?<ʞߎڍxdHQ[I{%kNSwq"m%Dݮi@ZLWAHt)Gw$cׯa6:N1ޤc uO-?۴C_ $3~?ۻ4eҽZ76 m1P6a Y[(D~J'h-B@P P[;B<zȱ͵?+z99Dɲ-|w8|&8BLP"m.Â`ڎp.EUljP؆(5RFv"((BМfs]€EDکKI9Qܨ{gz`7fٌvJStZǡt=^0!aCIriֱGH$nIa1o4 Kc/d+ZcǏ6[y6#kq^הd`({u"T9c<}qϯOq8ʅeP1>vhf{c+wYJI1(pM%X%\wAUX,Z#`Dx y(( ﴞ;O?矩}NR)S$1 $oxp6aiIڎ-ݓj6Obl FvAt(uo0jEGlbFJqۆOocn9;(I?!!)k0|pJO' H%)chJ@,)9~ö{~ҏ፼?,bI{|? \^uhGp {}F1;N'9abs߃698X}Ts8/?}O'XX>ϟÞ _gYacG=J{S'ۯNO'w{c{,|~s㯒F{`g^z9agrS}DzRrsoG_$`}OO~=tilem-2.0/data/skins/ti84p.skn000066400000000000000000002555471220200411600162200ustar00rootroot00000000000000TiEmu v2.00aTI84+Duponchelle Thibault1."TI-84+KKaP?(p=}-A0A-,?6,j==qn|w|x Vxv*WL}*MAm~;l~*9i>o},;j?"k?}*G-K(,I:&l@<Okj|Y{\X*|:Rik<}l{-<i<lz-;mAm| .1 )-9hJFIF``ExifII*JR(1 Zif``GIMP 2.6.802100100C  !"$"$C" g  !1A"Qaq2#B34Rbs$%CScr &5T'67DdetEuUV(FGW01!2AQ"a3BRq# ? @ а!ZRE\VWAxᤦa)]XJzD{,GJ̾yf~|?\+MI5 [Z%fHk)VоHYn&9|B ܭT\e~Fem:|T"\ˇj0YuGw=?]bBxNEIJ”% Dc9&Y3{!7K3.vY_i~azR 1qsdx#֨%xe1 o)rBbYc٤ ߺ9 l Ǔ\?/CY?9PηJPJ@Q6BD=-?l?*;2L5I>0'I6>9Zyu 줨cS\?c?( # s ۤp&=am)$\( 3!#JkOenrY:6Y["V } ^it84̵eyEVmBpDe5ifuyak䔸 2Mnh3m}7ί0h͏҆;7W6rkwg:H^bk}$Zb2F6.LJS^ؔ&uB}"2u&*MZXb rOʲ=IOD9/#;c=#dfu snzLD6#tR'V&/6 WTN'15Xt(_1E-!K a9P5W 5Vr\mzJz):K-d):ٳ.L6*PH/%B籜]:̺O+ -V25{ /#x69Mk 1Fc kA@حѦ3jZiM8Ql#㝱&SMrTk+X. &ݑWUpu~oxK4iL-^Cd1ɮ+G˜5ɥtuV]W}`` FDv+-2vS/>Ta8_3w]+t 5H} \;)Tt)J;\e6ҳd)$' `IQR8]󺔺Z>h7K: kյxts pu&e'57,lM<:s|@ø=e)6j\}I*BVEy!+Pم^JZyA-]!$\Z䁩ŷT],jj(nT/$ǜB3%*(Ub^^:=9S p^#)mӊrH&h%A`H_xձ6nGa?uAns=i'4%PT)i9-EIXMMXQ(wi e_^|xwכ %J#!\!\@?SI[MPahR93R2SY+jakqHUna1ZLA s2ܕbN&^嬛+Q^#\\릝޿=UJ%Rjbaiʡml|cxiV֕<f9X oQ.N$mfݲMGX">7P:ue-$H,7-X_8SI8)hxVzWz0\K`J3/skd㩉lZTs#nz;$pGbeVe%Z_@c< NU]BR|Rsi:gɮ\2/6埅>{,- 9A` @7 @@zgfJB \uue\uE Vs)NRj47Ȧ7lEMFH3-m;.lRJ;ƑƸ2J1Y7N~IU% ;-qOT(mP_RHDJHz"Cm.gy-CO&]"ijrպ$@H7ditY @&&C(&)QX[b^JnaƛJKiM B܅qaF1mD1?fqCM&f:LyLL)T\Iyt%BׇŇ$? v Rͼ찙C '!6 59na *VRx8\@ڍfRJ~JE뙝^FP&M:X,%)P r5!qc䮇<Neg]EƔeN0T(gSjM))eAeBoŋ$ 4LdʱOze u!Mr&e0@ZBň&ӳ} ` n>ͭ׌6u;FrF7:|c``G`yFG(NlV`_7S}P2ewuf?' nh&'^YGBڎ̧p E~$(Z9NEJvcp.W2L-G6gubك ohƐ/m`&/{ ^#x KWgefzQ.)q.3zdK}5jnΊIC)[lO3hOfI6SdkXsIQ腮QI9 ;KQ}7(pv^|U.ՐPې$9H|&+KíL jo23%jS}NAT*mTg2VJƖ;S,3`tƑQf?#+7NP}ZP ۴n0 qWP#~M09wc N:5>uG!:ъٕ3ܴPd3ED44FfdjkA}r_-u E.pAn1.BeCP$jl5 1!jJN5dZA PR|oOs756Τ)*$)^#:z Xzvu bb-+OͰS:lܴz\gJRIfN{r Mbsa6JRja*N."JN{uY %[[M֖ Pc]bN,@B,SFLAIT^rRa('MFǞD8Q,[Ճ{ǜ.( a`0;alMxX3mx0 apw7N퍓(b^}^kr9o O)9L܉7"=;fS3jIH'" @!N+[~f=/M{b}ؚr睈 ?>>>;妧λ셦u?cm PZ:8cgg p|[ӽA@8ui6菲>h9ŔC^k63;9Oʂ?ut_?H}/#N#i#"<kFʃ:G}lgoØ1(3yNji#"=oȂ#ч}~mMzuդ~DF #Ĵs~mI?DrO"H/j?>-#Rwu܈ȓß$t%'>i_lMpe2h[NA&1%$X!oDsWȳv#[덾D۶|9#_:_)HG67Lg>F~>DgRYtHG64w~E \|"HZW?##Rk?>Ec"6O4I`rGHKJ?H@4HG7|8 F7Y_0$t=+?Q"?ljhvϰ 䎑B4۬v s/YՎ~Di3->%'DY}mRypx]\Rd%%FDOBiŒy[ -|=}=i_lH/+Shczv ?? CB$v5+1^<ʞn ` K@IM#DOL*6Džp}B:\mYubURvZ;(Bi✬If0MԷTI$&CTyT:1ϙ tН4ֶ?)6A״`7 i1):ri @dcr#9AI- :|l)z۝`)[c&r_uo#(h|"\mCRnlv=+h(f-^3ZAdoGh&7`-ټC؇yhf/-vf35ebwR UJ90Jr6fjRCUc)D HNnPу"u{XíX|tn 휿n/q cYiR*)W4JqoEm:As1{T(8ѩJhΠv\v@NfY#뀣k` 4*>0.{I\kOscdhnl`[K>lt34p=aE@[{ Jn80 }w~E÷XM7i#xh)Kդ=Km{!G(:4Be_j]}YJn6~]a5לJ^Y?ԾS Ir tPpJQdo؁g.qN ?O~1;J xyD1&Mm|DN݆!1's38Vol;әQ gyrgI?i:S#n;U ',G>y+ .,tzQ%ϲ:^82y3>(Tj| rPL_}EeJH>b'U@[BqzH0$_[77Iӭͅw\`mGmkC2Db\;"!?)L=PfVYu:.vxՊE|iyLV'lX]6Q#5pqϤLVBXSܫ&beRXKZU;1N6HxܴvIr^b,4(WWBa1\q*)6i&hA6*t0:ÒN"b7^S-R'8 8K:J=Te2Fl* RbR}DbylA& 6t$7yo MKoRXb]m{!r:>F7< ժ3Um`-Ԃll4z^au!Cn]Q mh)*c1}B%3@MRԄgU՛B2Z9J,oXii,As&'=I ~V~Ԍ~q|K4@J+!=%N/uS3LU%V/Cq%0KmB`%U ģ*UvT}pvirRmq˴QkI]TUbWh!IHk~~1_ZSerI\4Aud6˚}UѲHXTk5uzDL̲&CE A-0 uS;>ڝf+昕R^:Hi<iiq HRT \[ *h%rt4)aSKod b4t6*;DYÌPRWeKLLSmbnv슓R g)f"v-&rmT&ѐIҌr>"x2zA6EՀ1UgtU0B%z34-{uFքXר8ӤpN,Я6%7#űpeΓ%L@.^L/1G3(zF̪|>eǢke*q~-l$k7;wÔO7'['=q3zh/\E䒛F[p/FlPF Ѽ+$bn(5l~9>@pq5zG"^ G_&g=$+;fP'Ё 3S@Ƣmn9鯌dbNыWd+Qm--ZOSԥ[xN !:0 3&ˉ{] =fQkesQF6X 3 S,H̵tET>U 6+y2!#R!C@l f ”iy St3)B,G' ӥ)T)'$BJGUV7=9-!$1,JqfJFv]R0e %iHXB M ? MOb8ˋ4)zM| ($j]ʕ2Ze3iI L˄;"O ;SulmvmH$[BIn" 60 [Ǻ);"KV=TēSXE >Tj>$zviWơD[QEQ(q3 kO]C/CuMkLa8S-%\5q) /&{9l2r&TVV@WE!%abFaϞ}$Y}idܑ{{00øqO*GtŔ[5oռPP$fԐl"BwUEƑ6V7RbB]8j\K;l*sV$g/,=! oԨ-'A61tP +\ QOVr<*áJ,o66쏀?O0Rmml>2X iX}l-"RQ H82\m5}-m o ͯ!: -mO\Dgfj)9$&fK9$z$A`B4C9c r{t<݄l_M# IVi6Ȥ|#H|aO{Cܾ׍F!-a^H|#O^~3'J]D҆\(隘Exog?ix:{s"m#lA@i}؃'#n (P4Z9uG7tnQq}_m-'2?!ɝDcUBuiOe˟(|&ULra ]>>hCX>‹%-%lSJ(9uj+G=hRL-0DŒl,BCx֐3_+gO"w">$ɯ~Cy1X93)l^B>v6B3o ,S# ')KBG(`oֱ+:̍c'~vIWt02Sո1ѭA0TPR>͗>DZSr2/NN5-.YR7'T pLH'3tz* rHN$V+Y0lN2JB1gӱ i-VYs*R<=q DaKȱ#OnVUiŒ qcs!sJ {:^Y鹈/mؚ"xIQdl#xd^  MML,'HGxۭ‹]'5a~܅lG*S,rEe#kMY4qFV?UbJU:꬐IČ,~=~uϴq>7ĔKNfmսv6>~X F߃*W\jE>s W)Ysh{,M`ŋUfήHlhbGIkx}R}>4ͳ* QGUFSƵZiZ24;q' _ygpÕ ^nj6RkG(H 菃uCQ{qPYU}T$2q߾KH -:o,Mq{ta_TK*2ko\<@Ұ L.KSUTw#~A4̎Hq rV@7RkWUnRѡq;I*cZ@mqh);5jcvL>y zF,&}jmc2V @ ©f66LɥViN\q_%|3j,- Bwć5xj.n dvFmA6bcDR9kFgXOdg[^;* 67$e7(yBT4MR矑K쎙P`qO"ֈ')5: f''f* 4u ,T<*MBfy\OĔPWF(GkEAMM x^u#0 q:2) *g$k&U/~)!JmG}3m-0]S+N%/6Vt%BV@bV*XsLY917Gq udYv\r Vz*CtxoERNj3ê xY 's.&YiM.:P <"]tT^@mـ-"{ J1`~zUqV%0lJ*ExP#%b*|=SntAɷ /r-#';IW8JXߺUjt^IV A 7'%vc:FR} 24:IrVB$2$/x(j=shCϴZ $DDPr^MeZ% x2Gљ[T|o8]q 6 s)۴'5,=OU1 uV?0!P|[ЉTR|)kL@5ꃽ0\m{D\1hnƣ4|~dāQ*ik h_I5.|1`v$/>,;i+d>R&>@zxxkA =~3q+CN;܍- bΗE}f!QL>E{LJx1-QoGw(3q0z0XRЏގǴs-3TUäLWANngs Шn]F9) y,\O$p?}3r-V3Zli:_ C8ByxVT>rYoɱa]|KBSmSuC)+P!b@nuxz^V(OeSYćqh$Byk9k@AYns|kOҞy* Zև|̡9Ru36Vu&׶ʅg6 Tɷjs(Nܣ$FmaAni7$ $oh$~q~`xmg17am 9r0%$\쌋rc[[X>;D b',iZ)M%Ih,&׉beiqmv`L`+?uDQ iSRԲ#"Κ^NT7^!4YR -ɹT *9Tr7\άʷGMNK+*[MfM;bR\kF$۟#Aqr6A5 "6{\vƩ׳2tZ6^ h]V,vXߗ(ê9HocTGsob- ٓk.^E$޾xsr\\ɳXt,"1maGq <Qct.Eqc+x6):!qFY֏b$|LX'nz#Xde$Q c @磱L&5ԒwEk |IUNQ@?7Yً'0!|ttef6{fSaq`JyQff:$]Mr_ N>mtBX zɸUJTU4wߑLUyW LJRM5P? !%LL:I9TPܒl.FJ$Jlr%A[ H$9Ur`o)@5 qU}< vkqa~(=`$\H#kR9Ӗ{EĘ 鿌cK\~B:~~$1{76>ԋm /ijcr66,o}uћӔ"ĝM;`E90in+lWHa|o1 D'Dܩ!J^E[mƔЕ*,DT]Z鈩uJ yؐlw B{ RT_֦G 襥 T~ ;ŷe _C˾ *@`*xvD㚄It|GoUjxd,nOlIR@>Ku$+0l܋_ ťlqm0.5Xhm0@ͧo.p1410}#vuADdUl LX<pR<xoɑ~Qgy<aӿ4qՃĤZ~d=lC-=9@E^0ň ; AW˵cx8RmV cco߄xj0Vz&sEo3\|_q*xc մut@?zμ>Ky1kݲ=)j<ay^=bs{fC ^yJʒӣ=Zx1WIN?~\G槏ic^,r`l>\)TtD6XLHЩ;i֑9_6/,aUͮ~y\0GL'TFeόT4k"(~.⼭>*8voHeּaJʞEB< +/$}|b=g3LWiL6␔,Ӻq iLJPr{`t)xIAR약'MۑkaV0L˕Z̠֒nU) RC Q"].b`n Sr'.óuJ/UnnGom$QO8y{Nyp~饴)a(S'*Ԓ,tOjm_oҶv28é_@s|%=m8͹iaŮM/i xN̹3LbJtMd$>, yrňSad'q,OdſaaŖSsOݗ-oɓ` a Mg[ H]"m9^`emy ܬ[a\%E9 "X FRϮ*qJ;*wH߅?brCXbl{0LSkՖ䦊6Ȇ ~('Ipi4r)8hT'*RuЛ \﹆W$q{Q/##<7@q8BV^o~  Nu2DOk|Zo쌧/+Da\ XQ= 0u>GM4p*I+&k |FU&m=N\ùYo9wQpU#Cʇ-:B39F8b!IZ$IIrk$R&b,S)5T4ԌPyi *$-cJVW(Z\fKnčpy@5!5zdVv2\yqӤ$$ڒnYT4g))} Ζ"tU{FstH4.=M M]N9v Ía,M8Q4m_&ߴTu`) CBCLR Rl1BR.c^Go:N/;kҰ{?ч?GħOFI&=cL=}<Kpt;ck-/9t_&*qCMazR⼏p~Z:p-ǓaN O71=WHa/ !O[Hi~6؂@OPZ.OeQLaM1!Dk\aɛ~@czg$6© Ôl,IvˇSEkJ2?զG+NB==_0ڝʅPo0W-g& T  ~Zz'$*Hٓك|(6v5#s؂RmӺ50tyV<(d{kJaTXCt0a  $VzSS*TcSPgcaDaӀZm>RJ o_-sn6O3rDTrVlzH?N'I6ӤOApAsؕ mn\-<\6vvAlc&a-20v;a1|'&)~'cYs(*RWXRN$2lt8KLebٷ67j>()ȩ1(H~Vw'*siױ bz}3BiTc3[Nn2K`$qHj0ii92ҲrI˵-.l@ @+u?5_t*^}i ,<[ J=+([0cF3?RU)2vB]%QdѻmU#F0헨 k:ELj^kUurN͢56epz1NvRnYNRe[lRKs3koKJD)#K d\jN֊5+L.Js֖RBtZUSZMta72VTH#:ﲎ@t탃 '4"׹1Hw 1GLP)69F Ņ,<(4eER:Q0ӳj'*JE[q`KIn\5w:Q${{E-}ؾ]TTAJ&qUYeJ•dY#%1xq\<]T*Xo}NvF:slU|8c!JW.Cymnnqg*\)8 3 N=-.mB_[@E4jҽ^s\n1+aX~NSN˭},Á:4e9B*UfcG,:ХYatM$| 8)Us֫Iu,,$ֹH's$eA5ߓb2M!qI==W$ S÷ry IR*nfd3yIι(eU<51,ₛnɺ7&qT9n @CئHXlG%Rm%M!* 'oTNӮr0gD︍_Qn/{6_TH8n`;Eq6*+N6͹kuI7ey!eGVjnVvF$w rM 8ǎ@0mc4 [82ム$Ȱ#E!]ѓy 0s Brb,U1ďsˋYON@%y$#~Jt` P~4럢0"Lj4l,T2sZo11ӷ iEeQSRّԁT5#XtLTQj\kC](KP?!ыGBraz0E6ިb+a4;ol% %"uU񄖸7쵣ŽQ#B,RA,n Mƶ\@mw@[Q{ 5NRO= XoqƖ܋Q?jSFI+32sAǂDZZ& % $:QX7Iz&u$I>RpatO_i.]2)զA$bIa(nV2@OL .Fkm "8JzI*!t0)ι*܍m,^OP pM"_@ŭx X^6ԋjOh>FȮq;LOɼwl*=wVؚH_u%xH 9t^?I"\.N}e;(86?*jr)7A,Bҧ-EFot=iTiS6tE'`~/(N}9l+Mt+WqV0+’yN:mK1!G{<蜣y-T( kbZ{*h&7vupnFb$zIU9HZ4m!W'z^ xs fWUV%&\J*te -kV!w`Bcj4E)WHBʣh "D ei{ܟT`5݀s}do:AA4X0N@UlO|Z~Oi.U?>>dF61Eɱ7Ga_aDh(lWeXtHNdEþ/"?kiѕ_@/ 44sDË#ìno>q ge#ӸA?i{e6#[H~BcW=ddP幭A?Qdt}ode$ J,P| ,66ZkĈQ\(h\]G7˖wI;;bKL1)rPO"y^ȕ t7l)q $N>B9B%hlD@$?t;mvViW. P`u?1J*XhpYR7ò[;tmp sRnnΓ)&4{h1QT!7i M#A(z8a|o̔Y1mQCn3p.&6ebӭ:C_;32sM>Y| 1lQIB) ӅJPIOJɁ却i%_X8O*hh[uGC9tS6Trԭ,l^#߲ş5+D`=YEr/*UEЃ0̊XI>&ˡ VG+Z6MZ2H%uKqK?Hܘ~]O2/X)y^jêTa H҅u/mі fF+-)%[7NlXÕF# [է0Cmݤ 'iE,}99 ʯӓ4q!H9M}йٖ<3`sXg(J=R~yl um̲e. A:JCn;c7 d^ah;K@AU=@%C L sќ ւ+c[]eAeJ2`h:+2 rx3( %].{`mmM s?(S m $.MK4{XCJ'$-̎Ihykd% -4[|b$ǀi̛WNɶdʕk" ԚʉV $ QqW #MC $]0[a'F |LJBHRMBƥ&)'ԟC7`=(ixC[EOMMxю/2Lv´8)1thq}ӿ6>"&'!ϝP#X[e_+,h Rm`P m d,5$DtR šJZ[ yaiVU'ARR%.ny% 7-ڊV9Gu)*R8+ HZ^ 8;4ѕ98l'$,2jmxCM@|l@";_&hO-.U/=2ۊHl㯊'U4B':D}"m|qdK6EA^ )uaJKИ`7;?6î!HmES[r7絢d[eI ؂pּ5V3WZZ3~ai,mJEKtcɓ8h rV9FN)&F\T^>nSPkߑ7];Eղ_S~V瘴^͛6]m*N67Y󎯛 x|y>̎#.J4rhf0l =.ۡFYJlmmϪ$*B۲(Xs D-ˣ͓[F@6ɥ{ l _ Zb~vך_K ]a R5ZBYeա6*j$tJK^Y6 HSejeQS^;WWNۅӯε9ko^na2IJIhKOҴ2nrI>&\ ‚keA5o-%We֦jHZdBSQ6Huʋro74S)dq+ii!9 }YK@'>%_Oɺ&KXT eM8xݐ}kaա¶ҕv:s0ʄr#A/E-e$j*+2tegqi+%eVJs[_V (t=ֽF(As .V18qmZE<`UF‚$eA99/',aPV6J' 5XG:1xa8TBfYi 3|s6kN{4:Tebm<*!)6ܼ$]t'r J:%ɯyFgFbhWkf$”PJCeֵp]RiBP\PP`9D2N\VXFI-Y{(˓FRkp3o'En.J@md.URJE 0/3/4 蚙u{[ZzLeIh'c8i:7 ul*\ʌؿkTVѾp~口,I@'T?É|Ϟtg>=["鄍zp\yBGi aٙdmH>Z')5eV Be{ y)UE&^Mm2m8lVR  EBҠGqp^LKғ̓M9Ѻqn"; ĪBCpQ>ƶZO0]bNbY *1,v :T41A*g*)ng-H9Ov`v=f׆"J Ij^Y`Tmָ023YXw{uiuRR$J^#\dT6СfmX5TAQ) R#JmotKl4i")! XG{%JOUH6R AEN="^y ɷPl}zArR) ΥEzKǸcEKn(ʜC%7(=1'+!ҽc/e3&ܹDuAWRVNh=WA=Tk_|URDϤ)kՈVmk?i%J+ΔѶڀ7kx!ho[^rn I:2AImkD^wJE-̸.Dq6~Qf%ٙHR[IPNejI%D&FNM 4ufņ.AAtDp+ev0ezU7[߮AhL:M)^& U)柔J3*Ib5yI6ihT2kC$-I-)|ú)\% )Xe )2,ۧ"{1u%[eDz*`NMKhK1 6Llu'BOF 'B諳5-u/߷xC%vٓyʗVI&7 RLNZHYevrČ+Ld5[eaLo^0|O1Tf)[&:ND|VֺgSyW iKg&':Rm`[)HlL2 1FTۯOb}9?RP\,a-FtnK/N&CP&䑖rbM,J2[ ^D:E1ꌡm՚idj,\ mHY~gKZ.]k<( ={#2ͥ/Ly2-'2VNc&׭i`09<*WXaVaP;_|+VOdGf^MZ(m) C:BJ!m:b2tJ r[;DQS]3}T|̋,uJRB`#m޷M]Z5ZzpKbK/).e%ɘiMeE7[*5ɚYJ&\.KVVm[&1'RLs(Bl"Y'{5bLKP(^(i\[ʼnVҙX>^ O }w*-hYvU r(RMtU le}/HOGNQKvnk;okVGT;RQwTǀ ,(ХWRiS'R7Rk$BL /=-Hϼ&>J)lFpbRfW6NfW2Ya_]%Vh0MXCiÛzZihrF "$1W͍2$Dc|u}\GG5qM~>15}HW6 {c/|~EnNH\ MɁ1-{fei@i:~*aδc|TͿ?\t7y/ɤu=Pq[:8:z'K#%?L?=V!(i%'GNNsc 셌(is3\dre)o픧xuM< iZ`q9c:HPtxi~PUd&Oe3h11qXY>h', 7ӫtjR)"mԨB'b!PX шgHf2l#Tۜ̑7˖mẀo U,+I)M_fb ~Ⳬ »ROіSP ~&' @ˆ+aJbҹ9Jah7J(kUMs 0Emѕi !`¦*t ջK+ɮ`wji1i,aب1¹>`8*9y;>忢DZvF)?tzO Ps s1%'RI$&5!"Cw@>"nPU]S5JqFkAQ6RAõd\ߨ*, 1H𓇌 ʬuCTa旂p5ar8j.$oҵ!t#U)y'K7uV{W) Ґ h; //\c KyвOzP5}w֪ -b m2{2ybSV8O7_-YSXelq,:ڜYK93"rIM?~evOK>.ӭ;P`Дy ET)ty|4\Jǔr] ݉v 7Ӿ4Ru*[IR4eõDC, M%gWŚ  G8h kA*']Ғ30@nV-킊QN $\"׊#욖ہg؛y2a[ WhjzBrHUGqqN"㬖_ԉ*<_YF -4mMK-){ |emkJSb"Ʊ:MC"qlVxqZo+|Dt?"G:yQ ta@w_,ϗƩque?ВF,hXӨWvS֊:Q.혨teP=S\Ht3M:9l߅c&1ٵ?Ϣyav:Eu+m?;.ӗ:t75йHmL5dq8¯24Gi:%N *Ussn#dN⟢y4O)WD@)?d\ŢEN,jSk.'٬Tiʾ@;/(zrl0mmIP~Lۧz~PeUayh6lvRlB"?g#n '}%0AS޾f)26rY `/ M-}1u55._V G Kط0oeN]PlSYm rQ# y.C'p$Ra͎)qY86.0,Nx8&1KxƗV8N[K$~Κ<ԏô՞vyc-q tVZ0a|rh9<~<$Tv7P"_AG bC( GFO,"A_$~Fo'8UaI4F,*iԦJ@SϬ٦SȨ@k7]4ФDVl#AdEߤXa z\$򆔹bS<4Xdr³ $齄` 'OoD>RgXqXjպ{:DSAEZSVV$ܕdM{DDiFq2 ni-P`LBGzOMGDXO^!+k;"F[(n}ObRkD{bVoVdia 64MLf[Jܗ\+' G)t) ^kacaFfU9HnRN6U=K)x"UNr؟y5Ƥ3< C[zb i-Ie(ͥ>誙b%XLL x>LiL GQ |D&gIN* V}+cu"UiKc@6Χ@UW;)| P@_K_//˃{SѼQ87LG,}Qz`FDwӥG)Yo?hab멆[>Q~' Yn\nl9q`6Man;aXsaq= @ lu1 x5 -^{#pˈOXaW(ҙ18I7eI9uݢ6(7QwBBԣpI )7'od I6;,Ev7E&Z2Us/`7 "׽c$ڞ'K1 &hT*5fԎpp6zò:M8):ANĔ5NJlKp.=`GI2VV4îK!s-4,8IMB<ݦT^HB#ONQ/unDm0KHR7J HZ*U>ܢejRll68:Wcno %~(ܫ2˺^c-,{[p{ ?15{ TE.Q3QW(Sƙ)I!_0SHP JI7ob Y{և&gQf}9\0nl Dģ9^A\QWW  :OW0Nۧ*ҕ+|ܝFDQNK *GF+"iΖiǒs}{#EӲЩҬJ lN5&f Z½N#`6SkjvXPkh nj8Z `70^'%ggݛ},ysZN6y;3n[լRtLg i*yLKI*ZU@u+m (yZzQ֥2$RE Z6%n3$ܟ.SmBPn2d}P:-B,ܠ~jUlۨSjV-툢H-[E@HNe$`YGt6 '[^"Đ!a'G/{!l?D{] xdnb51TYϻ}qsbʒy )z?}8/%p(m咳P&58# SKp|̴[[K lA_>[8{R~Vٻ}kxtOpIԛ6ޓlx>Vc$9Gl73,aPwKV]cUsN)B͔Oʯ星ȂHxe_;~4idjՕ'RNaS=UReҴ%W%I YnJkv$kVU$UdGMdסAJ UjE9"NJK|R-:y\jqo&e4,33SQO[ʁ #uIrn4/ 7(Ն_a@[[ -(.sCod>Gqp*H%lEJV<~dGN0K-' RSY$czfK jF BV.uGQe*)4/1YԹ)0a%>&k2I̤%,qLI9!6D*aMXy!E.!I!I);5i[Ua: F777R,ByK9Z3 IEZkEY$HWl?b'Lxk0vƜ@ Muf~y vƜE1؊~$-;!(Mסi MY_w؏˘P~,(k6;\>\&Pia혨0B z;fIډ aL7Tt9!]GekíCR ̫4TLKBzO.̑k7{B)Ӟg2Q9](m)wF.9&Kt*(wZ&FK[1Fs-:1-c)*X.r`ݧL(Z58fmՠ;S:Rp|%$âx^dმ_`"}zZu*$Wq2T01*)ԲΡJ=}"qUȄRX^i9c٩vZ-V8s8뚩gm{<#,`iܙ^@PY)@"4;$R v}#xJ#U:HPMp'N"a<5$m٠FdЖIB-q9t^'2hNBv'*MuH0"Yv"ȑ&٣)5@D = txd؅(F]ttm"~pn*]uSe؛[9:h1-_lu:'`' iGQxixㄨ rG[q8Ue")uWkS4gJ;,t# > GG mEZm`:@P<Q M[72Ed 4[.OT#ë&[:zcLt 9[J|IgW=W"/sjI 灂n!%YZ:~ܷu<9?7PR#L&aE9ՇЃX2qJHեfNXJ)2mZl X/-NZx](U'MȥِK& wa9#\=NKU3I7RСnם=B6أPvQĦjMՙj*RI$/cI:S4W(ʖ!\VARM;J3Lr"i؁)t9rzuCzaPH; as\K_'\#_`o)uF1^ťjR j.9B)٦ena4a(I*ۜ(d۸qh-!=Ryjªldd7СHViwu81)6'ls^zLhEϕF%m=w6ܤ]G.q"YBXL dE! Y$T6rm~>,jY>I7AQ3SJz8H<.c@wʒu1>Pͻ,43ML$P2r!Q bī*n]QAm.j}zfz>U`/np TѴK(Hq gH!%j@ZRnR~uIH>TYpU L6&Z@$ɰeZbRWK2_dgB;B}E͵o:g9G˥"˩t6P$krǕʪF! i{_EY&?w+~f-)Mңw*@W0~4?LxӦ_? d#z'q.t@~$-~FVL@5o& ?%YpEo{U<>fG 6>9%F7?Ο b@Jk941!l#5L48{õ@ .Q7g[X/f4{BX `:jI;z2G>L M3*)7u:]KLAS2덲m*R֗I\S)J˔_$#\C}H.ZSZ0NQüLM=QTCO5--&FF|G䰇OR:Kk i#Fa{1% rnӥe=*’ಒS". RPÕ[ m- Zm~{r\3 E!97)7;UR&)q!C­AceHki0!>oT\K]_t!kG|bZIRsIk rl>ÓUr]l]J*V7}2DBq;v7W6N'qzKJ)jYZSL6%Rܒ@h"jQ*K! Z[Hk'Wk mj'QmE,2ȗo#Mc`µ:ޮ~$$eQCCRaOK|k픴6)'0 ę ǥmạ*YE"{Z3(= euae x" !BvW V"V2:) ܥI>qc53r7d `Y=dqJ-itaAe$ [fR&SǘFNz?]D)*9_J=nTyd'N| myn.u)(EJc^:M4.TblC=jM:9sq'0mV%J)xаUHK(9YjLw<1vqѼ07!7'PCͮZE s>Yw˺ۚedt~}zT u%2ml²NN9'.Kc2P}Q K6{LRsm$ P8K.0m}#L_KF-ZMʕ%hʠdiNµEۨZ 'tu^9s"u38thR@}n#|xXxIvqjh`|9GaPu \Tlp4^P{:tʜQ'wa#J]WerHW^N+)KJk\&aԩf(n5+tv뒬0N!So e֤&+TZ)=0J:RmYW:@®ݽa92K.kE$ABZ*~_W9%1lRJFa=b Q.~Ǫ1cN# .ofMHꞙ40+|.MCߥh?q'q4&?$. NZ'}#/Fr.&Ppԗ%FqgCQ=[$DԺIY>-H?Te +Ҽ3)'+OmꗛΨ"܍ -$J͔mK$w ajab\+Zh9E3.(K8IEҺr(?kvL6qgdS. k^W;AQ=>mPNt%JW`3o1Y!'OD8E$v` 89M eFS&qce7$ZDXUX5TrM|E@R5 enw[˝j*PHwmO-lTV2xf5Oy>MMk|l1xM2ر\ &ݢ*4lIQMRcaT[[C'SSϰ It{5#KC&ܕf3Kju()" ƀXOL6BWJAPUQ :%A/KsɝK&YX BA#}4MT]J Y N+=yKK}+ULZߔԌʂiﬡE+ `o,AH %Vzoʺ|̃oUee$f[N> ciHP Ć l'pM%j!WkƄ5[MT9tS)<.]@>!ӚkߙGN)6^I딺~ v´*UHمs8JT-cko. }bJ6VS˶Д"9,j&핖5'_X5a7f'8PaMڒڅeAs:rGls/ 0)723zhtw*Yjs Km"2_Ӌ iPD,ẽt# >Qj 6E/7Px,$eTi1$o/ZQpJ+669dMhk=qSX lDqVUלff7Z;_dtܡSZU%<lj!%AI J.4p,Vm C͋)6#7^m,kUhC$ %RU }lMju;Gks,`TƝ [*sr\7%X`Kh6_Q{h+Å8W؃cQ} Rodƚ(qxK {mh̤a"Ez,l$k2ةBk-3II$gߛT[s<~@RR\X&%ymc*o~QX3nv7 _b`F0'nAXֆ7m\DviބDZ~\"PuqVq$uOLMDWd!{&*:'fOkaWs:Onk>՗$NK! I7 h4xq ˗Q{ٴt>68%_;-ts,?QvVa=v4TI uN1uJ{_labR,񗜫UZZmRHӝ_21Xsz;0?P˴/l4n^I+f,$_XgG!۬W,!+Ko:8}wRUu$Tu~/|0˓C $7um b.O"a~\{"J ŒN_E/˷Mv,Zg6nN4UJ$ i ɗ)%ʅ/k~J;O$6IFR(h"a_T@|Hu%8Tf~J{ $eLLF^`gTh}{L6\trfd&#Y=MѴQMWJ|DoAO@:'4t& 2c %dtOpcaa߯dRXpMO2ogmq+ eh [CAri[noU U-b=EJ.tw1|0&l)|E ;<*Mne)=~ۆҴ\\2.~5JCפrvIUܳqe앍A+iB7!18_ʇNgi/[3D)D\jXXJVHesrϘ,rƼ@I*q)#E!~&"La9@*R)U/Kؑ#2;AӔG X/nؘt$b_;Un=Vy6ɉ1Ҍ~}=#XyB1Gq#iS؏!m p% FߜL[͝] &5Гːe~TԤ}QVqkyu q{deTf7C?$uŒ`|?|0 ?|9-*:ڛCҶIK. @ s#P"[q@@S : zOJht2R\r $[=JY%y:u˿+Ϲ2&E*Nd}ݐ?<-wh(,,4 k^ThHHZ t^HejaU])$mxM}^Z@,rޗUnJ I@PXÔ%$Y;%Q\2_R"C!)!+EVAԍU ;*YBk´"y]e\-&^隚RuLEN~IܐIxcd{{%WDrQiSr RsHRyh!)딥WM |;]]I=}Rn3XbMh}/`J*,6e4Wp35N7NmXDXP[Xl/cPW2uԬ&pm٤;&e^wJ[INּi~4VӸRm8܌Mij B pm{F]BI*q iu+mt,zC hR.S[3rJRH %6Cȡi%JmORZļP,)@Lo:L(˚[m2e$% ćnJ'Du 36|:FT]R^嬊\j+) * 7Ӿuvnd}pjMp!IT1d!6ocdm<#t4^ijPImGPuCz-LiRK\7 *X]+)&Xv]ٹ9V%%Cn) "5bר*ҮGF{:*)m\;_%?Lr:x.A\ ?h>-oą-_/oo_`O(A-0.>T_[˩D/EU ~H럋%#"?>A3p iN[vSʿ(v Gl5} Iq qVFlЌG(+Gd]$CE^QdgFFD2΍sǴ\#Ur~|NMOH #Q K%@,ciXoa'8ykThuY6p!*,*R4q.ԄjROd9Ĩ=Q ǓN* xત c2k|(C6RNe\uS *[Tq r2N2%KJPIu4#Iq{ɉN :D Umq-3xGS1j,J94mN[VQKоH)tg'f !΅36YI%*'7*EN.eʚR]\e);q cڄ45IK:H^~*mAe}P4Ӿ+.B9T0 zqO &UeܘWR氿hemεf6ړ8ExP-X Dw~zuȔ wML*0%%5LUL,={E<+|?M\$Z`V@ P#[Xkt3*d0 &bd< ie6E' T1 ;:[jWJJUQ[r[/Ti|K40UJuN\ I?7RÈռbfMt{_7^1t)ʷO2! u:n*C2.H3RK)%g#A$$ kg.SNlr) )#KG$t}AḙڼYQ.T.;%}:72% QZS}F>em>\z3 N/oW]2Qn mah79pEcR*S(2xE}mnp<^IEaU5tB_ T%ɅE[bo)& i3EK t<5hHwkF~$~_?G2sҒ w3M,:[_$j>9\=_ϤV4!*xFܘ3biks:'pګI5%6(YVoDlWj+m>vJ Sy6'H*]Ɵbcd+( &5Rl@C 'R53aIʜig&{@N' ~R e;<"s<+EŸ/ 54IKLCKNNjY{XfZNOe^sCL?2[mveJrnv_xO/XG>֓y_gp~8S#MbZ5%<~}pfek XNV$HiCB[3Yu4eLTTByGg/PGm?T>ji*/K;O);Vd:ԦbIm)@wmP7%-. n%VVQrv'\"6)Rv]mm<u< `pILH26T8iyҙVJ@Z3* 'P-xvX/ )왞ɗL,#WlofJ]kI4{YzqΑp {ixOW8gdiRY &QR+˘w\g+ SڒOJJ@Нk#D|q^v,8bJ3NLW@)Ij7!$\ju=u|_IRj'ʽ">)VOLwުEPC"lmEyEp?YL:5($qD>b4#dv~1,&RUTmI&'ĘQͷ&Tu}Cm}JY'OUv qmxؑEy:_Y&Xz$YuE~И26=1ZS4蚲>ؙm313Ȍ/&ݽ4!л\}(hwE۵`??Cyp?-{_BZQ?~8luqciĦdb+W7?\pcG\Y1r1w<f~a8tKLжo_ kWwl9Lznsҹ:q,a:12ԩIiJJuRodUsiZ [="CjK_M O*1NeBڃkaX[*y/Q>=4lPprN tL֋YfQ;,p \`ock1|$Y\*_!]"ɐW蘸j"aE(k (JURfuGe / XB#*D[ݼq'q ixm>&a{#V]TOˠdOGєkIp')t y ٩ KRJnEº7'6?Pa- 5P=- HUJSTRDJRu{<ɯ;V6K- }3-)52dsZ1OߕWFuLxzk.gR26km9/x&P%m j/BUv'(VCsFYm.{=--+ؚu9XQix*_7,, vkdJS PS! `O=M=2O1_ U\s闛I+Jb T!}W⪵>ONk[ JC.@[h\U"Z=+XۼF{3=~*_h/,l[7HgTmtL)(Y%I;@*k6>S:6l*FQA,D;̟ D&y5p#yn$7<;Slni}##~VAbjajP=Nps&YuQqOlRu.M:ZkTv۸n [Wgt?"\&]98m^NA+ުZN:HFijêdb£PS% bBB;.oa~ryE acx*^CC3iT%Ґs _H$ɓ,:ESBIP˶Y,T{;MGU^1mGh2õ$Ԧm+%bNO # ed ӸvTBAX ^ݶ7 /8m=[RDPCWzޤ,jj'X?uKZ3Xm: `%tm`!L_N7Bx y2L DoΓ]6cHT@qV*vŊ{4q18䎙_3 fth'=&/Ro=3m ?0״'m? nspHk .&NTCe@hۡ?l ZO Sp *%VS6 `@T.jRLŇ )wNPP(,SYE.!K+}-6u)J bʭq7H[{vXdTpԬuɞ}u%wVmX+Rgprs&QG vj4B<Y{c4;"il:d۶Ğ}/b:R/.Vqok_W8p[%R N8i:4-LN0ɉȝ\i+H'=lQu 8W9197R~}`.($ } *ײqV~):hMؔyk ^͈oat4}o9,E =`" @lYZmsmEMBX6NKu+ZBmj w թ)(p6ފ*{<iISZ߯Q*ĉ̸$XU2]i+Ye'-]~eOyם:”ʓauh /عJYOY)#P ;v-HLIΔ)HiJ1U\}TG]2K[n8!n$u}~eڍFbu)k\z">oQCVj8&9:! ,%Dh SNAʴk(X b9:.Hf&'P2^^#ҺHWjH/{_hJRtMfEJ$gh(02(#6jNPMzTuULJH@RH(5}VtBؔ$8RNkZluj,>t6r,S]+dٖ%craHu¿IY h˘f^zYT)i˩$9r{rjS3 * )ӉRpM/% Z~5 p4^Ȣ ۷ѐӅI(iA!&!ɽiL"rrMiMhi)lm~kk[nq*KQOKn6@[Mf;qSAey0qO6( ؘ$Z\!) *Q"k#4\2EnEζz0iթI d<B5[۝2RHJ!K-(Bט Iˮl˾:{!Ce uR;ZTEXVVtȴ=W1ӳ }eM'@n&YM&6Z=#~޽FUӶ˶?7pma{irb Tl(!z>lu)^cHVV&Ω̄_1$R^po:ʤ{kB:QM[Ҳ<CV#ځ."+&`7;C'n=*2;QOΧ EE~ lH[xw{rƷS6/oe">nǟOb>p*L˾$RjU2>1$tŒˋ5sB4xhO;sLAYFOD6HI[vFR-tHRH^t) C.Qk7b\=*=/N*s!?O-ȊZvvzbyxP/^Q=m=LN0) gQBfZ]M%B@T};}tBY﹀~y&SN=<7E)QhکʬE?+{bܮǦc )ޑlbs?ir9үD&A5YRK4GQn}qDӶ8ٹif&Ou2msAݶM6]t.F־"#ԷTv$uE&="q3;Ÿn)/ ;tMT"Q*VT{"& RĔSUS<ˠ "]>ȼ1ɧ*^2K*jP6R:rP[2{)ve&&ݦ"^Y.dmѡB]񆸓d㒘]>i{ث 2B=,OU%*4:F^Ke.ة9"9%i4\ƭ2ABHJ#ZRtj-!H8u5P@py)tl蘘Q!:{cyUW7l/`I֦fa!*V'] dBƚ{L3gNHXﶟ\fM"Y-l:z e M!Bvz>0B^uOC'Y[NTݩnJ"yPYlcp2fx*2S,7՝[aEI$塴"|( F^MMCJJ‡W2t ʯCB,XUUW#"g3)J#ÜCTy1beu}@5nZP:k쮉8[;Zp0:]>cBv]fK;SHM Ie>X[lV7&W,0UF$֔ s$\1ҪS'OJͰ<ҊVv#j7^؇02MH,'T!I 2s@sSqjr]#Vi$ԬPM^r8u؟M/1Fĺ@K$_2H$+91(jѧ̆SJ(sA#Tx1R/H:Ra e/3eG S A+q R.@NS3.ے`|lDlڂ˘d;L3M&g]e j\itb/J6.%H|u 8"W ʊm]{ۘԍE'qVq U1=&h_WqӋd)uYH˩[nױ 5,t(E\dE8˩&U#Z|*V Kw؞H̄6P4 #H˓%NJ%rh̜=mGrYmotk솙;*_Cl/>v,DO3E;l6EsE7i&,Jɓ{ \XQ\ЍjdLi-c|xoDge 3叒:%k5k9>i 6bM?LtOŘGhѻl!ہ 4SQ^S@/; SKm`MR,uDRqJϢ-L$0ev͡.d Ѧ8 ==ń9عc2b5=ΊT%$sFé:ŅLX5 Zra)!G0*;[|q+ct,Jԇ7+mJQqòquD&qu*rf2(,-Hrى"i 5v0obo#qUJT9DeD >QIVߖSZRn{a[/TI>J]I'Tml}>1 MX>A&غG#Gιkk~baRGJʸиW1[+D۶HI5;כ~ٔI\%ONyvF)+%))ED ASjA;iIM3t10tfEšԛouQ`G qQ`UkjlGtM>6FUbYRd)gEU ekB[O nJȻn,>+. >(cj8*ɥ(jZB ;d%֩E oҰU bIR#`d)0pצi#^6Jj5*swS[la-%3/:Vx33lGG {/ yU%Tf`hʉMA'CcZ3m-%JOUv툵RVbVhN IDF/XJN YHB{i2l&cW߷óu5ꙆLClUGU$$s `R~W%Œ/eP:-[b%|8G$k aVV~raRa[ mO%-eCks~AT*RїcǕ~N]9d˲e@ndQ򶔡E7)Sl[kbmU$a I)LmuJXX>T}{0X59U 5:l>1$tKŒɍL75T' 8:/GwoGDxiCc{šY&' f7 m3dgK$]%J#z#LʂN~me՗OI1h]{P@ ` Ioŵ<&RD $tY9|TI´p4TYe'w :EĮISO-JNG $83gN';n&bp>l.NP'JI%o9R\;&䌲eX5'kH(q<ۍ4![!8,L6;^JRѦ\[ Hr\ADcNJD J:} R3A  RB)"+RIJqe9Ht%)/0_|[L=Z_0$]i$#Lzk ̩7T}R:@Xϊ2M0+iRZ$X*(I)hzaa8"T}2Xuf}-e56mtٙnNf.,u"%˶^&Q(XHH#ZеBԀU#6{aʦV8HL;t/'Oo(@r(dB:ci}-mbtP tF0 JAZk X._hթ2)"er~uk_N+"r]DG5&S!F:Ǘe^1I Ry2 IQHh9EFn0#agF7UpJ.\fvaHh !-W_ɨĞw&$$jYMYe( },r62TȲtM|^$9H*an hv/X_i"6뭻#7FcigBba6tV`B.4ۺ$J8?mU2@ B $0}tV`U`/odBaS3no(Q$ ]*=q:ОnNZ[Q2ә}nmA6 |n%OPq)U= h^6#cljRO@H(LȜ^4{67/7(eֶVӡEp|oh0XߟFᲖ(ޑ;ZMLvp*U c83p;IW838L zXO~(9^ bZxZ;:/2Y}f'ҶOV蔄$`st%7qمBP% ) T )D;=tnRxIo)efa_ui@"-y7B[|?-Z A-;*D@]lO?G[NY/V[7L ڈk c2Iij-HZbG:\RI:G9jKˤY6yʛ2hIx \[a!#A- %`-{Ë.@fӖ翷x0JrP #Kip6MwQ=qq9D&*seN @k?\CcЛ_ >|&vKą"f%O@C[ir FSF*=[̦\59"U>w1P_6xygcޜ! @;Bkޙ rQQ-Ghi ,&d[h6o/*5&t CS9#Pnm|POz0kyFKۃ˜DI%Z}³6R{|Ly_ô)j \veM˩7iIWFnM;& m<#vM$ ȃ(hxp/a/6m2Sc*JU EH:fb Jiut)+O%+X"ڝ/hKX zD~}-8Z mZn#|N9+CdTM1n@~D'W4J{\ePtUw`3:R9!2 (_3)6FT(D[U:[Bָ;Ӳ⺢j@t m›q*ICœi_01:s iʁ)g# MbYPǩs2 M7SN̸ Flz%W$cobI8vX#Cb-5$^d 3䰸5 SsFYB$Ȥv!\6&+ٕHQR@w^PM8ZZRVHjalRV 7e Zah\F]2d@ H7DŌژЖaꃸ.cl5Njm2h΢9HN -w>؜;9)?)$ܸWrb\C@ 6kiؤBePCZbyI_C͗}-^T*`c-+1 Ў0 "nB]H$fXB[F Z6fS XT0y9 ?{"9":۪&zQ7H۩vZW%^bW(sK+-2Z'RT l qL(SjMMq=E$Z O# x~.aidL.T7346MND{EYBM۱.qBl@W;NhK4sK=yL(N^PL}ڋX-fv찋n& A)=R>Qf$HOOt RP))#Dz+wQRӿhffrF}*r }G>XѶ)Qm;dtnu-C)$_H| 1")Hʙ.ߔ`|Ru`-9z\>-Q_9+ՙdy-G7J#4u)şE)` 6+4jf'Wry\$iRzBm-)1ݪզR,`)y}B9v31 jq!otH>RR@7WOjI|t _RegxǶr.' r&ɾǜ9d\D\aT+ӾqsXIǎƤTDeFAiME[>75pe=7,6cߐޅt_'[ {_~y07Am6TH[$+ VHm2@pZ#ԠOѤJ*+E|XIAft@i ᦯ΟO1dM03K&V\O0`Q]${Dt30|=*wcF WFaWìw)>51#_l, XBdW*BAH=t6AkJ@iTb] -kפ2eoy|e(MJ0vHK 7[)9F_r7+SijA@e+C7J۴E6`47 J&╝!@ʥ]kHiuME+KCRuJRDFHUuQN"KL}N],U%!J6"U r)p4;!$J .mkoe -D:Z4jMDBEJ\NG[lu_N S '2naLj.eҞlU֯.O1*]2F!`,8Wлt,0$ھN[Z[HO!/MNO;]A7R,re#ǶLRS$.R\;<2̻Iausj*ӓ&N0>{jQGFRA'_HvS%h4Dܐz?0+&CPK9r־zfP PhApp-P j P$By,5l䄫N:[*!'PUkNLybCkq6e@؞`&Ghq1PlL>[l9]?J&㲎!dq:&[npVbJ}Aⷑ+0l H1\'LJXiJKK*OU)` 5%Od5#XNꎯImHLMI:q]c;”OXmy#-=MJW~䓙I;$ˤKX#fRD؏x1ht;#URJi/AGHIBOT%.5b<;Sy 9Z}!YG؋[_M">,Vs\QMZ sfzU _J=b:Rk$ôxv䣎H3,[h$iDP`<K”pØ^=V2iVh%Zn%:c|Zir\Zh _xnvi{oVvEh(]x+>#KRYLӬXRѕDYE:FόfY*a%R^vo*[JFCn$-iN(i{L-=eA$%'}y;Zĕk3&VUFfRF@ByL䢬pNLef/ G!!_@[XvALHS솤$ee,)[^1ľ6'Fi${]q!q'ɮNBv/+v66_]xVnisN$x*{@߳dQX=xɷS);/ࣜzn~#`E˔ Utn-}A7@w,Y@Ŭ,FxXܐo}jI(P=U44سͪN+;Ru*bYw2߼u!!JU=9ܘÒGjYBI,rw ϒ&vQB̌pxdH佄z0uhzZG\ ?i(sdT ^<8tA̷6Լc"FRr)yt`N!&rfPQ$Ay-Y hi mKSQ}PpHMS] 쌪*M=(57=v@JFCw'HH:C0 xMj4ȅXg-K\kĤ![!:=nt*R|opmBYaB[@Tn1X3ɣ S[C7Y{(͘-WCE& Icl/r}Tv* 2JU(or2'#dlem!rN6* (; O_g]4MܗY7ԧhiˋU6QTRJGk*Zp΅M.eLHJۈete'D+)Dc"Mpf$Ł(t:ǏE-nvYoD*d jltq )mw2 &c.G 5!ITTuS.,}ILXn`*bЦpěH\T? sQ SIbu)v):\s<~΅A%咖d%HJd ["} =(&^aJ}@v#adܒIYCs/Yi pjsiHɨt#U5~,֦eԕ6ۖ K(wYcch"`&NT{sƺ59S^@th,j59wTTIմ!5m_V; XmIHj-1u=>^ i:*>0~lEKĕAƒjĎl k>/ҭ|L]؏1 _(wr I*c$8f$vԙIwF_MFˉ->F1tmLd5%zƾ(LXXĸ'Cm>dgszCaHo~ٔk"Fq*%rXi{ 9Dn5fQDQRD&3ݖDcai6$i&^Yr]d>w(.QL jCQiۊ ů{B֙8֕=RT_@ziTTl9ja\ԑ<2r}5v%\ŵ.ʄIwE{%06T\~PGT8MT[w6G,2jel wP!@{R"rK_.yR2OLgEhkpsS2[euْy:%e]v-%F\ 9nr)%5Gvt%rTR;oE*:'_TY6:򕘭ܣ9=osUn)qļIN%Sv6!e ҐV(:(슓LM@לDx<šM&`r{_k)+|H? Hm5H=`T x*+8Ϋ8⑘J;H7-+/<^X%#•兴+mT%"d&=wf8R2 ? a!h(M@2MEs]af4Tm2j-S7P n;s=z avq o: 2y2OQzЪz4VIJ\eJ% HPlDr-¸FVqG 7GDVp3( ëވT'Vt*>DJLqboРeGXxZI .Qy[ˡ*eHArV.,ͽK>1n!VfS4AXjh!7#IR 4gUIJQŀp2ÆdJ!gbhm&e,]"" ƓXLEOe.7l̔ nvXܡP87CH=OGFlp}FE Fٜ)x>+0Vfn&U.J:4't[uUӜ58}5Fs_|aHr]G.<9 xyL~W &j>V}H$%j' c%%j]lh%#@=BBH(o-$`z .Id_{}qZxMOìetS%? atG8$op;u4FGj?3.933)eZwQܓ#riYJ-dZD!ka޸ŏ˒nDPnHqlh@Д$E~[|/@N[$-mdnB HQqR, }wOwtmBF6gkE7.WsZM>ڇXu-"qI6 +d ԥj @BY^rST@%9?U0o 6x#<|`=Ϯ0 30JrusӜtW^$s2o5wsVOK Ҹ1Z6=.= o XȞ/ s íol.U*R%"Z=u%7mHZzKfr 6&&쒤*xL6M) C6*ײ)qD@,0oQй,^V[v 쳑`aµbCʪLF *11(l Vš0Ӷ 5.ՈNKurzk( (c7^3ea皒zFN Yv):@780lԒ)%}ĒX2R4Jƥ AcruH٢iR:Vo|S\3xs2%InMJ붮ړŠ;cIIz"R  E|%9e 5~UYI6fJ7Ʒpn4 ՔmPI0_*ٹT}.ߕ?l/Ct/Ĵl+E~[nVYܕHܓpq>_JڗBz& @7Q1N/X QJPz55?2Y9u%=nh֐ w)U"i}")NC[+ueFV/aB.Ĝ}ie[ʁB~#73Qq̬%JJ֤Z<6IJx}ꀛvu #C6VWP qVdi7h2ī)JJO/.T/hRNRuDC΀ހRMՕQUZ"Q!ծ,P  JCak͈YDakBE.k[d"cժp \J <Ħ60 ~:O2xAp?W01;qjH*ŷـˋG'$P77qcjZuh{6A"m5>3:[kO>man piTEh=(qaVSk'(U&%}_F6Cj^.%'ZF#Ĥ10%RouE6H@'HJy:eRc/;!O}yo7t(zt0؂[xyYK:n(q`\;Ŗj΢hO6LK!GR=n񴬨~Ke+R|5nffEVvEKChW+ÂU`U4aqK*ιҭrGg%6١N{ƪ˓+A˖OTg"m`NYG*Ii0P7;äW)#^u }d +(9ẑ<)59jz%.\J #I ivwa WA$b]Dnj/+4]Cf0%h>3C5m3u *sZJp $ pn/%VTKHZZ+7sS`q) qJU÷$rbbrr 9"$i4N@05<$Bv:7Ӵ,C̓G%' JO2^p :@p}0pJhȊefj&ĺjy)!*P:!SQWI6bu0S=}FkrI#T@lKfߢҿh9Lr6%&ٔ/A*_V>g0%J[j ŵd7VᔓIp$ʅ5HlxԻaw i1"q>[?TZ,*/0%)Ĺ+iZvrm&ewFu*_rr^U qZ9G+ٺZ R%mdi!)<>ൖGh)>BtA]Kn$KLs/m !/mVBAG,ҤR{s?mx\ei[Mtnѡ)W‡:?\Bl;%@_)N`--R kؑac*,H=bHGyDfJ\3KPiT\ [[Atگ'T^|` q L%Ql% iSG?8Mg@^"^D~2%97[^vROFSSL*:)? >+?Xž :-?6"{sb u$**Ĵ (+?d[EVk7;tu+$\m g[Xy.Ѝ0Y\+c`kMBfHi*>ubi m,H r0Ջ.;nKe$jsUrq7Ymt"mؓb L&WEb (I7-[R=n$?юEs_DRXA[%)|RME۷.İ;w]9O'DN`PTzs` { l;F,h8\Y! *:/Y"%,f EFi\I)YCH|7*$|-}CK{Bm+o1.7W}DOY]-5-&Z2HIDWɧ- <]4&a uhСfubvUM9APQ8_$nXqp6ƍ*%ҡ(u fBŕ6}u,A"C&p5%s&zd[d:ځncD[ "ા#U5YUL&bXd.eԅ2/G?g,^JJ 0^m:W!diim@RKۗ("*S<'? 70J1)f07n|\?LPiWne`XASgv3dAI"hPn=B;2 Mʵ6TIc7Z \oq8 %$}oL4X7"dZ--:3KysrgqEbu aXf UZ3M2S iYT4,[b]Whb|Sn)%]umk J ިom6 NeN@rŠػ9вp+Kh) TRQLHKt!-k{7K>NL4QaŧI9,e-3,@IQ@\r팱d#ʅhɶb_/qgu =>2_\!66R*ZCCɻ+-koV|v O~֞Bn \No3.gMz{ pVut%-ʲ*t-A9\)T$Z}uHZ ’]|GRRX6]n#njڝ<ۀ6K'2nvwl=%_yN)pX,H*h0O #6aжxE"*+(4 Wg2*qɴ9N( ? ZrGX0)!HQrevI#G q$9ˌY؆aAv&;z}7[7 V XOI(A#p­Bf]]@RRSr= n@$ uHӨ4䘸>Y/ ʼT)TN<)m>!9ΘJSug1bImAzоW!5Vk({RcϪҤ]mrh|x5úuSsM_#\tvW~QXJfME@XrxTXhPRB" Nai^N$J}7yq|"bX}|&|fMΙP+[Ra^\ Pjg'yn^LSӒ.2EZJAH %G2< aivm-2BER=P۱E-(ô@GO<9[Ms,ztMNzR r]qVJ'gNcu=Y,KRiP U$r*%J#Va*TCHML"!=kZ JAhwrNbj|%֜}!hPЧRDv%g(Yo1$zzD˨D˫^dֽTM(V8%H 0z-)^]Hp!C-ioܕ&7MmWTWog-K%d8BPKDe.Kh̥{ a,SD-="J^ZspO"e: w>ј+BE4ܵZR>_P̔t'y o)5TSK-P}D\YhJ$GS4 %b!XgHM00*e Z@R[bmtV-~SJLq/4))JҠUm>0_M *D5(@Z\ks 3u%ҤtdG$A+Î' 4̋sE[*dS!d͞@dijiѪ2b^TMZU,8L7j6{BAt 6XEh#Xn"~CJKɾyGd`^-l_(i5B{Nr8VN? ]: O|a,W5YRS?( aeVkHT*>ks3@z3T&Ҁԫu+yANp(y/QRpQpeuiѧ"R ͔JIO0V2x)CT:#R0۸$%Zl&[Vc}`/<mML6X _aQ8x!L3Ċ#nJ̢^9qV[jdv ǖh)T m/#j`)N&PDMZm9druQcU( r|1 7eһj\{Do6ge 8(E#:"Ж)14񆋁dq!Dt}qZ~vQf594}\Z'rߝߘ[#̵,NTlI(RS}Ltめ9T/TLD[3 -*㞚x~Kl⇯HؼE+贅|bOdE*/1aҤݐS9,9!D&'4}׏9fSdlZ7$j|ۭ1HXQzg}nVoŜ %ֺzYOt˲w9ǟUnbVqO#iy0 HZ9|X-^3im(Iw&7#|EbRFuqZ6Mr\ʍsb.Dn$X%>ͭk145Y%KSڜQifCi?K(1TVTɾ)?%B+<3uЩ0/>&G cl}ü’jmʴaiM920%P)ܲsZXhyCEe@⭬s9 %Bv-% PIV^Lɉ[k()Ͷ#ϩ0ʊDH Y߶9ϏRDaa( 7%*\7>|W": JimʡI:Hzs-os{iva>'},VC  /`eϣastusb-sC\IJλD~.iV'-ԳHڄệM9kI:0V?Q.tJ7u7q_/}M\:fM< n@o;#)4PqVׇ_Ñ6}3<0Ò>I1 P su%@Tn`J,5>ÊR'AjZjSGI鋄 si *`Җ^3Dk R v^`+N 5Hft("5#sYjS0U_XL9$$[sDUy L+3OO-6҂y V m"E81<2'^t)ۥu:JP5TʹRmM/oyUzĻ(=FY@@$IٟSѤ$Un^!Vp^+>xJ:ѱ7Ф6Jnm.,#-5,6  KXq4,C[da|%I&1RR*K%10ʕylMmlNuVj|`ځIM{oũ'dp lÕ1'&]?.2J<~i.sK tgk*s 6$k )P6 2N.syj%<&l:V4R`BF[k18p( \u&2P>/Tƺ Q<1uFJP[@(v9aS},s,l/˜8azNe0TTP ʈw 0e .0\em)+pYVe"N7OS?|-;h ܁5 ;M_Yy{l~>I=sU&dU\K;-Tīc,;/<Ц54tjtքsHP_1;3WLMӓ8pfVF]k6* g)1PuVQ*TBʃc 5{i:V? cinI!I{ܭA#rI4l.tji-FRVTSjrgҒ S$a4wek9PRT jYZ9̵q-<"Ԣg{rŝ(GhT,ל:Qql% U)N'67 DXbc ֔S#/`|w,z9u 'Cplj"Y59 J*'ha\QEĔOQ 4~qk}5ObMSW$X1&2.ҿ.cЦU[m ]Ic |MDʪbUiN,MoO!*S~ݞ|?Wϯqy$t5lO$WW/Px{@b:vo\AD!--yӿ}=!*ܻ!VCm_(=G=4vdSGHPBG3{XZ:Ac],1'=Z`a/;%KJ2ԣ@D2v03! Umtbe>wJKCo-Y$|Iy)+DoQ PHJPIa ]8H׺-$ߴ1ODB^psM>u"W߇e1ƢEzA&nV5s'|+VZ܊Oԯȁ ̡'ik@tTJwDo[=:rGScL? HIN5[8?SO0 R`xscz0Byeʞo]X~%@TC ٪<ӠSD%A$Fs]aBē٦{}* RIs[}vzQ$%< A7P%\[aIKQMt!;O~Y֒|/jB{yū=Uz4}t$\eی!N^a ~E)EIĜ:U&$%6!h!K>5 dY6$o4*:g2J<92閲BzR37)&Z:E7[$Jy%pbL$c)MTvmmɵ1u4"eì 9zTI$,OS6lf&re+Fn˂NZ2M%Ki$ sm p(9M*ֹNUQisȵ0pcQqa6P+Or4KO?9G2|V!ʮt}%7&s6T̙ng@.^zIԫSL+3O - . /q?-vBZt*N* Yq\bZr9I9(r6G1Ny`K0 m%*mF Jm2,iv'2AD;Uq@~*غ8Ql5zҞ@q:No\Rxhˬu}=-2-T%v -hy$1Ǘl~u.O:Iœ,Y |=̄cd0[Ԑ!t3)ڎHSꦑ4*Cs.N s!̬sh YTq1&PbXN?r)E(%!%FO+u7 * Lm=(Nv P'au*U&ESNt)Kc|xs@4L3($+AO tZ:9iƾ&V䥴RcLMH9Q֛%7+MKtz%d҈AtuF.//sSp)k'@-Ϻ؅}Jr}>eZJ_r`\: R1RVD>j[jaP^|$OZHqc6?9rJq䩶V)(6=m/?J̹ZZV)˕BeԤ6! _#ptvik$%ĩpΤYeo1G`7Af0A鉖*6TŁqDwL&*̮.[u~|GUX 6^ TNyYJzaŔ N-1 㓓xq!*t,/Yg/TxfƊ-MbQQ'8Zi/gRY ^ѫdɚLZa`iG2۸Ԫ B"M*aM("TEq BkBKg,\zeU*P^*kk>& xG'&ڂ㙀Z]wqĄ6ʔ 0&LV:U6`m}M9#(ĸdҖT= Ґ;buRPȤX7?.!GHJW@'J rk,|CƼ핑gX1y[ybu.oߑ :Ģ@ʋ]@UGSqi[ѝtH3ei>8q_͸#ѪL󫆞.m3@ s=%A x=e*_dt=!S 0SlԢqNhMчJ~3zb%D鈝Vw:P4X xžK@-C 䖧)!i#hGVQuۜE_Xvfqt $XZ |`'$})6{T|i$-!'anȕp U1+Ô2”\t)%J6A$dhȍ }Ab;/t>nӳBXUWx*QLt..F|dyk4Ją"n)rhPw VRn@qdI2!^o>.vD`>p=(eIZqVӨ- )R$n 56YB:O'2c o:-b:6}+xiϥ~H px 8?HDO2Rh"^Rxs@ڻv쌲xL#KiT4ہ]JmMI!Ԛ3 vXr5GA\;3孍&%-)X0#B}q$.mm:Cm X Ȋ'1)U3P.ɾ.)J">9`z#:B7uJGh"b1ӕꪮT4m$m'\yLk쌓D) ݑݞH5 X.HS*mD6oU/{Eyp&5ՙXq%lࡡ+2lLb/֪4=*fUjRJY:%  u.pE /i4 f2%*R ̒-ug'GUҘ(S*\5oNCLiBR,4My:P$%ۖƸfFP Ȁtd?f(-*%pM^CH qȼfvjieŨ%)HNu*ǘbkJS6MnՓ~eR'$%A[7)\otwg2gvڝv!2 b>>7#koTvȜ`sHc6rRKҘa!R5!,mBuXhj,SRϧ2T^r=0,e; sh$~*,q &n9mR9u1ٲ &2HZJ\WjoJ$RV^]'paT@+5os凊$KQJMWSiZsA"&\h H)35D\JH3Ib`6(HR; I <`3pEŭ}=pNV,8yhBRTH7rsa6^4}d 'Z][rg󔲎ei 7lGÜP@+SMu[Vqe{e6,*6Tr;4|v/9#h_R_EMqJ%9YLԜ$626e}qʖzIQm9)$S'D,!$9_ǜt-ARTs= efy@n.<)+:'!ub ?~MDA0mᩉ|LW}?(_K4eC؊Ʃ#?Tp_Al}*̩'2ySEVivĭG&za?ۊde䶔=1vy{Hy4,~''Da:,E(E>c83VVXs&LNhN9PCLBjR\c}sЎf(ZhBUKM- ZXht oUPza(OO,[]e]cHpEy{"aÌ]QOӯKJr]Bm9—6\{1ttDD^eRPN*-5LMSN pIU1&VdM%eU=ݑi/Z_5%d)n;@AhJ^dh.sqȽ2H #Byj\'vhI'&F(ȏ/8ODilVXQ$xO.Q KL4r?S(Қy(uߑxvfRӉmɗa 0Q7LT^Bӯe bn=/lRhɱYÕDJb]d"UrL$X7^"?qI_ZrI2 !@6o! 4tUL̺AAQBWkHИ`Ykko-U?)6kSbj*jD%zW,w"s L;T=$4RFmD NJu?]%Ϝs -5gTܪ֪Kξ!%;)$r6{z]f u&޸%)[r%FwaD&{ឳCMu>qv.tF5=M'֋K~R|8wBfm ZHx,,P'ZKg<}-1qU2](w&L~p_4&+IUXH;]-u7Ɨ^;v7Q ;b'&uj+2o0jlm}mtbN!Ƽ8y 7-(e^j] L.4SX*)iv eҕ6CG{ aO<%Pq9%$4$D%M&zMrpfBKa a+} 57A9lͮTa|)v']\yխ]^g^Wi'[~\Jlp!XjjĄgeVÒ\cw.(2WS,:7Rz ɉcy+JIK ^Q I]9;FTuUuNyBeUrϛgF=5fdeiP]BʦΚ^XMeXQiz4Dc 'Hr<ĻV.+NmG*]%ДP-!50IxZkqjv8EDܐMy$"t&i@YL̳\>(NXơgwrfnNMvaρQY4wDAz#״AXI6Hהy@?щl7 5oX;fOVu=t^̪0Xt؂tDt4r`nUI^s9 EI9RlUty&yDxf:9}#L~^Lr?0-p&x1Lwɹkjl)h@^s~Cf%(e˫O]g޽IxfeJ96|AWh{cQ:D-#Om C,>` &;}* _%}6%E?ה%Vrf 9mlL$IXQ -QvF~=J! ]Bw''0,ꓢ jҭ4SdeZ ؃F5afbRqgz7XSkHĐ iZ| ԫ%6߲#sdНLxi¬O9ћK"bfaR$M.uY.t,F{Cqh_=ϫb(hSk 3r{<.>UhMK 3$뷄Cymi`4D'i.- $Ԍ'ey[}e^QmYomL#5y$RJ7h ezp,_e6nq*L~u, '"#R9C2REKBJ}B%T2U/ @sJ- טa"9pq'eܜBˎ:B!T[cJ%%0հ^4j8~.7BJ6 !JI/궱MaWcx-pI1Փ]ѱM2Z0RfQ_*ȭYP&d76Z_F,Gj{0R eF-𠢡mnnEX1=rci˹2IȁJ| ȞVOe \KtH*HBmaEucv1ml5QbG8rDwQ&ԫ ɧA}:}+t [ͯ;mnݠ3rK `)҇93{diGk;.mxc6 t\G}*U.] Fy;FgbHZr:(-9YdyW0"WN,`:IHOT)7'ǙӋ!ou+^אΩpq!GԒ&inA0 Rz_SǓxUrVg$Ș#udLt=fTSCS9'&%tq;K]UPw" ٯ. onR.o,\CbCME=B^a]seW xऔpLRHBUp\[Dxu1j( !z(r1OYx9ZSk P]h %yv@Ey7?$'( epBƹj4a#ΫTna{a(JFݖaso{7J]:at0?# 6e6m)$ç@ij.[JJVGJ)3R9+52ue/eE/ i NIZi22LWHdmRZ*o7כKN{\s17K 3.Ĕ,b^1*55,JVN?;7&&)̉ ia!iM(6k4v;yo2n`tɖs#*oEsa<Ô$̴ð({rs[G; &} KY ^YZrraTw O7MTo2w#(Tɉd%.%mJEϮ͈JRatr͂ƠֵZv8ɠ<ɑ+Ԡ*H=@F*70ۍf+"u֚ _b\J]4VĕNU $+M`uDxrٗ.nB_W[M=P|n1:bnK=+LHJ$jk Ko\?3xq27CdXV)KaE.L(9gXw6$ #!JUzMϾ*M3 \xoTIܴr̤%@X@֕*6U50°-z6_/aG>p[97 HLR8]T 4t 283uyyl+b|lq{OmMYrhOPYUցWe{p%WsX%B׍PBCQHEb..&a+_<8kkƉS$#9!i:m'>qЯT- ^-j@$GmȄ, m{b \jHF]@f Ʒ `tA&q 9l +* -K6KO)'1_ :Omk4UIle@  Lhʙ,}F UAl=;AʦjBuͨDG?I6맚fͱ<.H*9]aL{q4sTzܔ/t_7rtZeZϓlƝLc[ ^eh!:)U4^̴,!6 X$|^Qn163vQs5Ԝi=#P]y X#g )Ԃn&H?MwC0ee(ϣ~Qײ(s̳Ŏfe%C5u*qr#|1 1f_{Gyji*Va;\ui)('hGwSщC\!^ 0ŎTzj7ŢMSfSbMJ;J¶f) p.L]=e+ušu)̴R&n_5R:[xMFiʞX(aiGR[S6:t%>)@'0Eƾ3TcTk ҫMvs8ڧ95Q~zraəT/wu(\!ݳ]if#KvDy AyWuXurtZlw1@”2[KȆYJN0oJhoq.UA M zpEnI.15(Rn?FuXμr]/n|۝DLP~&bVmB~ѵóN`xVMK8^uS/Y%:RG!+J3wP )ڝvYoivq] 6>ɍj#FU*SMIʴu`$\`?x~ZZp7*,ʶBHN#g _et k jųj;}^6 Aq]V;>= ` UI_2 J)"YFoʈ$ FXPH>&4PAF6JNe smPsg U# %[_t%l B.#AzR$sc sG8^de:u[$| :t a?4H K)=>`ױA&__Tn8sxJXX0C]L  )$ e(\/*G]&Vz3<@6IQ&o3tw'qb2#ެ9)$-\nP [URh!5,2QWF|qhH#@Ɯ9Ӽ\#gGLL#h`ӱ5g3!U~YIRJE,@:I5!E"g .b*LVm6 R'ԻËe<ٲB'O!TA'X1:m5 sSHXu?|a{Wr!2kCF!$fӼW_ޑ퇗- f˴-!_Qp!"ݜݱT=-OxꟄ3,Pi-m-x@[cx94khM7CT*{R@^+m1VMNJϦ8vu> jTeEƈM-T=!ktUQZHixa934$ҝr*u1V-%ilt$+bN9S ?II ~GB0]$mhT.DӶ ,zWyfJ*AuX>ͧ1 Xϵ\V-l!1ĪhJUЛ :s8 J0V>q(w:A6!-NHċ@KxATƞȈ:0g*MQ\6Sr vf+PY]٤0BHIJEXBPHNMRJJzKVe~ 3!~"j O/+$#eCK}tҍ NRӾ\ a<2OpBzi5o1lEa~Tr[؍䘭Vkl "qJΐˊQ[^иs7.xi$إY7Ngl'J­KRu ,4x$؄۞N 6kXܫ5[h1 mt7d\P5 7LVҍ`9`Bm tHܺ߿(uJ9@"AQE)xM7Z'ɥIS {RTKi:xB]@:v7Y}_"h`.v!8iU|@ܳz?SߙS!A_-r}QRʘvl\6@<NڈCM9陆$SvJ$Xsk R䥐PezϮ9[+[mK0?Es+G~Quw$#ȕ&Mnh ǜ3}*nidu8qQޑiT%\q)&=:61˜z"xR.,3^b&1b/h 7ox0T4ұ…!&R﹆ãMmU\ztۿ3\Z }c%îGtێ,(W\r~P0 "%:7=棬}raBޖzBtbEL(\7WV2=)a{U&++~-a'Jnv^ 5m팗;mÚo…x\!H7AɅ C/mn>B|d8;`…pն冤mK(&P8N,9D#%P]os~FWs}c= #^PXP;msN~wA}&̠N6>CY&,l^X>}PKڑ RyNnb$4yoCIΫ M& ePVakC3D\IObo5c:XaR,/awT;H? ƖE6 xuʵHKNWlw|K(2%eh!"J:o:kIO:oGM%`1G\Ө/h㓾!>)͕%ɨ8)QIGtIEY=8@ Gv)R B @#BtiYFP}bbCt\lhUF2-T=*O䑨n˲s(ed-'N_2|O¤ʲ+HQttr҉N{7 ~VeqHq'*lA Rj UdDu] |Č~]e*ȜҪV:!: ٔCdjܔMݱW2Fьa*M?'}1*aGǟ$yA9[[Ych{k A$n sFR|&T6H{},S .VB@ f:`*Xcý9UΑ0X ×q9&հ0y,eDc?`4c8K6 c9V\BL2{}X ochMv@.k}ts/ :CY[[zAa8ۤ!`sQt0SbDG 4 -d#̼W&Hے{kI:Aʢi U0w6DZ(ߜ1 }=er>Elri&F,.NN8R@15 @ Db k0H] Ccȋ0A"ӡ5gT"0+(q$@؂ߔ$at:ӊJGP2QڜCO(GV`%sq.!uUs R?.#EhlR59=WSTӗ]n~7XUKLS j,S\tH%/`vZkzt̡Lmt6Mq]'khYV5$kFpx^%ōHh*v\-qhӟ*eb<+ϓ # &S BKfl*9:9AL] ={aQ-d߶6lSB;鹅~`QH=b2LVw=3w Ц=S B<3vXd.Вn ̃ 70$c7|+у )t%y+cQOx}`&`f0! 0|}삘a1oDOL B-nA WQdM1.㇪t]^MLcXkO1NkOO>2 RR̲KEUQ2l'%=BɈ회6<*Q:i*EA7$UOt)톺]6bh`T]I.f_!Sl#"NzvqEӢG29æG)R3RrRqiu-Dc|84,K /6"Im.2\x*nmYMTq ӫr{TyhEg%f @ @ @!`\1旉)mMcѻk:<бOix+Z䥉hk~ ] iO:Jbl]]TjbVf]o-V.{xGh@(ZM6M555Йzb=yWNRsTܣa,-$$a2fRG0Lw'fv1b-Xag$fP[uXrsg&r@%z~+)jMd)i/ 3"4KDvYe2 VOl)NKD8YC$<x18FhaH jd@(b\bHdFt4}`0bd_X9\"HS)$q?jktcqCE 曵BAZ3Qf|ֲO%h"zGXͦ-!Bf i?  0 uV@?m=܂:9SCjd.ΞrwJDux>q 垖Wf;j &݋/ޘtM<>+ɶmXRL/.Zu'58GS2H XL/}K$|FF_bqc3w4 ZMJ;C7G$jlm 7n2GAl.BNCL >W":eévԲoA_BרЌEw"7-O ͛Hpx\>$_/ѻtTm #tҘ_vsusJ IJ6bق>bQ"n`2;jBQ|o`5ޝ:<A-SM֒/f$7%r&X[@.*/5}[}G:^|5DMg\qai$H!#RnF>NSݤKa}6[q*mugߓo bQgdzYPg ) +7V{J)-^ČPdXyYܜAp*{Šy#Q-?'[B۸~,[xPEp&NK>u=W? "NSr4A @ @ @ @aoQhv&B}řCؠb#P 'J"c@g }m C[L;m]YvMQu~gj-!+M|>;ο3&~zL7UKL: Ÿ1onݍ#ot^wۍϒ v#յ'& #(Tᱹ3TG~f'+ʷ̶~ * =_2A_u?RaDJo3`t돲鏲dyBqԥNX:`@M8Y)!~Qr_%2#1Goq?30w_7$$C6A2{$N&+Wg=,! ¡e;eǙ'<lpGArT*;-cWϵVa˜14g3W(ikM?Oj<2ǷnȿuZra$;W|_uϥF*-/_B^/R}XeURJGO:hĭ4 ʖ <VhwE3t^Fڭ!&Ӻ%EU djݳh#tPW6x}i˱&FVP<2\ˮҟˊMJ:(Qjr뾦>[;Xfo"1Xefi?_秭Q0aQ+ZMqxNI%d鷝I] 0y mX3//jȪH+4|8UJHV͹?Lie{Y3Kݑ)>KB}MHn#mG"Qq\+͵jd y۳bE pȜzg֧yWFZH]gH3ihrJ\ T)#(翶z{V-).`DU "|ޟ~m5JMsk jko~3֫J_JIƻ&bX+2?:J$EGf\}kqҼ _tqwZU!Uwqa'\xAGW?"2bI~_>iafN>Cߟ«]fsF,_+˓n޽Y<ܙH y{|6.z.H#\4ɘn\96^އ=!Uo-Yߞ'֨='Y~U&g}y=#:TSo3W?3#lO6'X[;gjf@ۯC7tӗMm6Pnddd3 \w N_J2ao{V:E U|/8ӎzXKy[N̥l*nvXQj)$@qSs튏P]aO ,g S%/22T'k{{Sn`\⏧>تҰVܻc_Wz%&2ƛdof?qǖ`"ƨvqA__#v?+ש^kq(nfY̟LXYkY2}?_L[9I6f_x 3lPZ6kZ/^x\;m慼>jG#V>fi1G?^vktpۥ ׮rm߯7otث#?y$m/]ˡʰb[g 2Ɲq{VX]x2n[Y$=_lM >[J?D32fVhտs\mcmy#{dfZ?axbt\{xwU"Cg̫-RcU}ߗg4ws)F$jF<֢;eyUf@8<*}K(R]w+_==]3´RnAIwk4J\H6i#Y?Ce#//| tVHmnQ]] 'Y_h?pKt6~Q?R[d m|71in3ZdR?7⫏+t hRv^jc&o9CWd(.#d\/mF~W1)Fܿ)mrFݭ'F;sźTQ2}~:W/ s7VYϮy?OoMtFxG?8)[ٟMhY3ͣYNmI"2_/f1Ҿsm~VSlϛn{Z]NRD>eXҲs^Z~GЍ@ \?."K*@u|Ej#}M|̪`7۷+?퓳t>o~DkS_T5?镢?gn_+͗jsPR Η1p땏9sK'|uo<Ɵ%ӸfFݹ=?=֦X7=}kRHы+*L_ۯ5xP^]JsrK?yjO)vefr)4`Vϓi7wz}/&-nQY?u {oH"2B^s^wqW9}{,?u&qְ.~u\y> V8?皫#*p~a=r)ʽOifڿɷ oo/ojjA- 7ݰ~N$eHQm@|R3 :gq~&V̪~?>B4(]mMd Lz~]:ږ$5V<% zQH :ڣ/?x8?a% Xz|yw^՛n8cf7HYdž/FW>fPBnbZgf=H6И,5KONF0lbYoTK?α*B}J~gaF:qQCX*~g߯/s3ny[cqסjN@Va媏qW__/O&T#?A|;G~54^9=*@sӷ*]ܫDF?v'=*bfbS:l#TJUh97M _s{Vp˹vOr9̃%|<͟͝9\*} ?t2Ю8kp/TQ7tF6jv!ZFYb1J(\0hu* z?[ iF^{\˔n-̰<.O6O><]J>,oOt[GFd/dFz?ֳfФ'_B*,?;s]Gݩ9 VtO$!Bc/<?Ʋ%fes߿zcXZ8Zk↥cc}gq ԞOڢuOwu6eyϳꫫ/ Yo|&'ɓnwӟmu5] =xɝG㱛ʗ=ӏu%'FXqj;3&x5 Fߞ?uE&f]37ǏgU{f wҼ0_OjS|?O #W{/[~zu~qkƿk|H*{ϕ/}WgÍ[kk?u Xr(<^pbeYv|]h˖AB?6!`Bȭ+ Uv_o;Uh%??Z$>SOl}3ҹy&^Q#0s߈;6>WsN< {!KUhd#gRxOs]?eIR6ɕ{~]V';/*$r$(d^S|?Ccp}w\}A(1t㔨U`ʹՔ' /猟OJfڿ Emt;}i(,En>_w&JKRqztԸ8vG~>Ѵ,HIq߻wߺ?n}=$;aԏdS63 ne]{ǰU٠`NHOS !U`w;B7>X3?_W2$I"؁>+| Y 2 w2٧'o‘` )޻}Gߏ5tjrۧωhBájFz=O K4}olxgࣞvc?ҍF $].[{wOm$7~Us_&=CS˒Xn2bϝO˷Ni/k]ծxR/0A6n/E}7t_~߾ ;DZ>4Snm'}Kt{]B?7OT_#=+tet*ҊR?Coo¯h.=cOyj:]xqk\LqBxW㗄gfo}ccm\ileiYt&Wb+G{;X|3Z>W T C뿧?~ MPW%ōլR?y[c55/+~!>oO|xTe|hѵxŚoMR-> &$yC?F|]N^oi} ^&2?~G$.㑉VmGҀ "1_͈{¼Z|;𕽖yǠi1ڥگu+duEV=UX#`[?Z)|23y/w?sԉ`FA*O+ w]fCI<Ǐu9؄eYfw?'}Ler[wZ>_GD/k| FB&I"LBۂX>ȻC'q 2ʪ́j=O_Q(ȡK:uUt)Vf3/;!tPwh5QweܻFsaYfKXƛJ۴3,y_ qPJmuwg;wOIϖ۲v<6{Rv[MV_!2m,[$aWyUǧqKE1P_/ǿ^Ib@zFǸuy_Jz~ cW݄%l?*EI͓xVϧ[ f <=ƨF?EmD6 Uf2?y6~ťK5?|0^[,RBXkCSqF']j^,O;3Eg1I-yX8{Z*u  '!;>{fK0$I&}z~ oZi)im9]Iiy%Ҿ;<>g(|q7R+m26֐}'9;UK$g}Wo11g\˓ljʷQ 3\C'!_|ZUC9#?#_w0֤-<Yۧ=ɣb궗=={;Boǟ%Oiz#y뵏?Q_?_I;wIz֘5S4\c^2.UڞgjL䃗S[Oȥ/}$r20 7ɐWyp{ I$JKEž߇)ޥx.˟MO7{?B봳+mדԍ CX[??=y\EG-yѿwnȍ?Ǯ=pX0lEӷr^/)ZO}?"lz ǵw>+K 9AJ\?ƩCٻ 嫫oSì.+,g؇oDF;VU?!\FrwzzS#>W7BN~O\^Cf,sҌ''~.Xba^OzK9=EI'EJNαkk9ǽ?_RxB񷆵MGC78]uO?c/ϲilUͭ]ڿSvЕR>g#Շ}/T2JʈK|,~B85 ^K[R( /OguVs]C~ϋߋ?Q?|"? d׉<3N_ DlIy6i~v\Cy6hNw)srƙ_cω Ҿ$S[~d붒X-Ǖp)qay/9xY/q>q7گ%Y߾^k!߉]_-;RΛ:ѵMլB9J>g7 '5+9naH[a_#K,OOx3Zgr3Tږ^~x=m V,mRYmk?R?97=gCw_|Ti17ʭ,RG2)a/:}}}G[e}BhQn>KkE.aIƻ_yW3/ 9 ;k:eV:n}OmǟR!W> xOG5xM#R8n>'n΋ʖ}ozݡxna*[唰;/_>-x݅Û]6Y]Z٭Ymo(nO/kmke-S$h&6Iq3\K?ŬҾMwLi\re[n~ߺO30p ynִ12jTJއ篆 <7x_UMKē~ԭo..mhaO~/UşdV#kɊX|?}H s1;r>_y)m`mVy^o~cS,~]<'I`{+[ X#&kh]<-awo>jҰ9WR]X o=ǒsK[%zT1$ufor4g @!FUO_{?"E./1Th^eDžU]gyKT.n_}2QRyUz߮59>?t=*8EKI01_PB~ҷu)>[)y]푐$o֤GTfh_1l?*"fBB{89{G nO~EpIK6G\x~Ie\{{(V8+cX"Pk}?>9//AHó2n^qs#Ma;o蟏o:Ԝ1Bv(m[?'km1?AߥeQJ]߷VܲDˑ6|x3WUb# ,mezzbbT|c-;~FBQ=ӥ\5?wrz2bVeC Owi9ֱgܟlSܬW=xx~|͏׎+NTM)TOIl?V7K/}=Vzou-cS_u~ZhXYl<}qrŷ'T?zWdre۾O/xw]>} _me@<"1y=kȥAY|!`V$4?ˏZ! ߇\l!JvgmGư)1$jq19wJyL{w 9GIiޝ?sx#M'_qϧ_[I`_+Eu.%fWlbSnm6Z9<=}? ^'Z(EcX%E)-? J9]IGIK|Y1Ibې̏j6ڳ/~\qVu7㯯]uDo5}>b_7y>P-xTy*q'~Ⱥ2?&$dm;ڣ?緕{یR0`Woӟ0k XxBwG|~V'OJ{S/-C)_殴yjT]"4k#*7Y~UGVby=VQ[VRǛ. ~49 gʲoϧ5X٨={RcT;_Ӟs YoǕ.NUc/ДؑX7)/u٧G\]37u1uUT>mD#2O#̥I2sgy i=guOOӒ^_yoΈ6[Bnx&G`~2._ev ynn7/?Iј[kEjj F,Nw0_>3J=K+Ex^ÖY~7?6ym?q^߅u k:t#ҵ .W5uz`kwC_yx} ,M|wu$]RMg?: o7ts^*QnsΔ^G$[G=h_CANxw@$Mof_en>ˏcXzSxxTVݾ>os,d"9?ο`%!1Yǹ  }okI~SF}J+4V9^k)ʵ9K4J}}OĿօ~o>fǦ}Aog7ks\⟆|{^"K_:՝. ?H-?f}ו?ھ/?ٿ_^x?|/kzڎu-͗#L枙/_ th6SxO!Դ{k?_gookNXi*T Scs񥷍3>?&k㏇֏ ៊5thu[izl/?s}_ϊWq_x/AjpmxMVhQ~s~5&Pῆ7/;?*I5u_6+syyⰫ_/iޚBocO'/ {(|Y.Go:]}hZ;_ V}AgEhu-:[]BgYX}n_>N/ i|ƚk]>D/Q뉦fz~̿]sƞ!n.I,Rkd?ǿJƧ)S~_?fw֭7|=_gxo?Z,E2LE=G}S| ⿈_>-oߴ>/A׆?5Kgag{,?c wfD\W|+kwIMLJ乷Y4mef?ikJ~<9/i>K&K/.il}>k~?V lHuI9|A6ƞ$Cc[*kɡm=%ӏ+x❼:->!xJV5 lռy]x>LuO,gDPZ'E/j/{M&mB=CG>=ֽwa4L?hW?~_ X.gӬKzkGkYE?<_=.|''\GJze7< ]mUgy*lh)G?<=P|VHE $[ eq-mK;_XC{JOD_iW|KÏ]Ӿ- ~&V2+)ɵ)u+;/ٿǥ~7cJSvx%V>o>hma(gAKEfQ~]9(?|cGq_"Q🌺L|'G|RYp@3EUP?<'i#|_P_޲\*nWoGk~0o' 0h[0˭x_j9 H8k7}:QvqTӱ-))YV6,>Yب>_"!ȷ*q IzEQoLybQ`~C_R CRռ?Dif:̇˛ yTSfyJuKdIUAߵXosڿ+W&OF,jT?~u?<{ iS?[ROxyԖuF?uEC) csyXOsNɵo_ +KYciy \.#5ň,z2?OO׾~:sk?m.8xu/2=O7;0a ?v:t?c5Dʲ='kmЁ$qF~7?˧yc"3${VO~yZXqou4=8TT:i,v_U21inXʮH+ %}4u3;t=+:3 Ub+ѐCjl6FV_WTo8_~ֽᏚ#|P|4C6$^_?S8M&+ d-yk L>*oiu7/2[;Xo+_-quQqyh3=kiͱTI^ynƥCa?ρj6ƿ1}box$?ǀI$Դ~mB/1y=uUQí{5vvI~W\{Rn{%u~UX>8^iO92~o59:n渋_?8kQ?k/Ōiٱ%c(&?Qo~ Oodcf?ǿoRjT =l_x/_nj%K8Zhmc|?v[?J?ڣnԭw˟RoZ&ş<1 \v7e3ĒxP-v{mTƿ^7ն(_|a}FO6GN|;K&jڬב߯}si1ۻ/"=Ozv:W"8fueۣyVGh˺^?>ٷ7PQͲxݨm-Jxi'P0|`ZiI$5(Bw"ȿOZ(cx"]o/{ki3 f]nO3Uu9yj_שrѨkCͫCHLK$_3o$q{rTB<q|L^5`I/ߚ?i~ҍ_ٕ]-SsyUY}6yW-OFS\2yl? mFK.e }|TW_nwRƝ_|ae ^%Go}[+_ס29myOly;uS3& >v{wyq>,~kic'?-*\v5fpFW7l>Dhi+ScmN{cO)҅ԭpt~xߟqbmydܱ3{n?~ G@5eihտҾgYH_} ~/iv#mo+r5Db)ԡ22y_=oPUi 1f?Υ_G"ʊ,c'wǽLiQ|'e2}7O3`jPU$_*</;㗂A,#q#?i›~تU^/\{ҟlέ}S7\ztBe?&eSm23oR9toD^o㏮}k??idۺxB~}ӧzs۹楇,.do:{*^_{?&~,?W+^g Ju8YGʿ{37}9֝ ?ڎ#Q|ob/`N7L/?x:Ӿ=3{+,_~?sXCIS!fylLc҄rۚO*Xo|S2(-"G?O޿hMTDTd2j_>Ok*?h"YeTr;Ѧi+ň\>2%SQ*g>d_N_Rrdۗ̈D??/aXB6s5!L3cj?lXcMfF<2Vq\eIw V2G"UcTu"y`3:^kĿj}"Yt;/,䉇ɼ# ߤxM?ds?_~?uuco5&oDh?./$ΝJ~O] yGذ$?'b{y tnk+EkJG1gd+cVol Z1/\Ͽ[^o{mO Ud0Gm$xfEUƉ7qgҿK{ ?3o Nڻ2*TWӟY6PI={w֛ro1_ l1;1gZ+! [)|9(8k3'>3uC'4IԿLz$S]̻vc_>7-_gi??9>2O/̘Vm'?_cWD ڛ ۣ>zt*?>{Ut%Z-~Uk#2OjS[G.[Fۢ]_mjvcjswUG==oEvv&$0L/?G%y"tyg1?8K6wYּܧܝ;⾅23FZP_e!BbV?Nخ9\?XrP/Hgf_2Hx_үC?h*['`v33 mV'[:V8#C4kt'R_-%tr6lf7ݥ;aڀ/݈=zvxO[v_gܬNkj:cVٿM&0>v!#W˿#?q^+B٫Hs0evNy?1~8tT._k"}iG)/{o|FF@o/owҥJº?־6Sl[G/% ʭlZ1R>He1/f\Gzuem'_}&_+ȑ1x=jTJm{珯3_.^S-h" Rޮ[ʚ3²cS>oqcs7u;®ϕ]vvjr:Gqʺ*n]]r_SD We{y?j,:F]͏9튽npt{ջb`W,/v3Ud)(22s6g?߶>**;2mvw>ҾME#e*"Oe'xmp$n6XD}g7v}wdj\2~_b1;Qn #q&ēTovoWQ"3p?km%m_D}ehuq4C?8}^E#ե. s6oQH gk~lcfe>Ox_H={ 4hVefK;A[{J۵Xkr(VhD>~~f0j/i]rj:|t*ȹo$?Ȃč>I*&u??]֢+wfF3 KV?\|R/uQby ?u'QZl7iW"@[gx i^_RTPi>gO濵rX++Sߧ_MHk6Jy_,)>WoD䑀8ͺIL\ӏc^)DpCrOCUVwW*?*_#X_Aęqdfzs_$!GoS/A_xA$T7H푟鷭|bxcDVeoLVF1SfWru?ߞ}j/?m HUI𯊮gk{-`;Y~_~lû@l~xM䱇^|_'=QGՌfO}H ?y.ʸM l_ן'8?wV f;Ecs=s_(ͫC0$#jIZoKc=Ҿ׊Rv??WVem X~Sj DhEw4F^"iOHN@+>Ƥ7%o|S8/uRW]`?,/WϏ>QU߽79?Su@X€F(__~ߧb*FH-]f]=ϸW~X=MDJ(gn^ڴ-}Ъ|3sz?Oö<WVD5f~qB_z~քe!;]w[Y\mGiFs'̞dl~yҬ-Vھo?QaJ#? %NWv_9ǚ40o#' m$G9VۄF6wIO׎8㚬]ۉhٗT_AAWri?y?kDE)_E<s=v'OHQGD9+2 G6U?Ywdlw۹}ο*~//B*s1X=U[s0ftUJGԟ}DyʰGi/_=?UZ1c4RT,lxjqF< w:cʔ?Q P#1Gvߞq~"mO˧<~Ϛ\ƍEz~KVCxJÑ\㿠 c7{ 3Z&?9q4[U!gVL__ i ?W{ZXLfe?.o~^٨H]yg{#ڬ&1c[83Y)T7_7DrJ|?>=r_i &?{ccȈAݴ\/OYb~Cq%n[Ub[ (YtӄzλXpW''5jkE2\*o ~ ~|K-Fzv_EÓb#P5.Z/ڿ{2Kvf\C߯RQC)Y_˧QU-K_O;<{܎;W xrx*d/c^f)^,;9U,og__ҬEl"GF=*5d1g=}?z]\m#9d[ˏu>eK ެCE_Zy_g͉_4Kc#rdf???JլO/~t9vArB:E}_Gtw>s1^S~3w`۳bcq7_Wt(6؟|?gLH̿첨$3/M}sɌ,MTJƱpsֱWR2(Q>t<"7O$g`csEc,R4x/F7z\ZCVm:VU dl?ۿ9ۨÒV#WŸ<9ƺI 6I_ s`F_e_^+[ .ِ0`yvǿ\zWwͧovbɰitwXN}xmm]KF˖;/_BKc/?w| gϘ>ծXk))ZV6C4kgע$X/6:ӿF8 9WZ9e[`:-Lj͏hq+RHѮߩؿB$V1'izq^ |D!IÝqa^xoqia4`]q˷J }Gc5|E77t%?,l"#/>}:W>&~R?.hԔ2i4ko\ÕcRaw) nq{Vk,w'1fn(>s_;BP1k Asg.N2躿8+t'j*#okקZ5![jy[~?kI mc݆ou/_=("Hd336G ո0e-sly\T#dYZ 1Ffa%r(oK_ep)R'yhYqO}*a ( c_Nr">NJUU/im/ȶ UGWsެ6썇gW{y^Uʪ$K,|~}{fWRj9.x'2Kv1ݵx.:cLv-{v0u(ݶE:YcEEVHvy?z%>깪̿^fJ \b\`]=?Ϛ%*wIϟO1+hX;cvՈ *.|?Q'ٖ!ڡʖp mqiD@("?woz;q6ۻ'.G?/?q8+'8M̻x|gLQTP Iq| *%KmZORoHϿJǚqhvUf?LmL¯!O("73,yzH̊cmۛs2/:v皚!;ْ=cr'=v/g)ZC_?̼ukӔ$$Og+neLHn IJ\9-o3i$L5fmzndkK|:WWu]^6XyrTbi>sб,Y>oֽ2ImOGdNJ,Cc֮Z0sMWTطE ѳs8_^*5hFVoYќ\}}kH,m]G>o^3z^hyN_~Õ?F_T24w쨑rIxs^$c3Z}it#ae2 ïxFPI7$6aKӥ0p7($ؖ~m{E뗭w>LnɸzO^V/&VƊ+t/6YׯR|y>_$e94|k}j~+bY?l?/{\OG䧇O~>|yUCwH^V8y1.W&%^3i#(6_+}VxKb`c$@#o=1XVQhtP  [nG g=z*ɵ6`ޑrGV?=HԖF- 9cW3g|3Yw;"/$Z䊶O稯K,FPM^O?߇TZ޷>2oد3%N~[>\/7w?#ug,`H˖z[3|L}Oټ;cfɍmR6(׿ !n0qt[5HAأo%ƹ1y$/s7>OTS0%amYUsYNG*|OFvEY{һ۷rmt?9LWǣv΄d]osǿADmBXuY?ߓCOٮח؜]~y?xޥKeIO+w=^#W7=pwgseT]=qWBPeUmrGDEF\ӷY7 %;>Oִma( >_泓b8S ̫/~mi2sC~8?׹k)o,1{Տ9qrA>mʫI\rLW!^1ȼ6lFrno+'<Ӕ=~VXp Wm~LzEZ &TYcdfAoa+^}ZV5d'W4~=`b/ÿjFU~^S,W?`{5vڿszoƉ74\ҏ&+.__+\UX#or?{LqM{> ,^knv򛕺|os{טơ#D. irO11~IaUlo^˯CUQL#[Z2繯W/~/IKQAhwi<ϹU@B.d E"sڮX^힢CI t__5RQzG>|_ұ{7,2P<+$c??܏*n-%u!W?k]IcMbc_<'Apu7y<=z~>]\-3o# ;m]=_)M?M'z_v{Bɲ1$jř>n}WK[x=Lqh^6<*KO _&.so_֕i HI"fYLmO=j+8eE~4>ѱY&cs'ڊc<{UU\cmJ+Zt3o:UhbYYg7WĿEt+I z1,xG>? xUv4y?~ξZqq/{s릊L?5~?1.a?&IVH̡ndE\g>zW y޳Ix&56Gu8^X]Lt<+ @W&ݷ'`%]J*RNo>Rעhcؿ͇6Q׆¾>nCm*zkav'>ݖÔ6F13G sxGV^c &g"B|?~N,Y۷K[׷k z|ha+?uF$?ōiܷcqߗڑ"DTXyA?=+MGqt'8VX-XI%iW=eǦ*lۃ20efo.V?/?)CEwr_o#?绕P8Y6üU` AFSU_4y^Zhqq>_p]-`iB,̫o_ʴ!H/@vϧrH qV8jv-'?3cYM}B&62ͺ2/| yf*~io|~#,ayzqXCno ʰsMvօ ܍\qn1'*ɹ~\οb3J,F7gSjVe@ʿ0ݿ9·/fWÿ~Ȝ*bHͷߟ{UP˾oU )fC=K> Dh߾>cIys] dd˭[U9IQ/~>ʯF p/}4ʀV@BGӵi4Myyb{}% {=Ir$)(=3Z+$ +4yEI1)psݮO _0ք%mLL}qP辷.oZ\mhU&-zʴ  3mlG{{T` $03Ys:p\b8m4SEri ,Jw+.mok?;{ 0]_/|<~+uYjL|y~/7H;R6+p>vczՇ/YDkҳ ȬZ?Wl|I}~eh1O^SRRo_+zT"#P kxIU*$CG8P(v誾f"޿}SL PmcE?nՊ;K5"4nB%[,UF?~PK6_R3iD$ȏ*Day_/n._VIv݀ цRFd]+Y@T4'C׭0` e ^>dB@YIs+V?5+*w 3/3֫UPx}ǦW:SU?mbwm_u0xŰs?\M}Cqv\Ѕ76<|j. 7*D=åPö'_}&6!C[xHE-e/RĢ(l~Oe>թ!q[n\$)8wvc>ь8Uފw'Lg9ΈA˓vN_I呷ynH{%5W41N_Z~i>ƞW7#u㥷m_aO.I<|_k;F=?xVZKg1MNyy__2I+6$~|m'|c:XQӧC?5fYBȑ G'ʣ '=8̬̐$ Siy:02DdǮGSM;VQ\4I&o>Gvk\M$2Qw,-C1VuMߺj[8_oIOra?3ƱWt?A>5cgf?Ux ".]mrc9~_WR5YzA7|e+@Ῑ^]H|Y+2.ƏS;⻫ ?*X\wXEđ&ȋǠiUeVg}7){\ EQd>߯5mnҋ az31e/VryIЀ?忦 Y SE8˗^g~_*y/v3y#E F]NՓ)zh,YQuu<~DTPnmC,Df9Bl+rcN/{ͨ.w2vUfO.=}oU[s9 ,oׯ}}1֜j#h݋d#$O'Euɵ_+kӥnR1J/} 0]^?QU"1} H2~.U"Vb"ݾO+u0sXʤ;y_NxK*X*~ z~2#@ Wjbu[v?XUM̠U,~UU'{v~ K)ܸ]ŤbzzKTv|[H>K 1|[y|7=? ˉQwuH_sN?3H~c?=+E1̅w|ǧU%oۿ*dt+5paQ3Ib!êhv3"7ϱiGҟWSNܪeu]Ei̡vF´{'>y9 |m?ԇh '旟h_U7[펵i@Vf_2.36׃T!F*>b[R۴Μfhe?aU+"/wb|?ߍmia0"ci=}@tffr_s[:i`+?OF].J7mWa\mel_.3feۻ|;UiDж߻_%~՞ aivcLq_'x_J^Oonkw]?NUgCsgZG?3S/ }3}kbʭ/V/kw8W44[=Ey!+ V |I&֓PnWL ³!}yȇs={?%s0[o䑖?(fҿb&ߚ/XNu%G]PVOߑ@MU/$ܟ:};Gv8;2CO抿e \=R1U ۇڿ?j ^*FBe=:@ZIT7ɲOZX_*qXo~X&|\{c_f}#lFXmꀕhg~D> U,gĻuo"_b37nEz&/wF|/vy{E8kF' 7|wI3to,[޸n{>jDG+&Aߓ/_C( WpFy7 y1dOD[Y_k./oBKѪ*"dQzݍbƿgN?/WF6U%wqGNzT2ɀ_$S뷞ש%]#)>$lz}[Rb"y?*! $|w?sگW@Fsg缩5-G$VS5b3 ~Rx߻szUH ŁOg_^fj~ӅUU~\sZX<0-ÍZrBV]|_N5̄?}秓ZѶrd-Ee/=8=|z&[z3^-;vm޿ZW1Gͻeߥf, i.WtlXo_q/(q[{n=sk;c/βTfh/GD r??w5<{?_Wͷ?\²Y74TAOJ#oO"`H aw?{ XR}hDA۾Vo,6|ϛck>D*TGfnƵ#!vmy{zInU>~1Pw?˺Fיu,F HylߚTn\&emœTќ[o<ޣ%^hQ|~o+Gx۔5Ljm)\QvN68u9 ?LJC&c,՟n?UăiUeL/ۚP4,̼||;ǿ~[V51x9}m?ڣ]ɹ?4lD~HºJfU/㟯E(Ge# [޿ћ <w-8 }^i?Ѹ]Sgf%vٴ=|+`l,7)«*:EMwv±So1ntǟ;$EEɽ.;ssIt~%e7\yr"xǠ9ልl9˶zJ? %Mܾ \_P)7Lٿ._Ua? c%O?z,~^-ʩFGx;1K.E=dB,O_ WhXiMnȮok~go4;/˱=y5ED]zVogʲKNzIgM` z}hZ!$Zr *z%7pݏ$-6S?kw- w}Z )̓>i~j\&iO[[Mqҳ~Y`GfS|׊YC-GIB|'r>Flk'WgW[:68丟>_үIo>Tty)߇?NtԥN]4R h+M^~Gߑ^hR0Z?O?q^weWJ;1Q^rΟv= u%(ӗzGP]U^_Ϸ_3V-#U2 <} kh?9ʬg\|J?W<n6$?>F> $|Τn^3ӌW-vU@|tlSm?w??sަ̹gtn<ؼO:yDdidy^߮G֭[b7K'c'l)f=R2^PePdohyxqJvNzKyi]c_Bp)eڪ=+F )Dv8-!1 sgkFQmfm_>*t"Q2VG-H vܲ P{5J6 ?6ȃx=<jod+/;ӓ_/cҋ9ry]O?r-*/;U2clWo?5xu*,4GK>q7ç{o[wKQKcU82_/_P"뚨w,E/l~z,Ly&ۏtAK&)zzu-UrMuQ.)M77?jT?E8iXD;[߯N RF̭,dޙJ˃f|]='Ҵ!ڤ,f6 KTRF|hf?+Îz҅vF7ZX?QAnv,+-?ǯL1i_2>e:8Yʌ*Cm^6"ʛ|yi8Wh@+fP6/m= {H˶(g[Ǵ:7k@ 72o~Ӛɂ3+w,yOڶޒF`qJr+uS\Tm;3/2G?Ҿ.S˯)A M۶umkA 6co.?/0k,3A'De.j~)Tn[- 秿|&`єppx vA+2 $q 8Sz33䥌*lZK߻R??EH2!diqSOk|P Pc?Z(+Ygߵyϊ0|FBytN~$^Q~lNȶa᝛2xeWQIc.z#VP~QnS}=k1_؃'Z>v%\\ÙUP2*m+=IOf˚8v$~վ²> }lofӵ}8Q $CYƨO'cxDuyy^I#.Eg[ؓxjrai9-!YIZf߇qEh"U+#n=CEw?)dɶXe6:_4)~$U+"Xxbo3ˀzcY~Ey°[o՟/O\5y,k#T[oBD`$`^x Ftgbҏ@,qxglcCVQ#W~L}'m_3?#AO^GG #?$\eߧNpVEwjőBVOמ*{pq6~b~ ~i GHeK6 ov*d+#z/2v3Џή0rܟ˷kiߢ96 ̱`[2S'[Si~P2Aw%UW9/'qZp@NU|~n2~"mvZKK墮œ|x3Vbj|O1~+w(6̏'qvF(Iyjg_RKbϩEyhͻr|Fk"f'Q/c?M1H@O/[o?v#綦%s«H+!-#*d^j P/VIȼ~t)G.e*9O^qVX cef=y5V6@ye_9#o*LܭGA<{J"b[kc{˿5n<< _'on>%Ypp [L٣FiG *>JU_tT Qo-?2}q=E# UX??oV"@c?sZ0Ci>gjd0V~}+RV6Tge#qM#qmeϧNkF˪&l*?ǎT)ߩeAc#c3Zqʳ񝟇cy1QO*TRIב*dPwG9^ώ\^mw~ߙ6$\T_z_H32?9y~?=?ϥ}"8Iyɏ39Q nXs:zgLӖ;y4.neݟ Z$>q,.;ᅱ#r8m_VOڛ6mX|}=s_ h %;y z>kgoz~|Z2A os1QP]_nϱ}M8<|Q~'0Rzs_7)o->/r&ʷGbs-]Q@8+qLzഥc~$Mk%u8~UcOʣ>o^T>ǁ9}b_-O'i?t$QfK9?iWKpJ#U4Tm5(O]wI!T\C>~uyjd;gY>j؊r>Td=ㅂoU`f,^ĉ~O̭ (uYڊ^ȾG~?~ jQ7FF!FONo%=gÚ~ҿťD 'ǟޏo'>.*ʆ( ZNݫᶢ~+=,ح[G?}v*4sv?Bk u+f==W).w?{7><Ě!Fy==QW(p!(?z>:e?]ot,˿_;Î6_2!d\Y&<םLqAwn>Wԅ;\Y5VoԿ2B_lq,J$:W*E?3wmbR?x^o_ir(mG=3 _OE{]d >T_o9*aA"SdQ`~gBQ|̪:czkzS5\|&% EdJyߏU(,T/n}p1?-_zuӷFe;uߧф!Tew+ohl(̫'>٪>;.ۤoo{sSĄ0r di|s"atp3_[?8Z #X?~ո#qU"?Iϡ,I 5F͹lT?d~fB>|̾g ?痓 pJ,}bq鞞S18o& 2mszD uUfFFH!XmW~֬񒻕WoUNV*r_d߆]>UؚL7R_?j`6ܯu-}> deZ0vdU2n[8R~`;ϻl-3 VP͟Wn.*'?&]=sT$ʖ_~:-n.Po|;^**bՂ<OU`Q2#6&??A@$^Lu/{O! |eo׿.&Ғ/_z" #wvΤJ|19`̌}RqYuO8|KbBDvޝi3 ̚-N/ ޟsCb +̏/,N~_e(Ɲ8? x1谼m96}#ҼĤF2' g /ׯl׭0(>`+7=sスk1~ͺ<-_໏yRGĆbʬEwq> f:_~ _gOo;xۧ[^}7׺Ӵηom1Z-l<~#":O4ݖ#][l7o>L~9Q3*ev%p[kM?0/z}qEt<~=* `uo7~~vf(Wv{sLԔ G#/\_qO9ܺY6j%ڪ|O!:(QI[Gcl d-{ p¹/?LjJ\m2Fp[.gUdʎv"Ɵ׎,[[eXՋp1ܫ_jb+mvy=ܘ|{UԔ0Sfݷk,}>."? d/oJ2v$.E}mRQ\׎?n`<*':-׏9m'-;mXڞW̏^I'_̭7cRnT$.~߯:gzըFY_՛rU? jӀ[UWZ(%|w6|oY{r1+ʲ3 wFLOZF={"lF0v_/k}z֥1&MO+"^-?,_NJزtVbF">_JʢVy` ffǏ~1NkG|Qn^Լ-,Syw̟RtXcW`yWzy )Tp~?/՟]~ UeֿDZ( Yd2#AlLWDU';/:ѹUxcpra,qLy5YG-G/JRUHk/>I ^bn]o?+8Z׫HQ[q^e9yt,F]_^e/e?า"~ ~Um5cWi`[?ޓtfHcmR"|}7^y_y}xKTg8Fb\د{ۦ3 !,omr|m- 7t1{>l܏vlٹ6wϧOp|Y-| Eo?ᧅi?{{m. ?mn5{y|E s1hYR]/v';o]RE|`$̖7>!|>uWˁo.1ܾY?M}oVU1.|~Sg/K:YBf*1WO'-$*˷*8?}8Л!UwŨa񶖭Ǖ=/C^\c&]EB`f8<7˞>ֽ*ɼ8;Swn_nyƂ# vw__zE$1® 7Ⱦm%OvJ/'C˻F%y'('j >f$-sGO Ƈ4GI}k#)}_[y|Al|ߪ?:dK1b6>#3D6_|dP)cutdʿ?r+OǗ=BҤo4/+3 %w"G^{B QyeuEFeǙ!FW hTH]Uoƻ?_?¦p~NY{AHJq,K7]]hnx ->>ߠDQXVv୹v~?kLOLi?R}6vv [{:QA+c%\_# 4_Ǚý\_4%vUJ˚=~}? 241uyo=߭h4.YcF6`zuKB'Wv1 ?u_NM;M?2b;3&⁈Feڿϧ*q4m~H.9{sSFbC7Yv` * w`Yt>?nN+Bɵ0z~>޵f0`|ğS?ׯj>g`F-E>*dWfue lIp+Ycϝ^ceȿ8LODO/#X-,qNʌ&ٛ9~/*PңVVPpx??ǿOtm̿0+`ZC}?Ú-!E28۸K #(`}*U!U/>cn~XTMǗ^2#(÷`xWI͊|BUUqkmC[ysz,FҏFӏ.Ef][wٳS2rm'wz3U`r1*ѪVt</U,|4/wvʟw&f`@1_G^ߗrXD/leĀ!EE+՗̋sǷ&$o[?ɈuWv6ŸOܾU Vq7ջtq|XEþ?ޏ+uV24ֿ4'Tf6]csCc1:k I>*^4p?#e; \hc]ǯ7Ͻ\?x>νhX+3F}?qxVVVL3x2ӟÎkH|+mdw~Oc:*6t@`)ӏ׿W'3GFe-/ɲVzc5ui,T%InW{q_EA?$|mr=7>$aH4dS|ߩ~?wxkH[޽|Ri= j8S]ck .=ݷ_{TO-̒Ge^E~oosM.t}YcWF-GYZڸmؿcPLj.=Ϸ֊3)o͍x&u]F7Ak^ ^ cMwm?05-`*r. \n| d*}]/<YlG>S-x5|j . mff_欄=5 ٤oIxì$}ǧnOބ{tFJ2 ?N͜9VIYTnʜn޵|Aqm/Z-K=SOvG?"d2n롱66|7_m~#4 ,犪?4S嗑&-"A7́˥~OO؃vkn#}۬/d"׎zیPr̠pO׽##-~8½JU(\;?`3 1 ǪZ?sgt<7Z7?YBmỶLm[]R-ٓY}Mq~ܗY f,{ ?p"Uhnr^%_yeQ+cp,?ytֳ;c~6ګp5J/ #m* ݹc?(?\ڡ:EϳF[?t<Z< g'v4Vhm;(_ڳW.̟|ez0~x-=hP~OE#?Z|5d b£ml/sOS_ pm>s@c,4̟U> k@U>fyQ~G|+`ţ\v:z"(ff|C_ֱY^K~'Hu$PꑗUVi,]sTP<mꭺSC=OZXڤ2,~oUGmܦ~][>hsc(5?29GhXȫ$ryw8R!YV"_>/4`5 430-ۗTgHw `q>~735gPQfX?R=*Kd<6xS~]>>襊:k~(moǭL>oPJx}VSOI|XϟտSl˟ ],1^ z~Z0cH`ż_*,\tj\_6No˩Ƨ4q\8:7cH)F{9N-jE<ַ|'0s_Gx( n6}84rj~d@){>,g[H.jVۿ?>wnWQoеH eOֿRM!V2Y>_8dQm__idQeZ ?gvۮB4-t]^^J+EMpFmvk_)FmԪ1瘓`e?|{__Td3E”~# s3<~ LZŵ8ݺvxgDz@D-rЏy, ̖ _k ZXweݏx}hWU1?y~!́cm3joɌɆ^G?rv66_p8Ҿ_ ڃ#fUU<:nHP0H?* ? Mp?w>ᗏ,iŖYd=}?W'YI%24OCa;$!Xn?呈}S.2,{cgN~e7vC י)ظK+4qS/?_N_x 7mYrjQ[lV~W׽~.1^v;ڞ4aQ>^zWC/iO9>Çc1 譧&M$c7qW.rGʑ#\Z}g¶ڢ.ڂ_eW Hѱo.5njS+74pؼF[6*sr_>?'t330j jK[0M?}1Lx 2F'Y`<W]_O#eE/]Xb:?>?2ONtqVs/)wӥ"6WAO'=xʡ]Oo~; dX#U2}'ED+v7 L߁|?__|7yBe?aWQ^_?hV.IS jR^xo+>o{lsbel4}c eDSf7m=7$ GY/'rמ$n TA^Fd2KiZgbR̫4|/z5p6$VPsּA%R7ofUtω>m|E^Cf<ɧXz)Kl~U˖NƥO㞸.H j ?MUUHb*lEӷ>¸}B;KFg?Woy^? <)9T:g\!O 23 VVc#Wz֤TYv㜞=>s\tŬB!vEZ}^#'E$_թ]/Ӓ=trvW_?1;HGھfc`˺0T߽?a{O2E*ďITTw aHpntb;\mn߿ךѷ3}?AM7@6Q-[wǃj=,Q{jCUF,coߊG\P;Y~*z{o@$+1*ۿuߧ[[yߋ4H>bUXK'2C2P ~nVK^,c,ŗO7I)$.>_Qs_rǷj8{)"_ޔW:KӖ(6\O(?&򄟙?Jc_h#YǖQ9,hw;}j!>(mccoSzzuwVO, _n߹ӖfdETeY~}>},oʑ&H*T 8Acf|Ͻ0B@ʲ ysae۸T|+/qS-kb܎Oo_¶SO}? -lSʪ?wj"Nuq H~N~'6w ,?ULD7WZUye~kpF7m?hUuӽWIdX8WMzQ'm~ǸVR[V]܉0 cN?m?9ZuObWt qy! y8֬HŬzNպ*GG_ !UérʦTIob.i e?J/h/3CM ʋw)SZ5h' )>gxcwz{~XwG% 0mf^hiw/,2=մ7-%|y?zI(d+ץcVW> (ԧN?VP#EvaH>};s+RͺR l'_+ޯ,.\"9j/;67qG?yǥOOӬn>)7LN"L~*`n#V?z? _HwHm_ W(^%Cs6gZvGJL7$ܕ2fU[s y]>+_,о[/)[~ W`~']n>*x|oF 1|gʧ( 'MS̨(;THy2;}hwk"8I_yQc񢼯V=>h_*o!n j a?;(A}Z==ǹw>o5o{zgĿEܸ<Ny D|nYKN]cFX3^~BIY[kʛ?'$8+Xyy?_ҿr?s5?("DA;d$ޘxǚNA1HPv3?ZbMBK[,LmV7e9=sm4T\q]qץ]sg_z/M\Rs[#/KMLXui#_2GI?u=ʼko|;x OXh,n+X|?pZO鲹*%[yY_>>"%|Aյ;O5;svWv YkxO~{x|2G0Wxo&: ooKrU4=g{>2ޛ>.?z+2c>%֧BĹd{Z}&/cI֫m[w_q޶?g}=ZBme59{id(K{6oٷ~4ԩR8Oᆳv9eTeq 'b0na/OfxWĖz j^l?=_z"hχ~"9vzmo6eo ki狎ƾ'h_[êĖqjVvrI/٦2omPǷ^&ƌۅm˩[nK!-b4ج5+yˋ(˚?VyDg.q'%>OC}[Q4uhz_IQo߹3ִ u5CHmůo!Zu 1}C?٫mgX>_3|'$g7.#xN?/YKψC^]>=|6O|Qo%x/O<9Zѧץg+Rm\[=MկjJ:q?̱Xs, PlYcoi7o=2Hi6Vn d_>!ֺvzbie<7\}쿾]4=q_zjz6W7WGQAccT, ^7><Ǎ,<%_ce,!57϶G_Q^M-R^{oibX鯕ӖᾭVVEU7mBĹ|TxoOտ&2gf'a?LcxYn\55-UuInmǬ7_a&Y7ڶ}[G}1~=@d{̖>48|K/zfC^?sM]jZn3H.^#ʵGh?Ҽ8TF?Yov;rܿ~پ?Y*x[>;LjA +@-#)gy=F(?fnzk~#ڗ/ ԚMкRIE|ɤլZYK|CF4m]/Yu+=?S/"eV?lDJ**{cʲ?Cۚ3/|9MK^$Ҽ?ckPů2Z|.eW"y:>o/|tv$8ཀKxd sV)ԧO s' 4O0,/..&kyeR|_OO|U>Yj54tXɼkn~ӏ1*hl>[i~(nb.YU{Ġz$Ytk]'rԴ^{uU*sGlV3 Nq8oo y>\/Z F-2n#O6_˃"\9U޾1B!^䃚BݮXȃ_ o i qY^أaKMFo{_I<25xo鿷Zc|appi 'bO~/xQ|gkzFotu%ĞT>tg7[_μVoĔ{yM6E#}OEG뿝?oMc | N E񗌼eKxOf/-t[]:X5(`F{Xmm~o^2pT:nq7=[i]_W<O ᾭ?YԜI2|.+T_g-o6`bYt딽.#In@M}Sbl޾4)<[> 9o.-b]|G5Z,h> _E_x6oqlAMMh>H46ǰB~iZ//{Gfѥ!~D^C\yn٧^ҧ{_}gQCOOO~'xs^^o#d46y}?u3ƺUźZnyaN%6oɷo|AYjj0ɡrc_8!>Y]ĺMRG컭6 "^>/qX<5jV7[}Yiڬ yq‘1E8!޻]6Y%$m'> *Z-,ַ>Mg^Dy-fmXm~˟z}ѶB:5ʫS~F8ƟD>$3/?Uxe,Q~g?Zi F!oOkssҼ+hY}c~_N8Fޫg0pχƹ3)'C+sŽzn|-?Z >&tVOݯ{M_˯me.YOHfY8+Gzs_ӧ1~Tj Vm?R_˧u_FXJe.[ǝ98k#D ;t'øcdEL}(G1?u.W `ꢬ,:6+ ҊOL'oD U3_exSy}~sxXF-K7wW {_E'0ƠH3>Te|IQ.">W 0T˗ Oz/TFv(24Zm?3g,~YsT_WZf^353QO+.?<+$j1Ap7/s?O-YeM?zf*z{_^cJm_kJΪnl+K_c =ۗF7c;Zڇ"ӯ#Xt:}nmqZ \Y_[6VVU\ψ<+[[HG+/ͿpƭH˗?|?^ohZޗYrC-2maPYm.m0R)΋ʗ=w|?{^fXF{ɮ|ifX^c?f#d ~"#;x_ÚmE] ^{]\K5d19w_g@X]~%ִKioq˯; y4km?'5֩wQI0km5(a?g좾O8oZE`^ugo7hA(c.U=}}LT~G۶RF$Vv*23]6?k}2I? oqBOǞ3aR9mssmkuj`i/F~4.KSmu9_x{onWk_ !v~Y%ͺ/.}jKyjZ.ڳ7zFc2;dM.hFgכ3s}k.K'p[ˮiV^0}Rh~!'A_;ca&_i_ivHhsx߄D<-I,Z?Uڡ`G򦵹Cy߹Km3ִWHnfu ƫK-3> 6Z$߆::_,mm-sOmB֓Uѯ"L7UH?j~ӚI.<;zƿ{6/W!w<o5e7C7m{ڿI>>^8h?b km^|BŞK?ڗ_eݜ_f_mg_`|ee?-.YP5+C$o'zo5VP_ZJ_օQ}>l^jeK[^57CX\Zf켚隯;}-Z}XQ[yQC`G?AN}Rol56ﭮbeyֿ <ȳ_Z^{K[N4i~(2ͣZlf>uo:`Co᷄|+m+Ě{@|9k%oX.\kmEW_\xľojg=孭8A_}_}|-No::דIxz}uM6"_*oMfC/F)Bmb[>j/0`ލ_˧(~ hPgv~Yt~t_'{75\~^Kf~^*ԯ>OF|GW㖷&Fc&q!:yeuږMsO:m6q3j mJzTW~XrM˛cޚvi4wZ2pDo,.O>8k7:j[jQUzqcRFxJ9獟nK{~'JM7,Z)h0-=fF&(|A⯰<}U%?~𥇂! MviVpiyֿҦ5.{7Fm ~?2,uh;.?:ug5wk=An-Nb1̫/?痷s\o5E0t|_6>$NoOI>٦]J,}Gswۧ'lW|:/|9^`o\YKsow,7C]~S]{~lSWekH- Z(eO &0+ϳkO=E9е oIҼ'e+CT5zI,?鮵t+}$4O'w x)7Ȣk3s?#3S~n!=cP]|%54il4ih󠹶UǝZJއ[;xf)A[ż{?:ŪlKyoqk{W=:X3|Z|Wxוg4c[>xsWvulGK; zV!U)NVߚ^ =}3S i^W򤺿׵4{Xl\˿_XE[x۾ԏy_|/gC=S}l<*fsKTEԮm糗ž7֡zNJ~.m?vk[}^]ķxPB#߯JV^)~xIkϏ~u/PO*M{f궱K?n?m}1__q &֣fl/!+l.o4#Ǔq9~Ӊe_~~L&ˆ<;M&Oxú'khڧ?6k[{~ ~_hTšڷo/..%O%?s^Uޏq7][_=iVCGl{iבY.օi}7~J_l>}e?j6~Ц7:֟}M[K=+JKthؿ?g\K/~X?g)k_,G$מv ?ʺO`2oSNpqo5r>gT!(?OaO #jZ4KF k[}%im[y~q"|U,мQjq-U׭ZPvťb'7?~}s^cK_K\^x[Xt}/?)z??dOH8|d7-ϖ }+:ICj*,[Ct)<12 5񿋮u_x_ËsɫC=K^C խ?MBVUU&k|ݏ+o4o :G!Mt84;hcaʆ- xkwl/W4!˾(vben~W#W6>y9^$M n {ׁD5(tzҚ>๴ml)p _v}K ||O+jj/~f/qۜs)Cw0~#~<9 OJlu.\ǯ}FXi7ʑo:Y#j'w$N?VDkTDgs<}ձ|'N?Cws_wh˘)Rc&va4# /rdc',xx?#us,u\;WwSį#ִ!] C ^Ek?唳qs=z Q_3o3¼KLԯVK 7 )5wwhڌQo[G"E,~_ꥇ?<{w66pg{?j/ P eUFGئX|e |K0+dm.uEz~6oF?Jr`_wYyNAef+rm]B opT}P:ť=qKmؿ^?!ڧK9 ګ S%Q 6gz{v9U2) OG{\W-LJѐZLG0ZCzyQgnZgIۖQw}#w˵kg_"QQ*c€&s7~J=rG<_]v{ᎴroWsGm(|4M5tpw Ɲj?ͺK/kfy4>W)wooq{:}jB',۟VJ_4Sk< |rxWEŤkJ~x+K)5[fFܭiG?/y{WUA_wxNܽN\zJTRo/ŘVZ"Ghc-,yuVnR^>S߽Of ~b}̩'1~YW[mfVn^OǞr~r chF~H[Fz3ľ  ON|4>ktX#ѻ?S`"*3л.Gƾ(xy5ogfi"/QSڼ_'?"+c]ѿnkjxh;[؏$H˄EB}Kw*d ^S 9hrgni"ҽ3]E5?澈jZ4Zºo?>$b ̿3g>_1~; XJ8V3x$3{i\M=ÖhUanviǟ088JL0_-c?})d/p6Xpe >V ۷9bL [nYN6waukv| >ٷ.o7^6diS,wP+~X;FgŚG4jn |?WFz7q.:zզ߀a9# {Ywq_j˅VϛӸBѻ42yQ?<9FOݺ;?M i_<'iz[v7.7M {x#TOe]MtZ}浭hNjWڦycmn(m?bo|,ޑqk7/,-a_5gSV:4备=n*-/G/CL\K5_'Iawfu;s$\KG^<cT8+znuWT?ؖq|s𜪮ѺcOk_s7tiR;R+ ua#"xLŞokZu2DŮI,Ѭ{o7Tte/x^u?sÞ0/E,<)#kGxK?W|pwӪ&qfYKeWjXz{׿,>u_b*V SO&SG Uk/?pK'ƨ?>_^ m|Ug\M7.:O&o"G Kڧxx/Vzc-?{&OK{ْ/#rvGQT䉣mwOF>Cqyi//[KZIvm'3 }~9[5 ?rX5ku0:_+*>OQ=k M_|_[~?^Ӛ3UN`{/Bŷb:Ho mw3'{Ɩ+⻰Jhz*]^߯s_~yr/}*$y }?CErTsJ8 ~u^>ʬ 8dXۻ'oOZ 2ܩrhON}Z˷  y vҍ2˔OS_*2Lr_dw^/4``!m/:_o"粨-YXbM|#D2f7}1cLu*Kͭ?tx/ 7h =׍.Re5?+X?}q- g$OV+X}NN  YY@{Y-#H |Qo寎>iMdža-h5-^;Z_R0E⿇<33H~ۢ?I7X+xg*\noG*@2Y:4T? ga~w eV׬<~"eMY Dc$m~o!f?x^~ P+aXƟC0Wn$}}k'4&Oho^ EE$+"Ě47Y} ^ki /-"6Cf~9ѭjeXɚϵwO:9S|Ebճ&k}eiK Db~in]RB͌lx'o~y_y24Ho+:E]GZ<=|=_~&Y9U|Y˵_^k(Z񡍿Ӯ-ol9zR KߙD(ܠڝaU}}{W[o 0Ǐ*Lkxo×Q\<ߡ㽳6'!n~U}ɚ/OñQ ;qe ˓>`z~91l_LHov/ Ž^>]e"/ly/=ߕajgx?d *>vW۟)E.[l.g[C-lj| gI82俾Xh!K?.51\w9LK (_bCq6NO< y>G~?:Iج+Vr.Srk>\_2eC+j#w?(~jJV5c_v#/]Ř.fO^h_+ب7[v`]Sb*/O2;QVܺ__5Jܼt)bm9UiZPo,~ɥ7%7}?ڟൟE;m 33n_MwæzM`}xv?]ep_w;NF{WZWNK x?^_]I.Նk Jk{[\=ZomZF?Ztr]?CllqʟiGNG^-tۃqgEg %#'/U {޿Iϧ`|Q_~X̚7n%X?ux5 Jo/zZǟ_mN6bo6kn3%a¦"D^oEVV?WjX'% tU؛aTQ_7`J Y멍WqzvKJ׎v,/'\M_?Y_]!ֳxTeꮢ?e??#g\:TJ|c{RK8g۾0󬟼q~$׫p~6)GO7w8WOsvփ;7vyjZ-ϴ_)F\m/M \4pi֗${yÏC)\Wm=>.ّ.,Luȡ_5l<]у'ޔňBK2|~=~=.mrߋuɖX6z>nI?鿝7k)$qu?wI.[[c幬> mЪ~n_\z,A&m{;0?_C\؇ZRwK&+D%U3<dy=}JrېɹTs&e/___מ/\s?7_UX巖h}6>nhv9 6|8k'1ag9foxǧ.r\\}zZ05!iU=?SI0&r~H>?'48 ,~^ޘ?Va- Dצ{ q~9U܀Q˓؞x'ZkҚ_$h&ݹ\c:FPF~n>V}z}kU?('*L͝kg,?f?_̙~qi ',o}iC(UWf\~^6ґ6w>o>jR[hUdV>ǿ_~GVG;q"q}sba*VA/Nhr 6M?{xҦA|n-LKK+{[˂ {yeg{hirZ}<ƳEO/fo ];CRyKv po==UÍۣ_Oe{B6%7`\|zdp_n?딿M&Le=xRm?1NIc%vqYCsRx[3clj^ onb7EU]e_r"g81EڥUdokjC8+<QZF]:wHXEe+ϧq@>f ͆y:7Wjڃ/[?`ˆXciEfeMQ{TȥJ0ѬmOb]bGN2Bc.6/Y?5R[z(&,y?4UVtWa#*mVb@Qp~f?My~Wd$Ve[cʻ AXYV5>|Z; 6_Hr>);bȱciIi<7tΰҮ:oR\:ӚGA- IG0y??~3;+(' 3n]OOkҬqIV$y_AJۥ$e 3nVr!==Oֺp1isc4x֤܀D7 t;[~+ѶGڹ=@lt{qFk0b8a={vc<_$zwAJ 6۩%?_ƿ/"[\4~!~J(+?ILR[ol>On$-n^dOw[oA?W>_v'yka4k<4 CFca0&)᱔[8+ԩjc ӆ=?ً~e1/]iMט=U?d/OE,m&uW/}0{1} ?"rMgu/5r:k_?>quuB>y8i>Y,z5~ "~։yC,z 5 sk=,,¹^#xk}g-2֩q'_ ^!##I]FS|'=y ?77FGε40 |ȯGV{gόo4ߏ^ Sk^1: 7{1|UQ??#,W)^4^m̶m\lW=k{ormg@ +Y^}Gz/X[ gIԬbh)ch_YK׽~Pۿ>|1_n .xXmn?U6k8(Z0Z? yo>#jjxlfWPM;Zs"ՙn\j[춱_}5>O}fh>y+xO>Xnzޥgzϕ}n.ҭ~V4moDž|y |F<]jv7'5֩Y\h9MCϵ϶%2 Rad_u?2FȰe#Gq/ξz; ?R bXmjuOmmqcJkZ),dDW5m_;_7R%VX5ԧGK bMpt1']*B?Jܰ\6$/;܁ϿwkMˬi:E>izVsRF?ּ6o՞K  V':7b%}A;Q"|$}kJOVgvtj/)|+P=g]UִdHo5 E'OYc5Q}Vu+8t5 e<Julu/ zxcm7Pմm :I"-ε{g{ ts_Pw_iw̳),XɸIk_wEkzu#rcTNXoP8|i֒2溏ʏǯOC]ҺV>bXz\:F>jio*@d d(~/|%h Ac??Ƣj4c9_m˞6-:x KH/O~N82)EOヶЩ$w~W~?|4\~<[ .3ɖ]6XhmmsOLj5 U,|#{QKyL~ڳ8cFRٟtSg^o>1kx3:OYtM>T/?f?6cv1]iW|9cn ͬ`q 3z ּ?T2*tbNgh>~ K~=|2Z˧wLu,Үm|CxwTa9KǺtjl-{kC;k+f?TjfNMjtTRpk[0M!˓אypO{Wub6Y٭m{}r1ؚ._In#ѮxWzĹ+_=M ׫$~Vx"Y][9.Z4%_gok~>;}J?ѯ[A6u lf~ylM{N]7O͸y1yQgaR?X15Oc>O۷̱o?v|ޣ9Jᰪ |-wu%._;|eDƖ/:_wX[~?X]~om?fĿE?w6|J7z^fyt}O׳|ecLxЅ(Em_I7 t4 #~Uwؿ_׹XR <sߎ%V ɥ&{s<;Wo&MCGt4[G,WIN%,/<rb/wq~'#4[GU;2G9~+#6CX}_ Ś)Y.yd|g<~VW-a+qyy IJ0?(E~?j}‘{d~\SM(Do#]quXfr{H>Y&yH=8}I?lקu?cTA$IዧN_kCy&0!'gIY_ٗ #ʼn?PCӺM5_*.۸?J3Tl7 ~/D{Zy>\pO\{QZ%p DQI!"4W?9%(QZwox9]/~XjhE֌E rxOo~O~Fwjsm&ϳ75{FBu~{]k|aC]cU9 hMxtͩ_j؝ݿ׏ƽ;|O٭w KǪ[ܿ|s~(˗OVh&x]|{J pSTegr5R~nqSֵ¾IW XT*Oc`/F_/]L?TZ/9Y}N+#* 3OmܻuݗfUvzpq\F?߆/l|mƚuȶImo3]E3ŭǝ}9lj5O.׼I|>~jZ懣K;xW[ K\y_ֿoxƾְfKJ۷c/OZU/RGe ]ir w>qo+_džhf 7ҼWXjVe',y~L0j_gZ^'> ~??/?U־5ּI]SKa{9l0\_vtt\tC.u],eh] l k>Σlq^fdGCzڷ 4qj?͙[ oI*Aa57y{"[\iﮥ_?Ř~1|g6Fq%VzajwR?&7f& V_:Qk>xP_3s=ׅUCId76~q&)稯7.o;e*r~^g!?`E jV?'|/?xwi3|7k=kˈtѢih%R:g#d)OړEѵ7^sk?-bRcR6ut-?ѿ~=O*7/vfK3᎓M~T!Gq -mBiϺYm>]~>|6||‡ ş I}{ΎsjtVfJQ4##^63௎3ix 2xᶃ /'ĉ@6C@ڵ>MzƗok]]c햐}t7G_<?~WĒk)G$64}Kf(ti~wi|NU_|?࿍-||-Oah:α\^MR.5K\Y{?*?*_(XSӾ__-^CIC4wƣXj7t/X-Fkqkڿ4t(](-fY$5OM~ߵς&_)E]qXOMWhֽj>\Y>kK,[xn{:Y \MZ3zUjV?;nm%gO?8K U%JM}n*u{ү͑HjB8;|Sdd3GIOIJlrncz_iB\X>?>47čMuoixA徛g} j׵+n<۞-E6kGŋO<$-7P//^!Դ{[{Uh???o > 'x=?Mlܷl?jp8~»O߀~*WZO 1|nu' __jKסR˯sʶ{!~G mj|;k 9|yBI_v5Ux!{_|j~~uQ-me60.uKɋw-t?_ xjXivYoޘ?~)b%ZX?^}uuԡNQcy 0Xwu`WL_}/Z=ztZl[O[ yvS.~zH?%=7N b3k4q|ms鉶~yR4hԩ")U*SW^<Yiv};?skw]ψt{P5VɎZYܽ-} ~P~uVǺ['˗KҟfEuua.+jjZ\$څK-&yWVGgƙ\HN]vbbGJg~6?f=7h=RkLqoku$0Cg!qq/ ,CǷNkh5?ho 1+!M;ȼ]~xU*aSNq8aYJ<n{G ?ڬug񵕌6]뉬N~k[ZY<|Da+H {iq0i\O5_^Ҵ6 I ѹM'آSק__JߊUkKT3ZkCCMcymgg?>z2Hb?S'I¿Z4#rH_턇2ţZKk6|*C&UP/ xw$4}rK[;ϩMs7}[5kώ8λ. RIcڶm?Z?꿱헣_Kx?_.cP-BKmb}3+1fk?{_K!SXO-VYO|17ŴeS_(_;X=2L}Qoxv֢E0_K>>_Oß%΃xvQSngywk~oUື/^Mo>MM [{<'k.՝f_"o8,JAw^'hpD`.v~\uUA/ Q7 xGXqCmjq:n7ګ/24N\^ &5ܿy|<%vKŲ<pY&C]\߳g7_?\WyNT&ψfɢaWߍiF_热ax^7ib6[=1,l.[W=q_گ?ao.{|J,<inh@62ns>?ϯ?oHw&mo,dOƧ ߼?Rk͝~)"1FUcvw?Z$|ITeonfvoۦGYyt?1f*Y~{VJ~zx83C#k>0[XBgxV[}OSOQ 2SyVvth+ֹ4u)яS>e.iz|I|7xI?hT6ecXҮ.u ?ko ׼#Bv _d𞡧ἴS7Gm{9ޞբj..-u}7.R{{O/]>͊?j)< /V>^k5֩]cEo?_CE5m^;Z:uhᾭ$frZab' @ljlw,5ˆ<3k>Լa}PW 5.MR/Y-J o]Mk_i|tҾ6^xZ\xƗu,z=x4s_o-9'?#4Z[' .VRx?RƳau6}\K5:bz@~P=bFja{j4J#lt;goWvP\c5a _Lo6/h.2J껏:zSqV>z[Uci͉tTM>lzz~_z+/d⸼#oϥZn溶O_Cf:ow7M'O_ES ^M:<eC?~ʽf*4o9}}t^"֗}{~]kZ?jeltAn~nk&\K7"ŬڄPRއ %/9>J5oÿ!4'%zd"m6KںUk5լ?|}O\0xf14j{3";-v^JoZ?u\z?rXZL=׽$1ͷ7OJVO<#4EyQ\`̾zX]Iiui_һBdTsOڇpucI_/l{{{V`yշcUKh\6vgLɮĖd(bݾ"z̫moILY[6GKC7S.zUAx#6.q;u//?E}uI#1.An1"<,-1ɨnߺzɳ^%?<#)D|Q#@p̿gR?y,z84[==|L{qI?vAu}/vߋ$0KI,|MŨŸ@En~]"g` 6O1qǽCq$vя1v6J($_n߇?^j~}nC)C_Oƙsş .naZo4VC43EQW3~R˵|0=ֽbg*`Ҿ)DslzA4,<1S~OzJJu}c6᷉-u۴kş4|Ed||Ϟx-6_MLi.ۈ嵅Oh`h[we۟3/Ql fC÷Z7>_bǯ=E}~ܦ9cc $2yry漇Y^[^uH.Yd/DZ^^OU~>>&l~ZZm"O^}+޼Ҵ,i`+~gؼ!Uo~!|rԑ ^ |ơi_ZӥA+SZ4iԩ/s-%kI"'1?Rk|@)jKwg~W;ؿm?:hu$*[yk=$s_73*+A5f|wy_ןO\ça}t_'5o{_|>ӓ^-OGHxn=.O!Uh?|}}neڮW-|BS/]ZmFXϹ.?RCZw_٣U⧉<]gȷ>xg6zU/wCx"_~jsuSf8Zi~oٿhJ;)Iy ˕mD}랕' {k'&xYK']TX*+>|~*/d_ \[+j^O6uvҮmU_/jS^ \Xnd93ּ/mGԧE>cz 0P#;QxLϭT!yx ^ֳ4?$tcJS)b9ΊX=I gqgh1%=ZcܾY{+f#A_]*?oׯw;kqWVl<]?UҮ?kU4T5}?FҬ S-l,ibmIj>jj?mPw"_h\jB(mn,?)JS'6j ŋxŌQ/4mljڐ?s6ĤX[w? 6Bd E#> *j:[~lcZ_\"Rpǣ|`*u?OxC`2ҪsdN>k~-mڈءVC\! )[:q/#KU>8͸UEM=q[^H8b@_ڟ˃#vu>]j'oq$:nCak_\\Wy;[__¿O!τ0񧆵ĺCo 7ڇ#[˝/]R!Kkk>m/;x>/<[F8jT8_ᾳ`Y?|E>j_6K,>!x P;==pKz 2ho_&ϗVp|s޽?&![x8^//~A6 _h]}.Z ^~0|}kV!>%֗X7QjPqq͛<<=KkY>!S?u[o ?:E:ٛI{b^aľlW~w{/_!|IqX%~pwx^O7M>iDW<x^'Kɦ48b,V~l7fF.S9ς~yv:>%?T練KiaM7n._2x iG'a2R@ؓ n_KHUI'KgWc?q_~8'$¿|'xGZS2Eg-sE~?נy8i _Q֦&i-Èy|)v9{X>+|IxgCڄ^}}햺7᳻>\/]]|4WGYٜ?GDV:~g5g;6+; #}5º|:NHa5/-xz/E%)ufo&e5zƯ' <v?'|kV_7Pfk⅛M#qk4?[gڄZy|=~*xᭌ?t{%<_#M{,au_?gyɮ+t4ZJ5*XZ4~a?Vbp_XRRUYⷅ7kBxo⾱ëh3^k:^ƿسMsuuko𤓛{$ko2I$oi^dws~w.>̟˹LfVjG¯/=3R hkGLoQs`RUxc5{kw׵ jJZ=KC%W^o7}(_rkv PJ=n.k<0R>q5(F?x6e(OB2jRù/WIl߇z5ż"7jXvv-!_׈oL>VE-rkYXK1}̹L"/M|~Iuo_GYR~:]~u / ?ji&o>XljB̞[:+ ͼz4~lTyֺ]~^.8u~NbR|7G׊1}Pju#?%RKu$jc?yruY ]{DIh+#qE;<ҟ|UԵ [Y 57s{[Wi:5ijCDžW`pXxi[TOͲ3G?gy?|1zv>֖!ns,qշWjķ go(3\v/޿K_xw}g:n?Y~ˆ?&+ qh >ߋ[n+oσjQjxIʓT8&ϰ C*'?L^{|#kC|9EoG-lZmc]fP?m4Vn4_ FqN"4!moF{}{U|Y]mlc>ɬ\;?3H˗3ҼS Ƌ'ſ4YKT/wZ *<0 QOG8<0.ɏѤݲ8ߐc E ڋ2)\XJ>=,;/H@fȬ#?<]ed)2*Vq_lP mʟho3^,$Yi|9:pz8Er<*Gg;{*c95 mn_2_z&0WdS=[Kvs|fn[=@n νj^vw1?|oKxү6)w(O|?^\/.|Ieϕ-:!fTcIc]-okXA7o м-7 YGʼ2؉7Xܷ4; @YTQ>Qz*iB+)$nWSZ+g|)'47kE=}?}~k// yjM+>T_1_?0iA[.^te<\Is빼)I>}#N_嬏_.>v?5À4]?Ϩڼvf->f?wdpz{ł?32rFz<^N#\j vTs<湔yeO'ce?D0T6].N/;qT(#v?JY ewۜ+2?h42,ᜀ8ۏns]z?^(a][I;?-KbsϭniI}umg YhIzJu)ʟ.:uԧZXf(?Ÿ}R;XaE."b?yP?Z_Z~c}4WwQʉ"Oqs_)?mo.Yܴcuu-ӤsY\y0[\٫?@|%;O DVojqg׆ 6ʇ}+q[:?~W=Oܶ'OJ$yt۫ Y-dkm|i发k?m, x42{˫6?&[X,6M[+Qj Y&⼓-bOuX5(%#.!V+yg\7a7_~|go)3 QO?2Umu/:޵kxg6muoo K)'Bo:k,j?oW!@|hw<@$o c4wnm'ak/c71C^kڀ,ЮqbVVZ|'/k%rOc}Q/b{lWa+!ȫeb>տ HI$z='}Uc3㿅>-~y3[xOˊ=c. QujVgݝq˟[Z}咈ŕFv|c871D5ع_Ayz~;X7>WI[5ϊ߳_OZմ)uƞ0<>~E7,>}}Pڴ_˸.Mt?|Oe|; ~oV~0zw$uMz4PQkmym˻juhPfo*R~ew}{C("5|Y<%5~#6~ ~|V>774mP;}+t7RY~H.nu~T:,qkukmq w,|⻝WJյ;]7Mʰ[ɥvpڏ&֦eO뱱~пdB80~x3ϋ^.GAԯ%iͣǕ^W'\׼]s[{^?q?O|߉>+x\<JtE#&[|8de_Ui0ڣq +#x>Lp8k(R]|r8񫇊FY32nG'o-f Tol0݅1?9ucخthhy\IM U>kXq_?lf'w_loߴ/<h(<+'~+>*xfk{߰j[_`Uz+L?f ~:oO?MSG⯉}xJ(V>T4m_'R_|q_>%Dg<⯋<[u>Y_7]CX`GA,?KS%Mо~u ߲?|Pk]iv~2no}/M/mضj{Is{VDc{#[o߉?h]?ᶩ|^irYkoMg?ٴ}BM-֧\&4ߊ?k㏈9qxKͯjZ?aq]F(nϧso[Yg?]CjNA.5tytokI*3V ~WM%ףݟ~6gyf_*>YΤeX)r3~|2 =46Nsg$Kya((n?VfDL?mM @&yy>;%1[kOO$ X//?* 6"U?&9yiƚ qY~_}@?ǁD+nl~<@z$XX)*_9b(Xx_\ƞ|zȿzFCF7Dߺo¤l*B]޿N2horXHԭ!R{ >?uі6udq'jc?nSQv\(?|}&GK &?ue!{i?um~q_vvFj|Yohӏ) .d/Kîs_ok]mſx>(u>VY#v>TyuqXUMGۯ(YuG4۴k][H}ճT\L0g.ij?k6'ᝤguhn4u=?O}n?n k sjv:qQG cTNMq9mEF&nv-7I;hcoc #_ŧ;K?_Wfӵ߈zi/cMO/c4hڿvQ?|:Og+?_Mƚڴz7?.?.C dy'8Ulqh/i|+,ddWGZ62G$,y#\D 8mO-]rG;mbE確WOi'rwR1`<[^cgs1RN=ݾH⺆r1eYsz|mR *.zs⒘n&U)vg_M|1Dr߷sqN>o*45O撖6.зVl} ߪ&{}Ϯe輧û%~zwm6FK [ZՌi,QіEe # GEjKoh.eiˀs<v}??A6PL/{LGÏA']~f-xc=~~r&RX[##2o\~/=>((uf|xoF?;#|/4+!̬Fy:z;}H`~h=?/jV%/W@5٨\moY/Dw7zqI =*Tr NUlg_UFG?tOO(;W_=r$|j_]}Ι?ҵp)~Vdc s߸8%&Jfn8\VFe#OxMi#? 5O SjZxh߲n!+m>T|?}w ⭩=߆4?<7AJ缊^<7A:K?,F&~n|?϶뚉1~^nbk>u/\qb𠓻Oױd|SC-uGլ5YuWx0/ٮ. ]m&ddQFYw= ¯e,fSk<5\~Y0DnPyӯO5&|:^2V}K7_o}%(XK_70`x~AC^Z_,=/hzr Kz%>ׯAjVѬѳi=zn_Oi`$.{o?3|<Ռ\Y嵒4?αA7Pw}~I U<8o,[\x? Ҽ[a-,_][VFZ| >O!qxI+itK^x>TfXXBP8a-NZ9?ye'"ڌ}5i?yR>͞^[뛀Օvu_~1Ai^ xtx;=zOKsZ_c?ږ춟fKZ`V&k/ng1EK7x7([[4&}gh,4&oZ-.//< |"'βrϯFQ}?m ˳>a,GlO#'a2IB3n5GkPBs7͇] 7/2kek=Oè7  ˯+Zһ=0V25%Պ=>L$";ZiN Bac7nyQCe_n{X5>ګiIՠ)Gu+fWٿ[~go] zJۍCX Y.e1AǝSRƑJ|8R?s hRPvB{6[yp?<޲W)Ozyz%vTWew=RŘ;Lz5t-Y.<$xZQn?д{X.yxB|m7X֯)Eyi|川)7E;|¯}aX.Ǘ!|Zۖk?27 ;txy_Fy[>\- CeV*3njycz{Mv=q[QOBd{3C8 OCff_3W߼oq^&2Z{8::"]p$>Vi1'OJLB;N?%.-MZLIL|$ܽ, p=o> z7$=b]v_' ~iDbCh{"_ow+sUa8oFĞsSNfgpI*E6y<"0WGW_=k,+,R$UݣyfSN7sEyI'=>4|`V0<_(j کMҿ?3,M"+OO_"do ; Fm_/_̱a_Py_rzO0[Te;$$YضrQwCヿlzWW(e45hf1 *T=2kSuGDWg`7 mڧ|ۘOs٨jw>l{wV=zR$zaN?Oǻ`DM'Umͼ|*yl.< VǗOO?#G?sȵj.o^.Z'KXZPhfӭko^O-|$ g|s~|y|B7ƏρukuxF_ï&/G?kS@WΏ[i;O}沽K^_8b߽Mm!|, }O6hz~XxF?jPjVg.5N.=Sz^a;o [N׭|7yGJ^iT^,῵X[}W}kcTtڗǾ׃Ǻ?~uZgqeJRO=+M=,7V蟸(S {௃v#yֹO_X4{?e^wٿWGpwI~Rm5k{ӼE^g9[;  ɼ,?3tG \?<~0dI.Q"no L_?zz K߇l _uχ60^-|GM-4ٮඵ?L+;wd~7RK]/Ieʋ7G4|y:mů]\!?i?g1$Min06;+"mn%.!]2z˞9խiLT vkϯcg7-@x߻=y~SH,uy8WoAV ҵZ2 4Mqsz5ckyhVVzF}ko/5 ו!<} x?{wZ]ؼ_YGo7׮}>Ob)avC'V?XU0}':vuK^SWaX99/ao+}/̑{yq*V̟lK}_xuTTaYbd"Et9l[qyakp<7k5q /ׯ/F?LⰱܱOƯi1语%6|6A_ ηo{ҝmyK$Kkc2C𯀯#cyGvuoExƞ:f=OKrP>p?^"MԩF?:G<}:~bܖA$H<98{MLJ Ɵ.x{Gyқ{9H?1i- /n.#y^Oj?xG|+y_fz}޳k2y6pKy^M?:WvHѩ}# J}CZMvG[=SĚ֋|<`^'e$C hjD%W[^[-KRko.,7~}?CӺk#_|%?x^|*񽮩>iSm?lqjgoڟ_?fߏ 5HsO/Hvžo5y ѭu-6mBo?K4SOg0(ӏ=įh NOҵC^&$K-My&g.z: _~z:Ys/kmo3/ĿM|_Y{¿ [a Gmԯ!}.uu0VmK x^Ὴ.A&?:Y bW,Dj8z~ƦOO}WndIoX.fΖYb<{y4r\M~usVuţC]j;X_Pb2`ܛ~_oyFഎI'˓5'=5gM*1ѧN?mg6 L~ҹ{_0i7_\VWPZYy76KhgH!\S.i-V٥6m?[{潧llUw? n=SPѴ+ϴ}+Rʆ3ZS}›?6w N4}֩-w/QEgXL}+W똽wmvijWPX)m-&hm^7?`?hkKO)Z~k鏢jMKM7G!5-zZTLǚO_x6M[QogzO׍>Tf(mٿmC]12y1T_~C<{;k\&O1q,+:3GcH<^ޕ~~Q x~>񕞽^l'Jl=Ie}[mY|[gERYL>On^M y[_3o\t?ZE_?:%F_?:k:ֿsP6KuO*5HecOz=O⯈ڽ/x4zO=S^%-/Gn;(*}^]h=ӧ_Je>L[8wƭO>~>$ (ҵ]> +M:65us_YoO5?'xx~(xR/⿰n'RK]J੿/^ biSo~7.-j!φ.E<^~P׃^&msiPO~+e|wu/1:~'־,x[4x< ZM;ߴ^Wڭ 5:UwkIѭ|+?1K|;<<?eYi.Soڇ_ CSK|'7v>κѯ ?~(%kbTz0)O;߅g}i'z6StuVl|zwkɮ:J65XWq{ix^D/mv]ߟ+,1-[D.s^|θKީ.ȁYW ǃ<}?OqN\YG7}OpNTU?ѕ$$n2.Fq忼_,FO>vKq8.zzwV\|Tݫ8=?ZdOٗRM/CޥWO楣K gkJP]zyvS>_~vNl^a??$g,Ám&~F_jBHfH;w7?>+ ٻMo'uO]i gTm>+:OAoE覸_i yÈ_#uH̘e_k2۶OϹ^~tﴏBխRKPd,&ѿ峚Y`o7W^nKo4jזrn{i|(ʸzeRd+S:g^Z a4 V_ӭ㱁m FϏsFtw+1P~Rf'LO6|Af̉ak2!r0+|Vgt??ֻ&*ꁏo=*{k+Y#?oNUF\i>Yqmaڵ o kɢG܍-žO׿y֙u$Qm.ݩ,x?_T4yzZÿ _ x~_G&_67&xWhν4V~>$YӛZP_ُI71_t/$OxďVsax]JkK J𸷵,QHuUrXB|T-%&z'|~߶4ڙ|ikO9mXѼ[u9AưvW跍ƚςGxnm3_𞷤EO%{o^;^d3Cq)%&<G@ԴYNK=T'56cnE7~hi=?V_-~|D>(|BO8l[j |iFtu|7?펡]jc]uJ7 ]G GŅo o¶z7Yc\Sm׊x{Þm6u|I-soO/Uv 9Kᗂ~|N?4>^>!SĚ[R˷[_+Oe|ֵ(<;F-[PCVۯ|yZ4J*>.wWog73kV7||%q7t?+jxafI.GoG[汴MIL$\MpDYn{{cۖF]yTz͇z~׫{O7<%SnѺGQo&lLfE 3z2Guxc'i.!v1IwkyF3HdqK#:(h}u)}:nV=N"2'.s(.}빳͜'͒Mѣ|ݲy~|ɨ> [Ad5k n m,w~/ax1}:+?ݶ 5@H亸j$g?4}ڔOl4i8-~n$tP?^-}y|H>GPփƶǕj l.M{4壊? wQ|RImOJѵ]b]_&i?ikڼ HLHSZ)b˧~bN<ܾ<>+}WĞ=6P[*ƅuS?L"Oxn1v=GٍxaI&Vf1[Ϗg5W-"k6_\O;pk){Nh]O㏈ƍ"W=_!xS0sYG9~$y&Fv͟-Sqz?cYoߙ9׳|ЧxXj_7AYouDjeoc޼RM;7t^ף53'?/?LרpU,~0k_*/Gooc׽~ $#of ?ǓO <o5DŽyKI'{u&Le[,+3?)*|c|~5yoKp߆<z["B`?xwr%3wŨXzω<6/)-leO6i_}_趷&O~4zco/4%o~TKۏU}}+t}.-iN'Z˛H;Xg?{]:{Y#*eG,SSH}gƫXi:Ï_xwKLR}xc.7_}O|bkgßa5MKz}#xAEw?o;Yz~=JϽyrHW'w?3֭ Cοc~ZK]6P"-CG-JXgHFm/_zR4j{[_Koپs\j 8ߕSYӔNՃRZ?cV6<\?c=sVd3 E?7?/ǠQTbZM$g1Wtqx/M~#פyOE?Kx?4oI!li}Oav`\HƧ8o4c[ i{$͈ǡ<+xB݋P}>H21_|/Xo/A_6/!_͆k>0e>dNIaooKo7ˬjj?K}VJXylXΞPehqM /ivk}oua`bY{O+]ϕ_2o6EWHiᦉoYI?᛫i\}}/f.~o\gz K3i0h"cʊ[tY(ӕOgϫjpY1#ѷ12;}uYUvOmx^>%5?gcCmo6{yCNՍhԒ1]AG:rO,ZӸ$[n|Nk?GVuIjMugǕ/<=sǵw]oOj2ZLkkV2^@on5H+7kZ?#=:Đ4ɪkz7!ԮuiwIg^Yaqiԩ[}[R~pcq-JExxT[S_?\'U/Bm_|YK<[jVVqe>>ړOÏ <AZA9<:h0hw6h]q_q|~tm7]е 5|7jlXtOq?_Lq<?g7\[Kb#S?r [{m8_?[ /&U֯MԵ-EKn a>~N01:ƣkZżC*\y͇O}>s=*חGlԿ^pkbMnn>Ok7z9QS5ɘQNc*i>'yFӼq}i|F_Y_Ч/kgq7MKu5ծkg7;hfF7mu8B̗,yW'idFאʾk*2g NjOFRh|בYnw_ܟ_o;:p,\ky\$({I&_-x@?3sF{ C9z{mIʿ_h!Y.b%6YgiW~α: :+lj +2oss_)>lF#ZH͢'Rv=Qe;TH!Y]ߛ'zŠX2 2wS?BsEyN_~ZXR#?s<ֿ1u ie:ק{~@xٶw<}=+Q8t9_._Q`~U_ҼE?`vEYOmޜx+X^pgw>% hګس2/.`)KN=T~;8 r JFTD8ܿ~O:0I*7n ~/^Y (ջ\tm$Uw'5b2 -gOMܨsW[vbn[dl'o_N?_go_/7_|vQCYis?~# |;ri:_uIKM.jZ:|oחkP?]-ԛ^omlNXī+\[_OCу_j^<A |@>~ }{vwv~8|X"K'aK2O['OYaj~fS:U_zTtplśkC/?ҿ? &|o?f߇?+Η|jcţj<1#.!%y[]6 |85Ikxz/_C(+BڭΡu?~3#){2%-aCiۻJmdRM1U_f*]%[7rY[,͈|{~UXxzgVZt"CDi'uXaZ>z? CH vH~]Kӹ]sw+?ˆfv;k OӏC]|'X,K9"MtDq`t#ns_?ݐNHc/|{ x?ᾀ&#ZWZΫs{[xFGOxǿ>0K:o"~>(,>/JIˠ:=q}Knm?ַ>G@ψ5H>]Y]'01\uz=2k@kO0K#$}!~#Y-,]quoh_?!75|?%'o4RŭůzYܥżwv$$O^bMt&6~~: [E2_44x_8ѱQI *O'qүΤc.t:]NRbU4Qt%~w>IBMr̊C9=ZV9qǧZӲ#ܠ#"ZݿS\gܫg[ywys! 3I5Z:& '3${\~W-3~f?~%➏xÞ?A}zezok_틸҅'яJ_}|:vgφ>%|N"GTKk8/>Kz5+Xqmsq++vs$Ѭnxu/C;e?Rn㏍,"A,|7ky}_?vمYwB[b'nl>#FIScz>*t :-豤:WI㺸],_jKhLkm-3~xHFЮ/JGs-bo}v6oJe5 vwmB2/6).Wi|iZ5};D4[U/7K庼ɵe<_jsҿ_?'x+F{~#}?y?~=噶~qt]~ğ |O> O\[_zU,.l?m/Mj9G+UsƿS'uox[vkײ^Mq,Z}(]?374_c/^lWY,:O趶בőۉ?L7\Obr"O:h?hs!CvF[-՞˚AdʹEtmW" QGKOIcS~NObտu&y]cUԭmn]o7MӚ٭tkTXMqn߹<:ƸkĿOOxT]CR]V"JѬ"{=7JǷz=8Do$?^?qJ5#=:=*J2,@ZHǗɊ#޵NJUb)>eUwd߶}~dcvYTd_3}k/aъYdvYC~Eyi^GZ@&~ljFxWL5E6g'|:TB]>5c^py]?+$s!іN=8@>mofmq raNUSE&?1矚A߀|Etrf_2O Y\us_6Hh|5GG\XÑW61 g-?v^fl_ی۰4qX od}6qbjD_d7,<饸F Vn-͕{e-_'~GԑQ\.?wɱLgVo=ԝN`?Ͼ=|j*uE#̏/zҼ+b PEqzg߃_fqTUo_=Y{.ͤ-=FNA'F9.{'/?烊5ޜrʱ%^ߝy]3WU*c0۳b)rqQ8]*|`e1Q72bIu~s_F)@+Re><۰v[^?ƲՊ|鞵z#9 n>|Vfg.U\?YOfe y׮+>xSNϋt jZ-qgS[Mm?]~gy}{7?l.k|_mxÚLj{qkTϋ#Zg3CcXFnm?ۺju+J/ rӣZg1񊦥u??˥IllAf=O?}o|&:SY_`зR鿹*񏉴o M sXfp~ɂ^޸YrSGF"OcJN'b^v[BO>4AB~*%ZFJk;1)FVqz] o浸{ilF#3o4ע4 ]fH457a(Z\ ~7rmU?մmgc{ E?hZq/7+]k,7 uF, ԣ>^-m-O#q~0|Ag5xW 6'j?gaoAy{~^4)V۟r=5r=TrR#_ݷ?n<쿯|NլM[~h.}Vj}C81O?;&OB@4xGr&UĉYy?zl$m$w#(o/w̒/5ӻ$~X+=znQ`hkw:CkԴ un ;L~櫓«?-?m_ςh?_~i_ YwƷ-txnMt6%2">Ҵ>~_|xx4zK-cl+q}Z\Z/K_e&x&hsH{^Ϩ䌟21o/˟cJ_ T??|׈ox¾(l_kUxYf|+mi/ve+՟ _< hZMGEkzT~M|I{}cRK&(.9gvwZڵwU쿼_Zұ.gmrZP|Kӷ?%UxK;c<7o}'y3ZNٯU~sXNk3Nn~}uWgR T ?βD)ƚ//*ϛ9hv[p^$д`~uGj!u"Mh>1^Ή'j;=q5L'R}ԥub?<ֱ+9|b|Oᯂ,|{῎tAl\i'ԭl,$dPOs}@\C0^Ez?oW_/>ƅS>]Svv3At A6>.}?lګYy7~o:)2Czo%0ܾc^eQnmG$|W&5kbV]/Q:/t7w\ 'J{Lڦ}j3}ڥ^?n[ˉ[L=H`ѼE*mO~UͺW[v>kqR>T64>[GsxTv~*O*OnE>^C'777GWWW#T['~"y}zb[ƫXտN;ýK0 o a7w[{+5yy7*LȾmK[Kc6AE/יZҮ]x*\yRC~P쑲˓|y?skkzZIj:çEm"{MִN3jJ_焫YRFki98o/XfSt[kO8tȘʊ=m>OۋSYZMaqQmi8?_^6χm˸41[Z;0/$,O~P𤊾[a/${zףz}7As?ߋf/,Go$3Gf/gH>d?_ 涛G ?{?g+?fCoZK_&hy!{;GÛqN*𼬱"DKp?oZ }oiS Z8z 8:Z;")E-+bNF:QZaDEb>]q\ywߵ? a~yӚƿc;P b/fֿMk[epJVdɾb8"ݎֿWS'oi+,mOmpaXFgݷ+GJ$4K4n٧t4֗*d=՗-9)J'n`.ߧ>*5., wҟ3[?} >@Mڠ;;Ԗ}znDN?1;//JNpѦfI$3X;l2I nJz.yP]z~|VOzVyj|Cjγ]6}n/#G,wx|bkYϼ;W4c#m|^ Njo/,7.T.-_``<=OCxCuo Héh~$mbWV5FuiSN*m\p'Iw,Gkw::Dd2Ĭ񙛫'YRQLol?mtx;_>SE;A o Ϳ-nGGӑCZD2?iR>U5=ڪ\ol m<[kcdگlK-u+xn&omyhM/參WOԮ/Vq ڼ7?#p{W_$ HծrvB[P|8jIߌo>'5)49;y4ve͡|;a6} g7Yfy~xb[غUǙ=zuEDŽmxW7ѷt{xa)mfu,һI&~m.s#3=zWc_A|pn|=q$-ukgQGqy}0E50._9VOC#N8 ƼA~mbv5?sb!Ie]'$G/=ӌFs3*422mU^gvSV,dq3m=I?XYn%N=>!0==w aIU_洣q4C1ϛ?J;zHl#=s֭D UA%dYqϽdK{ *B~y}+>rs ߵx fgP̤z{k_>_G#º*:R8lJ"Yq ̆;] ф7/>k4pu?}Zox{v[_%az]լU<<0Y]\xQI,YC.OkhD}#[CGlC4P~)c"/,u<Ǥ2}q^{(SF"S{lOp{LsȘc"3mGvG=}?T鵙BExmXa=BXYͦ]M!?{0/4}l5Q2_w'ߏ~>W}k)Ӗ3ԃ}/dU(wщ#h _ c%}t<9<_'8WW{4k˦b-feDK//+g㵿x%P#~~RyTyƭ1QG},j_.3 h[hnuR9&Z_fG޶|%.-o)Z˺:ۧz(k:t[Ul{\l·NJW cD5m m+]/zk'ky>E_5qq*VloGZ:ti3,bWW]| pcWOC曆>x=?~ }Ц8`rcX/s_ٔzuR Hck?\WFЪ'2?ךx,gu,?Hi_>/x7Ś:[q~wO[Yf~gxG=דybYJEsn\+y}%:K}+/  +D=CTk} y%us~?Zf$rfqy'9L)BT#俈2me2G7i,:z7Ų͕]l1_UxȎqhؼO3z+/.o,k=+CT39]Xe~u/ώ}<1|3DwA--^W1Su8 s37??_W5Z ) g<.N%{>/.+M99e;J͋ɚ"&[*/>c[l|׷O˚>ِ'Or5Ǖ;i>Uч^1oNimž#=IZ?>eWfb*Kq?[wǧտ,J4,hd97ځ B"v\4S,I6[,L44晜2' q4W1Wt|lSlzþ/5|[}_?Z5vG]N6o7寝F#' uO#guM?Ɣ ?𕞧ulC?/K_ZYA\rBq YI?v'oxrm{Iz/Ԓ Ϸy:o>(zsS._w4oo/?[~|c}OGM-.:~h?´{ !4WK:^o[hj5ڦkK;n?VL~%~MMocsg.f[-5/%˵Nx{O>V4m G#4?:w\eʫ2.k+aQ jD^>u *g?i\-dk2sKZ/oק_LVRdt]ˆqX17(g _}S¿?i焼QoxV .9Qhej_ok?Rq﹚M#bUҫsZ+"kx*2?F?}g~ïd_ |?#=JCҏԚyfvN*x?2oSXG?S?ISItWXvdt2q.a>.:{Ösz$='VHf|IW "Y|&_ ]NS\ti2[4{Y{} [Hn 漑[~*S.4}otD563>VM)̫4M'?Q8[)kkig[9*_?1[&K }rO]KYZ3*wOlsHn,W5u3ௌL8ƭc:~g{{h7g#M.tˍBץխݞOڮ;g.ߊ?>2if_zՈ>7즅j9%\~9O4}6֡Iz|Z^yq4V]1Yv|G.3n4co-x\Ȭ'R6o_5 cĞ0X!h=~l?>~8nq-iu)䶰4k-?笱}N]мzO1_򥸸yQumb]o; [[uO9E>goK *~w|?rѭ3~?:GƜ+/X4vPG2۬}:hD1 [(w}~NS$ ۣ(BL]W䚖:K8m$@?IjSh ƱZ >V.T!t;T-2;;{o\]~#,*w'M|%w?'̖q}ZzuJԾkqT.X /h3r|(;[?/WXf% ,?&3| ZxOH7A=ė_s8.ol┺!90Gr>qT/y_C}L/K}u><mV84$.M)b.ll4q|]=z~WĝS'=zLGv *PRҿ_W?W09&Eu-dG$^?mZ?fo_?|?qqzƋZM$UҲƤNE`b}5gNo{= Fmb?6<[u=tk_OO hz{Z晨5X=ena>>0L@SYUcNG>#k:7 kilխC%yQEsOAWܥXQR/_|7Mޕ (!oR_L򡼺 2DH&wD_ۭy xO:IsKKGV-l-Dmb^=khpZÏMW[K>#4sE4~L4>vy7K}S=m5NjttF1XUu[Mx ƓV>٬km?ZG]$Hј $kkyO_?ΰ g eظ/K͒O뉯.9)Һs]׋ȷܷ4xǬKyW|y |D— `_-{nzW~#1{܀c+ωn,FdO5ͨ[g.P[_G?1ş ȣ,qתiAI2jNg%;naw/_L#-Cnj#/W^Wi~ prj6l 4řCg\^UK}MgHɭgx#ߋ% moֳ}z U{yG K)E,6E|>6/ 6/p$]R+{|;a՘qOQJ+ E3I 8Xd`X7v:O#3lwԡmR޿2/W6wnY~n,hⅶY_1T_V=4.Դplbc+L-|̲/{?ZM(gx:&c,Ρ*L>_tz}=^ [~b~i$ D)]ͽnu/_Vrk6Yܯwoü{3M֪ 7g/gEKU]>r=Ɋ_q\B?[yۅ'7,Aϵ=n"6_LȩsTrFOվ|47ĭCQ|5og=]kW }ZyvE,7g7K;?k"ƱSwֶս%sXC7Mn-n>t, |\"VMYO*_|qIeG޽?ς|~|M6kw;xﴛ۫ t?&Q՜Mnf>?}Zc;o^<MkBѴCCWZ单Зퟹ s\_'%c]h5q}pKu0gMz3b)Soc8510-㍩,?$I'$wjZQP^W0??|=ͧIZ652yW:~tZUu{s{WM?sZ;Zޥh7yo%qqz<=9'a)Vo[x]̷z;I>u?y?J-…6}NɋnT/ʹߗ^9`Uy*q۷~s˿zя7C#)?%~<ؽ=?y]Ք-q5yM叝m{([sEWu#s?bS늡ukcd_[G&vgs|a \}?xZn}2oy}PԶǷZ_?xuM@.YwQw_O;μ=W)s:kIZI!#[#Mc\m|Xg1}qoxi_Zs>3[~kʧ̚X2TƧh+<~2ҴcOijxvXe״Ȧ?/-]NJd}~ ^&4Ӯ..* .(a]mNOM$2G Us/_?]kF{:)Ƥ}:ҽƩj{qzƥ^^I,\^^I\K,sN*'1çK2~Tq(gOAZ?5}S?uEtK;{X&ԿҼ}"/~Ѽ?F žc^~?e2x&?gW:e.X_V82c2?Oտ$ 4۽nwS֙}˧]<noQWQGDmDrv~U$BuUy_#.kijĒrJ7_[z^ľu#e4˫ ?~4PBzyõaAL_e>]+'*67yJTB%.}aj؞_yaZ]smS\Cצ\ڿ.aeԧGKC ^L?릜jk Kx{ĺ} R\Y^A{Z7g>swYb(S1sV![[?]_\,u-SL\_*?^c#̂e"v˿qmw xIēx&O.u]r}J+_CoA 7+WY:X//U1aBY,kQi~}z0/OYxFme6𷙉ԿsO_j|Y!U|ݩ4y_ӓW/VUid칏?Ƕ<)&y{$Ѯm~?ʼKr6>?_ Bi&nw dFQ^)m34OY[jʼ>.=fdH̿r9A澏 z~cSt$ 6zg_zҿ..l{̙?x+l/Fr6e?8w矠>ş/|aSsn?i+4#G}m8<돯︯C=r>\~um>??LW 4}:wXOK/oC/db?N1b%Q8F#밲? ݓ@\vCh[xX.$#D?3#g_ErYs:۪[_kZѺ!beBϻr{p_ߵW$lꐩ<#_}+FO5np_N\]Ŏ?}.nPv|ܬj}2;F.mcI},?DqԖS$b2͕v\y~H}p6Ϧacor?~Ly{Uh_K/ٻW㍯-_wÿ RK&u֛43yyַ\~)~#C2)ĚVO-yZ] cBZmYԺe}gTc)|( Nضh$f]gc#*/G7"A!$?nOǟJx ,h߇t[\k`m?|okM>mLmnӋO׀џ+^+JY_GÞ-Cy?oѯ%/#ME=Yʥ>n_i$GA$)ϓƟh_28a(sj{m@Rdhyuh[~$qfʟ>xZ7>&_^Ծۦ[_jX2<9n<*_J16Bܪ.Ϸy]k5t@RiU?zҽKl{[x`|?o]뺮Ꚗcdj0gSNUя5JڝէNw?M>$ɧX_ٶ6v~=;}jh?~Ц28b&N?&g q7r8<Mr6q11_ݿiv÷_giwourAT{M#u-Jk8Kˉe<)(=U^-K+Xa桢"ys1jP~ _Kۏ$MVk;}R].__osqj?:8Zve<^[([ydUZ,8^! Sw=` SW%k\ $xщt?Z>e_M~?I?5kZKG=՝~U2'{6' Ju>_!T*LЇBʹ:2ПR"heEM$sM^io{"GݤG7sè9}1Jfצ7j} 7-Oeںeyyz{s?K#C{zW4 {=FY[ u$##?^L/!Ux/)Ys][ť b)}}UeGKrY[\nzTSF#!G .j1 ω5'y{tҵ5+YmeM=8Yj*s$6oy?y/O4dLdA1,.ydꯆ,jIuu7|Ek}Hhg4lVpn"XG?sB26ʥhρ"D2ƿ>?}Ni l '^z~S? &?oX`IYRPy#mcXIϽlzţo K ]cG7?tNdԭuKysy_d_y^4$yay]fs!*5#)(ԧ.YS6.C?=.;lO}+nu㝢X;Py%ϏmԿG oY[xc.QmtX;yOfup}ڛJ"OG kGmySrU]";<#2o)j|?װ௃ j?y#]&+N'wb&IO cۏݲa/_-t[8>dƯW^QW~Ip eE?ſ1gO_'MOO5$*Gzq@ ^9-~vۇHuG__ٯ(Xg'5O,>ֈ^Mŝ6sOmPz__U\GX)g~)i=/_ 4=[^$|ya/<Mqo SOfDZ2rˏXPi)Wުu+_?<~+??Zxſ bw|e? ^񅄞6Jű:5-6}6=mkl~²?>6ߌwĹoo?xV3ZoJG5o+[{S__iA^'>Z6 ~?Y-7}c*q_Mtȱ#~y;\zp7G'/mj;GĊ+,n? ֤LvȑU]Us= g?c|[БmwώM$Yf,f/+zϧZQ/ i4H尵TMV/Gz,|1 uݩ_ľVr^-`eo5Ŀb/cY7ɝ^y_?]5g>ӗ/ שn<?\MD~zB,4ǖȟNc8F8?534) VO ^elj(_+^!ru O}My8ʥjq~RYv?d*ďi xñ ?x÷Rau_}~$#+YWi_lz_"G엩>Aҟt"Ur˨Y2ki~okz{j?ss5BWU~524c[3:RӵxH4=_MՍQ]C7|wX <s𿁴m'Bmq}{ iZլQgOFK}1'/Mi165Բˎa-c??A|Xi|FןCW7Oiν ԩ*8c3J-?bOl;m'Ɩ^j^J^6_zEO_|&-t%5k>+DTe0ӭ_A7 -JXm"^ yQyg^loOz{k-v:F̫Q1{iZ2?ޜ#aQqcG䟎7]>-gMg^K5uu{ohNu;Y,Fk|9MqC I{m j6wV]G3yMy<5 ΃D&ğcYkga[o/kKb3OssoWj*+[?7n~үK9c&?:V-HV-X\5}ɇ}sq޼_#ھ]6m.fec<.GW/~1~/Vm|:񇉵 Q}JMv?5bPw>gy(xw⟏Kx"ڰQ)ʇ9o<=+R&U i?J>QE͵N>{K{؏gӎgqTۖS,?7>zdGTEM'Z;{zzwO+uOD7Kq5i7nl|ť,ڇ{\oH>_*WRԴ,!fI?{9ɗ{ 濎_ j$?)V=3ŚxoI^,ʊhbOMH.ykkoOI1׉*q^nO ~? 5 XyV~/Z`I/KJEHMJcG G sJYңo42d[/c7o+M|Mo"ȿ7ӯ|-~8k><<1qB(7O盭JӞk]-q;wi70)z"\J_y9O$;XxAHKl˯1(e2PþNWasj:FizփyV2Km GV?,?wZN0m$?&+ >i:ַө/ (Om2ԯ[5-ӏ˚烼?co?Ś]4"񵞡MU7L. %蟶_ϬqXZZ컿w7DԵ 葏*/x{{Kp[woZ׌ܶZwϕ,*v!>8~?hbǾ QO$Wt_hu^u<]w0kN{3W}^}#V/~+4+cm$ l"tkHto Uhf[caԲߚ G!Iceg?2CV?~R(h-D鷓7e=#j|[x6ILGw_0*hk8Ub . ?{)w ,zuR8^P\s/9y#v?z2C?;j|x^Cm:UͻGo~=~z[vBTn)[Eqͭ"o$E~1H|.goXi}ϰpY$\I$ '/3-J b.^ٴ9&m>"XK\~gq^,~U,h?_w_ 3m/۞JjV(ڤ RYz0[,?M~cßcN][ȫ`̪4-4/~^ׯiYD.6>K}???xH@v 45T~䶃ׯcx**޹SO:-Y¸lnܿΨ&A,嶁?_B~4[̬}{=*lm/-'.n1v˻`0N~V\lcm}z?JomK6m X>e._!~Xf6@˺EUW[|35%ѵE$ko-[^GE,V6`Mq7-suu-=+]Ee߻?ҾE}Fu#j_iO}{=./}.n~mnׄO,EGGO^x=?m'~xW ^}=>uR7-.>^yI$Iafi['j"j,{arXk+(lm͸K+/?׌t"'ை,G}izVZ^]}?_~L8u[sUrS #[?mVa%3Uܭc]__yGfeUc]X]?uWPFcUK]l3Q$lU~^n~~XǪK=8ht:m 42XI*+oo+r:b_ Hw<-mt{ NoyZ}Υ/uu s=Ρ~i?z}nd/ ɷb=WϖFm3RhOաY'W^O??"*ڱЧjjӧS'CCso$2 Y{^_"~7_%}KVԴ[k5ϑe+X;ơݿ꿓C C.|3mStȡ~ i>(uIf+?Y\K_x3֗B_6+ȼ=8cbh֧O?K4i>ѴEJl-mc6a(0sBҷͷSZ=|idx;dԵ??3^.<]6~7N~MqSҵ߱Ou-f+8,ϓ x_ΖyT/(`UL0c/h}xgoC/ُWl~:|N%|[&q|9f|Ě}}Zi .GGS!6iO{W} ſEz楯ƩkơujuK5tϛԚDU _`y?9)hx\9||/Hu_G%G$P;M3@>f2Q'/jV>#&;iwooy~O HmwUY޿VSO6 C=nswc_?xG֤9/:[]uH/RU׍99.-mT6cۛfTijxz~O _9B?h xm[Ὕǝ]_>oѭVg-!sݾ?ˌѿg|e:WS6"6ktMO[OUώxd5~Yfm0꽻z~.Si;uio_;/q>YbvՎ԰^O_tW߱?E7,mINhGI-俄Gɴ`yz=}-|>"ObO XjRF JPveU>6:m?|G /bOۈNAmߥo쭨A$k'EǞ~FO_?1XY=RHO;]*J᷷(cbEm+x;<]X{/5k\."6?:oy0+t~2iAl4>k(.SU{oky+`~?~w7-oq~i- ^JoEU^-VOgWF}ڟ?jI+=)I߆rgڧ.$HSٞmk-#?-Q6H~]Oӷ^4M&*B=YfO=y:IU\28]9tiӧNZD, ]=q<;sŚ;2U$\$1_㩮;$F"e^ܟcs_F~̷V6#W-ƭjE_sE~wM.#=f6/5=dvVG̓~pcSoQiᅿ4wvqn_麭9?/UZN[3QԩFǎxė!=ZUšm.^_'ɸR &_t!hα'㨭<$M:MԲM x,Բ8󦱶5.BIMgW3oV2ʘZu3*~[a3% F9ce?>?wnWHdI..H"ߊέՄrKXe˒98?匼￞ /DKm&؋HIegGO}+4*)WΊʍqM#u^4̟`,(qcnp?ξ[xwmd?_ξ]uFs.kܷ8]{~WV=>\r/YmO3{A !oOz訶/Ľ//f{y A7θ+_1,s.Ϛ\{q[+5 E ;YylG{k˽ ?07yo#}k+YIx%a 8防ec6?.HE5&rhE[/XhfjVSpi츒Ǧ?6|g ,;'G|=be+Voޕm OmH?T_SOm^~}pVWǿǨk>*#)b_LW ;No޹y?oKqnHݧ_3WBvѡ?{Oz&Wiv~۷}/׎(#-vNxe$iYdm$j: {5_ݱ* w"1὾_/t,~oON㎞ޕ#\wXƊvz}q?D6f~`w*?kJ8]6$mxLBv~#B(??>qTَߋW$~'漞8KqkRۿRV#ery_;~ 1A->j7+㮧C_NmC&~$}kj[?F}ֿ<>1$Wϊ7K_Ouˏ덤^}K}pM/oGq?UG锩>qkcLջ:+*{}9JKBJHo.H5_~tSgwsme s*qGȰ^3|EcY-%8cXi8 ta+8R߼ǘۿן+JQ'ďcTdlrѷ뷝֠($o0IzcmV jW}ׅWcyX|}WQ't?jK^jwnQJKصV~w>[yf-о6_𞽤[j:kw.g=JY\[/~Y^4T> 5z  5j:[YePڿWW&8_دabNO28&cE ԆVVY?z u_ 62Td yw0?-}w^q-&d ۖ<=8W>7uY*x3jqN+XL>wOneOٚ⧌? +? q(vUB,^YL+>k*0*n]Gb|F_Oנpv vڬq^kSRFM5CLȾWsug?m}pEe4~lsoEsXjQB#>.5{_ \~ǚTON^#g|ObKy4=CT-TsZVvHa_}x_ %h?Cj Isz"GxnRH{O47|?-WOK .O{}+ͿXaGԡ8S_|]n>#x뷞&ѥoٖ#(bGWٸ*j81ǂ*b*{?lI)g㞟sxxMƇC>>TgluQ당/SuK$eKf?}?h1^\4|AphwGmK,g=J >N3Z&|SOjZ/,-|&)n.>~_83{4 509a577\2Dx0G_Tf0o~Հ~U۷?ǯ~zO[SZs=ڞrVB e5>^ KdtE)o#}oKS^^*uXzu{_cZ(xSNtXl<3䶱Cq <˟&(fBio]\[i!kR7T9|¿<9i"gT4CPưצԴ9y|Gɳ}?>W_[)/9|+*x1BTq18\EJ1OcѼ Z?h3tվԼei6youM6kϱ]XKоEú{ NomrAXs}#JX/⻽nϵ[gy/,F/?]ś\Kz4yI1n?7ٿy7){'Oio77I}HD lϩG9M_@}/]/4V(?*s69?\T N®?uN1Xute??'N3^9Wn.f_.XU NZUHUڱq,I#G嬱CU ZFiѩZ_qUMWJV?u7y^tm$3u-?JCnH&Fl?EiOZ"ó0f_Cޣx8TNr&tK+/E^t<'`w{gּ~fE<>?^Dfoyg_)r8ԟ1{vdq?i/{[l'Qy>OOJ nIIG9:?]N~u&~mG|)[vo+3l'suMuHaEYMϟ7˒izzwƾZ?'}_S@o/דK( q@AUase\ 2c}>ڗtf6ev??+Q"V-y_z.mvP~hf%^HZQͤQ_ևi~}A~mҬ>ךERI]k~'&#;F6Ϸ9߹'u!mS~\`gۆ.]tѝ- &I?˰;~X[zs.e\[cZqTTeF@?wP?ASOg;Z+_2e) jǃw}]:J(WYrTG6kF1Fw.֢_! ºMA揪hY:ۼRi\yS]mn*}ߠJ>T m?oY ?> 5ᾇQ8Q<ݲ_6Ok)$x⬄Xbq=je'/ %?fLv‰'׷׽}?7?hniU|.OMC?鯷8c׀nbcexAY9[jZŌ7Hȹ=?#oxÞi:~XQG\_5ÍGr?mC*U#?cMkFԭ"O[Ώ }?T$dٿ8oZ^vV$94>O_>$Iw|{_ͧ~4jKx|'ͻ ީ+y,Gzլh+;YOm瞻6N\)Y=9Gݨ|Cy;ڦFUo35?,WuvEƳlRA8o_1 <|uoG,3߬g]>ot :[˿?ğeβM-Z=|3qs*8ʞ+TK=rk3GrmEKXM;9uaidg~bg_>=wM-}'.MY|szg!YXxhoHK=68~?53һb(Foާ/*VJ,rgx~+~7+/6Uҿs?KxauI}jF;K6!y^mSஞ $"Eea.?(zoOƼ;X|Zy}2yq-JE2Grq޼VO Ik֬6{>XUAn?O=C~uĜj +1~?u$Ҿw OWHryޱsG_DcC-h|j!b`:^9Cx@c1e[>fZa_/!Dq?! &tx˨FV=u`fx&ۧW1w_}ʲy&FǧשCGS5S:Tפ-\1Uӎb^z׭A<;4;V9XmsǷ5rhh_ޕ|F+:^9YhHi>wo?jygGॅ_&}o:_C'?Y 8?v_kV{-|/B?R9·*K(m1Co/D|a9/bxm,mp`c*ܢX-DXc/穮?লOxAѿlWX-t.Uj/'}a=yj姇=%ӎ>?WV~>0o#ZRXÜ﷑_ Q1~k]8VC_0{UjSKr6qD?\A 9H̶w߯f#SOOZ_~ |O[H$i\$wC&?CQҠ5I5> )~FX뤓?S_~Zm/Z^㏅+>iq}xBrn?x洹GfU[Bȿl."8*c᥅ OIcWU/<3uq'o>XE,߹ ^8K]|Əz?zԡ6|Ey=֘>Vgqj)|wH<׫~O6lhI _Zm-մKoxo]m'95)ǣi^o #lU/e")[S=~j~!u][Ponqy{q,yyf=+~9v_?j5 >+P׵_/KM8zڋ˹WKɭl|iZ1i77dmmvw/,aE?Z>(M=yMsP\^xnuIu=>o#˖#g o|3_\5alԮo#y\oqci_Rc\F'SlU7NhUͻY,qHMQqP(}D<_]^_񶹫iz}u֛y5[ټ7{f_b-:WftYնf/_ӯ!ۄ*|=iS5ka?oᯍ_p](=/~,R?C޿f[=NC$kr%|V\Kkg_O \HcX66ڎDD ;Ta>N{_5|\> |\{C -eu/xOFuO?_oGMx9ӣZ?mOre*||V>ǎtV57ß X.bWlM4h?gLُ.ohCM~9?o~$|suuK;}\7_eɰEΛnmn"{F$ϖ??oz{j5 :< Fo#HUNO|E u6h,|sqeO7cOܾTO>cOٟ/o[íAhd\o=~hgkkmwywg>6^k*.Vkğ.//k}s>K^q[ݧF?OampߥF7_ 5\h"K rXO@Fa0aW1Jn*2yok?h -xVLҾlX~kMv?_wW|Xն\KM{R=,o?áOO_P6/|/ qǝαg '#JxKR)/ا ízĖkksF6l>uyfD6~:wھB?d/u3ǬFmc,6!d9mb[8GZ}HVV X#u?|tA˖7/&"`:1MmA]E6:mbuT?׳\{W OƏk0)-,>g|HcosEtN6}1_ZV4ح`C+*m|7_Kѕ5O}|eR51\&ϙ#2(DX,D]֮CյpE̐ cXibʆ}쾿rk3& RiE}-Z|mİ랝>zLU?>3՗KvOyCqnmzǤ75 23Xng[Soo&Z=#5ڻXI8sM+?~=NG j[{xu) ~lmTb {lUo)aawiOI;MQ)+] JmFl}kbCMBBcӴ//&ԟ_m# ggbĭib(`vO52_Yqo ~.O':̫&x؍'{i/Ϩ~[yZ=|iZW4*tec^+ S$Ox۱k ̾b2|5fkϽ?sX[U_Nhwb$2y)zW~Bvo[ֿ/&d;i.T$_tۍ$,'{~u\jQOO-VI?WcaO2o_L]1,!zE2{mxnb@ G^G]w,IYf0{] 1?Kҿ3&l/;__!kHfA-y?W÷_1(gZK9@zg|PO,~Wn@nv~}wkmeþ${ג0I}_ˏ\9&t~N,,$?޳B86Cs!և$٩,d7|ɣj$I 'dwO3I7}D{Uq=^;~I t0$3I*/o_JNP)|7?qaӬA amGt?G^t8p$EXUE֖Ue=Kxg^#7ƿ?Ԟ^ / >uok7]Ѿk_f?k_'쵣//k>O8׬4}sMO:-F׿,,~ըi?e\Ľ]:6rZ'pW,M"i.۶~o~k_On;\֩47 eHhu+;{Hoߏc2G|kE?0/>)xFWV< gg.fC?K]6f9JV6>}O -5)13(c9֎ xt ʭl)'PfhO .ߥƺżfʵʇJ}Xn@~[_ l-3㮽?iv̍mE֥g.qMӜq/S=>^Z0TJho3Ҿ@m9׊>3IӯEhn-/q⋤ѴfgjwNk/s_×PiT|;ovEm,lΥo6?_^0>!k&ߊAsQ=-SP5 RS]^\cجr歈*qO]/c(g9uq%_ Kyoݭiji ?0&5KZ}ϧӦ*Io2/ mc۵׫0;Tʿӡt:tӧOңׯ*O0-ky#+$-ؾtlfhbxWTx{>Ķ/]I>I[iopYDN>_\77ŔSG SM2xH{[k4;n#͊fO"hMo43ռ}+fXZYivX[[oko6Ÿ(~ڹ(| j爵ϲ'oq45S]]]A_Oů9wUqo_OGʒCg}mbFe,:[]h &H/t9ẋw$;J-ij;7x@o<3%46W7౳?WphHDI9Z+'bethb*{j a[6ꚏIwqkZ_My}$w\I]]K$߿>>/?o+H;3?{_?_Ozs'L9j'>T_8o4\\k!wT<~8JS_ߑEkl-Uu OMؿƾUKMRkVvt1>u/%>v{[ 2+!L~%w\y dm-H[hjEyP4z],JϚ_?$tH&lE l痛Cӷڼ|Q=x? _֟&ߴO­#w)O>^uNopi!u)bon~NNJHUA M>R/ۓXiI%H,t9_Ԭ4!)}&{ҾPtWLI7KL{/a_g|u"6+EqIݾH>H7֯D4NhJ6̻t~O_ǏAם*o-q-}~%hߗ櫻H|X|ьwuתxK]Q_:ua~OozG ;*iVc?.;he؏&~߲4&iƚ#?g>զ[w_k*B 4q ӎ<_ᝮ& 3eg^ğ {χg6r@<ff~mqk_o׸x<}R泫~τ~(j,=S=͝KͼԮy~E/?gyC J6<1TeP +?S'jhjL'4H| ᾱ&MCXѠM/:]]~>f;*L'ڟ_mt ok\y=x~Z-M85CP*C\.ZO_Ҭƒ]Wr~*'r\k)5}:ֺmVxԯ'嵰{O?=m׃^k^Yn.eizǮ:.*19SvGP42j/w7_f4 K(UE_eӯ*d1Ao9*7AK3+Defox]_<yGYmcGg'߽S}yL~%e=?{s ~%vt c.--:nAa䟳]smoD.͏i~?eg%˶<y_ӥxw>H[VHiE3Y Lt=mykk\]_p^K/,6vsu^qsADžqh^%M:aʺaʿPa\}N|]iaUv5F8f|.;ghz|G]Z[RZhGxZl6gy=}+R8?g4qڜ\: }>>mJKxd1\]yy>U+z⯇#RHݭ復kh_jښ}uy]דk5ExKE- os%2?^?6:׉}{W5)-o)O6Yr?ׇ)KZ2aGQb~N'V͆ `˱.3m=?uP) 1??îsQ} #eܑE9rn5cr~?l 8u&DEFV%qqu돢g[61^֮{?.Y|U >t<\[_yDvQ?Xw"~?}ݮIiqg_1N3/#z8|E:~ڗጫ¥Ju)өjv|6=д[ nIgy|a#aĖm[_{_$C. ;OeZ?O~* _I#(wk?O/'Mb]%2lO?oG?ficݐB9T<k84+&5Il 6k1XͼfGkIxl7ʳ?e??-_zlI"ȭDUժ?6u9N:dYXI|%C4WQKzM~~SO= |Sӛ:n^ m?^t?c0[]z`3)J݅*ҷ|u>M[;{KN ΰoz~8xTUM 6 Z#ȒlTF?:Yڿ4*uj]]c9#Z~z~u/*(1 _aMsl}?^:V{KR~ƹI.xPs￧_N=ӆIbKp;$QˆKitX8«ʿg[߹ҽ K 1eK6[j_y?xƂ"~"ļg!bm?L3#o'wp?goHܧOag{ܟʿ"Ոە_Sp߅y&>`/cPÓ0oGgLWe* {~_i.|ym33{sk$}3F%Yݣf_$|;vUvޙ]d,i2oP80hy_o?s%\ga~ЂC#G[^׊@x{*33 %0rVp}ǏWJ;o ׭ SIqqsxa^yl >de~9?׈8:M4=cIi% 7Eu{[yS}F Xt=bLk{Hө*?;լ?E'TԴC÷g>,W}n-s\nFcZ朖ntZ]Qۺy/|߮1_HxCs;;MBuKKǍκk7x| l?O ?_iVgm6k;߈I$SKGofI](VW<|a8xyI ox{GTyci|X|:__'x^>&9G~JxJ˜cڿ1,0mZ/<>}?JMJ4iӧ/VRУ{?Gk_u%vO/Jj0R?'K{ j/[sMsNڟƟ%}E5s%Vb*a*'ѣ}wG/Y.iV8?Y{c~+Ez C[kTV뚽 o?N)KO|<Եk[[폪iVqK7v4M.;]:#X8?P?>s/ʝ8O?/劏4~c> 紴px{Mf~зKupq?5NQ![26 yX~FL!pxv*ۿ3W_O ؤљT0wya[Li?c_C6%;6VK!&=folW_!_^;Iwg%,W5-+NxA?c>BZ5[܄`tǕyyf):?p5#{sC7.׵F ;CRt[]6nɆɃ}k9^x'hgڿwg(to] 5qol4RV|?z;ƥ|?{}rUlU:\_שf(eOE,7%Έڟw[HYeǼ?op p5jgxǿIZ 쩫kyko}q"yE^ǽF FSčÏZL֥:('TkQ[~{' 6x¬MKIJӹ%BY2MV6/?知{]mnJM%&#>T^i~~ֿle3{ǂ,q%T~jzp<7S_5߆~#+Ī~?}xaoK,od>YY%oo^"|uԿh-SÒxJzև$_meo>?Pq_C>C̆Q>OOAoJSRjңR<9?N? ~aw^>zE+nnl4oK|~MԭC Tޟ&on~c yQ|٦#׿5# $74O ]/UB)?~?ӊ,owWZfMkg$_h"(:Tp\\T?=|]kxm-O[oqy4h]bJz:5ƛFg{/ͻ/>?e/;o. GꚧxWTص-3Oo_vMV>#|kx^添fiiliITQM]yqv|q_YyWgQ,ҤcS˟ڥuM 3jZ~K-78ǚT~|Vw_ D55:6=z%\7hWYus/=k5eyaw_n'k?uOk=jNw@G{w+?W*[RJtpğbb?'.pb 5g׈L,emRKo:k6s}[ⶅ}J ZIf!n-"t6|mWR2f# ^M&Yvwc.u_K (uo[> q],=?smoqx~j4S??aZczy{j[ZY_h u%uyhh-3Ҿf~$}O2jʹ6hk{[<[la-fCldy/s5oƋ%fWgzzWeݿe^WOQow #tȁ`kq\=kB?>p|~szA*XCnɎ==+pŲwdpHz,'Bwڻ.|O4Dy'1\2*0,wMq>Xz}ltzs^_8|^M:maW_ ]-6~YCMW)v́<]ZOLZw?>GxൈZZ1]E#}z7ih_I}jw~;#mN_/™!e.[n9ӥC3cha_hZ*/>ȷ4!M|S,G5o+쏈~(Ӻ%ai?v!꿧on IⷚtemFHoW,}+]}k.~,Y?_}֔eNU9D|2fk>sױbĂy7z{怍wxL0Gzk/_G<2/z^:I a{~˗3 ~ddX۹[k]e5{FerRϨZX`+}_BreI\ЫyzQ)s?/)  Cn^8ُ\g~TLjwƭh?߭8lj$nkg97[w56#iwqqձUmۈS{c#;y\GcbOχI&},&/ SGXlזwE͵qOgi:aC;VN?$ }Ǖ{1iC[)& ^2̉S8ItFՁc\3G'[q8ox<̪y}pwmG"RTz_˥EuXKxcvѵ'қ3sX|_&{?D\H՘#Hk;i~Wi_GǍC.n#&if6\Whw 6I¬TIo#͵n +作J>{ju#3Ene/eA.nI_\\\t,`nl+[{{hGu7 0RNXG >Ə,oaO/^CxsZ-bI<Ѵ͞h}7ٿ~e?7ߏ+|[f|w}{Q[mKQkXW?WL|~,|A?:l%o&Aj.,?_˔u3ljY~Se0[5k9ZTӿ~>$<7j7Ki|/xFݤʏ}Yٿg?W8X$~!C/dk]w:ޟX4ŶMk(`_''?|)[˫ kh'{]D?}g{zLS+]䕣S}{{S5`Hc?(c׌>#|I__} Վx_ARA#d??_nZ7@kM+]|7u俷_ GO!͋Te_hyX-p|߹=9luJf#/{ot|mػΐ%_hzn<3[>? XMVgYY3,Ho~?^8|I64 ޗmb? 6)y/5oo>{8Ʀ#TO şjQE; yQj^i5ֿY nf(_g˫+k6zCd_3C4izֿ_ Ei|-uO z}hY۫4{/lSѦ^WNs^nuX*'bʏ|GxgVGú]Υ$Vv6if?⿎*o?eX⿀j|Q=_/lƱ=V46rgl/ȺUb ? < &Fqgi12G ~֡y;ְgvS ϗW:ޡqNkt]?CDkjGϓǿzG^=.xwo\/$~ ml-b?gg٭^>km\d"Y3I+3apS\ObcTcVrx+Z|e9Ew qn$y<ڮy_ > &$M?¶7rc+:o78]mͶ灕ʱ6[:I g.$S ?Y|~neZ2?֧aNi4CR8t&eV6!zZB,jĢvïxh: 䩩+l?y]M57y]ݏ]ˬGjö_I}M>3aq?αu%R?Xm4KRI08|Xϥ||Jǟ>лi:,j-F"[z韆 zVSRפ X&>Q^|iÏڽ}&i/<%֟,P'MhS)b,hԗZݼW_0|P7~%*4w M=?sk&Ho2=l'h}t'_]j7Ky[#rOZ\;|:RiZk\O^?.Ʊ$'`W?/^`ɔVU*wt=j4r[ob^?:<<WE!y.c>#j;o^ElDCMjè_Ivɵ--纑9ۿ &ƣ29Io3ޓQ~~ԜTd_D?_?j$|=~yn9NQrU6V?xY}|7<i1$3>uI75eP?ھӺd7\F[#qˏ?"׶R$j0tiɕ.Ky"P"~m $GUs!'i*q^Q s˖H[w9 <_?φ%ӼWyQcIc'΋I?+a3 0J3sM< $ၤ7" ن_4v#$ ^z|K?2|.2l}Wm%̈́l_LּgZ6տ@3m_5:c<)w ~1iݬ7/9G`|LқN)&m6zNސz{գy2n:zǨ2nbpdl:~fce;?3/{lG I ::!D->j&G+~?N:ҒXvz4<楉 ;~ey*h>cGr3&KFa{o ?؟u_dϓޟ?g=oSð꿴' Dw4Y[;J]rB_eIk`F#Z=z}jϰ#LvQ-=3'~Þ#SYŸTye% >_o"qH#M?^B%yN#]&1Eig~y >m}W>_E֤%ugOl RӬXjٳdrGR慄+)zyПz(tcL-.4wHknz/-m}xѾ~7ѵ_xsKYWvCp\A ԱK.+Ң)TN3YN4iI˓3 K:o=U6u6֏szg# ZAs~ 1֩}vTgج5l&og{_^|/>#. ;sPm[Kmc'˯^jSYk^e] / ~"hUYg=B_ ;iȟ]k~<5oo"Cv5?zB3>ZiS^>׵ xMhYt'T{W|k+ j!gf{CKNڬڕֱx/Տ TkYxKdz,da-o\SY\kzUͮq`+?|5o;?¿4f׵ZZ!QZCXn/&9lhl,ʞؓz#GN̗pf]QڦԕRc.}h:'5;>MC!u .i}>Yn-mH<-iZ.iqw1͵4[y7qZu*b0Ɨ~rC.Zu=S{2TMiⵒX{Tx6j?<7ZOw~aunXo%;zjLtGξoKsxV cN񿈴{9 4]"ͭȖ^MEaE oyOWZg{IQObu*~5?|ď7 _-]R5lj4mq?:0}(?Ntmo7R5(&4sㆱg.{om4^M^-Pnc1KoWnO3VRQ"ͫj:|iq[Wl/,n "r|؏Ҟ%eRF#9Stre:sk}^^\Kuq}ys'uuuu75sZ+k|J3I]v}?ϭN*|'{y^{J+}9YK1 >Ķog_#xߊ~ |iOwg,RCikZ[yc*|nf'X} ுמ(5֖V;%qM7GW^t0æs+-|M% a}Xf7UY?_.|O2{+rt[Ks\Vce|iHfYB~?w_&bXWT;Is?~ ʞy{/m]6uăRԵ˭{XDyAkOmmc u^bg[>?[<2-,߾OGfJ<~ ɰ)=?e 2?kgYl>j5<:kZlcn[W_\s&;|eI?4ضv2y*HHw^^;N|4F?jeij;=̆1zfwfn=߈u/E+ği4ع?>ι r/6;U$uUiXmx?w%vX| n-ӧ~#ڴ2F|x>}c͟qkҹ}%' [׃+ijA xCKx4. /~\w> m&ѫ10I7uB0e]Ʈ{Ț9R\F?Ӱ3g ӏ\Fz.Y(p$?E+>6]BH}hAlW~8c&1ŵ.?w||yOzx7~[_3_Jۈ[.yg5~k9K,xV(#g>#H%g,Emu]jOJ7O?9-5]Hymuc!7mҺOmh04ys _϶kj v:HU?\yQEYoo:&+ sCx4-.kY|vEn/"~/f 턣)SQ2%2D`/ cOČ~Hf?1 z]Hs2+Et̿OozIgv3Ƿ_{ĺF@D/y6ئ;yzsx@`VEzU:IøgxOlqM&ݑAż4r?n?TR! Kk.{nF{ǿ+ Vx;I|'oES,*GxuzvV[Ww|ӿ#P&M* nKg0B{ӷ4>Y- |Rv,g9J>I-q"gRwyGw\s73y6D<=B}y+v~T?ŰxP>o//<7w4'GG8i? GEtc$[ÑjczҦI5]Úd^vj:~gqK ?˞v˿DOkV]֋=卍5۵ h.7ϗ&+Om# ?+|N-i_ܵt-(=oXG㥕:`9%<67uլQ6sOqkz7+]HVFOц_ZS}PjМ2";?Ǒ8:\Ow./$RX\WS^Gw,wpC,sE7n<[raj|ǫ_$wV]hZ4Rjw ֟E<0eor(R|$֭=;ʑZ]lMaGO??k+ϧz]'h~U[,zWE.-J4q̥ÑпfXnati7l+[9fھ-3/iyWhjK 1}wJ^&ٿF|ۭ<_hbt,8:+RIoK̩hԧ0ʷW"9FhτWQ3Vݴ|?_Ozuk=^Z qu/ ~WM,߾w/kgl'Yi|{O8|&O 9X?;K 95d5jU'L܌yW]3՘`˳p30+Cwf&}ie[j̇?'אΤyFѵ >It?gKmyo<:Q^k/@J =|yjl&_XW߱[SWh^[O|7|Cw**"X8=5?mu_{^^彽_cರ4o⯎#Nej6eC4bG[[X":ox<^Z>4.ú[V;{?,zs`UEe u+*dk}>(\ϓָ1|MRm5:ú'm&&+&B5QԿK{k`){JgԨ~#ƎY6!;?ӧ6^eV%>Wׅv?Zym3s -~$؛9y'ۯl]\M&E|q]L)t7OjVv޼j1fzҫqп~)xk|@U6:$_iԵ'^kO+}g/c^|UI'yp&)zy6p}O[oq^U^95ؚ$eOFYc?~ߪKQԦy_q_'4WVo/ǯ^Sb}c/<Ă1"<3>ot7 Z _#ߦq[=[KӐG4.?5#FF[{Cz+H<_=~@UV2D'F3IhR_BXldnw زyb lru_ҽ?@Yo⻻etvf n[G$|/QhP >͢xn.W$@xU0xkGvoͩkAk.华KֿO ,ν  {Wn|A'MͤjuY%r%.E?XһpUG{o_$s Om?>y8Fme< KmR/N,xnTb.-WNvuu+{è {1_*62X v;^e8[e2;G.ѹY+&8Q}AZ ) 9*WwO<zHJvYUV"Ndhѐd*};7YTG aMo}}OoQRQ|ݲǛ5 Sal29-[vnw 普h^gu ls_4R'85|C }W8?ٿsZH%HaM*Py }'{?#k)-p+',O'Ǹ{]{k;JX][/U{W9bk_+%iL|IVRkwQK'~9-6˭oGҥSN5)oo=¬}3٣ |q?hs|̚:-i_#7[ϵZ#햿e5)Px o/ ?Je>%h#៉ ^࿅k]KźcGO_~f}Ai_cĭssA QE]n>~~F4.Xa}g Ԍ.f+t|Yc~>:.GdO;}\7_ԭOnޟE͈1K,ǧNO}dZ2b_9gkihP+4pG[vgA#c*GsnT7{a Kɾ ׆~,j Qeqh:mm Ya緷:SFOnQO툵+̒* ?7h:KiO Īy$Xú?Jմ<$ԭ༵O\wH߼FVVkyF\*3}> xN|o-_[ᧉUo>ϩd=܌W-k.(\Gޭ}q_%uO/9UpZ2ᑤ1ԼI7ԭ|6+33~]g#t8TG)5Ÿ? jC{g?e|Nok^{w.|~UYh~n,{x#;[x4^T0>~*Wquǁ<[{5H|tOXk6('ުK2mÎOּlҦ#Bj2tc*g9x8e2m_c\dﰅm:_gόkڢ ͇-?> g$uIf(|6n?mmO}WƯ+_~_|/:8H?q>ֿR59jb0ݿM~g{6M~lZQ=#z7[U6~o뾿{CXx + ?潱$\h1K~Ά=JqA+~?;+<] 4jSa&ܥ-{?9GBӯgFƏ'^6Z}J[^{vBe]9g+ 5HE3K9ğ.t+8mѕEm\j?q'r?7ϋ*Fa{HT2~csRterLǍ}26YBgsqs.DL߾{u8 zd_J,rHC'ͳy*_<pY|ߗd |C&Ymܭ+ۥjǼأV*<Q/{}Mbv |’#Vy*2(crww-G$0Vk>OtW;Kˉdݲ& Ο#ImPwVc~:QzL&ݑwLW$GN+> e[N}SŶ\Mu/ͽOiyoN<ϭ߳?h_$ukxOy{DKXWfC- XMEC ~LQy__q+ ~_SBɡku'%T6S;yc"4c?~NO~i_{o4s5Gҿ,q\_tݖm|3;Y>w_}=LD|ZH~W|Vi߉ 'XC{F78}-}+U[Z4EjqNſ|]-eԖPzck8]sgV&Lʭ}SW?e/~$wl/ đk%$zC-sY?Ь|mɬr-͈E&3?)էR:ʜ`dUŻά,r6 ?>pIk4ɣf_zm"-ed~9Nh;(~V$U VYn(͏OzH>`r oF>A>#b+ wcl%Y~HPp˴+An6,7{ڦQL  jOͳZ H>foZ9cMO:J~wZ~ /C2G-k,_}B?jL]?D)q_5XtsJy['skqOoq2Kki6yKS|z}c؊tqXzZxaj{H-"H6g'Ȍg? Dyԭ4!1^i׼_ʯS½/G'|Lcg@*[4?ްʇP`&G,.?MuBg{:fKSPQͰu=_?osޗ;e]SRWG袗Tf8?Xmj20+3G ny8+W_'4 :l|gPe1_!/:d/ x*),e$6,aL&_ouKyuk<>E >jx :1# 9ៅ5Wa5i7j.}.53pq_7Z^wM-kV%Ik0:Ư_R5K\jZ^Ky^^I]_jK5N.nn.<ՒZFgӏ?,. _G3 mLeoi-;R~]J|9%]3D֠0M=R/e5'xOo zxH4B[^[<^Tʶ;KYT*YM!?*aT|c^Z|7u/|u ZnneR9Knt?6%N\>aakr5hY G+?B=/B`tOty$vvLQyqޯ$/7\u$8׷]{;b HI嬳5 ]o}'n"?oJf%P`w=^/c*{:41$V*(6߇>|#C?|_x|ryi~9<  -Jڧ{?~#xGN;ZƱ cPYdTQm[[[oX#0ev$/h5< OKCZZ3ĒšᤗˏM*Ya?HWֿ|o~5?\ѵ.Q4ۈ涹yR,?>NX@YI 3xӧzVbK4m22j~ Yme4yk[f1]<{ׇ>;_>&|\ m{CEys[9/T/'afW٭8EKEn@ o?q=~I4SW?i>:.nZ?jn??Vw]U>ߴ866'D[ˏ_5W+̹1`w=O^2|BKŚ,%i6vp˭kɮ7^U_5]8H5/%^ѭxP59ѭm츯ͯw |.ljz=gN/P;t/MTǢ>zksX}~yڼ9_˟?JDjT_/q7Myس;q?O3ϯ_AX5%+"HK1ʆ_ BTLk0|338S1FFǟ7|NߖW2R1w2*cPW_.D4B6nqVH,Wjɉ"};.Ք!Q$nd)e.\`f?[OxZT<_$vK/"#"wĺGw 4uow?#V~ǚo> |N|3gyox ϝk/Kğ?eɟ;-XpX{¢~|;>xv~ZM1M=\WS,(b|1>֒@ʅնw__#;$)_Z rq岶l+\Q>kvu9]bc?Y?k~ufY$L"n#/G OzYTN\w܇hOc%me𱣅1 rx=e P?$R7G~}&֡okƠ2jcN?R!O_Fwԕmvv뼜=zwGPf(GfVWNvu/w]ۭgηOcNǷҰʅnJm-6?y}kյm-MɌy=?קzﴨľdB&n^>σMIҎ>c+s?ui~OE?c[o{k,|ZymuxN,8&q?/ku*?xZǃMm%wW\z-fy<)[}}TUǦ]Q%f̞om[qUW<~ O9x49⤳3.(1g-sLϵ}Gˈ[-^U#i 8:Εm:<[Y[aZ1K>w4,#qÚ>= <#-fnfYos~,?.Zp@=[Yc1{_Uݤ+TTxu:vYw/ @UWgF,IE?Ǧ9*sq6tD\kg(rڮF(ʡϱQ_ (UZBJ3|#o4m8=:F*mB?ǧӽbhnLR%̿S.Z=UUy1'<2%$Dr*,˱=A#(Bo?W<ݎhtR2ˆ?x߻ן[:1o&>G˿?ٮue@ #_^;PwqwMcjmy^G@e@[;?yE׮1Y.qVi˳/1I2(ڪQqCpew.yy}Ŵql&7tMYcBo}䃈\H|?h$rw*=bgSV\>f08B2;~o/~dܥHFJQ>ou*Ӵ~\ĶYM#~x>heVT -qHJ?DoC _=e5A$R0cvgo_pyBmY}3H?69NJ{s?K#\ʎAV*}=TPՙ~y}6/a9[tjFH2:]=qXV 70r8bu&.]B_jHʐUYU̞?zϋ%2i<_Y` Se-9*F_ϓ<~ܮ䲩XNqUb۹K4=*aOSj/==um K#i t|7[5sTbo&N%K6U6|Bxz oYY [Hb>Žo{q\ߝR՝ycG?gzVĿDV}gPWė>4qy?:l^ljC?־oGqNJTLT%*ΟO?_dO OxJwo}5տ?"^!qq,Ⱶ%R(a(DQEO=~ |G~[=^,1g7Z^O]y+bʘ2O/28b+TRB8z4Ok!r}?}SYrQۂfvW?寝/Jd`3m?/vzy<Κ2)V4W}=퐪M(52 EF@hS˓Vu߯3 YY_/ˏq/mnvBGs7FD}JS m5X#U[ӥS2._O1n"me$K"gLOUo/V,wܬrcPc<k{ ʲkε&O!,Zu}zb * VOyHͷQUsW9y[|`ȥ!G#6쒧Ǜ%ӣeYسFqc^hlCݏ_=Nx>kXIolYw=޲J_ϡ~/w~y?_L3l{O^2w[SMuxr/6iuuOϵWׅ~#\vK|Eӯnla[9'/|Z϶{y-J-?{O/[~_~_M_?oWFKOV(R/OI5_Ɯj~FTO;{ >^Xu ^#M'1]EO~>.[Y .||q꯰~-|dj^-;IaB?7T,9ZyGm=n'K~'O3e2[ {1eS1J2O5 ۵_(0ą^o-4Ac#+E26N96ѯ-كPlQ>_k4sĝ~?U۸?:~adb7V 9P;N۹ڷ~`o v?}?> +3b/?L{w A~_ά! B&N迏jlpacM;K`w|v'j8;r)p5 ,Oj=ҳF +rʹ7֤g Am۳/>h>0J7/14 +byYeUel4pQ<\~t9[̧)|/ё(RͻZ6tG ߺ~VR2 v~'#G 7_cw=EǧI`˻`}.OPcէ aiݻzniqʮamQ/ӯ5|WxCW:\suj+OmOMaK6m>w97W_޿pa"׍"Ϥ|B-x_xwM?/h?ژH- F*<ժ|zXl-LD=دgZyc(uq#Xi XfW4_f+y~~?4_ Ht#MI5 BX׵Qo:M:ǝمzGÏ~ W=ޓo p}IkǙ|>n.%5[ ʆYCէҾv*:_ }.OzV_)$b)97l<PN?zsZ0?4~9bʭ'oKqnuI/{b N\" l?J7GQ"eE^>ZQ0gwZ*w-梒'̛<7g_< 29^"̝ۤ/ U;aIɵcG|:FUs,OקJ*FF}ѷ˵$-?ߡZ'~%8aPҺmC!FBFFA EZE4#J>U@cEj4i;ze (M3o GQ=}X\legH痑ӷ֢21*o9BYf;}uJ~4*~{@3x#U3U.`48_9Ҵ%BUv2<{XB?T.d+BEl-#׎xG;A;ilqזSJn?_~;`Oǖ1w7w^4;Na6v=Od32,֦Q3 W7>Y" tq/&_o?$hQ]g甿}+&E"ioޒ.^+Э !icg_~<>֟fzRd&|o;>CpI 曭i"MC/_+[1ŷW:]~ozIJM3x_^/te-~?o>O|"ƧpY,l#-4Ϯn:Xʔ}W-5??Ooi(~[[6/DYfa浒w鏛u#|F|&wG x*I5XxN`.5Iz/UV4;xZEZM_.. =3t6Yof0[O? ܕ˙Xݺ_1O9k7۠"nV_}~^n4?}>,m6#2M՞I(C x:d ߼T/W/z8(د?D~-AX-lr?s#@}.,9N~és |-}CN ]b,|ngG[߇gU,s R3qkRNY/ɲ/^'+] ff%.Yǧj5xៃ 3\Iyy"G Iuwωm%wfy}J.5Hs ~(Z??ńܜ/ͱ?߇lP|#;w6>w_iz'5S35טˬ 6;emQHv/0sK9)\~}`ZSe3C1?o,NNsItYv ?TfGTp͸[-θgZK67J? $~jSvn5?.4~?5Vo aAC*KIw=-o \;Q|>>W?bubK?Cr 4i}MS;#_AEǵI/ɛ7+[x<֔ ͔s/)G5Ecg>xz濹~̨#I 5?-Q??e/mS^UMoj_ş.=.>ϪC5K9{r# g:eʬw//o\inLg0v~\p}}1_/~@Mj'׬⳷~~H 3|%f22m"ݝKϧLץ Z4# b#._#Ҡ&fyjߨۛ0WceQ~c~Y'6d;?Lqzr> ͳDQid;?n?Ts,<' #T|Iai]sM~n?_^+~뷋]>k /<3o_V_N/)6o',nx6G2/~Z4$71zռya,{L&qiFex?4-lޟ&Y+]|ԏ~}Zmbh_f?ד =?_~KԌw_:~6^I\JmN?s_}$#~^ xvl#ֵHmy_YlQ[-$Mk#7k㏍?<'+ ; o_qo_xU.1NxUJOR_O犯߲ol/R#53>o"bᛏ]>&YDhC$q;Msl,A#b>vi4N>Vv~\=??J}T'ztbX|)"efU/#sP#9%ٖ4n>KqDf20mUX)Wfew~?.]鸿^ʣݯed4IRcdO֖\#ʏ3y?{q]^/'IO&K&3۷A!&58%Yϥ^By%ϝ|?Of*F^)|#)_2w|O)(~Vcl_;36Ƹ2+ݷ.$ål;$F邊?_2=`,[s{o=:j9nn~0 QYzs,F&pplSn3nOy c`\~FPUHܞVJ7*I@}(Dcl f/&T%EUgdU{+OuIq!)`イ:_lV/Q7SG)i㣉:V$6e]IbܟG>QS|3:>ۀCXd՘4R0Z(8*.8(Sɧ/=B$eİb 8M6WߡHhkBE-%icWo'}N?u;ӴuBYX/~O5-` {A?ϷN*1)D(vm Ί+|߽ $o/vqȟ?T)Dj]f8q~QVP͚:uR `=5@e8]'EOq|4)Lcj(FԆpH8>RKiJAMIE2%OcqZ[򔲻"-I]Ry''袹#dg 7;Κ_"೷VBpFzc~Dҭ"UWQ~uߢS~h_@`Tƛo=0UL )l%&OVg-N2?)q0Ϥ|T+d`Ȍ#Va)ڊ(S5-41]??ʟq2$rM>mQQG_a">hPLʼc~ߏoH8V NnQEѕn#Q<( mk>#_[vvЬI(Ox{QEM?O EfLnqq~U0U ^zc(_Ʀe?DEr[+3yx~^q#B³dǯZ+|Tΰ\eI@1?3Z)nx'򢊸KΪc[$ʆB8 L)#̱1eXQZIuHid`md\G 207uQ[n\DxF&;=w?tʊ+{OՙO#6P񟛓>QEAtilem-2.0/data/skins/ti86.skn000066400000000000000000003715261220200411600160360ustar00rootroot00000000000000TiEmu v2.00qTI86%Danilo Segan and Thibault Duponchelle1."TI-86;GfP'5^Go4H5H4+G?4qI(~[k}{^z~dWzU%Zl'Yj->u$Z0j30.0@s0$I[cjHeIcG,e>Iub%zWix{|->|x#Yl,?v Xl/?u X00.3?u:JFIFHH>ExifII*   (2i%)`+ SONYDSC-HX5VHH2011:10:19 13:46:38PrintIM0300|"'0221   |'0100)   ,# 2011:10:16 08:37:112011:10:16 08:37:11 :dSONY DSC +  0H  .X8D   Dh<    $@ABCDEFGHIJKLMNOPQRST T \,)IIH2011:10:16 08:37:11 @ DC6303320222000StandardQppl5?piGJJa],'GG00戞0戞0yyy88eW9/}@a]J#]R((]}}ilOjOL׿/2928y}ppp? }rV}}@}}}}R0DU^V(ppppp(daViQ\@p^kZ^pDpspppnpDpKpapoFwwiiiiiiiiiJQJJ3J@J}ͽ1%} lw}l@}> AbKϽp '888t+Jtӽq@ q f͌@Q/poCLDnGu2_/GҺ daVRT1131L1ĽO13131L1 L1l꽽J iQ4Mj 4Mj }6E|p@JJJ^JJ p pG$$yppJp 'S@$Qp@ppJ^^p ^ ^ ^}h^3hhhh*hhgggmggghmggmm.DggmmhhghmgHmhhgHgmDgg8Ѓ8J8Ѓ8lZZӌ`6{h{>41OНv3rԄ;XΑG12E=_lO1Ws1P H)6'{1lcll@}C}C}T\=}}C}#@}C}}}$}}Y}C}C}C}C}C}C}C}C}^^V!pA@@R51q3sBB?Yh;E}s ;0涘͠^H@9^+U^p (GL(VV@}^^^Vp i/iirpep00U׉Ծ0t 9i]ɊH͓VFp˶ Ni5p=7\e\99|\e\]/:\QYpp%ppp(pފ4̊^ 0RR7~0@eՎe1:F}YOk,87 0RR7N2T|~S|Ȱ-}٤Ň-'Ļi|:u\u#9#O|}G@?O| L0&29+}v}380`o.;_"i+`(D83n d)zq2X͆P8})-"&,n'*2")"b!#sh}`!"."8_ CԖKb1jI<"1˧8ΔȽX Sc9%2&+t}8G0/K;_"i+`(D83n d)zq2X͇P8})-"&,n'*2")"b!#)3}`!"."8_ +ԅԖ ~4jI#U<"1UΔ NSc9gkR7#55S)0)ذ!>+5 h1/JD&X'ky G(j ˕./c-`8+9][{W#ڂ/E tk1"Ğ ?壍 Yu( m#n^-f֮ %wq5a .%6-7y7q+nf!  I: :PR; ;a1a5l(G7m_6 *Lؒ8&+zD,8G0W%Czs?_"ɒ/`(D83n d)zq2X͇P8})-"&,n'*2")"b!#)3}`!"."8_ +ԅԖ ~4jI#U<"1UΔ NSc9gkR7#55S)0)ذ!>+5 h1/JD&X'ky G(j ˕./c-`8+9][{W#ڂ/E tk1"Ğ ?壍 Yu( m#n^-f֮ %wq5a .%6-7y7q+nf!  I: :PR; ;a1a5l(G7m_6 *LS7E!T;d9d7KK$O^Ł4A#La#:* "()< s/ 'tAX4L#l5,&/X "= :q+/䛶6;*.REy2*6 wIAo%b7l&Gܗ"% HTk.=: _0!*ލ m=ˍg 1!6G;xX1NF>!{D0<5 $ .; ŧ9)6jD, {$LN e;S/ 9;)9#cOo , 9Ӥ\`5S7)Z]l9l9Z %3[m@.AO d a! 2&h & N`&ˉ5NO&QW07.Á]32r&6 ])IbL 9TV;#4&_v#!^3S?Fp%MsR.;09i!4yB0T2Bpu n983y/G _(96%"XPzu+e3Y6n`Ϲ RGw$F2l/<@&z*<)Z5Qj:23k'MQ >O*T/*<Phݚ6C/T 5i, 5:'1LU jy8N_:46$u-:*9,!0 Ⱦ1'#H7${+ %X Ļ -PA L#*,z/ 2kZ J^s*s}ր Όb=4K9~XH?>1s1\k`$΅- ݓ5o͊'1V ;P&*^5%,DW <Dc%P/+j"->)|u! .y)p ;j"5$-41I5!*rx;9;7u7\}W+&[1#6##)y)@R#i-,:'^H0/-( w T#E"]3b(Y: %Z-2?< gq1J3a-z7rq8kD4ZeZ: (<6n0t{/] 4P 81P5OBe.* ׸ '2 .X/wD <#r .4]F#)#ؚJ6jW9's.M l V('Nd R~i4r.V%lSd{,qB0-bSHRM ɲפ<} 7c"ZS%#T,Y0Y,R B v"y#t ?,&,k 5Pc)"Jh%w C."tY! H7:n 1PLǛE6Pȅ1EU844,): 2~+#F: 0Mo.>t'm &t$ٜuT7$˫.Wb9Zޘ(*\%0+$/9$2R8}&,"^`-@ j"Y qmn)] 8 gZ uhp$3 '\ :v(H nJ;!w)9 C;Еt7>\,g3u/y0k(:qn5g228q#9` -sc54qr(w*(7%-֢%>1b/.v+*"R"ѼC$>)Ϭ*If9*1$!G/ǡw ~"/p9  ?AZ6y6* ),-]Qӫ]`'~R&Il!>.Q5i{g;Br R у$<T-/M6I&C/366TbvI&|F8w^v5)5~al#e/s c56("C6cm17.9w40L1**FD#~-G,#ؤW368%2&+t}8G0/K;_"i+`(R980100N*E*++ V 3 K 4+T<+MD+L+ T+,2A\ d 0 'dehdWGS-842011:08:27 + +++(2+,oSONYDSC-HX5VHH2011:10:16 08:37:11JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222Y" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?^6/Ev)Œ q~u3|n}_c<~9ܘJLW7Jmܨ<9#Ǎf':#Q||a&A׮}$"5<.tJDS*c҂`9 q> O66OiZ[]xTy|y FIc9?v?#f֪L9xқDx;,"[4%pI*a)ITI'i=6t,~Hbw=<Ǹ[ځFlǯhI-q.a#y9?CTL )XKr#@_'?:ҼkYRq4B.? Xg1Te{w *zZ \GF%B ___~_w_ZieX|M9G0Vi:l=xdJ+r2xZ? Il"3W?ƪdsIP|>u֛Xx$)P.yʴdSei)8xCl#m1UF3WG^r}w>\T~8?N<3j_WVZ[`u$q(~#V?T־ ՒbK)PUg#>~"ҰѠ 2<|lMwKR#wn x sxQvCnCϖǜV<[KrZ9o++  h?gCtaMf$vܯ;yYZOCxY|6NzzUKa[tahcPs=JE[+q*  vHX\O|Vu;ޖ(yLo9ӁE2,Wj;=y:ͻ+־}CW[󏈼xXB.ddi (P{$k 6i(7> E[h%d8|2 ֤_6N |8?dX;\]R9(YW9]- J\ND$Kg3k L.aGSΦuG&r9i]iPc#5k=Ks&e)^+X0ҕnpI IV=kVM2t՞K]!$qÚ棂vv wyjaO-wKa D3wlreuebcK;bw;k9>d#`Cnk}K9%I}{<3ǎuZ(E'ZwO^2_ c886u$q. D޶͸QX%,r*^agp#,eF 4q%Γ"Xj+B:~ޮd67bӱjh/1(rZs7:}͔JY#}4=-bSBeY~ZsfYNh_1\Hzb6]e{}1:л&xK#t=E@s^n|1+֢ծHLck΅X̅*.m#Xp)(Oa ǁ|?kXy29kO>t1cֹ)KH.3>L;c+Z: )m4@I+MZgEe_fqn15ŝDeBFv nn5vh%1Isځ5+4?_nyu_7#Ң^%WT?9baQ aDC^)*3-+_hZ-4B2Qb؊?`jJ٘g-{Lb ?U2Cq).Lޥu) !weYQ%#t (; [ަ ?n'j8WQ|:O%AeM-|f> Qu3vUNyƾ7/M l'n#vJC(-m1\ў"5_3nKOEcPQEs"Gܞ?0k%X>֫EP"Ϳ z5Ei_1v?֊)i4p?{+r?!]ߞ3ZQHaEPC     C  " ]!1A"Qa q2 #B3R$b%Cr&4S6Ddt'(Fs5Tu7 !1AQa"2q#3BR$C ?Җm~#ӏ4 k$vwdIJ&-D22TIRVKIRMTR*ڈJI, 4zi-:H| HWl?6%QNB}w^gF#1l=%n&j%A` {zmjdh#j`)ttNyݭ 2J\5m@Un{LJ3}ŪjmWpS[z#RSSjQ+INwM}Iůuv'|3cl[>jκjMISkYRR6*HfUDx38%WR Y&QoXs*jԎ lJk̭?yJڨ|M'z۫_kʭC;c>yJ_;oO(}Ue a]g~t0mmJlH%kU>:KehJꂈ>*//2cZ8EՑju'豰 cbo-՟J*~7W7fBR=oPثGeFe)_.LSmV7m1[ВhV*yJ..E?hNCU/y靇,'`]70?Ry*Lyk`"f|tϋ^:}r~ič]?=*L51ӏ د0=V:ȶeśR[=‡1D5>9θ_vc\UgF*oHM0@ IS.){{LJͻE>kgˢgv lҽc0-@7ʗ>l7ϽG;Hɛo1/&~K3Uc"v?7K ;Ƥ *"/G k>wO(kOin(t^md5YiI?/vC:TR*Yԛ$6ݿ>uӋe ԴQB`5}~H(J*ɥ[kKIrޖ_TYuTHQNPH.ߜ|#6Qi64cp:`X߰*ǯ) s7*r1( 7'K7#};C|c>*Gz#kZ5e)ۂKzAL|jw_;F# *)q{\qՉ9`_DX~+*p?PE3Ι!Ezϔ ?xRؔ2Ko);oq tŲbڛ[Y%BqZgNͼ)9斳Dv]+xp0D)!.:>0iJf%N&C4+lOWPuU%ry^l'/PR?!_'G+mue|iրwM/)C檕sBP f(R$(ak؋xi6+HԵnG-zkkK,T޼<r =0IQM6IqXRBҤA"Q{*2RZ (Rm[HM)I$+Y7;+75; ۘ:wUlœj\m`-NH&um܎lBU5{|G<ϨCE=-))wYkWm'썷(G79r>S {SSP }.fDjHثpgT.i$P.Qș}”p=)qHw0MBFSRU8#ULfdX!HeH RIt Tf5&QԱArXny YD]ĚeS|2^1.ov*奪sNp9R-ZZ:v9)m4)YͽL.-Zqig%FlLKnFù[RR̶Z&0c&J6VG}@aO!WB@ vejէB_0bj"-k ^Y%%(Sn ($%Zn7թᑺNa a$[em#VjФÅN+``!z #b-uAV+EFtW6#b8n=mj'FqlA efS-LJB0{I;G߼ 6FTL527O҂%W;qhۉ* _aI7#Y V1rd"R03@s.M l&~!uO;qSb֣a- i9xh!BHLQmA$)e(Wr?9&pU5N(3:@;k"_źMۈUW%YR|Fpm>^jdU6U:Jk@=GV LF`Un ^ R5mki'v)HHЀv=EnlD6T,jv7VzeSɾkMAJn}\Z SQ>&Բ/XJ_!b*rQk-BWS %(Z;\ZP.h.|SߕK}6YJ?,XA W'X 5Dp}J#_U`]ō؋BΪJ)& _oPQ 0UJPUb@?t *$qI`a8\X&&mjx&]RJJ8Fn}&:in#Xy>Ʀq4!7ҝYrA&UB~.fjM ICt J.qN+q6SK!9ψpk7= La 5U`A뵯 6bZ2}}!R"5_9mL %ae,J()BdI#}GEǧoYE0-u)'rFoP+*B D$p7mPjG ddddXK*Sm{ƞ[Pf.M_oH$/66IzC.q*2oQEHneig!BMX/=5g\UK/16IფChehiJkI>r.Eh$[?,c̐ov?s77vg¹X+R^R|)D @YIm䄫ȫN* ^~$3&g1Tb窘RK,*0ښeniCYYԛ~VCJ#v@J$:@F8RC3=Ԃ2'U^"L KH+u>o;M˸HWǝհUTNhKb)QHL0Bm)*V؛\@K.h6Y*[jQObk?j|6BYK8%GS8JMoLr+8꺂Eĺ좕. =ކJ GP)Cgt>-N{,Yx~'b[Y)LׄsB.'Ona7+: ^cUpU.gLHLb EbYauܒjFhᴍWyő؝Ńeg[jJq{~p >9:~(ƸS#RLa)OY QP@E!ɟ=(ijlIHrǀYZBCK%J./ R=gQU".OŖ39]9XV(N;S!4\ INʵmpbޛRYfu/MdԫCrޔ(JV {J{ȱͣMe*%>֋m<'x u9oKrϪEW1:5!% zX / kn:pb!Qҥ)>'RWEn:oŹ1w#x^.WR=HnaPIY*X؋caK :ǕJknjNRr]yJV|5.\6AŇ8<и@6; ZWa]0L|whe9ꔤ2ՙz3F52@U.|_n7ڮ<<ŠJGhRM1)' )HWws@J$V;qxޠ|!DiDXBQ,;/ lQ)n*54l^;%91 ?&llfnep3im)3-@Fu77*2lՖ\Kn_BMoh~VbJaMM2+"/3s:6@09-/)Fm RؚCzʀ۹ΌG&Pe5DJ-hI ]"T׹NeR 1r IwA WpvM9x{ Ts6NbXD9ЖC:;2/xgN83/%?Xz(Y 5x)R@ Ҿ7>9̡"N%7H -tof 9,r$biKSƴiKQyj#cQKͺҰJM( rJd%x^rgZ$G{ZYzڗ%"C~mĠg -x?K?6d2+,]SBVVǎX%G{hZkZyEkeڬ7ML*.s !i!Ĕ؃>y9-nK-VUmhT67j{Dbhdfε$deZ%^ Fm/񓨢Mywq5RҤ./$mW:tb["a-M|S 1V)AϚeo~1[Wa+PSR[xW&𦾇u2 H趣5m%F-mk⛩֮.A% FktkNIQc1wJ:>ԅE>,e  7Iԝn"JBP7ߎ#Q+{**qMS=$<OedI`]6Ħi.Q@R[RE+:)];`ɹ|Gtyj"gC7BIKJ4 X\x9fr%q fYV&QUvP_b!4s3f<>0[.TE,ֆʈʋ#n!9_{UgܞQRpdrI18˪7Ax$fk.̵BVCB7Qt " Nbp-@k4&#ky1ѭYsqTXfK*b(mmZxIMb z.<[՚Е7(ٔQӽ$mɊZ=rA^b{8EeęKUs#pV\cըኞ^J8pLԥZO|Ґ,sT#Ĺ; jwNa6OzexbLrOu)(E5mNR7 Zw}&ĥFx֦dfX\aɚ2OצYm*[A ңNڢ75ΡnH 68&[.pHle9\؍8cΩLd$}D^^êgYq jk}OS.0qWZHve \EBh7m)4W,?T=q?I jڋ!!۲MYVk 8z-3\%5Qх4&Һ}O{IPB@ok\@J)ko&cι-0]U&sHQ0sӋAKkyJukZ)\u:v HYMvV'Gf/e{^oF-$m'FVm&ZfњT X \qJ[SJshRJJ$:83ilFm :Yu.'@;,\ 3zAo͢W:|-m}Iā{vFjBuĭb&RԧO5MWP5* VdVfסiIHayL2 df-fY~> CU z,Ҕ9 ,.7_Q-՟F_,Yd^nZ3I,I:ån85qsd9&(]FyOkqGܓR\RRR'8IR2(AX7q<+J=ॾ; (Ʒ 6<Ǿ愧lUugGFBؔ[a"ex,c[8j;%)ߘ*c+.ƟnA-Fmn}:#6qoQU(76rEF*$ {RL| F~ kˬ<; Z 7_% pdVqIIE)8J }Dƞ˺ A'M4V.Z r]?+ m)VZ{An`JhLBOG6:nmirKh&xxJӢ9}ARWO@ yUF_PKU1[Q*Ri7_kPd+B\Iߌ7/r 70PKt~4ѐMh\n o'wEwb3J]: h9+)o \Wm)D-Kny4ԥ 96lV?Xaێ; ҕ-k#Z6'E=Ng(6Ii.ob}6Mt)@*RqMjN)Չ:Qbjʂsq;yL &$bBZ!–{&~A߂&1N)Ă@ rCd*ĀM>Дas&`$ X2IE)a"jVNJjTGeKMH?*QOazP1%Azw1OҭQ{,V6R%ImP'@fn"@շs Y<SbV0JYԘB$ 0^ eIQHYDvmiL$&>OoVP-2Hu@Tտb ILpa×+(4O4BexVMkgGLTEFqN*h]:&԰4pI$ k󵎓r2(R4&E6ֽ8*!23.(q+jAP;XVca p^\ySh}Hup_UٿIԦHu ֒F&FƎk*PV]V03z5Xazy]DĤ|>miJU*6ۑ LnO~iiTBU}3fH\E+Z..++N8֤ss[\tME~P6jQ‹@H80I)$ I ϳR$' ʫͣ`7?gQ$X9;^&F.M7Plftߞ9 e#f\'hnMn YlXcc &I#p%Á Aʴ$MlmUBHhq!@"tޑ6A7%T Q:-ZY-ɇ#RIǸhӰ;Blomayoӷ&43(%7 [AnK Iq khn 6Ŋ# |&ӿ{Cˍ>`-SMBl!RwVg"}/8V[MxqK@VJl\vEɰ62QqNؖJw$%#sZ.&#Kci5,RU꽆oIl%#CLjP E ,~&9VrmݍaQpw-,ˤ^{_Ii${RSCixj[IOoɂX@-: 6 7TTc&Sv>Szll/ K(R/H̃t|*$'fm3.̸&D m9"XA+a:J5ܩ[%ϖSfPK"70Z0.K?^+d6m""ޖErNKT6ӄ,l &ײaYؓkf_A q%fMw&9PZ47Oq8'RP tD!4f%]ϙF=s3j Q"/^}أ, YVbN Rox˭./M-N dTOu$j@]BeN?Um(6n{6ZЅ2R&P _mƙ}ے!G"(uǦ ;}|<'K*I?RH:H&fS R <+սʇ \6bnNDzt8dEpUF2*M|I&%&}ħ~q*aAZ $p>s8/~qДGu) (DMY^aUf\7RG9#WgR 64qA mC`{aeun7(>}dkJ 6L]ʵEh}4թҙt?d_&+s{ێbt܇$R8Fs UR7CU*dr4w[@HIrI[b Jum~Gn]"Ga V S 3H)Jw>ilبv1I;qݍ;<Ǽ_M*Fғkr9lYmR6y.b;Ia(-/PH@>JFss{nzI8߼H)AkZoUPF:%nHAO&l(o96zB- U qEdr} <,H6IZm`y;؃$ڳE;7ڜdm=OM:mxIe[f=jE=Q'75yRh~()!z(>Rsn׋oћfXL$~q;۵Dnƺ2+wźOi?-&i+Wz\#;Y7+)&SIxnEcЧY{$Y QIyœ@H.v;.?;2.#-#ϤBSoChsGhKuDɤw߈pI%pN(V^XpI4an;%)Soh=63O(+ҒIH"u^`OH"߆="Q읯_MZZ,(%IR ;`aPCiױdj#˥`lE  2..=x1 [m]KfyR) \eeM+W7 JB@XdN6,IUz'P6ۋ[oZm`Ŕ#A &Kuk~,xoE)_8do"@}('7Ve)GVш+mDj _ZPA}ezW`Q 74P/8t6 ^Iڛ{suҫlmeģcoH%/H7ݔ4mj{r#nЮ6 dF()ˁ+> +kh%oYjZ*a$~G+5py!{1:)A߼L~|Υ Q"W4T>wgUo&n5Is+},=`* cIMan *۞xTw.JTJA 5 *;x[BNyLa˝Y*7zkF=muԂw&vd(ٲm i.\ǽBRRlӢf?0J@#Vos%6AUsl ܝ>RPh3kǑ a͏a2t[Lhftg lǟ_O%^!Zx1߆QaMy=:*2/}|oPv>~BX>x{GLRd24sJ);fBt]YA_2Q:pC+_嶦t.Memu>u;;9bqf-AKQRoubJ;"zjO]jH2`%,L@C˒f^E?eRۇnJ%&m}he\'IOiRqTZ㿤Ibr6)Ity-s(2G\p8Rhvxs0&XhlSVE ~0]J]N1% ^rbtC(*idw*d8G}t<) BR@-˭&IELa ,TVNzCKRuokxwȋdxm2:b aNJve $qy)^_qx~dDη7O/L1jI7o}bsZmU6 [+tqRǝ:cΘ}@ܥV*7Ƥ@&9suD[oFqā '6B~1iy 7B<^*R8]Snkܛ@l# )IXQ$}&CV6u7'\]-ѵx;$u E@ mZSC%K`PI*P\p;ƞuED/nij#k&_};vT"֑. /YhԢM iM kD|k(d!O9m.dlO7N*p,y(IOy@ E`q |MA-6Q|d&Pu4}>%JKøtA}2'Wi-l cʔ\ MX*&$}k}y3$I_reaaYɬE<ÁWV%=ody3I"RYɄԖ4fX$!RIҝqgA"]XFG?}X\GZB9責lWA#C1f"rym~cL F_ٳ|m|>".a&o,;jӤҮ <{D ZZT]F7O$m7ܨ#-F,/3V!"CV^}=51 X M IFZBң}GQuH)E-_NDx)Rܛ܀-Q+7aӻ.,]CPwg+≕qg@mZ{Wa­K6Ro(u6Kz -y݌,Ǎ Bknc trr,#hIDPӶiMiRB4Ԭ)m<[5H4Z¾"uLM(R@Mv5nox[J I~W}Zmb$ln`/k\{GX}( l q~[p]V㓷[a@a[[3BRG{oqWE Vp/RQtOHI$\8bdCH)Jd@9ZJwۓ 5)Sٍ,iRM<*los_ôb)Eԕ? Q$t{v-eϧD ߼H.M())u}'Qri"@ Z'PoD4oϵNv'{-kQ*SkJ"ָEM8nH)nhڔt 7'.I)ks)jղvuqMY> cTy1i qcKw DߛhRH)$ 'O6c~ @(O@=,,MBt8%+& &BD֤l,@fɄٗ7J4܍2BkXϡM`vD"ւRRucm8)-K%'-b$n izԐ2<W$#Ju7qO&TrҥjVcVREM _P>R6e^@QU`hH0ӭ l,.lcER47'.9oVڰ)F )7Y*_T } m!\߼%aj}qe)ԟ0ME{AMJQz',6Aym_QU܌6*Rq @TEjZS~ *J i,3r>bUǏWqt#J ⊎YڑMtR߅9/aqxƟqu8<+akO8m&- wO%[,1!dF3AN-Z̨ܞnM 6zf`SHmcٞ㿼쏫"CE+P@ &Lj/ZUr_u~3KQ>ғ3,$$K oߏ!)䆀voLᐒMp3mP[,ᠬò)iaP{þLlJn֎Mlgj )} n imkFW8yǤCU`IlqxY7$m&SYӺIs Tkiskxm[gMAd sɼJ@z/dOT9ヴR4{meEspcYJUuX8&({K츴L$V=.vqze ( =IEƚ`Q7]mwWsLVՍ6G! - ٷ,,;~1(vuҗ )+n6IH\6?Sx7؎{)hq6bpEFV X#1N]IHH%q"QlZe*1N6H<:Mj)J/b 1Fނ_[߼pM,,yk_+lob)K6ᤒNjͲB|{I;K(~?:RiTPIZEiVRIPܝcJ ws{*׸P #sR}BH^ T`xWLwDVQt1\JC6񎙕yR"8-%7#aJOXz`&ԥ CkhRAҫ؈^mm1*eV5܄k}rQQt+)O?I#OWH rN`sa!8" )noc :o?2aYԓ慔0Vna$W%l~u5Y̴?W8swۚ(dzʈ 7;i)JFL/¬о3X6.-EMO}lx"+!s"e.+=LA@Qpٽnx&WcFG!Q3 SRQFSbwO᷶{qf*by2m&u`-)  'kEqJmu2J/ɋBN RSe4\u#-exSnMj]D\YH"m &\.]GVӨNEŻA56/ J7$X[*JPQI7oz EU- K/OО8P!G7|Ɇ)H<Eݞ|Q۱ !pӨ ( =/ ٓ^o4$6睠h@7iP-r= w$4(&Ǹ*RTxu&Ǜ0 tTET lG50〔޻  |ӥ@/-jKlä$,vr:󋺶RʮN~B aZԥ0RA7spS}`Q<հk)ե; 7s [XlI 7@7h} ]QNE¢9n`meOU6 m.4A7 dѱm|m۾t; Z9075TmĿFy6[퐵ni|5F0Q (ԂOdJNw^ ܞ) `]I<[;^ըX Z~q@vW0mQ)hԒvI?َd=T)bA;wu@FRl߁KkW7CbV[+p_VĞo &vGp,tC {J wJVW#mVHPF8TvPJR}cuJmƐ.J)9)]Ԓַ ^6NrO3f% )(p }˰+=I0fI}R+Iژ?V,aE tI;ko3Q!׵}m1/rS֌_,|~禧˙w̚ P6OYh7HX`餅$ZDX}X5몾ҋmG*6p FB8Sis-s8ʌc4s֠j8mP: 0򣡿J&XęQ_VKf7>#e˃x)P;q<}Ɂ⩜s Bsxq*o *}oj.Tt갼EQmveA6xe'`TP*J&8u0smcgʖvH'm\vɵ .{F*܎/@%zoq -3ΐAŮJi\R$ׂ׊596}GG͎ p$i>*I?EU7׻"PrQ,9'@R}ȼ 3 *LEwS9[JSl'{ qJr= /-+Q: &hR;@ R$DǞJ|߶y.Jۼ*ZT-ap`)6Qsa%W-v"ѥmh5n1ۤkBkAcJcoq}Ԕj*g,G R7hkl$z4|(!W_tR߈. Vv0=!SȻ6F:iK74q-hJcN膾Dɏ *JHw4M=zU͸K+ P:R 1R[qL4ESncUIMq);(5t~n>پlur8A$jPJvDStH-)w)S0}Bq^ c,eoz6 {E[A' O- Vضv Ӽ#I $ ]JӘ%5*B͐Khk sa0K1/qDaى.]-VIRxGQ聶㘛1QIAf>sdϏJ|⢧c^v†Gt}!Gq3]}bA'E~e)R}D)"3̮%m̅0LΗo%mސ~I1eMN.s*E~1Y'&ѿF>??;}=)BM l<ݡ($BA ooh}; e$Xprvh)h]')/%tͶ։w.:M7776RJs܍1Хu!SîY =о%rGs9M:H¬ ҿ, ޔ fXvr\ w6[hܥ龡RdӴi]? H,?7Dz9~ j_/]\^*Ie M?߼q?\ VOY7ޢ?a,rN }:b*C.pX~u]ߊ>Zr 8,h:*70DۭEhgⓗs5o̳s0QmZE3L~%KدNiUqBoܱǘ/|Nr q ϲ >'omHHhKױfPY$N 3 rۈi\晸>%t^`p*)bEZ͊6I V|IK -O6#2gt)/gaeGB6V:vɼVPr+*!$?F|UX JG kej^0ݘ/I6AVͷ8Gx;{P{+^IձxN/%*EJMȱs@)v1]f>#y`I:o |DԒ*٪4ctؐ{!Skn.|CB0h_iD4O?pBn,J'z92ߍ\x-ۅno?I}6M{G/Bu+qkoEJ3Eq\%O`h p6?vZeF N͛zH)HNǷhJ&8䥴Y7'UJhmi ۱~  )-&m|@|uu&6-qNnEiv:6 *+_LB}fb0|A#YµqC_,)ݲBɱahD{q? )ՏݫږuijT )KX7@ܑa*ZRlbW/w#׆0XudjkۛBXdC?JJuHơ?8oXo8)Sa.$T Cn-btq[KȾhOk*`BJqar!:(< ;R S?6֛j ] GG0TufI M{!&ڒ@%sEI+*$0QQBu8R( GI}:= x1EKi5 >6G152wPf|kr>ML{6*.ՙ3DqkI(b}mLV i~V].bwrx } :vBp>frx 'GZ&_pE՚)z*c%܌S0ʽhl=JV!$Xo. ;w9UkQJ U~`T(O+ХG)j$\۴ֈo2ڛhHv wOVm"qHVet?' xAxOJ) .X<'~1( iCA D_Ɣk}R˧P)7҈ہ %$O-. } X)!=h5QJ@M'wPB-m–T{_tK%ZRv<\֔0RuMF 0\Oe#vI$kYѲfv:)@pN%W]i: 9bъQJoϤRm &F %,$ji(iK$oO)27KP$ n %gkz@P-0YZT:}`=.KځŠo A)q[ 92|ͤ 0-!N\c; [jMsܤQ Un $(zck.4knM lҫ&H=0';:%G*Иm`%AkΉJ 6@uW Pni:waC*$_Sa *l~7T*A7W89>NJ[ /XP+T6z@uN0ڼ6[IQܨ!*U=cvmW]r+QUw0H!ʬn=!aUnD )V0 @<:F<R:7=,=-oz3c`GwzR{Z]R[k]g]ݶ=y2򬅤F< W7'ΨmǴtgCK5a ̙E6MY'\KKrnY\ s4_Oʱ`7qIXP|kS3놎yhII ;GLK_CWOq3E ;zHec1n6œ_5"JJ3r^&Slz;C]Xtxd'ԍ_ܛ PE"}#hQ-l;D逑>@Pq4i6VS{}k%$-B݄lTmVA#@#PXxz#Vh6*;#h%$'E_$]wZFMqk6潯{YPE$^ MБ R q}J@Ӏg7`wQW'Bq}1RDm0MP CT7>.>m/F^!MUv+UOh +L]J7B4*OHsZp~;%~ `&'*SC*(RF&m {J:$[OܬM#Qe'QHÀ4tcMJm̈́ Vm?a'BJn5ڔ@gsmx9u"M-IFF~H**) )'Ql`'* bՏ$JRc;\4G"Y9 Nۨ`ɷˏNw'PY{,QU.x_)Sw 'jI0H%}Ʈ` N9̪w{%LmL4Fh(J X[ŏ2}v*b:Ģk0MzԜeg1%R`/i,cUj$r{ZA7R%I9 kjUM`ga% Ґ E&=cD 9dO?~G!7OS-(YXtia܍"}Ba!n% #h>殺Vs sS:{? Gˆյ||uX52e>(@ؒl?(/ɜߺoG~-jA )V!*em[@&na&+k>Rp~(|ܑ ^}GIkopM;9ls)݁sdS7$+ៗ9?[7-RSp5F&˧(eȱr+en;iHMA/&ft4;40cx"Lb9 /0tKK62PLYčϯLK:ˌGVna5,1VetΊQ"RlN\ߴiĶ Z);c`yH6aW+nVϭҜocb[*4ԫhQʶ( \:M<@SofaHI }h~!:J,/PTY=g+5*燦bj)PnVx)}3-$j[#5k,].*USRstT>U6Muk0/UarYqjR+gʨ*6nR/>ʷ Nd''UWYpTJPm10aBA&)Nޗ0BnW۱!OTI mL -b|)o uaa$R< "Z)*aĠJ@O+2+.HMlAVc78ƄĭB),I^[SeEEliZH nX![mh?N/*/IJ5I)Iz7^ {iBN4ǓՂ.m+_~/ɍ${4F7Z2ذƀsZ Ů۞#F(I}#z$6)J$eWǴ`JȺAx#`EVk@Ê!@*Ҥw O zC.]G5( a) r gFzaHPA1upGWh\PYV*{Q3.V LsBdBl[`s3?N?J ۾u_Ow&;n! 0`aH P@}@z%, 6S+d$GnЫUJI"FWb}lYK7.eRwz=#&>zDoVt5Q!N'gJ6d~d}?M9#DeZṾ J -͇=KNCo .7F8xK`XHn0J$&٠%JK%11)zZ[M6-{^th('n`!"EVIW}>t@l*ޤC7|{xSnSY5IUcaݵ,hNy ZO0A[%×E7Rݓ@(&QlMFRdb>TTɱK/ilACHOP )җO! ˣO5+A%wH[lJ\ye e$ rR&iZ:lMՕ/7tGS#:p "RTLG?4hQ(HU4-&΍cjfVt;[xL\)Jamu*vkRZ JIyiVSMil+1Lęeg?gsSUm/BPR=G G‡qٗ%jٗ[nw+Q&'f\Km @XwֺsgLy$OWIg RfDϥS4l :wjIzFo-6y7!AuΰM?S3Tt*^.O> a"ӿ9w][@QMWg2\iiI$57n̢Ne xPk[n /W`k/8̮YSO 'ݡBoR[!*]{$,ЛʬR$JU͊\ EMI&`lrreZCFY;inIXj S#& stgi%D$H x+٦]-ؘ YDIƠM:g|B駧̯%j~d]7*!Dnm + 7Jn,]o-c3X>zMRUm)vP$Cjb u$^# ʚz7ʙYJc)%7Cm!hyt֭%$TT(SI1,fdRW<JQ G Baku`ҁ}9 'YjД$,77y Rn1US9=m}BM–P[<)5)9aL(vRvMI7rkb?RgY"R@Kj]JJC$sba'Rͯ[53Gw*jlQrTzjȖYhYsJ +i$s^m Cw,xnTt﷘n'(M*aOLVʊ)yRhu)qVT[K1`sWKp%{p@Jyx_ k-> fRFdiT"XC-0eo&v`p!* ekJ6JțrCH$ThH;p4%2p@{hZm9khR[a+Vkֈh~-0JT%m r6ܰo J *l~NK.URC*&I)C* X֤3oK!Fba VвĕBmІ+Ӌ:ҽQ%IJ6nrQ21X,%Y%%}դ_|^ ~s71f.aEQkxux^9e(xYZHkߴK}6u+¥s}Ef0:gOԥJ!ʥ_ i)iHSBt(3JQ IfNN-*̺JOƤZ&~^]W Vv"YI*K-d65 j C[4UBIC$؁6|3rci%Sw.EG0HwRNJ6R"Ñ l))"_G3⎪IoInOޛj:>{?Dy-&0MEo8AEDH(V-6МNDRCs8P6P5qrz^>aJv\^ƫ3ڎ>'OԵURmgN|HaS}n$ʂNM?|)$֧6@h'cp= u٣i2> )6,`>DԚ<6i{Z- RzG<>Fׇ=& OjM=7y4j.ձyg&NroYZØ~07IRʹ6RamPCKKJJ )@@mȂg(^&eitRfXޣFHLSjzUo09BJT0֙K,XL@aZtmYXzScO_ޘ e}qA!6CgӏÝkiɸ)AiVIӸLK+Vt, XXG\ KIǕ }Mop~!HF%EIBZ_fUiTuSjIV}ʘƔ5-x.JLL-Ս$n'OhGO*H[nDX͊o:W~V̻.V-A  (N6[:q}2jCt~$b])Q*P M$m}aIFɓI#)i t}Sv_UrnIy&젩|oEH]5a{ 8) HUXiIZmd.6wҭ@=6f]fYWRjԳ9J"!*,uoBFН[6δa ‡-<*ˣėͧ!qID6j JlRFxn~yUi˳Kp\ԻQQ7*JBd$,d6:f6# jgbI[˕ žP[6`ߔOʥ^FP7m틊H vzXJ6RlMABl7mG &kĽV+G &͌/p2~^NLC`h@ M 0^oH*e0KV \799*C3z{D, WPe9Q&d2el9h~]E$ۈ< H2@J=? *m k x7h⩼u8rXZU=T>]y% *Q)JGFM?\lDbe|lD+~HSA8* %ģKm_I=Ɏt: A[J@pa/A̭T ')"qMH!A^ G"2`.-\ȳA_u3_st70Y2 Rxs># eo*07JaI1,z/2S/Pr\L)ԏE7÷#WJA%RUTeO !e`jEũP.e#iɿL>r]"o2&5^cJߝx()kZRI$nLq$C`Ds̢odl0bMA6H*MFhw6o~2VφŠe-_`C]8eͶz–R#N4T{ -o1#ȟG_S;^U ʊ>˫LJcLjOaC+؝t.h,+TڴR'_YF>`˩/P"޷UKtwrn[Y ^*YhJ~Aqr/IRefg|rG_qoxVHOZBMH.HhRFedf2p,O-.̳R{ |yx1e5jid&Ysnw<j*@X&,fJ3(Ae'OaoN"3i!*db2FJU 5(C J4l| v[j 7lxd < BNaϼfңTƗFTt(w"XQcu-bۼeIOMzV* ui?Gtmk$xp!%HIJl C CwUG gJBKS =H\2R`dU.$1/Dd9,؛_G:1 SQkc͡E)|I6z;HH`L* iy $6Ŕ2)Lܟ).LP@ N#x\Ê\$w1.Aab -*;{@D@%c[cw 8v)Tq"h5|3XI{ \$@`'6K)8S#HbgO"'xDxijjx!0hZU.h JK(\Eꛪ%f UɟL}WvFuJP)Njdn6M1i'Fѱ1RYBm+ȧGv# ՖM} yUҐ(&-mhAMlE !O.P5`!ӬmȀR0U ˖D qKWom7;>T QU;XetYHI(ml i{rO\'r)6w2J!‛Z0a*0P2UPpx ~U Fmq݈"Jp"ަjլ ԣb-plO+Esx%#C܈Uq`$؝.?oO W׆f ANJ<܂,(T-GD۵Ѧ)_\|cKzuLkr씕Kw}<˧>%y TNVU'r@QpnG3=3fSc5BMpG'%9SARTʯ}?;Ռ].4 )Zp=V c,ΚiŀFaq!M-KOoEӌ/XY ߛGWΦL%.po\i.jJ19w&ŎҤ{@2R<$ţiKj{\ ܃̈́`ls*[pJM PSw V{o,įێ`+$lܝw1+umX+eD XE$@@HI>6tq's_XJNn#)%)jAP%'cZxaTX mDخMגTB}= :Fq k|6okkA+X[nE.^n qEG==@Z{7iiUx=,Zl.mŠ6~W7H(iI)I؋n,{ !ĔZ/̄*񄗰A %%EC؎-jETnҴhM|h&J<@VK ܎m )i&ю2]G%h]Ci)*m(:h*0Zqk%)EnHmQ8|)@ #}@ YA aDNp[9H:.7$M:.} Ͷ%MBMI$}lI t+,6ljhf-␯$OR=8d].anf'm! p}kRyj.-܈-ԅ߂!-P&ؒN|? ";8ʶ?Ox L䛍Y|7Squ{O*8Z߬% +XRM֫l, ?-ʬkn)ꑒ_zY-ku&bJQ$3ͪNOSQɚP;`8(|5qJI0]¸ZpXdnڅy)֔l34 fVU X^$2'Ld8ܧЎ&Rs&nY9JVBi1Tj3A2Ҵ4$\}GRhǼu>߈ o AZCXmBF) A~{mJI76_`ͨ%VuX'PW)ra>@hK;nNJO fۍi|@#Ѐc&>\G ,J2JI}i?q@ؙ*?r7~JSg#_8j.ڍekܞ1r[έħ2}$lweChuKVnǍ}s\m6|S&yL4G}SxMIB>o|6Ԝ!8!"MHK|Π}(ht.~t~Ys!,]vs6{)fƖu@M.d_vILxrqkFT-F#mDoxkC!#[Ϩ%+Yk'C 5V#_f`Q$iy:NRoĒp)nMHAp0C&P')2:'YF?VlʡJe]SMl,|8r}]h3,(zf,I0G@uHH{_'4*+(3 Q_ao?+697( 8R-*8\)ץjmi5ҔujEJ̵a)'ig|!RbIR~2Tw ]un2I,+o6 yJ-i\*7ir;![9V^!z]]F)Fu7{씎OZMiUiL6vvH߼Jm1l ?-8tzXMT$BBe.m/ [N2OE1N2_aroUF^Aه5ó Ҥ*9Yc,zHB9,M,x1_g8,UVVOjԣ^LHgHR`#<¶#Y'2WF_bylL",MȚR/*mo!Z\P6⟉TBN1ئv]a\N[y.80ێ6- ~ی>*zb0~J\7W5J(S^m26K!JB4q)]⾝3G(_Eo& 5VVl`:Io/!D!*HZ׽U$$-woIE%5:Osj#?9_QS-ZHy4A6@C$'7'^GN0JofrޅDp̶ִ鱷p TSRpx%(?]6*9ܧI Kiv"MBVs7ܾ,6Ғ]UeI׽s WLZ]d(!~h-(,\!P\U)9 'sD#rhA*..?# `MI \@!RUt`f;5+8%qt75;.i< v7(-bMkZMT>J#s )č ۿ'3dʑT&b~]ФC졸}s3TqJWkŸmig.~r~H0edpBERVI$Ê[ggaE<\0mn]1T ܬ,GDSxq3?$R8RޣÄl==X39hTJ}Fm"hapiH"װ63 `oxhS/f$ξ!iI?]0 ?&L*E&6߃m!i.Vge? 6U>x~`:ggU.LL+[RW^{yu-F;eT;D0P`== c4_\[hyL!_B{TxyfQO /@gHTT\CLթR qj禊I}T@uno1g)uoO3KXWg9(H#mB^J=mmBKդ{WL-^Vd)c5J?vЍRR,߈STJզȼ”Kn7>[﹎VY}[I6ݜɛȡ/puխTIT|g?`|qI%MjJv0Z2"a`!v[_qǬy̙W1$UrWpy[OO?qc9." 9{Cb^eNWƕ8+.(%7p? J-j,#ku#ڲIʲ}$q Ӧ ֜&qmKY C`$=-类hx"r ϕ}iB*edնuwǦ /Z/ aL㚂sNC_$@|nttWz|GYd5kd^'ɱVM)ɩbgKIxK!mhXO6Po\5,Dp|L8ڪ*(rEyK3iaCNdxF0Ye&Ǵ~˼ES^RQԉvJ ؖ|΃z9jxVAXW4 $lUFsJ\a3hzZĺ]]\Pu@jbbn$}lb|f36qW3od>EIN2Sҧ)I7$[E-Ÿ xwFnQLU[O)R$C\BҢThcrʷ}L )(Fi7*90eT%uG$fkM}ɿܕ9H[:,Ӳd"fqeY& )&rO, jnmS*pƟ KXme38p+JX~D=WͲGwm$mE6yH, jD#>exAgpvUW%QZ?-.J-pstPGs6`ʎ\*rU;4ejx&j.vR?X̳,إkD.3?$8Zyø7Hw%-C2SMbm:A)78+,^GmCHXi%c͗~]E lڮ¬߸{0)Օ *l7p[XzWQشxWtuOdmr}btQ]>~3*i,Il}in֪Y[ri A &.l3Hv历(tYiT%D}*۶;"Q JoOk(KLvQnZO5ʤi︽&v>VSB0~rV ;'~lHZ$1fe3 q8lorQ_$ n4qxLSlw9m>Sj*>_)c@HY)EFSޕt%+,̴+Je ؤpA) 6vO5IuU6όa5AW?oǽ9P-R8/'hL0tRd@.Eno@*n6Ɲ`pxwdY22Bkz˞#w{~iD9[c霩ͩVŴ{'t\wIY9p|{,U^R"E2r2U%<I'Hn8wEC6N՘d+u]5(O)~qCka#>JsEl$HE&h8 J^O3]`am`ؘ$9 ܘh*_ H+l$|WRs'bꎯM?-9<_A mCh!6:w 0q d$72ʮn%isjC% fe'q,Fy [*۽j)XB[`K'SԘLĄH}R{GӼxjh +喝GgIR|Ш LZì6yJVk|c(ʥ~Y}7-3&ڕ1* {X\ǏR_e,/s&;Z[.KXM]\1_o)%/}I2ؑ,wǶ>*]]2R-`!pDtjѢAW$k}ʈ?HMȼ׺Zפ߼yO,=qg_Ok-qIywP8Ck%InJNed#Bm.A J@ `j}S7,;405+H%˅nnnI- PBՠ\zB4 n^`MOd_]7kՍ-e#ARn5.ߔ\<[4yeG?!UNX4rUN\_$Yd3̳4[i$7/$-7Oi,\̡66^T’SL"np:LZ$hޒl snL&B2dd阇 QQOKy3*ixP#qc%MAL'+]7\~s7*uznio~ *m@lvPI.=yz:/uJau"if*m|{`ߛ@ԓp6In4>:W.XzRuz+6X4ZlV%$${_s' Iev V vB2<ݺo()PkDEuY 3]۬1.=De.-jMӋ[JlQ@TSӆ{P[KS61TINclW]ҲRR-2RABZA*%@ncχɚY#FG\'0Ko2-{,W/1DbGvNyPK@cjXvФg_Qx5(2^B$PC+uEG7GR\%#npMrɤvOU-`Ֆw& }oGSh@BS$,U&+-:[TjzZyZYM삄7qqzIKV]mZUL*(%*,/PhTwAP rOLzk*B|GR, 6ha>$ܞwk$@\TˊiB9b"›4IcR7cBED'}B,t5dyqS jqi/2QU>{tz\yԕI-`54A5N!Ym{XrE^qyp㥏om٫|jm~#a8Y+) !$Iu#r~.>I54R>!9e6eˡ8Ξ DG[С+Uķ6b܏$zq;̾ F`TZ{O ْ|fS $Ҙ@ 6RmbcU Q>*PO_lgRkR@?<ʑe$=?xsٷQYi!%JIX>nюf&k JnHf|Q̆:)PK^#@U[;A? w,بKIjT39Uh-iIi, RY)MƔkf&^6me2}u6iRLM>WPNv}:!I\c v{Si=(A1gtXu6~bR^Q2h ,ܛܛ7澊oz#EnlanߩޡJJfi:N56uN^D5Y'kÆ[ᷞ2fBHzC2(Ӫ u>HLג 8R RG""׺.WDza*ޔr#s C !A'ܜp1Sg KSj-=-954q | JGR_-i,Ę oMbJȕKRFvmj`iNxHQ-{^&֐,S)<@)?&urڻLzZM!E+IDRY*$)-Kl\)b%G}. Skh93S_QCCH܍}md@ =zwô,mT3na wRv$b( ըu15`YI@#{-զujR`x.hiJM!VajZsM]Sk R AJA6WҜ0j[X70G–2Õ;_b1l_%YĬoo[$-՝;]+gјI$܂O ||]:YG֎/s;{6 HI򥁬{}~1- :&^|_, qͽܭ*YJh#9/s,>QUFpW˥jcJu$9Oc`NessͿ2TJQ`/`)'GK/c5ȾFp>o4ޟM=TL`ʒ7c&8V Ye QtNkVa`tRJR}HoEeM5ߣcc?WD-ui% 5na\:㔹g0vZ[KҎ%HVָwGz~oXTr"Zeߨd'TwQJ4D,-X Ǹk-U"$b-Cu%.2ΔPn$N V I3/?CyA(&YaRtjK~ckv4 fV VRvNePRʥIP<-yUaܖa%U_nDQ|'õz>[)J^EM)ݖfqBoČyBDղy$Q>DY6=&,}+RH;i`UccWNj%!HFmnMhF~ZQ4}#ܤϐu_\7?W+-NMP%R%PҾݜ(%#roaQ :tJ{0jkTJrnIɷYF*ad7m!rQ픱hcH[)$OG8VRkē_%?TO.eoLXHQ7ʟ,ѓtq%YJ-3Ժ#@>8Azm89idGNH*TW)sHla(s,G^eH?g"k,~\Ț%B5 mX0!}e<Tƕ$>,՝eR }BqqAZq ieKoTze ֒ $0Š[SSHI߁J20%Cs!$Ό+%*uuꔥ"NFHI$(SГP}Sf%<$o,eKʭ0 *p~tO I[P&0-POZP+4斐np-+Y"bI ^k.k0q"n[Y~n^^e+JJMk֋/I/!X eJ\{2)ȿgTLQ&$+y%" GћȽSɲH=S;HU=jUqX9cx|TK+#L4E)%Ir>GiB킈![Z!HMZ 5Zb hj(I6PE.}TUr%7/5jӧn}aK8U1Ks 6+hKԠ-cq$T[aizE6ku&ŵAW`7p#aHZ6 >O9ޗ \#0'f6kbxI̒8i$U(4mG#MH9):A!F*=4ˤ%n;QfY9%J"*'A2"B 7X\ |@<ŖCYa1IQ}yY -IyIӥ6Nk漈V$hN[O⪌3<5 [O$[ T;S[@]F9 z'.6f0YxoHpʥv(L!-BdN.-m"t{Ǹ-)ӊ:r }[H)'TTk,M%N:>QR@lXMEijbJ\SQsp l 71*2ZcUJC175aق ʌN9kLq1ğYq#o>mqv5ݢZKضVVMJs~!-NT ^ Y|Ki8U^CiIJ?Hآ-px,9h =m'I\t'Ӭ<9;+s(aG|L}7[c+{D~tCӤ$c"qTSK7ra hX֝#B "oq6t<xVt>0XQI|^4GܵPm+Iq&[Dsc 2I㖲sR烫UeG>e;e^˺:qOعǔ{$_҂`}|nf2ԯ R!o~ۀ>ˠeRVC;$6rqm%x qenn?< mdZ{D.[S'ٽvgb;neXW"Y k N4)ӦK߅[0?~͓#=t82YҮi58|&XJHax{i؋:$iSAJK).,:qG]Db)"ښJUkn֫3bnd8v<~-߹B)K;/dMwQ,4l i}iK >krAЂqk=a?ќ'jbv]WaԨy|JfJ<8es?+1 %o0Gn)[6YOwɸJtt,6IMԧ7ߋiil)IŶ縅M ȤDpr^Ty2۵w-eW?G^%`ZNejZRa6bW5/Nϼ̹O Eϋ?\=:&r4dRs &"^q婷S%V'mY_~+*5=3Y8ObE-+-Wjvm LPi6Iq7oԘ̊4>"a.-A~ u,jګymT*Էu)ASm&ED[Qɜf905ZhI N4okOxo&*$J┛D$Bi0z;HMED I)aPTƉ'fp jFe"%W( ?m&Y)em?iܓ|~$#sEMIl/TnV66;$2tqm  80%^c_ _6XQ1,j&%)P `F~ߘ4ҕ}*# h2W,X- 11;. PYd |c9sXR-Hh̜:4S)*QKU Yg`%+Kb{߿L۱qweLŌcLsjnjM$ nJ&ަ>(Du/d rJMn]" dTNA[UIBP,Rwc ( ΑK$N8ʝ:y)R_h!*פ ǨKniM ] ObUH=&ef ¬`Huچ,SXe>wHރG$Mԫ>1KN: 9J BƑk}8KhH`=IDmN ( )-!v $-w&(Q@Sl{mP+Wv A!Y+]e)T\{4UT,}|q->2UuHe[\)]vq~' !,#^I6TN|:Bjve vu\ΠbT wm8*ą*ĶiPߌGH$w*Gr5Y󅂐w"bʾs5 b)Fb51-%+՟R48P aR ˓f-L}]dvQe# 1 ʫU%8+Z䠂49<;ݛA+`o|?IzuOKg ᪥q-jl5dP*![1p(WRf1.ҙt4Q'E!}aNTzmx b|gi#VOCy2(O-)Jmk_Px;w74DvwKŹ(Jx`y7/SQy}f%ZD mOqaBZqv!%&P(ˤ[Zfq,#2t˾ I@JeavׇK葖~R[TO;S+:ڢM BR)\e'MebBjӴ*R($TuU*IQaKCm:<ŗ̍\uiC:$:E5j jRnΡ2 2VIf`umN~(ڥ0!E X)S5* GTUR-#uӷP*q%U቗14)O7X[3amkS@bHx߫3/VQ|Spbót&S\<! YP:AWHJK_Q 3жgLNsc R-陼k*ڥq%JBt.ּC< n]S6{ t:rMҔP3t5&NxNj esKI:!Ьҫ!nvaㄺ؛51PlO9)+*,2&rY\H֓mb>Q~LTZ8jbkiSObCI:JJIښC$!n$oXiFٿgKlf\MK>H8iS ,eUh_NC39|*1.~s⿏)zw!|5|0Fa>²CK*ΦzaˬaҤpmGU8fR̜e1ˠ)@%T()%Fû2>+W,p:-#dS&dR6qױ'$(ɼ]Lz~7R1 Jb4HVkhuAfФIQB[kJ5έ3SfE阘[]l>Á#2H@ roɄ( zZ7jUS,%7 nYiV7PAom'msВ@n( P"/Rn}A Y#VǵUA 6Wh)"{J@ &ܝ 3wJR cd~Z1e~6~hm4Z@SzV &p׬| ]Bz:uI N?mz1 /ASe+~'Rɲ<>Rm=4. 7 1@oL',;e1ΡW6qA$1ʟ؅H uD||GJVNߌ>- iFo t7C>$jlTN*=)LjLLQVS‡JPpvi`'t,F^NrCclGxV#T]-eyɇB\m%ũ% B~btŪ<KJ74~ʈ9._|7)XtSc]Ҷ02rRJõ^U?.m_PbUZk|ؤ3<>;KD u1Q)wj4SKq+q& e+ V^YcgnSi> q IItAVz\xdc1l<1W;k_0OӊTJTBgB뤼o2]5e ה~|zUuɇCs.} @a@ڶ~K*{<}m#iio# b)&K8 XIXreXFncjxbBIxCv$6ʀA,@K/:V-R g$i&HR?[bARejG-JXn x'C LQn\nIՒ+ ?&NiWMr=KcZknxGFieNat#˧ئcTh:ŲOm:*CP ([@F[(5G19X S>/QystxcRVޔcx2d Ke oy= I锡|,!V;>KE<Ľ:b<ōShtjH.:(- ZHS2lM\`R[dj"nR=V@( ^JM9PUTD cЈpSK ~8,>`<i ,7 9 Wf1'e(șTXɥ!GQdONA[^lB$\K}<D̒C^/J N3S\CVg<7*7* ޗmJF 7RwAp#EM$Cʹ RG4A"U%Ǥͯ1=ŅߔzH:!5zSfFq>fV( |[)&y ghXq7JUma{|/:2J9Ù}? `1gTkȷ6/MKB+zak(֌8\)w Tg”, `K=X UrV(ކdj)YqĪZdxe`9)<2dB#@k)h(B5UYRMCL6TSb~e#|$ފYaVQՌ>ۓ֝UúR~^bQ/pyĪ RnHRX Z|r}-;-):2OUtKDrw}Xq VSZu)qV$\qBquПSboΣņޕ7VTaA#Jg;:vtYP. "\^|[&V$-2hbyga.i*0u3$oQ7ծxO a*LM;/4nMgֲE$$H0jNQ&(Jhxe ~7(Mل6™m|&.85kɱH*JQTے<[sf]#FGH*zq.0Z T8eC>sN8 ڷ Qţl{NM'7Omүh+Veˌ$,N6 ϡáVÏ:CmQf;Qm ha 8y]3?i=&b:rFWuSZ^n]ZP;[I( o51IW&QEв;kX1M4XNBr<=%xZX/Qi*n#yb_Rˉ!ZRvmŲyE=2Z4j =$0wW#;+1i % kȅޤ ܾGf 0?ɷ%Ç^I$Cz8Rta~z`Sv 1擃:8;a\mH3d) R~AM˥픤;*PSs%(@wx{9:EW7(UNacHFi Dt,*Jaca̋O^$K8;@jy.IOX2YPސ* oS@ɢijLװ^[ HWcX^fNADrm)Y)(xA z/MTu_)9y&pi%M$i$Gdea$7eZ^4(3oO֬=QdPaN1 hUF?vrjYkK|"ӥaJU~ayJ{)R6䳮)\J{(x`* j~c@~ K*0mf\̼Iӗ%mb)LGBM,u]'#JlXlQvT^)A0RjGTAu`h''&Rmi%&~mx];q-T Z!Jq!'sCh4|\720_EJciS-OɩL2:m*ZT-\ FOfqϞ c'jf(RyR_l]RkZn(3تi.7gks-c Ԓ(Ml3jXb)l6a+9LJ!ب\"*ucyPyU` obb}[D=2:J^c #ViO6Qu-%OplRvS ɴ5 +JS+P"6V!dЇe)fЯo AGO8m\֎oM%{bݚ}ofV+Ȝ:p]S*RbrUy~nyɲ(.+v9 t$F4R N}˟)JձSȻOxŞ/nÍ?E5Zn46(Y&,{W{NZ`iSEbI+Rr,*zZoPe%h[gܓC_TrJn v r!VVvVtmK̤gjsWeRTg+KuH'T[YzQ66TH$,Wv)VV߹'aG+ɗ%C&/^v&2/),dfi}6tok*ʽ0~j|CqQ<LU2u]Q#"ye-:REn1mibv*Rr_lw1O,(V*UbY II؋BU&Fffs r/ :M3Քi|(cj)V=O(s wH G[oyo! N:)Y)y#2To`4I8XMf(OΥD%!O=!&6btsnefHpSI) $vo;Jx(n_Jzʶ Oh K"Fΐĉh6*)ā<dfEh77ôHR=2[&j9-ak%3< qƖ|YOm%{Dё9߅"qOW5^,9#/0q3ju:Q)sVBԤ.6cÕFNU֛E.a$%&ˀ/Y(r 6Nxh Q>(kA`<|w ay((/Z_jjr˚R%ԡĶuiO1.s!Kզړscnv+ po0Ó4%5K7*KJUr̿:%P\Y mTvB!'p;eGTfe$ة0+i.$m5 \ 8ݥhV"\8*j\rSJ˵Rug&?e!eԳiC )gpˉΪW M}.Ki:k"uM;Rq25[1()Jó3I12]0j4$/qaq 믧JN$<Yʨt%~^72ٰN%J̏EG#|o8ʍ#fi1XDTj&Ud-γ(q)ʼ:."*}:\J$ [ mX U[5:g֨uJy!/QmM: *V7Dz =wÚr!o`AXڛpKVLISSᴩ\ (T$fG9גgФUMQٙ >I<]0L;=Bw]ST>'^et<4RܳjB]Hu,/ &|ٱ΢?QMY\ uYDvPfn"쌲߆{8FJ*n/ki/MYƹaTLˉIFMB*J$ hY]vId;Pg@.cå:/|Ե 8$D!|a|?*hKQ+X Pb(Ri BlU%5e8*!ަ4c:N آWvLQSxs(*J](yT#cy)>KG&M% FRLvylIPc> ],['*L+MJT+ĜYCI+XNQ6BJy2]FQ{c,Zf! 70V—MTHz#,gbFvt2=Z(F#y%{ UDܜea%HQIIz=-xkJ:;Ѻm zi_5M[LWV҉d:Ci;(zx!ԴV6)+Q' PiMއk%FN o0':DmIC"yN]JVp5qH92rI%Eji+(m( .W0ˍ^^5<Ÿ,r4is HyLKZ؋+*r5Z Ū! F\Gok:֡s ٤Q%0cLv=4R .YEŝyә 뒞i*#/k6暴 \!?78W`oȼ*5Ы8)Y5J1YM;1̽/SfeԴ0dl (XMMI#i7=ǤIRPf=;/1[U*VZt9fqߔbJaO dAËDhj#U-3uH9uu'9?Ufi!&ikZIJzܐgi*tgȖj$,)m BT)QO*y;6(12S.R0rX\ҧ%Ң 4Uszμw]L2uChvZX6@< #z5?.<>X!hA%ԵpnH'>QfS{D=#b<3y^etb˒s i!V7[m=4A>izH- &|Ub!֗.a&icI h#ǃ.n9]*O"b r[B~v]6 H669d ٟSVqZSrSUn]R% )%#79Jm#ttQGNnoȍ?b)0m? VzihK撂d] 4qs9JfNKeR/<Ӊօ%IP(}"FQLcLQ$32Τ?q4}\'N5V >˛X˷jimmH{-H#[wq8*bb94f*iRl=Q>K.*;& 8vIV œ% .%BKwUo]'Jin%džviĩ:=-kl<waӈ%ևT‰4eCl,\9'LbDéz}Éea P%KU5MlSBX,?t` 59[?pv!q*w uI <-;+>34nm6vE7XRR,b(OV|pL*iMSOMygePԶ cqJOxp"0Z8#$Q^և6Q<úD;IIRA>c}"Y !;öRaDȿKM8*ȹ=vUnO+ɫ@؛zSS6W(4(B @۷"&*4R23 !68+PR^ŸW \F6Y Iv} #u(kBr8Գ5,(%(^ߙwU;(Ŋ?(Y'r5,%LUG`;kt9D\vfUd7o8BQsc_siuz\~GkC3U-H!I QJ|[tpK*3z!*EjGkۀXTO*KPt6^c]-JNK/& uhp:FbTQ^Vh'j˗ieUV !4CM6+CTyo^#ň ,P JD.ЦU--f屷76MH)`!(ԥ$rOegkuV=)2Hp̒3RMa!uaMdNTIoǓuYq: }?aMWR&$u_ohiXaJF%\}oT1 rSҙ/M/,vqaOH|N; ˌ3U8åA+MI=;TBu2 ⎔/- _MNڔn>'.lܹS*/ 5[R%>,$uzy*zQb)z&Ôr]:Jt{HjV]F@!.7?)ɿKFI:L5%1NvB*/m^AJX6)P; ňZC2IBCҠ87BHqIY6L3%,çJ.E6M䭤J~#MY#XqZOrt,[qv_lU=w+-fYc*II4  ۏ+P {hjkDj4W?u:E?4JEwsQ2Mm4'V7q_1؅n7 JG߼ sP%Mڎz7teb;|aԫWt;Š1sQM;4lt:wߝs(s%)&)1kVÎjQzm8Ѱ~9t,&KtRBC>d1ģߤu93b||d*m4n>H)UQ%5Y7Zm#qS6#cqz:9s#<[ oJHM?097p˪!$mHqJxk$ݚ(vU*Jn|鵿/ Bko4nw±\bv9eti]3 >&Z]M.!D v1< >vZ,2Ή'OeGW0$ԧkT!M-6 &诨<̌x>g-?W˸vij\,LH)Sͨ].W'4s)2sw%V@a2fQ_BEL #L|/wGY>ACd)xX#UfhVjT8KT~(⁈2$M3xUzܳf,LaԴ)JO$ m[:z[JcζvVL5B{A|\ ^}fw8(9po\͡nԝh\LM#D>eC*|؁}JO+RPC Do v:24cX1\YZ^naj- q)U%m\ K{[{9̦졯P?1XL\G@5|9]R˖JO9)%+H8ez\sAHe{oo͘f@4_0[Մ3FL`E+Q2؉ep착Jںbq.\,Y3rSIHqRT\<ԇA~E&LԩΒ~g p *( |mnN,IGAn)*hv/`e-f>[)ZJlSkЁ)SiaD&Cd&\ޱI0}&0R؆Az(l'A'~Eφp'-sS+ Y UJ2⒞Jn%0G ;:dj)ƔD}==1:+T;K'dez`˼o=Q R@IU'p%%.\RĜ ]A/_qeK?:_[X `9#z~z2f̷LfGN5 峊sTUqd cZuF > lERRUE$xi WigsRw0!c=LiVJJgV7"ͺ).gAiMNۏwH Imhl) H:`OoxzvߠK?qr{ޠ)!5:I$%dWx}&,Yte}3LIKScfN >,E]87JmVoH]SIUrɮ(VۣUf$RΥ ,lG De`'NFL[[n6Ejwm'"UIDYƒ 'ۘ5Je~rHVްRcεoZȸѶMQ) Zs+,RwHҔG5.~O#NNcR+B 6_p픧XEM$+>$Փ韚`$ظwN } ~U,i'IAT}'YN4?okm)cm ?\6'RDtImE'ٷH\j v΢ k # 202l4X? 55C$SF{ MGAP/FS\$ex5Tl8Y-( űm`L4]XMt_hU:vacKj$Qq GNl<_QM3P0=3*$,agjEJ%WiA[)EwYp$]@۰p`М!<"=ZaZHJ@H0e{v\IIC 7pJVgJeQP8*J !@lA>Le a`hkFeK`ZuZUwĶ#vͺP\m+ZT ް.`EŋVp'.J-@m(`Z~ʅ~*%${wiԩAP N8QIZeB p#lɔ:7p:m{,uZ5:fbHrQrSbIyFyiHNs41YGW&{JSJ)+K@b I4Oa,MIڱ Lmsp*(c||Pi*۱ bƹyi5霮uC~kR v`U G6eO~>IY9ebq.NeT($4,WZ8-1~Jl.B_ Ԛ^jg9fԻp ]F0 #.K[%)ڠgV!NYp%gJP@ulK%ԕ}0 T=ebԥ]ҴRR@#eX pxc)NDEAZoecRC$FԁͶJv151"eͪٚxKQ>س:t˅x]W;WM&QZLܳLYAEЧ:2tPɬGBR%j;"+I)rW[:.¹A>(9V*poThj~2mǞ.jنQd9e9JUL1j:ّ2&Hm RnI;HRsSc>0 aJIVD!hBqi$muZ+ʩw,T SԒ47?P Jsk{DiJ*-8UrGm ,B^WF3ٮ/٠3SDM%9&sݘo'GPJMV;m=pVJRC[Qoߊ>6BR/ĥ.jktgG7 0msxrz<Fvni9iYIU8<%)H%D`.cF&zpFj^]bBEo8M⒄*VbvLHJG6pj2E6s |6f4i*2B%V%d!.|[i_P  jjvfJV?*h>Gq켻g'u}!jP4Zp)@DGS3P)?kSdV!`P7oc$ Tr;שuAS>!FFoOvI)JIC{lO6Uc 2Eiu:m/ܓERћ|U. lEh{#ʀ5̐. c$ [#&2ͥ$)=?(vB-N)P1tN ;{g1ia'ŕ~ށ|+K~km$G i$)^-Tv.΢w~1/t:'M Ӱm4 %/5  M!uTG V7ein:6eYS :J;9yX q )A#dyԆ?ײRjSr*Fq)*SkJҤؔ$؎R!7LML.jbVkZTObI7&\34˥sunpȩM-@RNֽqJM>HJ{K:LhI|u}&30K5=E+}Uf5 +SiVHm,g60oS{ڲ%,Rh}Hˉ(aE5ɺZun xx6Hv'ފR>3¥ً( f)ɕ8ص[*ӧa[^lc7+jbJ*EaRTڥ]aA:AJ@$ z nCҿP~u6p Fw$q:O˺NPMJHNKHmdlk2AWW0$W%796A )hN AIw"y!į~kRԌr 촤}I$)G{vl/#S޽@( eGȓqhkAο2e93eO)D;w\]齆c$nQ@ 6>2M}&{9=+l눛A?ӑ;B77'v{XyV*7[Wç/$6c'qA8a⨨ ~Nyܣնt6# 4IIbA=˺ՉPW'tG+i2"F^7qC"ìcJKST-HZƓ.;4!?H*#2q(MRK-K6.? Ɗ^!p;mzhK3dL_vk΄y$*^&߇IJIfVhܗReG{QbV}<7$iaMn"HWZ{&$eJa`)*I$1WQyĶ&\Y>K̸\ABe,-611]89*- dG9N3(A]Gi[`q#GԢmhqk5bjs$OW-mkZ&CJDeB< j)3",_K)wX}o 3O%JA6 Y&NT,Ȉ5$5%IB7I1*儫dkaB&;E9nE lDJ7PTrvLԄ_e+*YRUnluLv} r:HqAW̩~H0ȬGie-?+&uSa7Q yX#O.9#&EO9k!iR8ğRq, S[v]RvXZ6$B/VIwB)2i:V7?iJ.%<Іt".+U2J머792IKh0R׬ZNʞJG ̳[ob(-eH&ڿI:a7q)Be^? >kQ󻀐X(g T }V 5D*Xq؍;=Ben.y7OL%F`mDf܊ĒTJ%n+SOd it0!v-tKͩW6d&pKe̷WJ8wU=&"qeě0f}фDTɬpk'K'pA7|u7)sa7[SKA.`ZZeE@{7e( lw,x@jSsNU+>rbEr^bX^#c*b}^zzCgDO;M.#\ˉZYU&Į ՌbfEBBФKZ[Eȼm5eHP5}$͌ZVd{\Ǥ8KΏt\ yjRs2̚V鲓Dx;4B.7ô1x eD?I*-غ#JSby|]zjjڗ)h4qB%.D,s@=6`OK؂;i>J@N̔8Qd{s{uloLP3J?em/TqKQx&熺XSiT0^XO /pL] q0e3į~X;qX`!2EkH4[—6<^ V[l>!=XaI>qmbrB^#n-(Oig[ eϥ|©TV-bȘmIJNrhx`YtK mKΗK翧fFUծiRs y. OcxX!Nse&tLl%*$mY P ??' vsG<9GP<7T(<ViDdjLVP8w0isG/:vdf ;n1iž49l&ܱDYɷd,|`4;6\Wh.V:ocFT !,SnP160Eq.cb1-%+bd%% LM4CJ(X}*a^$0<ƳsSi QB)MnIGфui>Q=ԫӟ!N"a Cm]q' 7)6GlY#t!Se"j*Z< ʉL_r,K,݊w\Ԫ&XSn Z !:7Ե(JG94!jqNh#em rmձ>G6he$JZR&B)?07R( R;êTLVi%pHM$[mM8F؛ $6&&qT&&D߀,Jֳt8@C -eG/scj{s@)v%ąڔG^|q5b*)BkG -niUibը۽eYIZmZ&'aOkeS8]hN41hy3ۤc,p7Q\e14vܤa7SsJoKבTYyeEϴZY6:V.kРA\rÑ]&(͠*cQ6jCamK;wO:KW0^y}0ˊIF&XSXДnۏg^dzaK*iҮ'iZA@EQQg߃Ӽ_Gc-QEmc: R}axg6>9V6r}JrTÖ71_Sf(I; ?"ղBH$Ǡ&% #e!i s]͗ C xJou*b)NL1 YmՄn^QH'=#s>T$R\*$!M!?e+.$Z+;pEi(N/YnI@PQUFIߗ&CJܭ?dN/<܋BJT,GqЦgZVĔ|FzˊL"炰!%%3/"rB0%eKn6mT7L<hjܩDw k6&3nMPԆ֗ii-% %!H^(Z&FnmF3RGpRɗomթl&}⧒s7(F;HzKA7'ܼ\YC1pUA2Zb\ʚK-` :|=#RH :WNßUޓ2rlR^W$O8^ Ku 3fbKb&)Υy9LK)'QKU kuyVŲؑO2n%KJ|%[\z`w%Nh+ҦW(T$ GnyadT;QJ ,M?jj3(+q:@Ԕ ۍ/ٯTu<_#Զf$ % "V}xs dy_ݑ)X"z;3UXzOqҞ klvrO0R] TQS ,]ĵB<ܓv]BФqP^vtgVإڦeLiipm6+bv&7Bz h3P@",:O6R*KN~8AN#'%& [a*%`pwHTJK祛m@'tB3MԧHҔjp鵀Q*)||7[^E:̫!% .hR*\\waN3`Vb.Ғؗ IT˓SBmJ Q7=)V1nٙ]KԒS@TGXOIvG>lvon6%}}u\IUhnvmjd6)@nuTy\tJ?6Ƹ<.8MSD7Х~8׳uˍ ݺ@Am{ ;s [CRHh_̗k)g[a=M}zTۇt >~TrZ Js*0cU#)@('I˪VXfFLyMÕ^uAn! iiRYi`W= ~yI5M^)af'0)Fò] ?#$aRB)gw\ynSH;)*՗gio:Ómiҕ kW'xPs OLw ba*C%nQiqջ},w#{ 00߆򍮕 Q)]j#djq7\kAÛ_[L'pl8eQZd_ĸ11d^RY̬!+DwJ*aJm7TVrR:,{S K[Ff!, Pڜ:D/Iӵ"GgT\yG qUW&ebbIB[B%D%T ga'L/) SIԐR ]-aD"kU-l'ܘÚx%p#&8dIY#6q<dzRs3)mK6R̻-!I&JRs2N58fq&JH -]F*4Ip<. {m6A=AD{ߣ]"f|:tM6)gq})IUX>U?GHi' e4*g| PI( H<][.GؖI!O8"*aGdsM0lũ6y{_>~(-Av >G˦ 3PL;<6a-A%Q](S˘JWb'gJsoPLFo:m#<ʲ0|׋Wϡ@h@W~+]Zr[[3N)ԵX-iw }tz}zE7'7"~#ɴ)/^kx4zk?վ(S44K'O"rr4ꥤ Z[ q ({kzKНe8δi:lc(1vXW2&gJi.fnS.)45(J@7Anz[ j[ -36rFt, zBE4&eֿzK! jy6߾ЧPuWl:JmB4:Uk9&Ꮝ92MfXmiղm(KJU w=S+SL*8OtH-EumՉLC 0%|ݸu+JJO}"%7:48./5t\{1Nl(@'s`G MA= gE'r=o-JKHһ(I=؃)q[T\&֚DbJң{BW+%80^DONLR6ӓSi'Ҵ G}BFy7ỵ8DjqÓJ-|ErO;50W0Qn(ܓxQFBqM. x:iYATlOXmRKJ8j^% ,vX1<4mmwrѱ>#xbޞ3QKUPqnN7dO}vf]+8VJyʼīSH-r["om-o^jYmZV2Uu)M4{ E) a65.BtӪ!e[M(Bq?@C.fԡ({E괥xxA(ӷސڄfw!*jkR(ҷOlO$L⺇Jlf擽(dIQ8ܥR8/TM[?fm ~#6+FIb8MnL`]Q?2;v|seWJ;0USJd[-d!D7 .Jk:x ] yʚJi@$&%dmojߔ"-7/ c1fRlЄAX,C XclØ?:*rA)*rAtbasckw!6̺~~Uّ6OѤWw6J54eӨo'tjm{RSdd"l3GGNaDEUS4PiJR AP,֏Ae>'-;U#4r.IMSZ S*33"fH'&2Nϖ/4hc bU貕'Uܕ,*rY+!T'AR@%76 mɡ0:a'IHߗI%Ifu8R P@0,IW(J3r5 ͯ`;<S1ʹ#9HF +cD_0d%d^'gitwFְ'qĹ:;',+ϫX-QaۈR|"P/,J5, bUW?W 2SJ޿}&$LoNBbZi(SSV%R *7R)=y8f&6l줴BcP"qp ڥ(%'ݕCÊuFq{A!.,%*| =bLL]b$Wn@ᵋ! %WRiѢ)ձ &#AqEIRAX}[Fdu+Rj-v3w;}NF͖*^gޢIH&XiV\cFT̽9J]2$nZZ}sK̀iI!WO6 9$0.=PU4{@TI6$`Lc&OC, رP sn23Tn?wA]BPSGrN5a*s?))ZJuXFש,;XS%0EYM"5CL"xC8iaD|x1%Q;ZK-GTM K7(Ku'Hr4 (vP¤tmEjvGSqDrIs P|,RA+_ m:V\H yAʓbJK1;*۸[%g)q4Cu(F=+7f6s{ KRR\y~P@}ynZ\i'S/(ڶMԥ(JRI=F.&f^ ?Ib/KpAPZEХ:ϓVf. SP E!2m![p~))!c1$BSpxoIդI qaorp16^R07JCNͲm+''90 . Ԓٱ LLόX!TDη*ҝC K0y])CH<7&t=<JNJzB,=6x!Q Q*$7=lqu&j*u=UAf6SYˋ{HI#ГS?Lf0YkR߫ 6n(zRSm'z2yK/a&ݪ6$!&,5k/:-ƫ &jJp.*rj'啦ߝX"sH?,/o#MRVu{VTI,!!Zjb6"zȜUfe^NL9&*- 4(+Y%-[$qePb5]!/8{5f2EyUUfMR6Jy(Ȋoc9h8s-ҫ8nm.0RmAФjOoQ"#5#F6+&,"(dXO2eV]һl7IB'i0;Tj&YSS!X#kͭ{6YYIeNRױ 9`OLR)>RTw&3OL:xeӰ s 3.ՈvǛo6FUBNR. ч(S$jHB}.0:V.z2e鍽f^.2 Aj$zSt_̧mVjY٧A$~QļTc&5qU5,>M|`dĽ=xHQM(Iok@3+'?'+hù|;2lYNV[t76XaKIklnvg9)N#a >j %v{ \_TLK)a)um4(% EtZ[uz!D$г<3sGyQ/ gWt;QMײҹEW*xkbixKauy$ܕe'WK(tt+wI< >)fen?֢]¡di:=:b^u>u~0/sX}>?Gq"`lMd -ݻzk:0|^k $aBMMѭ). VK=(n%p ;ѷxD^SJo[:I,5>!MBD]䨜2Q[K W􏔇37&lO1yt':I̩w##eHE6XQ3}x|E#8YqT=M./o"<x_snMS zFڐ/sTR[1UΟe^'ŕ%)ILU?xiyj R@e_?tRRvN1O&e֚n,m{[&Iz*~ѡ<2Hlt T9˺t!+Ma*&aH6N+:Qp[2{٥-S0ffQm3,Ē ʜQ 0'V\یmzOR-cbO"ZBncǘZJݡu@ oh%7BS(ɂT-SSQ*@ᶕ{ߕ CGVW:ʯ.Iee&uZP2,&Y|=̼E ?M1J&iTʊB5((\}&qRN>ɸ6Y]Y(.3IV]\6H6q,H$zFkdѪ3T}|:uY i meJ# ,w ŷHxer>,ʪEMs2G>bЗG* XI=?HcI6 Wq $~2WcRI_SԩiPA q~?{B ,S 0DPM߷ m+G-3h M ,_i_q D?tly6h:mKZnI* ˆ|$nC1oZ^S`?&.HmۘK) #:H!j珬u%*ڄ"&f^]u8 * ԒA@N'.ZH K!dT8QšUD>F:+`%ސy.tH8E"#&L58Zո67wDqԵ2;V\3*Co6G@mo_dj'\/+Fzh-̊((![AA84„\kq `w)N$FZI_AAH^9\/-vF3nةkyā@&*FUs% P?.mn. TT.nu]TH_gA/̾AH=5TofUkUPy3Vy)G/R\wRZ&?橯ԅ#>ΟEr2oT\&;\D֎ g ֨3"J8xA^x(h JRM# IAK8գښdN6CP1 aYM=dnVW eE+ UG6ZP=㩟{} rT *t$I2È E6 ؓq{oшJ_eRÊdQAGrR})#'h"WIRWd؊*|Vҙߜ2tia(Zo_RId  ueht93GL]yUs{Ce7_䨙}n]=R\é*}Ң;_x>HQNZmG /u$֖ة$XgG8t v04wEX8]IN)eWuO#\B!)Q 'bB"f 2.<@8ʵؽcfd(,=iCĤ]CkgJ*VаzkɦZ\Q=JCn\a7QqzWd˦b5jaCkX07eŘƷsbZj5 LM̼Q$~5,K4v#:]^Voj$TaíxO0lj4L}OcC4iLQf]+hi %`;r,E)ЄKm/6;=;c7lqTz+d*Գ>F~V%Wjm$OU4 &ԦFW򚮺Ka^4TP13hk*"[7F{4[Yɾ4D8J C*-}_T}J Xrq.Ig!ĕDp&GG?+*IjcǏ1mbisH؝O{H Ine,6,|҆}OVeM#d^Snv:H/xE7s0+Ym:;Yw]ų5'l1q_*(MINejU%e[8g&peԘmw%A'B/~jN(AwIeN@|A!D[INbE$GOo_4N:é**8zaXF"yyM%zSx lcͮu ^Rg0ИF%al:@U@:RŬ76BuGԪy;)n}.O6ܓüp;8ZZ]›redI $ YU^ND̼ ݔj*\M9jx~"\no2:Lԗ O# x2*Bq#O:44REMߔz8\_9R=k_ rF$oc}o0-KxJѻ&szNJHئFWJ:V!^QenwoUzV?# ScH( ՝C!2zP N $tmbwpE6vRfY!\I JҤX/ 3tjF JϘrW=Wg-CNʮ^|v]KYGdL+.QHUӲx#68/ ͯ~[;Xŗ’H̶k>*}WBl⮻XQ:V)]@byJjs"2W5 +%DA$(` efqt942|JuU /s™}Z]q5* 1;m7%ZG#[B {%6zDГNYK 9;10KL$*YbaBH{܁6DlwƫK:fMдȴzxfd0R=Y`:xa~0ĴF_aizuVeͭJ|WHߍ6 $mc3LOY[R$`Ɯ$)yG&W(O,8 髧p&cҥp j86k R\%,M|WZCKPaBE-kg^7&x#&?zch\*x+uԖ/_lA92O.yAHR.赬OmF9iO4dM}{tݕY&Y2J9KuT/SNNe)Cb[llFACUŇxsc<̜ģXRs3Vi!uj`\G^ r2vɗ"ㇺtĹA:'AFh5W\ 6"ڽŢ\ ɉ!z}R}&]P8ɰc}|*I/[OumVj*x~Ӗ&&_.8(lt{9'GIVb2Cy9޿g2J Zo1MʀƖ֓q`Gދ6Id-l=@XR񻓴Bϊ.} ,6RJRT 5 2j[71=$a3I~oZu)3i wIbQ;)q%x 5#GEӊ ZJD@' :/RYCaf{x:' Aа%ԬK5XT'uL6P]R eW a1>mSŕon;B}(`uAMwH(6VfkU<5^L.QCm \$Mϼ|sMo&hd1b&>Rea.mc"\!nBƕ#O#/QsCPweSMI qY#{m2)(oN9O\RVR#-IP$ HHQ7$6jԓsma2s;f%8W\W, x kChF.w=Rr6=cPf^(8I@*xjݣ5> / {#uɺMФYV$e,*ShS-x!:mIݷuW]#1Y8} Bӡ){ uz*b+yah8P?:–􅰴qԱͅ-W8 UT 2`F ΠYu6Ҕlokc5P6q)h;q6jQ*h?oAK{maqh;"q$wdc|i]b $MMKRm9QtcZK-EwhIV)[`mS@&0 ]Ta3j VMTӎԻlHqIjB; I*CˡGÔM03D R*XHfvI,ɼc1 -YU9(,+4V@u%Z1iLIyU.AP)~|8Ug]RXmZh]Zt4e/*|]~}1G{1r:iWӅJHR Z+!k 9tZʵ~.֩w-o) ys:Z&"=7MxT-A,nb[ѥ!VKbEnpR#<,*bb:iRP؞ ֠@h߱z9dTG_I2%VKXbPXJl?-R٩@Mm>P_*I+ZJdn!:0XHYM`Lh.%dPA6u`2?9'm_8r쨡T uRgiDidBiKWdiV~1SWD_tY(UM JOe#CK>Smq*lEn:kj_1.=fRl@CMPU.$m¤bA7-{@\409s uQ& {&JtLJU19qUpS|zNA _.@'puq.lPu{}2gUcOlˬah)e6i:Jy#םXL}aFiN*׼*0) iMտh8NZa|MLQ1+i՘nV0KHByF1q qʣdJl9L}@Xp.ZeT zXE-?+.*Ji&dq"RKSկࣦUڿϼa> P>F4ɂ)YM1ds00(kWoiHBTԣZYKm&Ģq6 ʆ8+βI ҢHqX!EJ{s{z:ŽD*4iE $~VDh2/_vh1t (Ru ;4߰ۇHv--]yi3ΰN!IIr uhJc}qr&6P*Uϧx9#INe+cӌù$o`SݔoL i !~()%˽qrVbURRC^ߌ\BNn`L jÌ6, `|/UPڝ2ҔNa `GC*골;2jݕ$]iҢE uKH-OX$mԥ !<ꊋ6""Uir槄)VXLWu >BKtzjHY+ėx~X𼝓}RIxʴn8=&Ii'R@n!=;gPu ,j,zn۠STJP\LuG#)&J5UË|~QS dL+) j&\@6TkO)>nk˜hIp:" I*m."paKRceCp:e{BHZ9n)T65^ƒN4nÎb`ߞB\UЮN 4&F&ۖxrc-*XeJJYU!7' Ne ҧ#Dc,a?(1ܨ .N}Xz {rAD%GgG'K;9BԷ^BP@x GQrwS),$X Iu+P_٘&b>#J_5wcFpㄠx&hꃺ@7M2~W;yLۀI!I/]ytRb 3 !D)%{_hw3>̼4)J&ʴ)QIy1)0UG'DԺ)>f`ӧ$HxS/cn>ɛ]r) -W&8>}wD-3%0u,ZII'H6rí2g\7Pϼ&jvEjuN(éSkJNh]c+h⻒kU=z—C2I<0BeV$5{-FJ9̪ Ꜫi2JKL֠trʵ1&ٟ2 /q+S0'$sn:ǭy|U!pE ZYr ؑwԬ )g4$ثmWfZB0ӹR_ǹs1)gӹC+7>HlP%V$)۱:$,hO-A 8GAJ<i\-ݧha:!^><~:)+RrJ@]9@ i@qiEȊif#B/b,7>gtd`LZp^#Ӑ0WfgZAqaWi6 139tQI;Y. 4푾>q)OYpM3'24i y%˩թKJT/ 9Ҕ}b9IaII 7lNTѓ-RJNJk߁pbR%O6$ͷqUO2*w*A 6mffCHҘCoiٷ['}"ggU2ꆤW+sfFJG=䟯ilb&3HZ)Év1#<x)4M0 F`jA d}7vT%|yRC )#/}ͱ.ùC/ql›ի+!E,ET<q0VSe6xWqv]9X )U e'TgUg ܟ8=h$Jbs+ewHP7 po+Ǩ]OSn̢<䦷Qr* m~GLEs(WTwZVII̷9*i7 D΍J :wԀ@ؘjTrxO,ܤ:=4\p+1bVƧuA|ʩg;5CX &Ğ Y; `nMAɗ.N]Rΐo=ha-J' WʶAX"}pKU>֋7{Z,}?f jeԻm&e4ҚX(X Tmϫ<TE$vJJm,BC l#SpE+BA²7DҮˬ̯<UEu!RaicSxP𒋒Enb2 4{nxzcrgVvA\ iU-,*GWUٗk߱.L͹x~K-?7>k$8),,m";mӫM"g253T|*JiՅ(ZըQ4Bg!MsnK}`6 -6. 2nf?<zKSQQ;vTzE['OTTc<{QMR!jmµl) .?V#ӤRS%%-SZZa$BS}6xnfxf~tTeysmxn@S^7qna]u_6Qp[A.=;ۓ4.<-;wszYl&2/gF*i;XnI`ʐa aE˓WPH LƝ jN1rNܓ,'ep|yaw"|!ӆ,wIүaTT ju_)uқG>-e2Do ,OЗ8KRE)ZۏG#鮆p+YO+}OQܗW&°Ja, 5F/߅~.PtG׆iXDJ[bo`{ަhudҧ&\fRq0~MݻXġ?Ӟ;UG0-1LqQT8u 9>WXfC9sbĴi:ajork4- ҒE"c&2,j}/; LӅ@!H- n8r#g*3HT0@o#xőyۈֶ$ &= p*mt(\&M]I@⽅}1~M43>2Q:hE Nڴ"UOͷ7sd~]1qJKl-‘e/kx} Nq)hL/u%+IB qo||Oi4n1lۈOpHQ1ǁRMe+Lq'n6|ogtdڊqhCP4VP*ߔN3km4f| +(KU9xԗ P)KǨ%m bbϞ1C0UcM8;bZ:Rʺ%]#KL.,ER;X[)4ЊiNJMP<xz:H6U,Xg]a×aRغO~-~Nr0󙉬CIyLAWq[F?RkښRu!N2*RRG~&,N]%F=b<$O)sY> ђ$&{k Nɸ+Øt!F'v6T oDVzQ_#hIKm7T CEʮ2JK(0huz*ÒiVhYlX: lo}ʿNUʚAOq&V} Lo)Aln\QT[#'H]a&RbLHS+ E7-6:\(ss‚շh9}+ϲʔLRJE-~!+s: ؅;}и"f]b,Ss(* s~#aznPR(V ywmD}/qhu0HJG7E{Y*m5$ uZzQ<\J[låP0KHU)hi.=.J%XFLf;N @ R20:x/xUPY !})}}WeSάT%g54:I/2AX9 C⚱5EkON(rm=ʞHoӦ'|z ,%ۋNjY*ār2f2:&nX>2%&IKshUR 7@孕]<4]OC;afY@=ߚJKfHimv1IG 3~X6݃ʵNyJ0elwI\u]Z&_^˟=i%צw SQIxZ!eе5e Q F?UgZOhM+8eJqm#}dV ƒnM{_RN:Qny߈59=1 ̿Y&fa+#{~{8gb6s!vP?5YҟU)NNS]smrv?h^ŭ C6rlη` OdToeU>9QqTMS.Dt%ZS@IVZăkOŕ(,WPgs:}*9h! @R^c*٧rT!2cV }A qᘯZB-4|wLxù]%KKaAR%3SN|@hC&)ƣh5u[=fNĩ*Ȍ[QЙVB. 6.޴tm'^r%IњH7R/gl"m kܗI!%jlح* ![DǓ921C'&]齯h̦#I* _NYXu Fh4 ߈| 7Pk0e'eP`(q$v46 @xSWњrm(zrb ARcXj).qқ.T XtG1Zuķ14-ouKOSOjl6qP\6LSuj䴠mNl{a5-t6lFv%"..bxb1-rfTX\BWcm~pdv *+*^U)7>3?ThjayT6hx$DhmJ,Z[ f.c!</0pJ`ߟA2,9vJݑqQe8ҏ9'*bB$ \#}lxi&L@.-%-ZXJgt뙕64ƦKAdfnmimUBAE%A{p:Xw.eejJH,&Tmn$:PH$Z|㨟ŒŶA{L y?2Ρ3?/՜%zbh*SnyٹoJ**aՁ^)/% ( d1z'?/M*2-٩R IR~5XQ/}VÑܖ- rM|ңIJD]JpaA!nZnIP;ZE?NNٍT3A9'p>%rIҪ=x>zIh*,THC!`EQVFem3ܱ1hy7^S*mSLUJ̺4pE'FcoW"-@sY$QMɶs@[JRT o.aW;y}$p鑜PdUZRQ6Ktu@ôԤ;KLəV,B-$n!z[.pmBեXUn! JJ|7|N*XRZc6fGU!NM2 %!iGtV9X'Ԕfl;eMQqfV ^\Ȯ$$˳HGb>~+d_q*.IN4 .:R? ,*솖0t˩_̉_Y byN]:ؖqĒ lADC]J!ݟ#,HNq(ee\IK#Z+y~:Ÿ]_Dc6ɹ*e*>)ϼV9qd<[a$})(:MȰ<^"> jkIJ\ f/aJ-'mlm4WynmoscTHga<_^G,nR}7{Ϙ8T(Ani6);o] . ;q&ΔTHRk셂7N${w uqŜ"DZ'G!@wSH uR*eS2445,K0.]RSXinsnNK+FMɹ"7@mI[RM /c:ִ2v }@(7ւ 6I*üF֝*S< RH'oxpksɭх G=t6[6 .$V5_a/2iX;(s5y늸ܗmd_oH-RumX$ɲrf9\𖫩] Y }6V&vkaD\Tcs jE* kfҖ%B$h(nJaY$} po{ԉ6(yN-XNJQrH(@ܤP`Fqh^3^>@LI!>cqɹ\{*+TEVb-+n~-0uBCt:We۞nX j@PRry*6Hm a= ;AS$aժᵅox֥Z-amn-hbKyuOv4ԅ37Ky,r}]Q֎0,̞A`|D >  3hdsΈS3fk7`m6DuQ{6ffh߰L-3)i_~/-+S+Gٰ6R᭱{Xm}=bLc+y7+NkҲ$]qġ@Q䈊 [a_x_zJgw[y5kҮUx!/qT{*#jυ0U"}JdIYci*m)l%"#@Z-Iʰ t! drnOp8;*H ;ہq*dXDb]+2m8ۈ JE Ay@GzFYOb\1JZpa?Ft IwR; %NG_2#}6BXw84KLBpҒHKJ%A'c1N4k7'fdfum[)RJTABE<\drǽ=OP+.A.JA)2Zn613c %;.GISk"*r6mH Q9٬%qؚ_} ԕ m@IpB` OBMҭe6w#wXV1ĥ‚]v15({} _6`,6d$ RP,ɂpE!Z@dly •T~09%lt} l ”ݣ[F&Ҭ߁C#w[e}`S~v6>6R=E` ronw !PT [ǛMPT7ן5LϧLkXbnRTØLrV7B+5lIbF K:_} )CBP%7밼(NRv6G*rY.@#{L{Aj!@p*,(II Q}#h ( \s@,Fl>$'Roh{HOIF/́M#KGJ}qkCTWHPUߘēOmA@ph DϤb.5*~p%.[O/X ,%'4YF烱!RA{ɽn/U4Aq&Xߎ*l;H t$Jbkl6;@5*"ݡ]4G (RM) V1cBtגx&) J5b7:`=v0R/p&ŏx1\;/X; q)Q$mm1QmP)]Wڹm:w,l!VUɿto=ɍn J)Ǥh>KZhJS-_,pI'ܘSm Rv$;[;[-I[Fw[h4ccNL ͸4ߵΆ3{WМz8ߚRTlը $;z x^9KLN3eK2'̵*"T D62~[:;ؚnY xl˶+IQVHV !)~9Rz{3.* 7ʉ&jXivChaEEH &˸Nm : S.|ۀ*_$F{z{ ncMTmo-q}GM;¨iHat"oU,UgW?:ˮ)H\ ܟd%& 2222̌ 󨮔"pf{弅vY 7bFSe'IDO.E =PŝieN3FZ@:.tEDy9:b/3+k/0;Ou*Ф_mf2fe52\,VE}lwn"'t|F2:jҏBfjlRԺҢ,v>:χP8/gIR]h'T{€}zu#y$Af]QVQ*}Ɨnm"wxԉĔ4mSF >ǴXΡ yt72]lI,mt] b{^+~%N|Agmc >Cm` Ҁ߬kBrk#eBv$U^Y/!+[){w-{ABJwt mW,PXU)HԤ70i֤v0%6.BVH=ZN$Ǵ$*t'q;BJw4"c}!F& @Mm+rA av$CJҐMxm`5*$EE-`MZ@تõ= 5Gar hZ@m$jVl,;@+6 uBH X@Z㱀)hRt۞`*~7[ V  Qq O"ƔӀzvOVҍ.Mƫs2l'c"Ā+r:VW?F00d +-<$w9T}d} ] @`_i:Ts3/X2V'J :&m28WT斥ZX{c1Cd'̹ɧŚJ]8[&,*Q oT-$  C8EQU-YO,t,8 IlT,HX|eLfjZ`%?Qy儥2_$"=Bf38ߪymna:$&Ӫubv\2$yǻ5:zRj$'(t&}izi'A!RTNB؁s5P3+y-਎O!~?ãg+rH =PS5ɇ/~^iq*_1.F@&>FG,K82bfQPShDI7)-zaYͺ=M:ΆZ)$ Iz Nϕl~O)s eB,(mXA_"E`]K 9aT(Q;.@O>!;a 'dMx^S_ۗȶJ+g-s.?r.<o{zJkҎ7.<f3RھZ2*,qh{~9f*b6\A*Vr'hSMRLIaۈD̏8 VNZPǃB8?&mN‰O"&<-1@4$JŴ Hjo%;ݢ$Ky]?ؚ#{}Uг% J$XÖ] C=? ҥ@,I+u_gK3_m\9Jy$4UrIuM6[xU7Qϗ{%AsoӴ&) ne-WarsdWێcKI̢8bs? 3)E c܂A6NQ<5ҔS@Js &;\#%=GT[kت*eEK ű^nm|~"OߢK6bvLBAxjI>[J PpY@&ڔyWw+,=a ?P]Z] MULm?],ax6$%T&6~Mudhb7RT@O,OZ|2yl9wW4k*Z$T{NjGʲ̪%YU$j7׉d]`ii\3dJ4t|\r D{|wuϚR:M2UXH.kyl7$BBTO.>B~:32A`=7H iXGIBG Bl PyߣFQӖ!i,OLݲ,I![߅[}76)z3%c1 nWGd:+!!%Z1@Q[)F(*VJNE/%(-Y-J@c#! HƖ:ۉ JT. ddkoVU{o{Z/˷+VR/U;ϩ J2 sN(e j$$O3S^Qdd *RRhEddeeddddddddddddddddddddddddddddddddddddddddddtilem-2.0/data/symbols/000077500000000000000000000000001220200411600150525ustar00rootroot00000000000000tilem-2.0/data/symbols/ti82.sym000066400000000000000000000347341220200411600164050ustar00rootroot00000000000000[macros] 0CD748D ROM_CALL~%j [labels] 0008 rOP1TOOP2 0010 rFINDSYM 0018 rPUSHREALO1 0020 rMOV9TOOP1 0028 rFPMULT 0030 rFPADD 0033 _LdHLind 004F _SetTblGraphDraw 0095 _CpHLDE 00A1 _DivHLBy10 00A3 _DivHLByA 012B _ApdSetup 0131 _KbdScan 01B8 _KEY_READ 01C7 _STORE_KEY 01D4 _GetCSC 01E8 _CanAlphIns 020D _coorMon 0213 _Mon 0220 _MonForceKey 02B5 _sendKPress 033C _JForceCmdNoChar 033D _JForceCmd 0355 _resetStacks 0368 _sysErrHandler 0374 _newContext 0385 _newContext0 0462 _PPutAwayPrompt 046D _PPutAway 0473 _PutAway 04B4 _Redisp 04B9 _SizeWind 04CA _ErrorEP 04DC _callMain 04ED _monErrHand 10C2 _SinCosRad 10C6 _Sin 10CA _Cos 10CE _Tan 14AA _SinHCosH 14AE _TanH 14B2 _CosH 14B6 _SinH 154D _ACosRad 1553 _ATanRad 1556 _ATan2Rad 1558 _ATan2Rad_83 155E _ASinRad 1563 _ACos 156D _ATan 15CD _ATan2_83 1570 _ATan2 1575 _ASin 1787 _ATanH 17D4 _ASinH 17E2 _ACosH 18E7 _HLTimes9 18F1 _CkOP1Real 18F7 _Angle 18FF _CpOP4OP3 1907 _Mov9OP2Cp 190C _AbsO1O2Cp 1912 _CpOP1OP2 1955 _OP3ToOP4 195E _OP1ToOP4 1967 _OP2ToOP4 1970 _OP4ToOP2 1979 _OP3ToOP2 1981 _OP1ToOP3 1989 _OP5ToOP2 1991 _OP5ToOP6 1999 _OP5ToOP4 19A1 _OP1ToOP2 19A9 _OP6ToOP2 19B1 _OP6ToOP1 19B6 _OP4ToOP1 19BB _OP5ToOP1 19C0 _OP3ToOP1 19C5 _OP4ToOP5 19CD _OP3ToOP5 19D5 _OP2ToOP5 19DD _OP2ToOP6 19E5 _OP1ToOP6 19ED _OP1ToOP5 19F5 _OP2ToOP1 19FB _Mov11B 19FD _Mov10B 19FF _Mov9B 1A01 _Mov8B 1A03 _Mov7B 1A05 _Mov6B 1A07 _Mov5B 1A09 _Mov4B 1A0B _Mov3B 1A0D _Mov2B 1A54 _OP2ToOP3 1A5C _OP4ToOP3 1A61 _OP5ToOP3 1A66 _OP4ToOP6 1A6E _Mov9ToOP1 1A73 _Mov9OP1OP2 1A74 _Mov9ToOP2 1A79 _MovFrOP1 1A7E _OP4Set1 1A83 _OP3Set1 1A88 _OP2Set8 1A8F _OP2Set5 1A96 _OP2Set4 1A9D _OP2Set3 1AA5 _OP1Set1 1AAA _OP1Set4 1AB1 _OP1Set3 1AB8 _OP3Set2 1ABD _OP1Set2 1AC2 _OP2Set2 1AC5 _SetNum2 1AC9 _SetMant1 1ACD _OP2Set1 1AD0 _SetNum1 1AD2 _SetNum 1AD7 _SetNumA 1AD8 _SetMant 1ADC _Zero16D 1ADD _Set16A 1ADE _Set14A 1ADF _Set14D 1AED _OP4Set0 1AF2 _OP3Set0 1AF7 _OP2Set0 1AFC _OP1Set0 1AFF _SetNum0 1B07 _ZeroOP1 1B0C _ZeroOP2 1B11 _ZeroOP3 1B14 _ZeroOP 1B1C _ClrLp 1B23 _ShRAcc 1B2B _ShLAcc 1B39 _ShR18 1B3A _ShR18A 1B42 _ShR16 1B43 _ShR16A 1B46 _ShR14 1B76 _ShL16 1B7A _ShL14 1C2D _Add16D 1C33 _Add14D 1CA2 _Sub16D 1CA8 _Sub14D 1CEB _OP2ExOP6 1CF0 _OP5ExOP6 1CF8 _OP1ExOP5 1CFD _OP1ExOP6 1D02 _OP2ExOP4 1D07 _OP2ExOP5 1D0F _OP1ExOP3 1D14 _OP1ExOP4 1D19 _OP1ExOP2 1D21 _ExLp 1D2B _CkOP1FP0 1D30 _CkOP2FP0 1D39 _PosNo0Int 1D3F _CkPosInt 1D48 _CkInt 1D4F _CkOdd 1DD5 _GetCon1 1DDA _GetCon 1E48 _ExpToHex 1E52 _OP1ExpToDec 1E9A _CkOP2Pos 1EA0 _CkOP1Pos 1EA6 _ClrOP2S 1EAB _ClrOP1S 1EB2 _FDiv100 1EB5 _FDiv10 1EC0 _DecO1Exp 1EC8 _IncO1Exp 1ECB _IncExp 1ED0 _CkValidNum 1EF2 _GetExp 1EFE _HTimesL 1F0F _EOP1NotReal 1F16 _PrgmBangName 1F1B _PrgmPoundName 1F3E _ThetaName 1F42 _RName 1F46 _RegEqName 1F4C _RecurNName 1F57 _XName 1F5B _YName 1F5F _TName 1F61 _RealName 1F6A _SetEStoFPS 1F71 _ChkTempDirt 1F94 _OP1MOP2Exp 1F9E _OP1ExpMDE 1FB2 _ChkErrBreak 1FCC _IsA2ByteTok 1FE3 _GetLastEntry 1FFE _GetLastEntryPtr 2014 _REGRCLRCHNG 2057 _CheckSplitFlag 2083 _ResetWinTop 209C _SetYUp 20A6 _SetXUp 20AB _MemChk 20BD _CmpPrgNamLen1 20C0 _CmpPrgNamLen 20D1 _FindProgSym 2124 _ChkFindSym 2129 _FindSym 2258 _InsertMem 2262 _InsertMemA 227D _EnoughMem 22AE _CmpMemNeed 22C3 _CreatePVar4 22E2 _CreatePVar3 230F _CreateVar3 2333 _CreateReal 2339 _CreateTRList 233F _CreateRList 235B _CreateTRMat 2361 _CreateRMat 2369 _CreateTStrng 236F _CreateStrng 237D _Create0Equ 2382 _CreateTEqu 2388 _CreateEqu 238C _CreatePict 2393 _CreateGDB 2397 _CreateProg 239B _ChkDel 23A4 _ChkDelA 23DF _AdjParser 2400 _AdjMath 2455 _AdjM7 2531 _DelMemA 2547 _DelVar 2548 _DelVarIO 258D _DelMem 2590 _DelVar3D 2593 _DelVar3C 25BB _DelVar3DC 2612 _AdjSymPtrs 2695 _DataSizeA 2699 _DataSize 26C1 _PopRealO6 26C6 _PopRealO5 26CB _PopRealO4 26D0 _PopRealO3 26D5 _PopRealO2 26DA _PopRealO1 26DD _PopReal 26E3 _FPopCplx 26E6 _FPopReal 26E9 _FPopFPS 26F1 _DeallocFPS 26F4 _DeallocFPS1 26FF _AllocFPS 2702 _AllocFPS1 270B _PushRealO6 2710 _PushRealO5 2715 _PushRealO4 271A _PushRealO3 271F _PushRealO2 2724 _PushRealO1 2727 _PushReal 273B _CpyTo1FPS11 273E _CpyFPS11 2745 _CpyTo1FPS5 2748 _CpyFPS5 274F _CpyTo1FPS6 2752 _CpyFPS6 2759 _CpyTo2FPS4 275C _CpyFPS4 2763 _CpyTo6FPS3 2768 _CpyTo2FPS3 276D _CpyTo1FPS3 2770 _CpyFPS3 277C _CpyTo3FPS2 2783 _CpyTo5FPST 2788 _CpyTo6FPST 278D _CpyTo4FPST 2792 _CpyTo3FPST 2797 _CpyTo2FPST 279C _CpyTo1FPST 279F _CpyFPST 27A4 _CpyStack 27AB _CpyTo3FPS1 27B0 _CpyTo2FPS1 27B5 _CpyTo1FPS1 27B8 _CpyFPS1 27BF _CpyTo2FPS2 27C4 _CpyTo1FPS2 27C7 _CpyFPS2 27CE _CpyO3ToFPST 27D3 _CpyO2ToFPST 27D8 _CpyO6ToFPST 27DD _CpyO1ToFPST 27E0 _CpyToFPST 27E5 _CpyToStack 27ED _CpyO5ToFPS1 27F2 _CpyO1ToFPS1 27F5 _CpyToFPS1 27FC _CpyO2ToFPS2 2801 _CpyO3ToFPS2 2806 _CpyO6ToFPS2 280B _CpyO1ToFPS2 280E _CpyToFPS2 2815 _CpyO5ToFPS3 281A _CpyO1ToFPS3 281D _CpyToFPS3 2824 _CpyO1ToFPS4 2827 _CpyToFPS4 282E _ErrNotEnoughMem 283D _FPSMinus9 2840 _HLMinus9 2845 _ErrOverflow 2849 _ErrDivBy0 284D _ErrSingularMat 2851 _ErrDomain 2855 _ErrIncrement 2859 _ErrSyntax 285D _ErrMode 2861 _ErrDataType 2865 _ErrReserved 2869 _ErrArgument 286D _ErrDimMismatch 2871 _ErrDimension 2875 _ErrUndefined 2879 _ErrMemory 287D _ErrMemoryNE 2881 _ErrInvalid 2885 _ErrIllegalNest 2889 _ErrBound 288D _ErrGraphRange 2891 _ErrZoom 2895 _ErrBreak 2899 _ErrStat 289D _ErrSolver 28A1 _ErrIterations 28A5 _ErrBadGuess 28A9 _ErrTolTooSmall 28AD _ErrStatPlot 28B1 _ErrLink 28B3 _JError 28B6 _JErrorNo 28DC _noErrorEntry 28DD _pushErrorHandler 2903 _popErrorHandler 2913 _StrLength 2926 _StrCopy 292E _StrCat 295B _IsInSet 2E46 ___bank_call 2E6D ___bank_ret 2E75 ___bank_jump 2E86 _PutTokString # 2E8C _DispYPrompt2 ? 2E92 _SetupDispEq 2E98 _BufPeek2 2EAA _CloseEquField 2EB0 _BufToBtm 2EB6 _CursorLeft 2EBC _SetEmptyEditEqu # 2ECE DOREFFLAGS02 ? 2EEC _PrevEq 2EF2 _DarkLine 2F1C _CursorDown 2F22 _JPromptCursor 2F34 _GrphPars 2F3A _PlotPars 2F40 _ParseInp 2F46 _InitPFlgs 2F4C _OP2Set60 2F58 _StoTheta 2F5E _StoR 2F64 _StoY 2F6A _StoT 2F70 _StoX 2F7C _RclAns 2F82 _RclY 2F88 _StMatEl 2F8E _StLstVecEl 2F94 _GetDEPtr 2FA0 _WScrollRight 2FA6 _WScrollLeft 2FAC _WScrollUp 2FB8 _RclToQueue 2FBE _FORSEQINIT 2FC4 _PDspGrph 2FCA _GRDECODA 2FDC _XYCent 2FE2 _ZmInt 2FE8 _CopyRng 2FEE _ZooDefault 2FF4 _ZmTrig # 2FFA _ZmFit ? # 3000 _ZmPrev ? # 3006 _ZmDecml ? # 300C _ZmUsr ? # 3012 _SetUZm ? # 3024 _DrawCmd ? 302A _InvCmd 3030 _TraceOff 304E _FNDDB 3054 _NextEq 305A _SetFuncM 3060 _SetPolM 3066 _SetParM 306C _SetSeqM 307E _TanLnF # 3084 _ShadeCmd ? 309C _PointCmd 30A2 _PixelCmd 30A8 _ChkTextCurs 30AE _FormToTok 30B4 _GDispToken 30BA _UnLineCmd 30C0 _LineCmd 30CC _VertCmd 30D2 _HorizCmd 30DE _FormERealTok 30F0 _RclSysTok 30F6 _FormEReal 30FC _OP1toEdit 310E _IsAtTop 3114 _ToggleIns 311A _BufReplace 3120 _StoSysTok 3126 _SetupEditEqu 3132 _RecallEd 313E _SetupBuffer 3144 _CreateNumEditBuf 314A _CallCommon 3150 _CommonKeys 3156 _Leftmore 315C _fDel 3162 _fClear 3168 _fInsDisp02 3180 _CloseEditBufNoR 3186 _ReleaseBuffer 31AA _numError02 31B0 _SetupEditCmd 31B6 _CursorToOffset 31BC _RstGFlags 31C2 _RclVarToEdit 31C8 _BufInsert 31CE _BufToTop 31DA _IsEditEmpty 31E6 _DisarmScroll 31EC _SetEmptyEditPtr 31F2 _FormDisp 3216 _JCursorRight 321C _JCursorUp 3228 _JCursorFirst 322E _JCursorLast 323A _BufDelete 3258 _RclEntryToEdit 325E _InsDisp 3270 _RclVarToEditPtr 3276 _FormScrollUp 327C _FormMatrix 3294 _FormReal 32D4 _DispTail 3312 _RclX 3318 _SaveParse 331E _GetParse 3330 _CpyTo2ES1 3336 _CpyTo6ES1 333C _CpyTo1ES1 3342 _CpyTo3ES1 3348 _CpyTo3ES2 334E _CpyTo2ES2 3354 _CpyTo1ES2 335A _CpyTo2ES3 3360 _CpyTo1ES3 3366 _CpyTo3ES4 336C _CpyTo6ES4 3372 _CpyTo2ES4 3378 _CpyTo1ES4 337E _CpyTo2ES5 3384 _CpyTo1ES5 338A _CpyTo4EST 3390 _CpyTo2EST 3396 _CpyTo1EST 339C _CpyTo2ES6 33A2 _CpyTo1ES6 33A8 _CpyTo2ES7 33AE _CpyTo1ES7 33B4 _CpyTo2ES8 33BA _CpyTo1ES8 33C0 _CpyTo1ES9 33C6 _CpyTo2ES9 33CC _CpyTo2ES10 33D2 _CpyTo1ES10 33D8 _CpyES10 33DE _CpyTo2ES11 33E4 _CpyTo1ES11 33EA _CpyTo2ES12 33F0 _CpyTo1ES12 33F6 _CpyTo2ES13 33FC _CpyTo1ES13 3402 _CpyTo1ES14 3408 _CpyTo1ES16 340E _CpyTo1ES17 3414 _CpyTo1ES18 341A _CpyTo1ES15 3420 _CpyTo2ES15 3426 _CpyO1ToEST 342C _CpyO1ToES1 3432 _CpyO6ToES1 3438 _CpyO6ToES4 343E _CpyO1ToES2 3444 _CpyO2ToES2 344A _CpyO1ToES3 3450 _CpyO1ToES4 3456 _CpyO1ToES5 345C _CpyO1ToES6 3462 _CpyO1ToES7 3468 _CpyO2ToES1 346E _CpyO2ToES4 3474 _CpyO2ToES7 347A _CpyO1ToES8 3480 _CpyO1ToES9 3486 _CpyO1ToES10 348C _CpyO1ToES11 3492 _CpyO1ToES12 3498 _CpyO1ToES13 349E _CpyO1ToES14 34A4 _CpyO1ToES15 34AA _PixelTest # 34BC _DFMIN2 ? 3504 _RestoreErrNo 3516 _StoN 351C _ParseOff 3522 _RclN 354C _Random 3552 _StoRand 3558 _GetL3TOP1A 355E _GetL1ToOP1 3564 _GetL1TOP1A 356A _GetLToOP1 3570 _GetLToOP2 3576 _GetL2TOP1A 3582 _PutToLA1 3588 _PutToL 35A0 _ConvOP1 35AC _GetM1ToOP1A 35B2 _GetMToOP1 35B8 _PutToM1A 35BE _PutToMA1 35C4 _PutToMat 35D0 _AdrMEle 35D6 _AdrLEle 35DC _RclVarSym 35E2 _StoOther 35E8 _RedimMat 35EE _IncLstSize 35F4 _InsertList 35FA _DelListEl 3600 _EditProg 3606 _CloseProg 360C _ClrGraphRef 3612 _FixTempCnt 3618 _SaveData 361E _RestoreData 3624 _CleanAll 362A _MoveToNextSym 3630 _DispErrorScreen 3660 _GrRedisp 3690 _FindAlphaUp 3696 _FindAlphaDn 369C _RestoreDisp 36A2 _LoadMenuNum 36A8 _LoadMenuNumL 36AE _RstrSmallText 36B4 _ConvKeyToTok 36BA _GrLabels 36CC _NBCursor 36D2 _IsEditFull 36D8 _IsAtBtm 36DE _ShowCursor 36E4 _BufLeft 36EA _BufPeek 36F0 _BufRight 36F6 _FDispBOL 36FC _FDispBOL1 3702 _SetWinAbove 3708 _GetPrevTok 370E _StringWidth 371A _DispEOW 3720 _BufPeek1 372C _BufPeek3 3732 _ReadDisp2 3738 _PutMap 373E _PutPS 3744 _WPutPS 374A _PutBuf 3750 _PutBuf1 3756 _WPutC 375C _WPutS 3762 _WPutSEOL 3768 _WHomeUp 376E _SetNumWindow 377A _NewLine 3780 _MoveDown 3786 _ScrollUp 3792 _ShrinkWindow 3798 _MoveUp 379E _ScrollDown 37A4 _ClrScrnFull 37AA _ClrTxtShd 37B6 _EraseEOL 37C8 _GetCurLoc 37CE _VPutMap 37D4 _VPutS 37DA _VPutSNG 37E0 _SaveCmdShadow 37EC _SaveShadow 37F8 _RstrShadow 37FE _RstrCurRow 3804 _RstrUnderMenu 380A _RstrBotRow 3810 _SaveTR 3816 _RestoreTR 381C _GetTokLen 3822 _GetTokString 3828 _PUTBPATBUF2 382E _PUTBPATBUF 3834 _putbPAT 383A _putcCheckScroll 3840 _DispEOL 3846 _FDispEOL 384C _TblScreenDn 3852 _TblScreenUp 3858 _TOTOSTRP 385E _SetVarName 386A _DispDone 3870 _FinishOutput 3876 _ClrLCD 387C _DispHL 3894 _CreateTemp 389A _ClrLCDFull 38A0 _LoadNoEEntry 38AC _GrBufCpy 38BE _AbortPrgmode 38CA _ClrScrn 38E2 _StoAns 38E8 _GrReset 38F4 _RandInit 38FA _PutS 3900 _HomeUp 3912 _CoorDisp 3918 _RunIndicOff 391E _CursorOn 3924 _GetKey 392A _BlinkGCur 3930 _RunIndicOn # 3936 _PullDownChk ? 393C _TokToKey 3942 _GrPutAway 3948 _PopCx 39C6 _SaveOScreen 39CC _CurBlink 39D2 _PutC ## note: following ROM calls are not correctly handled by ## SNG on ROM 19.006 31E0 _CloseEditEqu 3246 _DispHead 324C _BufClear 32BE _Send1BErr # 32C4 # 32CA # 32D0 # 32D6 32DC _KeyScnLnk 37B0 _ClrWindow 37C2 _EraseEOW 38B8 _RstrPartial 38C4 _HideCursor 38D6 _LCD_DriverOn 38DC _RstrOScreen 390C _CursorOff ## note: following ROM calls are not correctly handled by ## SNG on ROM 19.0 050C _AppInit 0684 _initialize 07F3 _LCD_BUSY 0801 _Min 080A _Max 0818 _AbsO1PAbsO2 0820 _Intgr 0836 _Trunc 083A _InvSub 083F _Times2 0842 _Plus1 0847 _Minus1 084A _FPSub 0851 _FPAdd 0905 _DToR 090E _RToD 0917 _Cube 091C _TimesPt5 0924 _FPSquare 0925 _FPMult ## note: following ROM calls are not correctly handled by ## any current shells on ROM 19.0 0A1B _LJRnd 0A5D _InvOP1S 0A6D _InvOP2S 0A83 _Frac 0AD0 _FPRecip 0AD4 _FPDiv 0BA1 _SqRoot 0C69 _Int 0C6B _Round 0C4F _RndGuard # 0CDF _Factorial ? 0D27 _LnX 0D2B _LogX 0E63 _LJNoRnd 0F03 _EToX 0F0D _TenX 8000 kbdScanCode 8001 kbdLGSC 8002 kbdPSC 8003 kbdWUR 8004 kbdDebncCnt 8005 kbdKey 8006 kbdGetKy 8007 keyExtend 8008 contrast 8009 apdSubTimer 800A apdTimer 800B curTime 800C curRow 800D curCol 800E curUnder 800F curY # 8010 curType ? 8011 curXRow # 801A tokVarPtr ? # 801C tokLen ? 801E indicMem 8026 indicCounter 8027 indicBusy 8028 OP1 8033 OP2 803E OP3 8049 OP4 8054 OP5 805F OP6 806A progToEdit 8072 nameBuff 807D iMathPtr1 807F iMathPtr2 8081 iMathPtr3 8083 iMathPtr4 8085 iMathPtr5 8087 chkDelPtr1 8089 chkDelPtr2 808B insDelPtr 808D upDownPtr 808F textShadow 810F textShadCur 8111 textShadTop 8112 textShadAlph 8113 textShadIns 8114 cxMain 8116 cxPPutAway 8118 cxPutAway 811A cxRedisp 811C cxErrorEP 811E cxSizeWind 8120 cxPage 8121 cxCurApp 8122 cxPrev 8131 monQH 8132 monQT # 8133 monQueue ? 8143 onSP 8145 onCheckSum 8161 menuActive 8163 menuCurrent 81F0 ioFlag 81F2 sndRecState 81F3 ioErrState 81F4 header 81FD ioData 8209 bakHeader 8215 penCol 8216 penRow 8217 rclQueue 8219 errNo 821A errSP 821C errOffset 8228 saveSScreen 8528 flags 8549 curGStyle 854A curGY 854B curGX 854C curGY2 854D curGX2 # 8551 XOffset ? # 8552 YOffset ? 8553 lcdTallP 8554 pixWideP 8557 lastEntryStk 85D7 numLastEntries 85D8 currLastEntry # 85E1 ORGXMIN ? 8691 Xmin 86AC Ymin 874E deltaX 8757 deltaY 8760 shortX 8769 shortY 8774 XOutDat 8778 YOutDat # 877A inputSym ? 877C inputDat 88AE ES 88B8 plotSScreen 8BB8 seed1 8BC1 seed2 8BCA parseVar 8BD3 begPC 8BD5 curPC 8BD7 endPC 8BDF cmdShadow 8C5F cmdShadCur 8C65 editTop 8C67 editCursor 8C69 editTail 8C6B editBtm 8C71 editSym # 8C73 editDat ? 8C8D modePtr 8C8F winTop 8C90 winBtm 8C91 winLeftEdge 8C92 winLeft 8C94 winAbove 8C96 winRow 8C98 winCol 8C9A fmtDigits 8CF2 fmtMatSym 8CF4 fmtMatMem # 8CF6 EQS ? 8CFF delAdjAmt 8D06 chkDelPtr3 8D08 chkDelPtr4 8D0A tempMem 8D0C fpBase 8D0E FPS 8D10 OPBase 8D12 OPS 8D14 pTempCnt 8D16 cleanTmp 8D18 pTemp 8D24 userMem FE6E symTable [flags] 00 kbdFlags 2,00 trigDeg,trigFlags 3,00 kbdSCR,kbdFlags 4,00 kbdKeyPress,kbdFlags 01 editFlags 2,01 editOpen,editFlags 02 plotFlags 1,02 plotLoc,plotFlags 2,02 plotDisp,plotFlags 4,02 grfFuncM,grfModeFlags 5,02 grfPolarM,grfModeFlags 6,02 grfParamM,grfModeFlags 7,02 grfRecurM,grfModeFlags 03 graphFlags 0,03 graphDraw,graphFlags 2,03 graphCursor,graphFlags 04 grfDBFlags 5,04 grfNoAxis,grfDBFlags 5,04 grfLabel,grfDBFlags 05 textFlags 1,05 textEraseBelow,textFlags 2,05 textScrolled,textFlags 3,05 textInverse,textFlags 4,05 textInsMode,textFlags 08 apdFlags 2,08 apdAble,apdFlags 3,08 apdRunning,apdFlags 09 onFlags 3,09 onRunning,onFlags 4,09 onInterrupt,onFlags 0C curFlags 2,0C curAble,curFlags 3,0C curOn,curFlags 4,0C curLock,curFlags 0D appFlags 1,0D appTextSave,appFlags 2,0D appAutoScroll,appFlags 5,0D appCurGraphic,appFlags 6,0D appCurWord,appFlags 11 promptFlags 0,11 promptEdit,promptFlags 12 indicFlags 0,12 indicRun,indicFlags 1,12 indicInUse,indicFlags 2,12 indicOnly,indicFlags 3,12 shift2nd,shiftFlags 4,12 shiftAlpha,shiftFlags 5,12 shiftLwrAlph,shiftFlags 6,12 shiftALock,shiftFlags 7,12 shiftKeepAlph,shiftFlags 13 tblFlags 6,13 reTable,tblFlags 14 sGrFlags 0,14 grfSplit,sGrFlags 1,14 grfSChanged,sGrFlags 2,14 grfSplitOverride,sGrFlags 7,14 textWrite,sGrFlags 15 newIndicFlags 1,15 saIndic,newIndicFlags tilem-2.0/data/symbols/ti83.sym000066400000000000000000000504701220200411600164010ustar00rootroot00000000000000[macros] # Nothing currently [labels] 0008 rOP1TOOP2 0010 rFINDSYM 0018 rPUSHREALO1 0020 rMOV9TOOP1 0028 rFPMULT 0030 rFPADD 8000 kbdScanCode 8001 kbdLGSC 8002 kbdPSC 8003 kbdWUR 8004 kbdDebncCnt 8005 kbdKey 8006 kbdGetKy 8007 keyExtend 8008 contrast 8009 apdSubTimer 800a apdTimer 800b curTime 800c curRow 800d curCol 800e curOffset 800f curUnder 8010 curY 8012 curXRow 801a lFont_record 8022 sFont_record 802f indicMem 8037 indicCounter 8038 indicBusy 8039 OP1 8044 OP2 804f OP3 805a OP4 8065 OP5 8070 OP6 8080 progToEdit 8088 nameBuff 8094 iMathPtr1 8096 iMathPtr2 8098 iMathPtr3 809a iMathPtr4 809c iMathPtr5 809e chkDelPtr1 80a0 chkDelPtr2 80a2 insDelPtr 80a4 upDownPtr 80ac asm_data_ptr1 80ae asm_data_ptr2 80c8 asm_ind_call 80c9 textShadow 8149 textShadCur 814b textShadTop 814c textShadAlph 814d textShadIns 814e cxMain 8150 cxPPutAway 8152 cxPutAway 8154 cxRedisp 8156 cxErrorEP 8158 cxSizeWind 815a cxPage 815b cxCurApp 815c cxPrev 817d onSP 817f onCheckSum 819d menuActive 819f menuCurrent 822d ioFlag 822f sndRecState 8230 ioErrState 8231 header 823a ioData 8246 bakHeader 8252 penCol 8253 penRow 8254 rclQueue 8256 errNo 8257 errSP 8259 errOffset 8265 saveSScreen 8565 usermem_offset 8567 flags 858f statVars 886c curGStyle 886d curGY 886e curGX 886f curGY2 8870 curGX2 8871 freeSaveY 8872 freeSaveX 88F6 XOffset 88F7 YOffset 88F8 lcdTallP 88F9 pixWideP 88FA pixWide_m_1 88FB pixWide_m_2 88FE lastEntryStk 897E numLastEntries 897F currLastEntry 8AA5 Xmin 8AB7 Xscl 8AC0 Ymin 8AD2 Yscl 8C3B deltaX 8C44 deltaY 8C4D shortX 8C56 shortY 8C77 XOutDat 8C7B YOutDat 8C7F inputDat 8DEB ES 8e29 plotSScreen 913B parseVar 9144 begPC 9146 curPC 9148 endPC 9157 cmdShadow 91D7 cmdShadCur 91DB cmdCursor 91DD editTop 91DF editCursor 91E1 editTail 91E3 editBtm 91EF editSym 91F1 editDat 928C modePtr 928E winTop 928F winBtm 9290 winLeftEdge 9291 winLeft 9293 winAbove 9295 winRow 9297 winCol 92F1 fmtMatSym 92F3 fmtMatMem 92F5 EQS 92FE delAdjAmt 9305 chkDelPtr3 9307 chkDelPtr4 9309 tempMem 930B fpBase 930D FPS 930F OPBase 9311 OPS 9313 pTempCnt 9315 cleanTmp 9317 pTemp 9319 progPtr 9327 userMem 0fe6e symTable # System routines (page C) 4000 _ldHLind 4004 _cphlde 4008 _divHLBy10 400c _divHLbyA 4010 _kbdScan 4014 _getcsc 4018 _coorMon 401b _mon 401e _monForceKey 4021 _sendKPress 4024 _JforceCmdNoChaR 4027 _JforceCmd 402a _sysErrHandler 402e _newContext 4032 _newContext0 4036 _A2PointHLind 403a _PointHLind 403e _PPutAwayPrompt 4042 _PPutAway 4046 _PutAway 404a _SizeWind 404e _ErrorEP 4052 _callMain 4056 _monErrHand 405a _appInit 405e _appInitIfDec 4062 _Initialize 4066 _lcd_busy 406a _Min 406e _Max 4072 _AbsO1PAbsO2 4076 _Intgr 407a _Trunc 407e _InvSub 4082 _Times2 4086 _Plus1 408a _Minus1 408e _FPSub 4092 _FPAdd 4096 _DToR 409a _RToD 409e _Cube 40a2 _TimesPt5 40a6 _FPSquare 40aa _FPMult 40ae _LJRnd 40b2 _InvOP1SC 40b6 _InvOP1S 40ba _InvOP2S 40be _Frac 40c2 _FPRecip 40c6 _FPDiv 40ca _SqRoot 40ce _RndGuard 40d2 _RnFx 40d6 _Int 40da _Round 40de _LnX 40e2 _LogX 40e6 _LJNoRnd 40ea _EToX 40ee _TenX 40f2 _SinCosRad 40f6 _Sin 40fa _Cos 40fe _Tan 4102 _SinHCosH 4106 _TanH 410a _CosH 410e _SinH 4112 _ACosRad 4116 _ATanRad 411a _ATan2Rad 411e _ASinRad 4122 _ACos 4126 _ATan 412a _ASin 412e _ATan2 4132 _ATanH 4136 _ASinH 413a _ACosH 413e _PToR 4142 _RToP 4146 _HLTimes9 414a _CkOP1Cplx 414e _CkOP1Real 4152 _Angle 4156 _COP1Set0 415a _CpOP4OP3 415e _Mov9OP2Cp 4162 _AbsO1O2Cp 4166 _CpOP1OP2 416a _OP3ToOP4 416e _OP1ToOP4 4172 _OP2ToOP4 4176 _OP4ToOP2 417a _OP3ToOP2 417e _OP1ToOP3 4182 _OP5ToOP2 4186 _OP5ToOP6 418a _OP5ToOP4 418e _OP1ToOP2 4192 _OP6ToOP2 4196 _OP6ToOP1 419a _OP4ToOP1 419e _OP5ToOP1 41a2 _OP3ToOP1 41a6 _OP6ToOP5 41aa _OP4ToOP5 41ae _OP3ToOP5 41b2 _OP2ToOP5 41b6 _OP2ToOP6 41ba _OP1ToOP6 41be _OP1ToOP5 41c2 _OP2ToOP1 41c6 _MovREG 41ca _Mov10B 41ce _Mov9B 41d2 _Mov18 41d6 _Mov8B 41da _Mov7B 41de _Mov14 41e2 _Mov6B 41e6 _Mov5B 41ea _Mov4B 41ee _Mov3B 41f2 _Mov2B 41f6 _OP2ToOP3 41fa _OP4ToOP3 41fe _OP5ToOP3 4202 _OP4ToOP6 4206 _Mov9ToOP1 420a _Mov9OP1OP2 420e _Mov9ToOP2 4212 _MovFrOP1 4216 _OP4Set1 421a _OP3Set1 421e _OP2Set8 4222 _OP2Set5 4226 _OP2SetA 422a _OP2Set4 422e _OP2Set3 4232 _OP1Set1 4236 _OP1Set4 423a _OP1Set3 423e _OP3Set2 4242 _OP1Set2 4246 _OP2Set2 424a _SetNum2 424e _SetMant1 4252 _OP2Set1 4256 _SetNum1 425a _SetNum 425e _SetNumA 4262 _SetMant 4266 _Zero16D 426a _Set16A 426e _Set14A 4272 _Set14D 4276 _OP5Set0 427a _OP4Set0 427e _OP3Set0 4282 _OP2Set0 4286 _OP1Set0 428a _SetNum0 428e _ZeroOP1 4292 _ZeroOP2 4296 _ZeroOP3 429a _ZeroOP 429e _ClrLp 42a2 _ShRAcc 42a6 _ShLAcc 42aa _ShR18 42ae _ShR18A 42b2 _ShR16 42b6 _ShR14 42ba _ShL16 42be _ShL14 42c2 _SRDO1 42c6 _SHRDRND 42ca _MANTPA 42ce _ADDPROP 42d2 _ADDPROPLP 42d6 _Add16D 42da _Add14D 42de _Sub16D 42e2 _Sub14D 42e6 _OP2ExOP6 42ea _OP5ExOP6 42ee _OP1ExOP5 42f2 _OP1ExOP6 42f6 _OP2ExOP4 42fa _OP2ExOP5 42fe _OP1ExOP3 4302 _OP1ExOP4 4306 _OP1ExOP2 430a _ExLp 430e _CkOP1C0 4312 _CkOP1FP0 4316 _CkOP2FP0 431a _PosNo0Int 431e _CkPosInt 4322 _CkInt 4326 _CkOdd 432a _CkOP1M 432e _GetCon1 4332 _GetCon 4336 _PIDIV2 433a _PIDIV4 433e _TWOPI 4342 _PICON 4346 _PIDIV4A 434a _PIDIV2A 434e _ExpToHex 4352 _OP1ExpToDec 4356 _CkOP2Pos 435a _CkOP1Pos 435e _ClrOP2S 4362 _ClrOP1S 4366 _FDiv100 436a _FDiv10 436e _DecO1Exp 4372 _IncO1Exp 4376 _IncExp 437a _CkValidNum 437e _GetExp 4382 _HTimesL 4386 _EOP1NotReal 438a _ThetaName 438e _RName 4392 _RegEqName 4396 _RecurNName 439a _XName 439e _YName 43a2 _TName 43a6 _RealName 43aa _SETesTOfps 43ae _ChkTempDirt 43b2 _OP1MOP2Exp 43b6 _OP1EXPMDE 43ba _ChkErrBreak 43be _IsA2ByteTok 43c2 _GetLastEntry 43c6 _GetLastEntryPtr 43ca _REGRCLRCHNG 43ce _ResetWinTop 43d2 _SetYUp 43d6 _SetXUp 43da _ISO1NONTLSTorPROG 43de _ISO1NONTEMPLST 43e2 _IS_A_LSTorCLST 43e6 _Chk_HL_999 43ea _EQU_or_NEWEQU 43ee _GET_PLUS1_SAVE 43f2 _ErrD_OP1NotPos 43f6 _ErrD_OP1Not_R 43fa _ErrD_OP1NotPosInt 43fe _ErrD_OP1_LE_0 4402 _ErrD_OP1_0 4406 _Findsym_Get_Size 440a _Sto_StatVar 440e _Rcl_StatVar 4412 _CkOP2Real 4416 _Get_X_Indirect 441a _MemChk 441e _CmpPrgNamLen1 4422 _CmpPrgNamLen 4426 _FindProgSym 442a _ChkFindSym 442e _FindSym 4432 _InsertMem 4436 _InsertMemA 443a _EnoughMem 443e _CmpMemNeed 4442 _CREATEPVAR4 4446 _CREATEPVAR3 444a _CREATEVAR3 444e _CreateCplx 4452 _CreateReal 4456 _CreateTRList 445a _CreateRList 445e _CreateTCList 4462 _CreateCList 4466 _CreateTRMat 446a _CreateRMat 446e _CreateTStrng 4472 _CreateStrng 4476 _Create0Equ 447a _CreateTEqu 447e _CreateEqu 4482 _CreatePict 4486 _CreateGDB 448a _CreateProg 448e _ChkDel 4492 _ChkDelA 4496 _AdjParser 449a _AdjMath 449e _AdjM7 44a2 _DelMemA 44a6 _Get_Form_Num 44aa _DelVar 44ae _DelVarIO 44b2 _DelMem 44b6 _DelVar3D 44ba _DelVar3C 44be _DelVar3DC 44c2 _Sym_Prog_Non_T_Lst 44c6 _AdjSymPtrs 44ca _DataSizeA 44ce _DataSize 44d2 _PopMCplxO1 44d6 _PopMCplx 44da _MovCplx 44de _PopOP5 44e2 _PopOP3 44e6 _PopOP1 44ea _PopRealO6 44ee _PopRealO5 44f2 _PopRealO4 44f6 _PopRealO3 44fa _PopRealO2 44fe _PopRealO1 4502 _PopReal 4506 _FPopCplx 450a _FPopReal 450e _FPopFPS 4512 _DeallocFPS 4516 _DeallocFPS1 451a _AllocFPS 451e _AllocFPS1 4522 _PushRealO6 4526 _PushRealO5 452a _PushRealO4 452e _PushRealO3 4532 _PushRealO2 4536 _PushRealO1 453a _PushReal 453e _PushOP5 4542 _PushOP3 4546 _PushMCplxO3 454a _PushOP1 454e _PushMCplxO1 4552 _PushMCplx 4556 _ExMCplxO1 455a _Exch9 455e _CpyTo1FPS11 4562 _CpyTo2FPS5 4566 _CpyTo1FPS5 456a _CpyTo2FPS6 456e _CpyTo1FPS6 4572 _CpyTo2FPS7 4576 _CpyTo1FPS7 457a _CpyTo1FPS8 457e _CpyTo2FPS8 4582 _CpyTo1FPS10 4586 _CpyTo1FPS9 458a _CpyTo2FPS4 458e _CpyTo6FPS3 4592 _CpyTo6FPS2 4596 _CpyTo2FPS3 459a _CpyCTo1FPS3 459e _CpyTo1FPS3 45a2 _CpyFPS3 45a6 _CpyTo1FPS4 45aa _CpyTo3FPS2 45ae _CpyTo5FPST 45b2 _CpyTo6FPST 45b6 _CpyTo4FPST 45ba _CpyTo3FPST 45be _CpyTo2FPST 45c2 _CpyTo1FPST 45c6 _CpyFPST 45ca _CpySTACK 45ce _CpyTo3FPS1 45d2 _CpyTo2FPS1 45d6 _CpyTo1FPS1 45da _CpyFPS1 45de _CpyTo2FPS2 45e2 _CpyTo1FPS2 45e6 _CpyFPS2 45ea _CpyO3ToFPST 45ee _CpyO2ToFPST 45f2 _CpyO6ToFPST 45f6 _CpyO1ToFPST 45fa _CpyToFPST 45fe _CpyToSTACK 4602 _CpyO3ToFPS1 4606 _CpyO5ToFPS1 460a _CpyO2ToFPS1 460e _CpyO1ToFPS1 4612 _CpyToFPS1 4616 _CpyO2ToFPS2 461a _CpyO3ToFPS2 461e _CpyO6ToFPS2 4622 _CpyO1ToFPS2 4626 _CpyToFPS2 462a _CpyO5ToFPS3 462e _CpyO2ToFPS3 4632 _CpyO1ToFPS3 4636 _CpyToFPS3 463a _CpyO1ToFPS6 463e _CpyO1ToFPS7 4642 _CpyO1ToFPS5 4646 _CpyO2ToFPS4 464a _CpyO1ToFPS4 464e _ErrNotEnoughMem 4652 _FPSMinus9 4656 _HLMinus9 465a _ErrOverflow 465d _ErrDivBy0 4660 _ErrSingularMat 4663 _ErrDomain 4666 _ErrIncrement 4669 _ErrNon_Real 466c _ErrSyntax 466f _ErrDataType 4672 _ErrArgument 4675 _ErrDimMismatch 4678 _ErrDimension 467b _ErrUndefined 467e _ErrMemory 4681 _ErrInvalid 4684 _ErrBreak 4687 _ErrStat 468a _ErrSignChange 468d _ErrIterations 4690 _ErrBadGuess 4693 _ErrTolTooSmall 4696 _ErrStatPlot 4699 _ErrLinkXmit 469c _JError 469f _JErrorNo 46a2 _noErrorEntry 46a5 _pushErrorHandlER 46a9 _popErrorHandleR 46ad _strCopy 46b1 _strCat 46b5 _isInSet 46b9 _sDone 46bd _serrort 46c1 _sNameEq 46c5 _sUnderScr 46c9 _sFAIL 46cd _sName 46d1 _sOK 46d5 _seqn 46d9 _Sselect 46dd _STransmit 46e1 _SRECURN 46e5 _GEQNAMEA 46e9 _RECNAME 46ed ___bank_call 46f1 ___bank_ret 46f5 ___bank_jump 46f9 ___bank_entry 46fd _ReadDisp2 4701 _putmap 4705 _putc 4709 _dispHL 470d _puts 4711 _putpsb 4715 _putps 4719 _wputps 471d _putbuf 4721 _putbuf1 4725 _wputc 4729 _wputs 472d _wputsEOL 4731 _wdispEOL 4735 _whomeUp 4739 _setNumWindow 473d _newline 4741 _moveDown 4745 _scrollUp 4749 _shrinkWindow 474d _moveUp 4751 _scrollDown 4755 _clrLCDFull 4759 _clrLCD 475d _clrScrnFull 4761 _clrScrn 4765 _clrTxtShd 4769 _clrWindow 476d _eraseEOL 4771 _eraseEOW 4775 _homeUp 4779 _getcurloc 477d _vputmap 4781 _vputs 4785 _vputsn 4789 _vputsnG 478d _vputsnT 4791 _runIndicOn 4795 _runIndicOff 4799 _saveCmdShadow 479d _saveShadow 47a1 _rstrShadow 47a5 _rstrpartial 47a9 _rstrCurRow 47ad _rstrUnderMenu 47b1 _rstrbotrow 47b5 _saveTR 47b9 _restoreTR 47bd _GetKeyPress 47c1 _GetTokLen 47c5 _Get_Tok_Strng 47c9 _GetTokString 47cd _PUTBPATBUF2 47d1 _PUTBPATBUF 47d5 _putbPAT 47d9 _putcCheckScrolL 47dd _dispEOL 47e1 _fdispEOL 47e5 _MAKEROWCMD 47e9 _TOTOSTRP 47ed _SETVARNAME 47f1 _dispDone 47f5 _finishoutput 47f9 _curBlink 47fd _cursorOff 4801 _hideCursor 4805 _cursorOn 4809 _showCursor 480d _KeyToString 4811 _PullDownChk 4815 _MenuCatCommon 4819 _ZIfCatalog 481d _ZIfMatrixMenu 4821 _loadCurCat 4825 _NCifprgmedmode 4829 _LoadMenuNum 482d _LoadMenuNumL 4831 _MenuEdKey 4835 _MenCatRet 4839 _notalphnum 483d _SaveSavedFlags 4841 _SetMenuFlags 4845 _RstrSomeFlags 4849 _RstrSmallText 484d _dispListName 4851 _SeeIfErrorCx 4855 _RstrOScreen 4859 _SaveOscreen 485d _DispLAlphaName 4861 _AbortPrgmode 4865 _Is_FullCntx 4869 _AdrMRow 486d _AdrMEle 4871 _GetMatOP1A 4875 _GetM1ToOP1 4879 _GetM1TOP1A 487d _GetMToOP1 4881 _PutToM1A 4885 _PutToMA1 4889 _PutToMat 488d _Mat_El_Div 4891 _CMatFun 4895 _RowEch_Poly 4899 _RowEchelon 489d _AdrLEle 48a1 _GetL1ToOP1 48a5 _GetL1TOP1A 48a9 _GetLToOP1 48ad _GetL1ToOP2 48b1 _GetL1TOP2A 48b5 _GetL2TOP1A 48b9 _PutToLA1 48bd _PutToL 48c1 _MaxMinLst 48c5 _LLow 48c9 _LHigh 48cd _LSum 48d1 _CumSum 48d5 _ToFrac 48d9 _SeqSet 48dd _SeqSolve 48e1 _Cmp_Num_Init 48e5 _BinOpExec 48e9 _EXMEAN1 48ed _SET2MVLPTRS 48f1 _SETMAT1 48f5 _CreateTList 48f9 _UnOpExec 48fd _ThreeExec 4901 _RestoreErrNo 4904 _FourExec 4908 _FiveExec 490c _CpyTo2ES1 4910 _CpyTo6ES1 4914 _CpyTo1ES1 4918 _CpyTo3ES1 491c _CpyTo3ES2 4920 _CpyTo2ES2 4924 _CpyTo1ES2 4928 _CpyTo2ES3 492c _CpyTo1ES3 4930 _CpyTo3ES4 4934 _CpyTo6ES3 4938 _CpyTo2ES4 493c _CpyTo1ES4 4940 _CpyTo2ES5 4944 _CpyTo1ES5 4948 _CpyTo4EST 494c _CpyTo2EST 4950 _CpyTo1EST 4954 _CpyTo2ES6 4958 _CpyTo1ES6 495c _CpyTo2ES7 4960 _CpyTo1ES7 4964 _CpyTo2ES8 4968 _CpyTo1ES8 496c _CpyTo1ES9 4970 _CpyTo2ES9 4974 _CpyTo2ES10 4978 _CpyTo1ES10 497c _CpyTo2ES11 4980 _CpyTo1ES11 4984 _CpyTo2ES12 4988 _CpyTo1ES12 498c _CpyTo2ES13 4990 _CpyTo1ES13 4994 _CpyTo1ES14 4998 _CpyTo1ES16 499c _CpyTo1ES17 49a0 _CpyTo1ES18 49a4 _CpyTo1ES15 49a8 _CpyTo2ES15 49ac _CpyO1ToEST 49b0 _CpyO1ToES1 49b4 _CpyO6ToES1 49b8 _CpyO6ToES3 49bc _CpyO1ToES2 49c0 _CpyO2ToES2 49c4 _CpyO1ToES3 49c8 _CpyO1ToES4 49cc _CpyO1ToES5 49d0 _CpyO1ToES6 49d4 _CpyO1ToES7 49d8 _CpyO2ToES4 49dc _CpyO2ToES5 49e0 _CpyO2ToES6 49e4 _CpyO2ToES7 49e8 _CpyO2ToES8 49ec _CpyO2ToES9 49f0 _CpyO1ToES8 49f4 _CpyO1ToES9 49f8 _CpyO1ToES10 49fc _CpyO1ToES11 4a00 _CpyO1ToES12 4a04 _CpyO1ToES13 4a08 _CpyO1ToES14 4a0c _CpyO1ToES15 4a10 _EVALF3A 4a14 COMPLEX_EXEC 4a18 _GetK 4a1c _setTitlE 4a20 _dispVarVal 4a24 _RecallEd 4a28 _setupBuffer 4a2c _createNumEditBUF 4a30 _CallCommon 4a34 _CommonKeys 4a37 _Leftmore 4a3a _fDel 4a3e _fClear 4a42 _finsDisp 4a45 _FinsDisp02 4a49 _setIndicator 4a4d _CloseEditBufNo 4a51 _releaseBuffer 4a55 _varnameToOP1hl 4a59 _nameToOP1 4a5d _numPPutAway 4a61 _numRedisp 4a65 _numError02 4a68 _Load_SFont 4a6c _SFont_Len 4a70 _InitNumVec 4a74 _SetXXOP1 4a78 _SetXXOP2 4a7c _SetXXXXOP2 4a80 _UCLineS 4a84 _CLine 4a88 _CLineS 4a8c _XRooty 4a90 _YToX 4a94 _ZmStats 4a98 _POINT_STAT_HLP 4a9c _DRAWSPLOT 4aa0 _INITNEWTRACEP 4aa4 _SPLOTCOORD 4aa8 _SPLOTRIGHT 4aac _SPLOTLEFT 4ab0 _CMPBOXINFO 4ab4 _NEXTPLOT 4ab8 _PREVPLOT 4abc _CLRPREVPLOT 4ac0 _PUT_INDEX_LST 4ac4 _GET_INDEX_LST 4ac8 _HEAP_SORT 4acc _STOGDB2 4ad0 _RCLGDB2 4ad4 _CircCmd 4ad8 _GrphCirc 4adc _Mov18B 4ae0 _DarkLine 4ae4 _ILine 4ae8 _IPoint 4aec _XYRndBoth 4af0 _XYRnd 4af4 _CheckTOP 4af8 _CheckXY 4afc _DarkPnt 4b00 _CPointS 4b04 _WtoV 4b08 _VtoWHLDE 4b0c _XItoF 4b10 _YFtoI 4b14 _XFtoI 4b18 _TraceOff 4b1c _GrRedisp 4b20 _GDispToken 4b24 _GRDECODA 4b28 _LABCOOR 4b2c _COORDISP 4b30 _TMPEQUNOSRC 4b34 _GrLabels 4b38 _YPixSet 4b3c _XPixSet 4b40 _CopyRng 4b44 _VALCUR 4b48 _GrPutAway 4b4c _RstGFlags 4b50 _GRReset 4b54 _XYCent 4b58 _ZoomXYCmd 4b5c _CPTDELY 4b60 _CPTDELX 4b64 _SetFuncM 4b68 _SetSeqM 4b6c _SetPolM 4b70 _SetParM 4b74 _ZmInt 4b78 _ZmDecml 4b7c _ZmPrev 4b80 _ZmUsr 4b84 _SetUZm 4b88 _ZmFit 4b8c _ZmSquare 4b90 _ZmTrig 4b94 _SetXMinMax 4b98 _ZooDefault 4b9c _GrBufCpy 4ba0 _DrawSplitLine 4ba4 _RestoreDisp 4ba8 _FNDDB 4bac _ALLEQ 4bb0 _fndallseleq 4bb4 _NEXTEQ 4bb8 _PREVEQ 4bbc _BlinkGCur 4bc0 _NBCURSOR 4bc4 _StatMark 4bc8 _ChkTextCurs 4bcc _Regraph 4bd0 _DOREFFLAGS02 4bd4 _InitNSeq 4bd8 _YRES 4bdc _PLOTPTXY2 4be0 _Ceiling 4be4 _PutXY 4be7 _Putequno 4beb _PDspGrph 4bef _HorizCmd 4bf3 _VertCmd 4bf7 _LineCmd 4bfb _UnLineCmd 4bff _PointCmd 4c03 _PixelTest 4c07 _PixelCmd 4c0b _TanLnF 4c0f _DrawCmd_Init 4c13 _DrawCmd 4c17 _ShadeCmd 4c1b _InvCmd 4c1f _StatShade 4c23 _dspmattable 4c27 _dsplsts 4c2b _closeEditBuf 4c2f _parseEditBuf 4c33 _putsm 4c37 _DspCurTbl 4c3b _DspGrTbl 4c3f _ZeroTemplate 4c43 _settblrefs 4c47 _dispTblBot 4c4b _DispTblTop 4c4f _dispTblbody 4c53 _VPutBlank 4c57 _TblTrace 4c5b _dispListNameY 4c5f _CurNameLength 4c63 _NameToBuf 4c67 _jpromptcursor 4c6a _bufLeft 4c6e _bufRight 4c72 _bufInsert 4c76 _bufQueueChar 4c7a _bufReplace 4c7e _bufDelete 4c82 _bufPeek 4c86 _bufPeek1 4c8a _bufPeek2 4c8e _bufPeek3 4c92 _BufToBtm 4c96 _setupEditEqu 4c9a _bufToTop 4c9e _isEditFull 4ca2 _isEditEmpty 4ca6 _isAtTop 4caa _isAtBtm 4cae _bufClear 4cb2 _JcursorFirst 4cb5 _JcursorLast 4cb8 _cursorLeft 4cbc _JcursorRight 4cbf _JcursorUp 4cc2 _cursorDown 4cc6 _cursorToOffset 4cca _insDisp 4cce _FDISPBOL1 4cd2 _FDISPBOL 4cd6 _dispEOW 4cda _dispHead 4cde _dispTail 4ce2 _PutTokString 4ce6 _setupEditCmd 4cea _setEmptyEditEqU 4cee _setEmptyEditPtR 4cf2 _closeEditEqu 4cf6 _toggleIns 4cfa _GetPrevTok 4cfe _getkey 4d02 _canIndic 4d06 _LCD_DriverOn 4d0a _DFMIN2 4d0e _formDisp 4d12 _formMatrix 4d16 _wscrollLeft 4d1a _wscrollUp 4d1e _wscrollDown 4d22 _wscrollRight 4d26 _formEReal 4d2a _formERealTOK 4d2e _formDCplx 4d32 _formReal 4d36 _formScrollUp 4d3a _setwinabove 4d3e _disarmScroll 4d42 _OP1toEdit 4d46 _MinToEdit 4d4a _rclVarToEdit 4d4e _rclVarToEditPtR 4d52 _RclEntryToEdit 4d56 _rclToQueue 4d5a _FormToTok 4d5e _Disp_Interval 4d62 _DisplstName 4d66 _dispSLstNameHL 4d6a _EditEqu 4d6e _closeEquField 4d72 _AutoSelect 4d76 _DISPYEOS 4d7a _dispNumEOS 4d7e _setupdispeq 4d82 _dispForward 4d86 _DispYPrompt2 4d8a _stringwidth 4d8e _dispErrorScreeN 4d92 _PopCx 4d96 _loadnoeentry 4d9a _SaveScreen 4d9e _RetScreen 4da2 _RetScreenErr 4da6 _SplitChange 4daa _SolveRedisp 4dae _SolveDisp 4db2 _itemName 4db6 _SetNorm_Vals 4dba _SetVert_Vals 4dbe _ConvKeyToTok 4dc2 _KeyToTokNew2B 4dc6 _KeyToTok2Byte 4dca _TokToKey 4dce _Load_LFont 4dd2 _Send1BErr 4dd6 _GetVarCmd 4dda _SendVarCmd 4dde _PrintScreen 4de2 _KeyScnLnk 4de6 _IOResetAll 4dea _DelRes 4dee _ConvLCtoLR 4df2 _RedimMat 4df6 _IncLstSize 4dfa _insertlist 4dfe _dellistel 4e02 _EditProg 4e06 _CloseProg 4e0a _ClrGraphRef 4e0e _FixTempCnt 4e12 _SaveData 4e16 _RestoreData 4e1a _FindAlphaup 4e1e _FindAlphadn 4e22 _CmpSyms 4e26 _CreateTemp 4e2a _CleanAll 4e2e _MoveToNextSym 4e32 _ConvLRtoLC 4e36 _TblScreenDn 4e3a _TblScreenUp 4e3e _ScreenUp 4e42 _ScreenUpDown 4e46 _ZifRclHandler 4e4a _zifrclkapp 4e4e _rclkeyRtn 4e52 _RclKey 4e55 _RclRegEq_Call 4e59 _RclRegEq 4e5c _initNamePrompt 4e60 _NamePrompt2 4e64 _CatalogChk 4e68 _clrTR 4e6c _Quad 4e70 _GraphQuad 4e74 _BC2NonReal 4e78 _ErrNonReal 4e7c _Write_Text 4e80 _FORSEQINIT 4e84 _GrphPars 4e88 _PlotPars 4e8c _PARSEinp 4e90 _PARSEOFF 4e94 _PARSESCAN 4e98 _GetParse 4e9c _SaveParse 4ea0 _InitPFlgs 4ea4 _CkEndLinErr 4ea8 _OP2Set60 4eac _GetStatPtr 4eb0 _Cmp_StatPtr 4eb4 _VarSysAdr 4eb8 _StoSysTok 4ebc _StoAns 4ec0 _StoTheta 4ec4 _StoR 4ec8 _StoY 4ecc _StoN 4ed0 _StoT 4ed4 _StoX 4ed8 _StoOther 4edc _RCLANS 4ee0 _RclY 4ee4 _RclN 4ee8 _RclX 4eec _RclVarSym 4ef0 _RclSysTok 4ef4 _StMatEl 4ef8 _StLstVecEl 4efc _ConvOP1 4f00 _isaletter 4f04 _Find_Parse_ForMULA 4f08 _Parse_Formula 4f0c _StrngEnt1 4f15 _GetNumLet 4f1e _Init_Prog_List 4f27 _PRGRDLP 4f30 _VarEnt 4f39 _RclStat 4f42 _ParseLoop 4f4b _ParseOnC 4f52 _ParseOn 4f5a _ParseCmd 4f61 _StoType 4f6a _CreatePair 4f73 _PushNum 4f7c _IncCurPCErrEnd 4f85 _ErrEnd 4f8e _CommaErrF 4f97 _CommaErr 4fa0 _StEqArg2 4fa9 _StEqArg 4fb2 _InpArg 4fbb _StEqArg3 4fc4 _NxtFetch 4fcd _CkFetchVar 4fd6 _FetchVarA 4fdf PARSER_EXEC 4fe3 _FetchVar 4fec _CkEndLin 4ff5 _CkEndExp 4ffe _CkParsEnd 5007 _StoTypeArg 5010 _ConvDim 5019 _ConvDim00 5022 _AheadEqual 502b _ParsAheadS 5034 _ParsAhead 503d _AnsName 5046 _StoCmpReals 504f _GetDEPtr 5058 _Push2BOper 5061 _Pop2BOper 506a _PushOper 5073 _PopOper 507c _Find_E_Undef 5085 _StTmpEq 508e _FindEOL 5097 _BrkInc 50a0 _IncFetch 50a9 _CurFetch 50b2 PGMIO_EXEC 50b6 _Random 50ba _StoRand 50be _RandInit 50c2 _resetStacks 50c6 _Factorial 50ca _YOnOff 50ce _EqSelUnsel 50d2 _ITSOLVER 50d6 _GRITSOLVER 50da _ITSOLVERB 50de _ITSOLVERNB 50e2 _ExTest_INT 50e6 _Dist_Fun 50ea _LogGamma 50ee _OneVar 50f2 _OneVarS_0 50f6 _ORDSTAT 50fa _INITSTATANS2 50fe _ANOVA_SPEC 5102 _EXEC_ASSEMBLY 5106 _outputExpr 510a _CentCursor 5113 _Text 511c _FINISHSPEC 5125 _TRCYFUNC 512e _Rcl_Seq_X 5137 _RclSeq2 5140 _GRPPutAway 5149 _CkValDelX 5152 _CkValDelta 515b _GrBufClr 5164 _GrBufCpy_V 516d _FndSelEq 5176 _ClrGraphXY 517f _Next_Y_Style 5188 GRAPH_EXEC 518c _PLOTPT 5195 _NEWINDEP 519e _Axes 51a7 _setPenX 51b0 _setPenY 51b9 _setPenT 51c2 _Tan_Equ_Disp 51cb _putAns 51d4 _DispOP1A 51dd _MathTanLn 51e6 _EndDraw 51ef IO_EXEC 52e5 EXECUTE_Z80 [flags] 00 kbdFlags 2,00 trigDeg,trigFlags 3,00 kbdSCR,kbdFlags 4,00 kbdKeyPress,kbdFlags 01 editFlags 2,01 editOpen,editFlags 4,01 monAbandon,monFlags 02 plotFlags 1,02 plotLoc,plotFlags 2,02 plotDisp,plotFlags 4,02 grfFuncM,grfModeFlags 5,02 grfPolarM,grfModeFlags 6,02 grfParamM,grfModeFlags 7,02 grfRecurM,grfModeFlags 03 graphFlags 0,03 graphDraw,graphFlags 2,03 graphCursor,graphFlags 04 grfDBFlags 0,04 grfDot,grfDBFlags 1,04 grfSimul,grfDBFlags 2,04 grfGrid,grfDBFlags 3,04 grfPolar,grfDBFlags 4,04 grfNoCoord,grfDBFlags 5,04 grfNoAxis,grfDBFlags 6,04 grfLabel,grfDBFlags 05 textFlags 1,05 textEraseBelow,textFlags 2,05 textScrolled,textFlags 3,05 textInverse,textFlags 08 apdFlags 2,08 apdAble,apdFlags 3,08 apdRunning,apdFlags 09 onFlags 3,09 onRunnings,onFlags 4,09 onInterrupt,onFlags 6,09 statsValid,statFlags 10 fmtFlags 0,0A fmtExponent,fmtFlags 1,0A fmtEng,fmtFlags 5,0A fmtReal,fmtFlags 6,0A fmtRect,fmtFlags 7,0A fmtPolar,fmtFlags 0c curFlags 2,0C curAble,curFlags 3,0C curOn,curFlags 4,0C curLock,curFlags 0d appFlags 1,0D appTextSave,appFlags 2,0D appAutoScroll,appFlags 11 plotFlag2 3,11 expr_param,plotFlag2 4,11 expr_writing,plotFlag2 12 indicFlags 0,12 indicRun,indicFlags 1,12 indicInUse,indicFlags 2,12 indicOnly,indicFlags 3,12 shift2nd,shiftFlags 4,12 shiftAlpha,shiftFlags 6,12 shiftALock,shiftFlags 13 tblFlags 4,13 AutoFill,tblFlags 5,13 AutoCalc,tblFlags 14 sGrFlags 0,14 grfSplit,sGrFlags 1,14 VertSplit,sGrFlags 2,14 grfSChanged,sGrFlags 3,14 grfSplitOverride,sGrFlags 4,14 write_on_graph,sGrFlags 6,14 cmp_mod_box,sGrFlags 7,14 textWrite,sGrFlags 15 newIndicFlags 1,15 saIndic,newIndicFlags 0,1D gkKeyRepeating,gkFlag 21 asm_flag1 22 asm_flag1 23 asm_flag1 tilem-2.0/data/symbols/ti83p.sym000066400000000000000000001054331220200411600165610ustar00rootroot00000000000000[macros] 0EF B_CALL~%c 0CD5000 B_JUMP~%c 0EDED DB~$ED,$ED,%b,%b [labels] 0008 rOP1TOOP2 000B LCD_BUSY_QUICK 0010 rFINDSYM 0018 rPUSHREALO1 0020 rMOV9TOOP1 0028 rBR_CALL 0030 rFPADD 0050 BRT_JUMP0 0059 APP_PUSH_ERRORH 005C APP_POP_ERRORH [romcalls] 4000 JErrorNo 4003 FontHook 4006 LocalizeHook 4009 LdHLind 400c CpHLDE 400f DivHLBy10 4012 DivHLByA 4015 KbdScan 4018 GetCSC 401b coorMon 401e Mon 4021 monForceKey 4024 SendKPress 4027 JForceCmdNoChar 402a JForceCmd 402d sysErrHandler 4030 newContext 4033 newContext0 4036 PPutAwayPrompt 4039 PPutAway 403c PutAway 403f SizeWind 4042 ErrorEP 4045 callMain 4048 monErrHand 404b AppInit 404e initialize 4051 LCD_BUSY 4054 Min 4057 Max 405a AbsO1PAbsO2 405d Intgr 4060 Trunc 4063 InvSub 4066 Times2 4069 Plus1 406c Minus1 406f FPSub 4072 FPAdd 4075 DToR 4078 RToD 407b Cube 407e TimesPt5 4081 FPSquare 4084 FPMult 4087 LJRnd 408a InvOP1SC 408d InvOP1S 4090 InvOP2S 4093 Frac 4096 FPRecip 4099 FPDiv 409c SqRoot 409f RndGuard 40a2 RnFx 40a5 Int 40a8 Round 40ab LnX 40ae LogX 40b1 LJNoRnd 40b4 EToX 40b7 TenX 40ba SinCosRad 40bd Sin 40c0 Cos 40c3 Tan 40c6 SinHCosH 40c9 TanH 40cc CosH 40cf SinH 40d2 ACosRad 40d5 ATanRad 40d8 ATan2Rad 40db ASinRad 40de ACos 40e1 ATan 40e4 ASin 40e7 ATan2 40ea ATanH 40ed ASinH 40f0 ACosH 40f3 PToR 40f6 RToP 40f9 HLTimes9 40fc CkOP1Cplx 40ff CkOP1Real 4102 Angle 4105 COP1Set0 4108 CpOP4OP3 410b Mov9OP2Cp 410e AbsO1O2Cp 4111 CpOP1OP2 4114 OP3ToOP4 4117 OP1ToOP4 411a OP2ToOP4 411d OP4ToOP2 4120 OP3ToOP2 4123 OP1ToOP3 4126 OP5ToOP2 4129 OP5ToOP6 412c OP5ToOP4 412f OP1ToOP2 4132 OP6ToOP2 4135 OP6ToOP1 4138 OP4ToOP1 413b OP5ToOP1 413e OP3ToOP1 4141 OP6ToOP5 4144 OP4ToOP5 4147 OP3ToOP5 414a OP2ToOP5 414d OP2ToOP6 4150 OP1ToOP6 4153 OP1ToOP5 4156 OP2ToOP1 4159 Mov11B 415c Mov10B 415f Mov9B 4162 Mov18 4165 Mov8B 4168 Mov7B 416b Mov14 416e OP2ToOP3 4171 OP4ToOP3 4174 OP5ToOP3 4177 OP4ToOP6 417a Mov9ToOP1 417d Mov9OP1OP2 4180 Mov9ToOP2 4183 MovFrOP1 4186 OP4Set1 4189 OP3Set1 418c OP2Set8 418f OP2Set5 4192 OP2SetA 4195 OP2Set4 4198 OP2Set3 419b OP1Set1 419e OP1Set4 41a1 OP1Set3 41a4 OP3Set2 41a7 OP1Set2 41aa OP2Set2 41ad OP2Set1 41b0 Zero16D 41b3 OP5Set0 41b6 OP4Set0 41b9 OP3Set0 41bc OP2Set0 41bf OP1Set0 41c2 SetNum0 41c5 ZeroOP1 41c8 ZeroOP2 41cb ZeroOP3 41ce ZeroOP 41d1 ClrLp 41d4 ShRAcc 41d7 ShLAcc 41da ShR18 41dd ShR18A 41e0 ShR16 41e3 ShR14 41e6 ShL16 41e9 ShL14 41ec SRDO1 41ef ShRDRnd 41f2 MantPA 41f5 ADDPROP 41f8 ADDPROPLP 41fb Add16D 41fe Add14D 4201 Sub16D 4204 Sub14D 4207 OP2ExOP6 420a OP5ExOP6 420d OP1ExOP5 4210 OP1ExOP6 4213 OP2ExOP4 4216 OP2ExOP5 4219 OP1ExOP3 421c OP1ExOP4 421f OP1ExOP2 4222 ExLp 4225 CkOP1C0 4228 CkOP1FP0 422b CkOP2FP0 422e PosNo0Int 4231 CkPosInt 4234 CkInt 4237 CkOdd 423a CkOP1M 423d GetConOP1 4240 GetConOP2 4243 PIDIV2 4246 PIDIV4 4249 TWOPI 424c PICON 424f ExpToHex 4252 OP1ExpToDec 4255 CkOP2Pos 4258 CkOP1Pos 425b ClrOP2S 425e ClrOP1S 4261 FDiv100 4264 FDiv10 4267 DecO1Exp 426a IncO1Exp 426d IncExp 4270 CkValidNum 4273 GetExp 4276 HTimesL 4279 EOP1NotReal 427c ThetaName 427f RName 4282 RegEqName 4285 RecurNName 4288 XName 428b YName 428e TName 4291 RealName 4294 SetEStoFPS 4297 ChkTempDirt 429a OP1MOP2Exp 429d OP1ExpMDE 42a0 ChkErrBreak 42a3 IsA2ByteTok 42a6 GetLastEntry 42a9 GetLastEntryPtr 42ac RegrClrChng 42af ResetWinTop 42b2 SetYUp 42b5 SetXUp 42b8 IsO1NonTLstOrProg 42bb IsO1NonTempLst 42be Is_A_LstOrCLst 42c1 Chk_HL_999 42c4 Equ_or_NewEqu 42c7 ErrD_OP1NotPos 42ca ErrD_OP1Not_R 42cd ErrD_OP1NotPosInt 42d0 ErrD_OP1_LE_0 42d3 ErrD_OP1_0 42d6 FindSym_Get_Size 42d9 Sto_StatVar 42dc Rcl_StatVar 42df CkOP2Real 42e2 Get_X_Indirect 42e5 MemChk 42e8 CmpPrgNamLen1 42eb CmpPrgNamLen 42ee FindProgSym 42f1 ChkFindSym 42f4 FindSym 42f7 InsertMem 42fa InsertMemA 42fd EnoughMem 4300 CmpMemNeed 4303 CreatePVar4 4306 CreatePVar3 4309 CreateVar3 430c CreateCplx 430f CreateReal 4312 CreateTRList 4315 CreateRList 4318 CreateTCList 431b CreateCList 431e CreateTRMat 4321 CreateRMat 4324 CreateTStrng 4327 CreateStrng 432a Create0Equ 432d CreateTEqu 4330 CreateEqu 4333 CreatePict 4336 CreateGDB 4339 CreateProg 433c ChkDel 433f ChkDelA 4342 AdjParser 4345 AdjMath 4348 AdjM7 434b DelMemA 434e Get_Form_Num 4351 DelVar 4354 DelVarIO 4357 DelMem 435a DelVar3D 435d DelVar3C 4360 DelVar3DC 4363 Sym_Prog_Non_T_Lst 4366 AdjSymPtrs 4369 DataSizeA 436c DataSize 436f PopMCplxO1 4372 PopMCplx 4375 MovCplx 4378 PopOP5 437b PopOP3 437e PopOP1 4381 PopRealO6 4384 PopRealO5 4387 PopRealO4 438a PopRealO3 438d PopRealO2 4390 PopRealO1 4393 PopReal 4396 FPopCplx 4399 FPopReal 439c FPopFPS 439f DeallocFPS 43a2 DeallocFPS1 43a5 AllocFPS 43a8 AllocFPS1 43ab PushRealO6 43ae PushRealO5 43b1 PushRealO4 43b4 PushRealO3 43b7 PushRealO2 43ba PushRealO1 43bd PushReal 43c0 PushOP5 43c3 PushOP3 43c6 PushMCplxO3 43c9 PushOP1 43cc PushMCplxOP1 43cf PushMCplx 43d2 ExMCplxO1 43d5 Exch9 43d8 CpyTo1FPS11 43db CpyTo2FPS5 43de CpyTo1FPS5 43e1 CpyTo2FPS6 43e4 CpyTo1FPS6 43e7 CpyTo2FPS7 43ea CpyTo1FPS7 43ed CpyTo1FPS8 43f0 CpyTo2FPS8 43f3 CpyTo1FPS10 43f6 CpyTo1FPS9 43f9 CpyTo2FPS4 43fc CpyTo6FPS3 43ff CpyTo6FPS2 4402 CpyTo2FPS3 4405 CpyCTo1FPS3 4408 CpyTo1FPS3 440b CpyFPS3 440e CpyTo1FPS4 4411 CpyTo3FPS2 4414 CpyTo5FPST 4417 CpyTo6FPST 441a CpyTo4FPST 441d CpyTo3FPST 4420 CpyTo2FPST 4423 CpyTo1FPST 4426 CpyFPST 4429 CpyStack 442c CpyTo3FPS1 442f CpyTo2FPS1 4432 CpyTo1FPS1 4435 CpyFPS1 4438 CpyTo2FPS2 443b CpyTo1FPS2 443e CpyFPS2 4441 CpyO3ToFPST 4444 CpyO2ToFPST 4447 CpyO6ToFPST 444a CpyO1ToFPST 444d CpyToFPST 4450 CpyToStack 4453 CpyO3ToFPS1 4456 CpyO5ToFPS1 4459 CpyO2ToFPS1 445c CpyO1ToFPS1 445f CpyToFPS1 4462 CpyO2ToFPS2 4465 CpyO3ToFPS2 4468 CpyO6ToFPS2 446b CpyO1ToFPS2 446e CpyToFPS2 4471 CpyO5ToFPS3 4474 CpyO2ToFPS3 4477 CpyO1ToFPS3 447a CpyToFPS3 447d CpyO1ToFPS6 4480 CpyO1ToFPS7 4483 CpyO1ToFPS5 4486 CpyO2ToFPS4 4489 CpyO1ToFPS4 448c ErrNotEnoughMem 448f FPSMinus9 4492 HLMinus9 4495 ErrOverflow 4498 ErrDivBy0 449b ErrSingularMat 449e ErrDomain 44a1 ErrIncrement 44a4 ErrNon_Real 44a7 ErrSyntax 44aa ErrDataType 44ad ErrArgument 44b0 ErrDimMismatch 44b3 ErrDimension 44b6 ErrUndefined 44b9 ErrMemory 44bc ErrInvalid 44bf ErrBreak 44c2 ErrStat 44c5 ErrSignChange 44c8 ErrIterations 44cb ErrBadGuess 44ce ErrTolTooSmall 44d1 ErrStatPlot 44d4 ErrLinkXmit 44d7 JError 44da noErrorEntry 44dd pushErrorHandler 44e0 popErrorHandler 44e3 StrCopy 44e6 StrCat 44e9 IsInSet 44ec GEQNAMEA 44ef RECNAME 44f2 __bank_call 44f5 __bank_ret 44f8 __bank_jump 44fb __bank_entry 44fe ReadDisp2 4501 PutMap 4504 PutC 4507 DispHL 450a PutS 450d PutPSB 4510 PutPS 4513 WPutPS 4516 PutBuf 4519 PutBuf1 451c WPutC 451f WPutS 4522 WPutSEOL 4525 WDispEOL 4528 WHomeUp 452b SetNumWindow 452e NewLine 4531 MoveDown 4534 ScrollUp 4537 ShrinkWindow 453a MoveUp 453d ScrollDown 4540 ClrLCDFull 4543 ClrLCD 4546 ClrScrnFull 4549 ClrScrn 454c ClrTxtShd 454f ClrWindow 4552 EraseEOL 4555 EraseEOW 4558 HomeUp 455b GetCurLoc 455e VPutMap 4561 VPutS 4564 VPutSN 4567 VPutSNG 456a VPutSNT 456d RunIndicOn 4570 RunIndicOff 4573 SaveCmdShadow 4576 SaveShadow 4579 RstrShadow 457c RstrPartial 457f RstrCurRow 4582 RstrUnderMenu 4585 RstrBotRow 4588 SaveTR 458b RestoreTR 458e GetKeyPress 4591 GetTokLen 4594 Get_Tok_Strng 4597 GetTokString 459a PUTBPATBUF2 459d PUTBPATBUF 45a0 PUTBPAT 45a3 putcCheckScroll 45a6 DispEOL 45a9 fdispEOL 45ac MakeRowCmd 45af TOTOSTRP 45b2 SetVarName 45b5 DispDone 45b8 FinishOutput 45bb CurBlink 45be CursorOff 45c1 HideCursor 45c4 CursorOn 45c7 ShowCursor 45ca KeyToString 45cd PullDownChk 45d0 MenuCatCommon 45d3 LoadCurCat 45d6 NCifprgmedmode 45d9 LoadMenuNum 45dc LoadMenuNumL 45df 45e2 MenCatRet 45e5 NotAlphNum 45e8 SaveSavedFlags 45eb SetMenuFlags 45ee RstrSomeFlags 45f1 RstrSmallText 45f4 DispListName 45f7 RstrOScreen 45fa SaveOScreen 45fd DispLAlphaName 4600 AbortPrgmode 4603 Is_FullCntx 4606 AdrMRow 4609 AdrMEle 460c GetMatOP1A 460f GetM1ToOP1 4612 GetM1TOP1A 4615 GetMToOP1 4618 PutToM1A 461b PutToMa1 461e PutToMat 4621 Mat_El_Div 4624 CMATFUN 4627 RowEch_Poly 462a RowEchelon 462d AdrLEle 4630 GetL1ToOP1 4633 GetL1TOP1A 4636 GetLToOP1 4639 GetL1TOOP2 463c GetL1TOP2A 463f GetL2TOP1A 4642 PutToLA1 4645 PutToL 4648 MaxMinLst 464b LLow 464e LHigh 4651 LSum 4654 CumSum 4657 ToFrac 465a SeqSet 465d SeqSolve 4660 Cmp_Num_Init 4663 BinOPExec 4666 ExMean1 4669 Set2MVLPtrs 466c SetMat1 466f CreateTList 4672 UnOPExec 4675 ThreeExec 4678 RestoreErrNo 467b FourExec 467e FiveExec 4681 CpyTo2ES1 4684 CpyTo6ES1 4687 CpyTo1ES1 468a CpyTo3ES1 468d CpyTo3ES2 4690 CpyTo2ES2 4693 CpyTo1ES2 4696 CpyTo2ES3 4699 CpyTo1ES3 469c CpyTo3ES4 469f CpyTo6ES3 46a2 CpyTo2ES4 46a5 CpyTo1ES4 46a8 CpyTo2ES5 46ab CpyTo1ES5 46ae CpyTo4EST 46b1 CpyTo2EST 46b4 CpyTo1EST 46b7 CpyTo2ES6 46ba CpyTo1ES6 46bd CpyTo2ES7 46c0 CpyTo1ES7 46c3 CpyTo2ES8 46c6 CpyTo1ES8 46c9 CpyTo1ES9 46cc CpyTo2ES9 46cf CpyTo2ES10 46d2 CpyTo1ES10 46d5 CpyTo2ES11 46d8 CpyTo1ES11 46db CpyTo2ES12 46de CpyTo1ES12 46e1 CpyTo2ES13 46e4 CpyTo1ES13 46e7 CpyTo1ES14 46ea CpyTo1ES16 46ed CpyTo1ES17 46f0 CpyTo1ES18 46f3 CpyTo1ES15 46f6 CpyTo2ES15 46f9 CpyO1ToEST 46fc CpyO1ToES1 46ff CpyO6ToES1 4702 CpyO6ToES3 4705 CpyO1ToES2 4708 CpyO2ToES2 470b CpyO1ToES3 470e CpyO1ToES4 4711 CpyO1ToES5 4714 CpyO1ToES6 4717 CpyO1ToES7 471a CpyO2ToES4 471d CpyO2ToES5 4720 CpyO2ToES6 4723 CpyO2ToES7 4726 CpyO2ToES8 4729 CpyO2ToES9 472c CpyO1ToES8 472f CpyO1ToES9 4732 CpyO1ToES10 4735 CpyO1ToES11 4738 CpyO1ToES12 473b CpyO1ToES13 473e CpyO1ToES14 4741 EvalF3A 4744 GetK 4747 SetTitle 474a DispVarVal 474d RecallEd 4750 SetupBuffer 4753 CreateNumEditBuf 4756 CallCommon 4759 CommonKeys 475c Leftmore 475f fDel 4762 fClear 4765 fInsDisp 4768 fInsDisp02 476b SetIndicator 476e CloseEditBufNoR 4771 ReleaseBuffer 4774 VarNameToOP1HL 4777 NameToOP1 477a numPPutAway 477d numRedisp 4780 numError02 4783 Load_SFont 4786 SFont_Len 4789 InitNumVec 478c SetXXOP1 478f SetXXOP2 4792 SetXXXXOP2 4795 UCLineS 4798 CLine 479b CLineS 479e XRootY 47a1 YToX 47a4 ZmStats 47a7 Point_Stat_Hlp 47aa DrawSPlot 47ad InitNewTraceP 47b0 SPlotCoord 47b3 SPlotRight 47b6 SPlotLeft 47b9 CmpBoxInfo 47bc NextPlot 47bf PrevPlot 47c2 ClrPrevPlot 47c5 Put_Index_Lst 47c8 Get_Index_Lst 47cb Heap_Sort 47ce StoGDB2 47d1 RclGDB2 47d4 CircCmd 47d7 GrphCirc 47da Mov18B 47dd DarkLine 47e0 ILine 47e3 IPoint 47e6 XYRndBoth 47e9 XYRnd 47ec CheckTop 47ef CheckXY 47f2 DarkPnt 47f5 CPointS 47f8 WToV 47fb VtoWHLDE 47fe Xitof 4801 YftoI 4804 XftoI 4807 TraceOff 480a GrRedisp 480d GDispToken 4810 GRDECODA 4813 LabCoor 4816 CoorDisp 4819 TmpEquNoSrc 481c GrLabels 481f YPixSet 4822 XPixSet 4825 CopyRng 4828 ValCur 482b GrPutAway 482e RstGFlags 4831 GrReset 4834 XYCent 4837 ZoomXYCmd 483a CptDelY 483d CptDelX 4840 SetFuncM 4843 SetSeqM 4846 SetPolM 4849 SetParM 484c ZmInt 484f ZmDecml 4852 ZmPrev 4855 ZmUsr 4858 SetUZm 485b ZmFit 485e ZmSquare 4861 ZmTrig 4864 SetXMinMax 4867 ZooDefault 486a GrBufCpy 486d DrawSplitLine 4870 RestoreDisp 4873 FNDDB 4876 AllEq 4879 FndAllSelEq 487c NextEq 487f PrevEq 4882 BlinkGCur 4885 NBCursor 4888 StatMark 488b ChkTextCurs 488e Regraph 4891 DoRefFlags02 4894 YRes 4897 PlotPtXY2 489a Ceiling 489d PutXY 48a0 PutEquNo 48a3 PDspGrph 48a6 HorizCmd 48a9 VertCmd 48ac LineCmd 48af UnLineCmd 48b2 PointCmd 48b5 PixelTest 48b8 PixelCmd 48bb TanLnF 48be DrawCmd_Init 48c1 DrawCmd 48c4 ShadeCmd 48c7 InvCmd 48ca StatShade 48cd DspMatTable 48d0 DspLsts 48d3 CloseEditBuf 48d6 ParseEditBuf 48d9 PutSM 48dc DspCurTbl 48df DspGrTbl 48e2 ZeroTemplate 48e5 SetTblRefs 48e8 DispTblBot 48eb DispTblTop 48ee DispTblBody 48f1 VPutBlank 48f4 TblTrace 48f7 DispListNameY 48fa CurNameLength 48fd NameToBuf 4900 JPromptCursor 4903 BufLeft 4906 BufRight 4909 BufInsert 490c BufQueueChar 490f BufReplace 4912 BufDelete 4915 BufPeek 4918 BufPeek1 491b BufPeek2 491e BufPeek3 4921 BufToBtm 4924 SetupEditEqu 4927 BufToTop 492a IsEditFull 492d IsEditEmpty 4930 IsAtTop 4933 IsAtBtm 4936 BufClear 4939 JCursorFirst 493c JCursorLast 493f CursorLeft 4942 JCursorRight 4945 JCursorUp 4948 CursorDown 494b CursorToOffset 494e InsDisp 4951 FDispBOL1 4954 FDispBOL 4957 DispEOW 495a DispHead 495d DispTail 4960 PutTokString 4963 SetupEditCmd 4966 SetEmptyEditEqu 4969 SetEmptyEditPtr 496c CloseEditEqu 496f GetPrevTok 4972 GetKey 4975 CanIndic 4978 LCD_DRIVERON 497b DFMIN2 497e FormDisp 4981 FormMatrix 4984 WScrollLeft 4987 WScrollUp 498a WScrollDown 498d WScrollRight 4990 FormEReal 4993 FormERealTok 4996 FormDCplx 4999 FormReal 499c FormScrollUp 499f SetWinAbove 49a2 DisarmScroll 49a5 OP1toEdit 49a8 MinToEdit 49ab RclVarToEdit 49ae RclVarToEditPtr 49b1 RclEntryToEdit 49b4 RclToQueue 49b7 FormToTok 49ba Disp_Interval 49bd DispLstName 49c0 DispSLstNameHL 49c3 EditEqu 49c6 CloseEquField 49c9 AutoSelect 49cc DispYEOS 49cf DispNumEOS 49d2 SetupDispEq 49d5 DispForward 49d8 DispYPrompt2 49db StringWidth 49de DispErrorScreen 49e1 PopCx 49e4 LoadNoEEntry 49e7 SaveScreen 49ea RetScreen 49ed RetScreenErr 49f0 CheckSplitFlag 49f3 SolveRedisp 49f6 SolveDisp 49f9 ItemName 49fc SetNorm_Vals 49ff SetVert_Vals 4a02 ConvKeyToTok 4a05 KeyToTokNew2B 4a08 KeyToTok2Byte 4a0b TokToKey 4a0e Send1BErr 4a11 GetVarCmd 4a14 SendVarCmd 4a17 PrintScreen 4a1a KeyScnLnk 4a1d IOResetAll 4a20 DelRes 4a23 ConvLcToLr 4a26 RedimMat 4a29 IncLstSize 4a2c InsertList 4a2f DelListEl 4a32 EditProg 4a35 CloseProg 4a38 ClrGraphRef 4a3b FixTempCnt 4a3e SaveData 4a41 RestoreData 4a44 FindAlphaUp 4a47 FindAlphaDn 4a4a CmpSyms 4a4d CreateTemp 4a50 CleanAll 4a53 MoveToNextSym 4a56 ConvLrToLc 4a59 TblScreenDn 4a5c TblScreenUp 4a5f ScreenUp 4a62 ScreenUpDown 4a65 ZIfRclHandler 4a68 ZIfRclKApp 4a6b RclKey 4a6e RclKey2 4a71 RclRegEq 4a74 RclRegEq2 4a77 InitNamePrompt 4a7a NamePrompt2 4a7d CatalogChk 4a80 ClrTR 4a83 Quad 4a86 GraphQuad 4a89 BC2NonReal 4a8c ErrNonReal 4a8f Write_Text 4a92 ForSeqInit 4a95 GrphPars 4a98 PlotPars 4a9b ParseInp 4a9e ParseOff 4aa1 ParseScan 4aa4 GetParse 4aa7 SaveParse 4aaa InitPFlgs 4aad CkEndLinErr 4ab0 OP2Set60 4ab3 GetStatPtr 4ab6 Cmp_StatPtr 4ab9 VarSysAdr 4abc StoSysTok 4abf StoAns 4ac2 StoTheta 4ac5 StoR 4ac8 StoY 4acb StoN 4ace StoT 4ad1 StoX 4ad4 StoOther 4ad7 RclAns 4ada RclY 4add RclN 4ae0 RclX 4ae3 RclVarSym 4ae6 RclSysTok 4ae9 StMatEl 4aec StLstVecEl 4aef ConvOP1 4af2 Find_Parse_Formula 4af5 Parse_Formula 4af8 StrngEnt1 4afb PrgRdLp 4afe VarEnt 4b01 ParseOnC 4b04 ParseOn 4b07 ParseCmd 4b0a StoType 4b0d CreatePair 4b10 PushNum 4b13 IncCurPCErrEnd 4b16 ErrEnd 4b19 CommaErrF 4b1c CommaErr 4b1f StEqArg2 4b22 StEqArg 4b25 InpArg 4b28 StEqArg3 4b2b NxtFetch 4b2e CkFetchVar 4b31 FetchVarA 4b34 FetchVar 4b37 CkEndLin 4b3a CkEndExp 4b3d CkParsEnd 4b40 StoTypeArg 4b43 ConvDim 4b46 ConvDim00 4b49 AheadEqual 4b4c ParsAheadS 4b4f ParsAhead 4b52 AnsName 4b55 StoCmpReals 4b58 GetDEPtr 4b5b Push2BOper 4b5e Pop2BOper 4b61 PushOper 4b64 PopOper 4b67 Find_E_UndefOrArchived 4b6a StTmpEq 4b6d FindEOL 4b70 BrkInc 4b73 IncFetch 4b76 CurFetch 4b79 Random 4b7c StoRand 4b7f RandInit 4b82 ResetStacks 4b85 Factorial 4b88 YOnOff 4b8b EqSelUnsel 4b8e ITSOLVER 4b91 GRITSOLVER 4b94 ITSOLVERB 4b97 ITSOLVERNB 4b9a ExTest_INT 4b9d Dist_Fun 4ba0 LogGamma 4ba3 OneVar 4ba6 OneVarS_0 4ba9 OrdStat 4bac InitStatAns2 4baf ANOVA_Spec 4bb2 OutputExpr 4bb5 CentCursor 4bb8 Text 4bbb FinishSpec 4bbe TRCYFUNC 4bc1 Rcl_Seq_X 4bc4 RclSeq2 4bc7 GrPPutAway 4bca CkValDelX 4bcd CkValDelta 4bd0 GrBufClr 4bd3 GrBufCpy_V 4bd6 FndSelEq 4bd9 ClrGraphXY 4bdc Next_Y_Style 4bdf PlotPt 4be2 NewIndep 4be5 Axes 4be8 SetPenX 4beb SetPenY 4bee SetPenT 4bf1 Tan_Equ_Disp 4bf4 PutAns 4bf7 DispOP1A 4bfa MathTanLn 4bfd EndDraw 4c00 SetTblGraphDraw 4c03 StartDialog 4c06 DialogInit 4c09 GetDialogNumOP1 4c0c SetDialogNumOP1 4c0f GetDialogNumHL 4c12 4c15 SetDialogKeyOverride 4c18 ResDialogKeyOverride 4c1b ForceDialogKeypress 4c1e DialogStartGetKey 4c21 StartDialog_Override 4c24 CallDialogCallback 4c27 SetDialogCallback 4c2a ResDialogCallback 4c2d CopyDialogNum 4c30 MemClear 4c33 MemSet 4c36 ReloadAppEntryVecs 4c39 PointOn 4c3c ExecuteNewPrgm 4c3f StrLength 4c42 UserPutMap 4c45 GetCurrentPageSub 4c48 FindAppUp 4c4b FindAppDn 4c4e FindApp 4c51 ExecuteApp 4c54 MonReset 4c57 4c5a 4c5d 4c60 IBounds 4c63 IOffset 4c66 DrawCirc2 4c69 CanAlphIns 4c6c Redisp 4c6f GetBaseVer 4c72 SetFP0 4c75 AppGetCbl 4c78 AppGetCalc 4c7b SaveDisp 4c7e SetIgnoreKey 4c81 SetSendThisKeyBack 4c84 DisableApd 4c87 EnableApd 4c8a 4c8d 4c90 forcecmd 4c93 ApdSetup 4c96 Get_NumKey 4c99 AppSetup 4c9c HandleLinkActivity 4c9f 4ca2 ReleaseSedit 4ca5 initsmalleditline 4ca8 startsmalledit 4cab 4cae SGetTokString 4cb1 LoadPattern 4cb4 SStringLength 4cb7 4cba 4cbd DoNothing 4cc0 4cc3 4cc6 4cc9 4ccc 4ccf SmallEditEraseEOL 4cd2 4cd5 4cd8 4cdb initsmalleditBox 4cde 4ce1 EmptyHook 4ce4 4ce7 4cea 4ced ClearRow 4cf0 4cf3 SetupSmallEditCursor 4cf6 4cf9 4cfc 4cff 4d02 4d05 4d08 4d0b 4d0e 4d11 4d14 4d17 4d1a 4d1d 4d20 4d23 4d26 AppScreenUpDown 4d29 AppScreenUpDown1 4d2c 4d2f initsmalleditlinevar 4d32 initsmalleditlineop1 4d35 initsmalleditboxvar 4d38 initsmalleditboxop1 4d3b 4d3e 4d41 ErrCustom1 4d44 ErrCustom2 4d47 AppStartMouse 4d4a 4d4d 4d50 4d53 AppEraseMouse 4d56 4d59 ATimes12 4d5c ClearRect 4d5f InvertRect 4d62 FillRect 4d65 AppUpdateMouse 4d68 4d6b 4d6e initcellbox 4d71 drawcell 4d74 4d77 invertcell 4d7a setcelloverride 4d7d DrawRectBorder 4d80 ClearCell 4d83 covercell 4d86 EraseRectBorder 4d89 FillRectPattern 4d8c DrawRectBorderClear 4d8f 4d92 4d95 VerticalLine 4d98 IBoundsFull 4d9b DisplayImage 4d9e 4da1 4da4 4da7 4daa 4dad 4db0 4db3 4db6 4db9 4dbc 4dbf 4dc2 4dc5 4dc8 CPoint 4dcb DeleteApp 4dce 4dd1 setmodecellflag 4dd4 resetmodecellflag 4dd7 ismodecellset 4dda getmodecellflag 4ddd 4de0 CellBoxManager 4de3 startnewcell 4de6 4de9 CellCursorHandle 4dec 4def 4df2 ClearCurCell 4df5 drawcurcell 4df8 invertcurcell 4dfb covercurcell 4dfe BlinkCell 4e01 BlinkCellNoLookUp 4e04 BlinkCurCell 4e07 BlinkCellToOn 4e0a BlinkCellToOnNoLookUp 4e0d BlinkCurCellToOn 4e10 BlinkCellToOff 4e13 BlinkCellToOffNoLookUp 4e16 BlinkCurCellToOff 4e19 getcurmodecellflag 4e1c 4e1f startsmalleditreturn 4e22 4e25 4e28 CellkHandle 4e2b errchkalphabox 4e2e 4e31 4e34 4e37 4e3a eraseallcells 4e3d iscurmodecellset 4e40 4e43 initalphabox 4e46 4e49 4e4c drawblnkcell 4e4f ClearBlnkCell 4e52 invertblnkcell 4e55 4e58 4e5b 4e5e 4e61 4e64 4e67 HorizontalLine 4e6a CreateAppVar 4e6d CreateProtProg 4e70 CreateVar 4e73 AsmComp 4e76 GetAsmSize 4e79 SquishPrgm 4e7c ExecutePrgm 4e7f ChkFindSymAsm 4e82 ParsePrgmName 4e85 CSub 4e88 CAdd 4e8b CSquare 4e8e CMult 4e91 CRecip 4e94 CDiv 4e97 CAbs 4e9a CSqrAbs 4e9d CSqRoot 4ea0 CLN 4ea3 CLog 4ea6 CTenX 4ea9 CEtoX 4eac CXrootY 4eaf 4eb2 CYtoX 4eb5 Conj 4eb8 CMltByReal 4ebb CDivByReal 4ebe CTrunc 4ec1 CFrac 4ec4 CIntgr 4ec7 SendHeaderPacket 4eca CancelTransmission 4ecd SendScreenContents 4ed0 SendRAMVarData 4ed3 SendRAMCmd 4ed6 SendPacket 4ed9 ReceiveAck 4edc Send4BytePacket 4edf SendDataByte 4ee2 Send4Bytes 4ee5 SendAByte 4ee8 SendCByte 4eeb GetSmallPacket 4eee GetDataPacket 4ef1 SendAck 4ef4 Get4Bytes 4ef7 Get3Bytes 4efa Rec1stByte 4efd Rec1stByteNC 4f00 ContinueGetByte 4f03 RecAByteIO 4f06 ReceiveVar 4f09 ReceiveVarData2 4f0c ReceiveVarData 4f0f SrchVLstUp 4f12 SrchVLstDn 4f15 SendVariable 4f18 Get4BytesCursor 4f1b Get4BytesNC 4f1e 4f21 SendDirectoryContents 4f24 SendReadyPacket 4f27 4f2a 4f2d 4f30 SendApplication 4f33 SendOSHeader 4f36 SendOSPage 4f39 SendOS 4f3c FlashWriteDisable 4f3f SendCmd 4f42 SendOSSignature 4f45 Disp 4f48 SendGetKeyPress 4f4b RejectCommand 4f4e CheckLinkLines 4f51 GetHookByte 4f54 LoadBIndPaged 4f57 CursorHook 4f5a LibraryHook 4f5d RawKeyHook 4f60 SetCursorHook 4f63 SetLibraryHook 4f66 SetRawKeyHook 4f69 ClrCursorHook 4f6c ClrLibraryHook 4f6f ClrRawKeyHook 4f72 ResetHookBytes 4f75 AdjustAllHooks 4f78 GetKeyHook 4f7b SetGetKeyHook 4f7e ClrGetKeyHook 4f81 LinkActivityHook 4f84 SetLinkActivityHook 4f87 ClrLinkActivityHook 4f8a 4f8d SetCatalog2Hook 4f90 ClrCatalog2Hook 4f93 SetLocalizeHook 4f96 ClrLocalizeHook 4f99 SetTokenHook 4f9c ClrTokenHook 4f9f 4fa2 4fa5 4fa8 Bit_VertSplit 4fab SetHomeScreenHook 4fae ClrHomeScreenHook 4fb1 SetWindowHook 4fb4 ClrWindowHook 4fb7 SetGraphHook 4fba ClrGraphHook 4fbd 4fc0 4fc3 4fc6 DelVarArc 4fc9 DelVarNoArc 4fcc SetAllPlots 4fcf SetYEquHook 4fd2 ClrYEquHook 4fd5 ForceYEqu 4fd8 Arc_Unarc 4fdb ArchiveVar 4fde UnarchiveVar 4fe1 ResDialogKeyOverride 4fe4 SetFontHook 4fe7 ClrFontHook 4fea SetRegraphHook 4fed ClrRegraphHook 4ff0 RegraphHook 4ff3 SetTraceHook 4ff6 ClrTraceHook 4ff9 TraceHook 4ffc 4fff 5002 JForceGraphNoKey 5005 JForceGraphKey 5008 PowerOff 500b GetKeyRetOff 500e FindGroupSym 5011 FillBasePageTable 5014 ArcChk 5017 FlashToRam 501a LoadDEIndPaged 501d LoadCIndPaged 5020 SetupPagedPtr 5023 PagedGet 5026 SetParserHook 5029 ClrParserHook 502c SetAppChangeHook 502f ClrAppChangeHook 5032 SetDrawingHook 5035 ClrDrawingHook 5038 IPoint_NoHook 503b ILine_NoHook 503e CLineS_NoHook 5041 DeleteTempPrograms 5044 SetCatalog1Hook 5047 ClrCatalog1Hook 504a SetHelpHook 504d ClrHelpHook 5050 5053 5056 5059 Catalog2Hook 505c Catalog1Hook 505f 5062 5065 DispMenuTitle 5068 506b SetCxRedispHook 506e ClrCxRedispHook 5071 BufCpy 5074 BufClr 5077 507a 507d 5080 DisplayVarInfo 5083 SetMenuHook 5086 ClrMenuHook 5089 GetBCOffsetIX 508c 508f ForceFullScreen 5092 GetVariableData 5095 FindSwapSector 5098 CopyFlashPage 509b FindAppNumPages 509e HLMinus5 50a1 SendArcPacket 50a4 ForceGraphKeypress 50a7 50aa FormBase 50ad 50b0 IsFragmented 50b3 Chk_Batt_Low 50b6 Chk_Batt_Low2 ## OS 1.10 50b9 Arc_Unarc2 ## OS 1.13 50bc GetAppBasePage 50bf SetExSpeed 50c2 50c5 GroupAllVars 50c8 UngroupVar 50cb WriteToFlash 50ce SetSilentLinkHook 50d1 ClrSilentLinkHook 50d4 TwoVarSet 50d7 50da 50dd GetSysInfo 50e0 NZIf83Plus 50e3 LinkStatus ## OS 1.15 50e6 50e9 DBusKeyScn ## OS 2.21 50ec RunAppLib 50ef FindSpecialAppHeader 50f2 50f5 50f8 50fb GetVarCmdUSB ## OS 2.30 50fe 5101 5104 5107 510a GetVarVersion 510d 5110 5113 5116 5119 511c 511f 5122 InvertTextInsMode 5125 5128 ResetDefaults 512b 512e DispHeader 5131 ForceGroup 5134 5137 513a 513d 5140 5143 GetRelSeconds 5146 DisableClock 5149 EnableClock 514c GetDayOfWeek 514f GetDate 5152 FormDate 5155 GetDateFmt 5158 FormDateString 515b GetTime 515e FormTime 5161 GetTimeFmt 5164 FormTimeString 5167 GetClockStatus 516a SetDateMkList 516d SetDateFmt 5170 SetTimeMkList 5173 SetTimeFmt 5176 GetAbsSeconds 5179 AbsSecondsToTimeList 517c 517f ClrWindowAndFlags 5182 SetMachineID 5185 ResetLists 5188 518b 518e 5191 ExecLib 5194 5197 519a 519d OpenLib 51a0 WaitEnterKey 51a3 51a6 51a9 51ac 51af 51b2 51b5 51b8 IsOP1Resid 51bb 51be 51c1 51c4 51c7 DispAboutScreen 51ca ChkHelpHookVer 51cd Disp32 51d0 51d3 51d6 51d9 51dc DrawTableEditor 51df 51e2 51e5 51e8 51eb 51ee 51f1 MatrixName 51f4 51f7 51fa 51fd 5200 5203 5206 5209 520c 520f 5212 5215 5218 521b 521e 5221 Chk_Batt_Level 5224 5227 522a 522d 5230 5233 GoToLastRow 5236 RectBorder 5239 523c 523f 5242 LoadA5 5245 5248 NamedListToOP1 524b 524e 5251 5254 5257 525a 525d 5260 5263 5266 5269 CheckUSBAutoLaunchHeader 526c 526f 5272 5275 5278 527b 527e 5281 5284 SetVertGraphActive 5287 ClearVertGraphActive 528a SetUSBHook 528d ClrUSBHook 5290 InitUSBDevice 5293 KillUSBPeripheral 5296 5299 529c GraphLine 529f 52a2 52a5 52a8 52ab 52ae 52b1 ZifTableEditor 52b4 52b7 52ba 52bd FindAppName 52c0 52c3 52c6 52c9 BufCpyCustom 52cc ## OS 2.40 52cf 52d2 52d5 52d8 52db 52de 52e1 52e4 DelVarSym 52e7 FindAppUpNoCase 52ea FindAppDnNoCase 52ed DeleteInvalidApps 52f0 DeleteApp_Link 52f3 52f6 SetAppRestrictions 52f9 RemoveAppRestrictions 52fc CheckAppRestrictions 52ff DispAppRestrictions 5302 SetupHome 5305 5308 530b 530e 5311 5314 PolarEquToOP1 5317 531a 531d GetRestrictionsOptions 5320 DispResetComplete 5323 5326 FindAppCustom 5329 ClearGraphStyles ## Boot 8018 MD5Final 801B RSAValidate 801E BigNumCompare 8021 WriteAByteUnsafe 8024 EraseFlash 8027 FindFirstCertificateField 802A ZeroToCertificate 802D GetCertificateEnd 8030 FindGroupedField 8033 DoNothing0 8036 DoNothing1 8039 DoNothing2 803C DoNothing3 803F DoNothing4 8042 ATimesE 8045 ATimesDE 8048 DivHLByE 804B DivHLByDE 8051 LoadAIndPaged 8054 FlashToRAM2 8057 GetCertificateStart 805A GetFieldSize 805D FindSubField 8060 EraseCertificateSector 8063 CheckHeaderKey 806C Load_BootLFontV2 806F Load_BootLFontV 8072 OSReceive 8075 FindOSHeaderSubField 8078 FindNextCertificateField 807B RecAByteBoot 807E GetCalcSerial 8084 EraseFlashPage 8087 WriteFlashUnsafe 808A DispBootVer 808D MD5Init 8090 MD5Update 8093 MarkOSInvalid 8096 FindAppKey 8099 MarkOSValid 809C CheckOSValid 809F SetupAppPubKey 80A2 RabinValidate 80A5 TransformHash 80A8 IsAppFreeware 80AB FindAppHeaderSubField 80AE RecalcValidationBytes 80B1 Div32ByDE 80B4 FindSimpleGroupedField 80B7 GetBootVer 80BA GetHWVer 80BD XorA 80C0 RSAValidateBigB 80C3 ProdNrPart1 80C6 WriteAByteSafe 80C9 WriteFlashSafe 80CC SetupDateStampPubKey 80CF SetAppLimit 80D2 BatteryError ## 84+ Boot 80E4 USBBootMainLoop 80E7 DisplaySysMessage 80EA NewLine2 80ED DisplaySysErrorAndTurnOff 80F0 CheckBattery 80F3 CheckBattery46 80F6 OSReceiveUSB 80F9 OSPacketSetup 80FC ForceReboot 80FF SetupOSPubKey 8102 CheckHeaderKeyHL [labels] 8000 ramStart 8000 appData 8100 ramCode 822F ramCodeEnd 8230 baseAppBrTab 8251 bootTemp 8269 MD5Length 8292 MD5Hash 82A3 appSearchPage 82A5 tempSwapArea 83A5 MD5Buffer 838D appID 83ED ramReturnData 83EE arcInfo 8406 savedArcInfo 8432 appInfo 843C appBank_jump 843E appPage 843F kbdScanCode 8440 kbdLGSC 8441 kbdPSC 8442 kbdWUR 8443 kbdDebncCnt 8444 kbdKey 8445 kbdGetKy 8446 keyExtend 8447 contrast 8448 apdSubTimer 8449 apdTimer 844A curTime 844B curRow 844C curCol 844D curOffset 844E curUnder 844F curY 8450 curType 8451 curXRow 8452 prevDData 845A lFont_record 8462 sFont_record 846A tokVarPtr 846C tokLen 846E indicMem 8476 indicCounter 8477 indicBusy 8478 OP1 8483 OP2 848E OP3 8499 OP4 84A4 OP5 84AF OP6 84BF progToEdit 84C7 nameBuff 84D2 equ_edit_save 84D3 iMathPtr1 84D5 iMathPtr2 84D7 iMathPtr3 84D9 iMathPtr4 84DB iMathPtr5 84DD chkDelPtr1 84DF chkDelPtr2 84E1 insDelPtr 84E3 upDownPtr 84E5 fOutDat 84EB asm_data_ptr1 84ED asm_data_ptr2 84EF asm_sym_ptr1 84F1 asm_sym_ptr2 84F3 asm_ram 8507 asm_ind_call 8508 textShadow 8588 textShadCur 858A textShadTop 858B textShadAlph 858C textShadIns 858D cxMain 858F cxPPutAway 8591 cxPutAway 8593 cxRedisp 8595 cxErrorEP 8597 cxSizeWind 8599 cxPage 859A cxCurApp 859B cxPrev 85AA monQH 85AB monQT 85AC monQueue 85BC onSP 85BE onCheckSum 85C0 promptRow 85C1 promptCol 85C2 promptIns 85C3 promptShift 85C4 promptRet 85C6 promptValid 85C8 promptTop 85CA promptCursor 85CC promptTail 85CE promptBtm 85D0 varType 85D1 varCurrent 85D9 varClass 85DA catCurrent 85DC menuActive 85DD menuAppDepth 85DE menuCurrent 85E8 progCurrent 85FE userMenuSA 865F ioPrompt 8660 RectFillPHeight 8660 dImageWidth 8661 RectFillPWidth 8662 RectFillPattern 8670 ioFlag 8672 sndRecState 8673 ioErrState 8674 header 867D ioData 8689 ioNewData 868B bakHeader 86B7 calc_id 86D7 penCol 86D8 penRow 86D9 rclQueue 86DB rclQueueEnd 86DD errNo 86DE errSP 86E0 errOffset 86EC saveSScreen 89EC usermem_offset 89EE bstCounter 89F0 flags 8A3A statVars 8C17 anovaf_vars 8C4D infVars 8D17 curGStyle 8D18 curGY 8D19 curGX 8D1A curGY2 8D1B curGX2 8D1C freeSaveY 8D1D freeSaveX 8DA1 XOffset 8DA2 YOffset 8DA3 lcdTallP 8DA4 pixWideP 8DA5 pixWide_m_1 8DA6 pixWide_m_2 8DA7 lastEntryPtr 8DA9 lastEntryStk 8E29 numLastEntries 8E2A currLastEntry 8E67 curInc 8E6A ORGXMIN 8EB4 uThetMin 8EBD uThetMax 8EC6 uThetStep 8ECF uTmin 8ED8 uTmax 8EE1 uTStep 8E7E uXmin 8E87 uXmax 8E90 uXscl 8E99 uYmin 8EA2 uYmax 8EAB uYscl 8EEA uPlotStart 8EF3 unMax 8EFC uu0 8F05 uv0 8F0E unMin 8F17 uu02 8F20 uv02 8F29 uw0 8F32 uPlotStep 8F3B uXres 8F44 uw02 8F50 Xmin 8F59 Xmax 8F62 Xscl 8F6B Ymin 8F74 Ymax 8F7D Yscl 8FB3 Tstep 8FBC PlotStart 8FC5 nMax 8FCE u0 8FD7 v0 8FE0 nMin 8FE9 u02 8FF2 v02 8FFB w0 9004 PlotStep 900D XresO 9016 w02 901F un1 9028 un2 9031 vn1 903A vn2 9043 wn1 904C wn2 9055 fin_N 905E fin_I 9067 fin_PV 9070 fin_PMT 9079 fin_FV 9082 fin_PY 908B fin_CY 9094 cal_N 909D cal_I 90A6 cal_PV 90AF cal_PMT 90B8 cal_FV 90C1 cal_PY 90D3 smallEditRAM 9151 Xres_int 913F XFact 9148 YFact 9152 deltaX 915B deltaY 9164 shortX 916D shortY 9176 lower 917F upper 8F86 ThetaMin 8F8F ThetaMax 8F98 ThetaStep 8FA1 TminPar 8FAA TmaxPar 918C XOutSym 918E XOutDat 9190 YOutSym 9192 YOutDat 9194 inputSym 9196 inputDat 9198 prevData 92C9 P1Type 92CA SavX1List 92CF SavY1List 92D4 SavF1List 92D9 P1FrqOnOff 92DA P2Type 92DB SavX2List 92E0 SavY2List 92E5 SavF2List 92EA P2FrqOnOff 92EB P3Type 92EC SavX3List 92F1 SavY3List 92F6 SavF3List 92FB P3FrqOnOff 92B3 TblMin 92BC TblStep 9302 ES 9340 plotSScreen 9640 seed1 9649 seed2 9652 parseVar 965B begPC 965D curPC 965F endPC 9776 GY1 9777 GY2 9778 GY3 9779 GY4 977A GY5 977B GY6 977C GY7 977D GY8 977E GY9 977F GY0 9780 GX1 9781 GX2 9782 GX3 9783 GX4 9784 GX5 9785 GX6 9786 GR1 9787 GR2 9788 GR3 9789 GR4 978A GR5 978B GR6 978C GU 978D GV 978E GW 966E cmdShadow 96EE cmdShadCur 96F0 cmdShadAlph 96F1 cmdShadIns 96F2 cmdCursor 96F4 editTop 96F6 editCursor 96F8 editTail 96FA editBtm 9706 editSym 9708 editDat 97A3 modePtr 97A5 winTop 97A6 winBtm 97A7 winLeftEdge 97A8 winLeft 97AA winAbove 97AC winRow 97AE winCol 97B0 fmtDigits 97B1 fmtString 97F2 fmtConv 9804 fmtLeft 9806 fmtIndex 9808 fmtMatSym 980A fmtMatMem 980C EQS 9815 delAdjAmt 9818 tSymPtr1 981A tSymPtr2 981C chkDelPtr3 981E chkDelPtr4 9820 tempMem 9822 fpBase 9824 FPS 9826 OPBase 9828 OPS 982A pTempCnt 982C cleanTmp 982E pTemp 9830 progPtr 9832 newDataPtr 9834 pagedCount 9835 pagedPN 9836 pagedGetPtr 9838 pagedPutPtr 983A pagedBuf 984D appErr1 985A appErr2 9867 flashByte1 9868 flashByte2 9869 freeArcBlock 986B arcPage 986C arcPtr 9870 appRawKeyHandle 9872 appBackUpScreen 9B72 customHeight 9B73 localLanguage 9B78 linkActivityHookPtr 9B7C cursorHookPtr 9B80 libraryHookPtr 9B84 rawKeyHookPtr 9B88 getKeyHookPtr 9B8C homescreenHookPtr 9B90 windowHookPtr 9B94 graphHookPtr 9B98 yEquHookPtr 9B9C fontHookPtr 9BA0 regraphHookPtr 9BA4 drawingHookPtr 9BA8 traceHookPtr 9BAC parserHookPtr 9BB0 appChangeHookPtr 9BB4 catalog1HookPtr 9BB8 helpHookPtr 9BBC cxRedispHookPtr 9BC0 menuHookPtr 9BC4 catalog2HookPtr 9BC8 tokenHookPtr 9BCC localizeHookPtr 9BD0 silentLinkHookPtr 9BD4 usbHookPtr 9C06 baseAppBrTab2 9CB0 DBKeyScanCode 9CB1 DBKeyRptCtr 9D65 localTokStr 9D76 keyForStr 9D77 keyToStrRam 9D88 sedMonSp 9D8A bpSave 9D95 userMem 0FE66 symTable [flags] 00 kbdFlags 0,00 inDelete,ioDelFlag 2,00 trigDeg,trigFlags 3,00 kbdSCR,kbdFlags 4,00 kbdKeyPress,kbdFlags 5,00 donePrgm,doneFlags 01 editFlags 2,01 editOpen,editFlags 4,01 monAbandon,monFlags 02 plotFlags 0,02 plotTrace,plotFlags 1,02 plotLoc,plotFlags 2,02 plotDisp,plotFlags 4,02 grfFuncM,grfModeFlags 5,02 grfPolarM,grfModeFlags 6,02 grfParamM,grfModeFlags 7,02 grfRecurM,grfModeFlags 03 graphFlags 0,03 graphDraw,graphFlags 1,03 graphProg,graphFlags 04 grfDBFlags 0,04 grfDot,grfDBFlags 1,04 grfSimul,grfDBFlags 2,04 grfGrid,grfDBFlags 3,04 grfPolar,grfDBFlags 4,04 grfNoCoord,grfDBFlags 5,04 grfNoAxis,grfDBFlags 6,04 grfLabel,grfDBFlags 05 textFlags 1,05 textEraseBelow,textFlags 2,05 textScrolled,textFlags 3,05 textInverse,textFlags 4,05 textInsMode,textFlags 07 ParsFlag2 0,07 numOP1,ParsFlag2 08 apdFlags 0,08 preClrForMode,newDispF 2,08 apdAble,apdFlags 3,08 apdRunning,apdFlags 09 onFlags 0,09 appWantAlphaUpDn,alphaUpDnFlag 3,09 onRunning,onFlags 4,09 onInterrupt,onFlags 6,09 statsValid,statFlags 7,09 statANSDISP,statFlags 0A fmtFlags 0,0A fmtExponent,fmtFlags 1,0A fmtEng,fmtFlags 2,0A fmtHex,fmtFlags 3,0A fmtOct,fmtFlags 4,0A fmtBin,fmtFlags 5,0A fmtReal,fmtFlags 6,0A fmtRect,fmtFlags 7,0A fmtPolar,fmtFlags 0B fmtOverride 0,0B fmtExponent,fmtOverride 1,0B fmtEng,fmtOverride 2,0B fmtHex,fmtOverride 3,0B fmtOct,fmtOverride 4,0B fmtBin,fmtOverride 5,0B fmtReal,fmtOverride 6,0B fmtRect,fmtOverride 7,0B fmtPolar,fmtOverride 0C curFlags 0,0C fmtEdit,fmtEditFlags 2,0C curAble,curFlags 3,0C curOn,curFlags 4,0C curLock,curFlags 5,0C cmdVirgin,cmdFlags 0D appFlags 0,0D appWantIntrpt,appFlags 1,0D appTextSave,appFlags 2,0D appAutoScroll,appFlags 3,0D appMenus,appFlags 4,0D appLockMenus,appFlags 5,0D appCurGraphic,appFlags 6,0D appCurWord,appFlags 7,0D appExit,appFlags 0E rclFlags 7,0E rclQueueActive 0F seqFlags 0,0F webMode,seqFlags 1,0F webVert,seqFlags 2,0F sequv,seqFlags 3,0F seqvw,seqFlags 4,0F sequw,seqFlags 11 promptFlags 0,11 promptEdit,promptFlags 3,11 expr_param,plotFlag2 4,11 expr_writing,plotFlag2 12 shiftFlags 0,12 indicRun,indicFlags 1,12 indicInUse,indicFlags 2,12 indicOnly,indicFlags 3,12 shift2nd,shiftFlags 4,12 shiftAlpha,shiftFlags 5,12 shiftLwrAlph,shiftFlags 6,12 shiftALock,shiftFlags 7,12 shiftKeepAlph,shiftFlags 13 tblFlags 4,13 autoFill,tblFlags 5,13 autoCalc,tblFlags 6,13 reTable,tblFlags 14 sGrFlags 0,14 grfSplit,sGrFlags 1,14 vertSplit,sGrFlags 2,14 grfSChanged,sGrFlags 3,14 grfSplitOverride,sGrFlags 4,14 write_on_graph,sGrFlags 5,14 g_style_active,sGrFlags 6,14 cmp_mod_box,sGrFlags 7,14 textWrite,sGrFlags 15 newIndicFlags 0,15 extraIndic,newIndicFlags 1,15 saIndic,newIndicFlags 16 newFlags2 5,16 noRestores,newFlags2 17 smartFlags 0,17 smartGraph,smartFlags 1,17 smartGraph_inv,smartFlags 1A more_Flags 2,1A No_Del_Stat,more_Flags 0,1D gkKeyRepeating,gkFlag 21 asm_Flag1 22 asm_Flag2 23 asm_Flag3 24 appLwrCaseFlag 1,24 comFailed,getSendFlg 3,24 lwrCaseActive,appLwrCaseFlag 26 groupFlags 1,26 inGroup,groupFlags 28 apiFlag 0,28 appAllowContext,apiFlag 4,28 appRunning,apiFlag 7,28 appRetOffKey,apiFlag 29 apiFlg2 2A apiFlg3 2B apiFlg4 2,2B fullScrnDraw,apiFlg4 2C apiFlg5 0,2C appWantDiagonalKeys,apiFlg5 2E xapFlag0 2F xapFlag1 30 xapFlag2 31 xapFlag3 32 fontFlags 2,32 fracDrawLFont,fontFlags 3,32 fracTallLFont,fontFlags 6,32 drawLFont,fontFlags 7,32 customFont,fontFlags 33 hookFlags0 0,33 alt_On,scriptFlag 1,33 alt_Off,scriptFlag 2,33 useRclQueueEnd,rclFlag2 3,33 ignoreBPLink,backGroundLink 4,33 linkActivityHookActive,linkActivityHookFlag 34 hookFlags1 0,34 getKeyHookActive,getKeyHookFlag 1,34 libraryHookActive,libraryHookFlag 4,34 homescreenHookActive,homescreenHookFlag 5,34 rawKeyHookActive,rawKeyHookFlag 6,34 catalog2HookActive,catalog2HookFlag 7,34 cursorHookActive,cursorHookFlag 35 hookFlags2 0,35 tokenHookActive,tokenHookFlag 1,35 localizeHookActive,localizeHookFlag 2,35 windowHookActive,windowHookFlag 3,35 graphHookActive,graphHookFlag 4,35 yEquHookActive,yEquHookFlag 5,35 fontHookActive,fontHookFlag 6,35 regraphHookActive,regraphHookFlag 7,35 drawingHookActive,drawingHookFlag 36 hookFlags3 0,36 traceHookActive,traceHookFlag 1,36 parserHookActive,parserHookFlag 2,36 appChangeHookActive,appChangeHookFlag 3,36 catalog1HookActive,catalog1HookFlag 4,36 helpHookActive,helpHookFlag 5,36 cxRedispHookActive,cxRedispHookFlag 6,36 menuHookActive,menuHookFlag 7,36 silentLinkHookActive,silentLinkHookFlag 37 hookAutoFlags1 38 hookAutoFlags2 39 hookAutoFlags3 3A hookFlags4 0,3A usbHookActive,usbHookFlag 3C plotFlag3 0,3C bufferOnly,plotFlag3 4,3C useFastCirc,plotFlag3 3D DBKeyFlags 0,3D leftShiftPressed,DBKeyFlags 1,3D rightShiftPressed,DBKeyFlags 2,3D diamondPressed,DBKeyFlags 3,3D squarePressed,DBKeyFlags 4,3D repeatMost,DBKeyFlags 5,3D haveDBKey,DBKeyFlags 6,3D keyDefaultsF,DBKeyFlags 7,3D HWLinkErrF,DBKeyFlags 3E openLibFlag 4,3E openLibActive,openLibFlag 3F clockFlags 0,3F clockNotMonthFirst,clockFlags 1,3F clockYearFirst,clockFlags 2,3F clock24Hour,clockFlags 4,3F clockFmtASCII,clockFlags tilem-2.0/data/symbols/ti85.sym000066400000000000000000000075531220200411600164070ustar00rootroot00000000000000[macros] 0CD098C ROM_CALL~%C 0CD0C8C CALL_~Z,prgm+%j 0CD0F8C CALL_~prgm+%j 0CD128C CALL_~NZ,prgm+%j 0CD188C CALL_~C,prgm+%j 0CD1E8C CALL_~NC,prgm+%j 0CD248C JUMP_~Z,prgm+%j 0CD278C JUMP_~prgm+%j 0CD2A8C JUMP_~NZ,prgm+%j 0CD308C JUMP_~C,prgm+%j 0CD368C JUMP_~NC,prgm+%j 0CDC88C RCALL_~%j [romcalls] 00 TX_CHARPUT 01 D_LT_STR 02 M_CHARPUT 03 D_ZM_STR 04 D_LM_STR 05 GET_T_CUR 06 SCROLL_UP 07 TR_CHARPUT 08 CLEARLCD 09 D_HL_DECI 0A CLEARTEXT 0B D_ZT_STR 0C BUSY_OFF 0D BUSY_ON 80 FIND_PIXEL [labels] 0008 rOP1TOOP2 0010 rFINDSYM 0018 rPUSHOP1 0020 rMOV10TOOP1 0028 rFPMULT 0030 rFPADD 0033 LD_HL_MHL 008E CP_HL_DE 009A UNPACK_HL 01A2 READ_KEYPAD 01B1 STORE_KEY 01BE GET_KEY 0115 UPDATE_APD 0168 READ_KEY 8000 kbdScanCode 8001 kbdLGSC 8002 kbdPSC 8003 kbdWUR 8004 kbdDebncCnt 8005 kbdKey 8006 kbdGetKy 8007 contrast 8008 apdSubTimer 8009 apdTimer 800A apdWarmUp 800B curTime 800C curRow 800D curCol 800E curUnder 800F undelBufLen 8010 undelBuf # 8074 tokVarPtr? # 8076 tokLen? 8078 indicMem 8080 indicCounter 8081 indicBusy 8082 OP1 808D OP2 8098 OP3 80A3 OP4 80AE OP5 80B9 OP6 80C6 iMathPtr1 80C8 iMathPtr2 80CA iMathPtr3 80CC iMathPtr4 80CE iMathPtr5 # 80D0 chkDelPtr1? # 80D2 chkDelPtr2? # 80D4 insDelPtr? # 80D6 upDownPtr? 80DF textShadow 8187 textShadCur # 8189 textShadTop? # 818A textShadAlph? # 818B textShadIns? 818C textAccent 818D cxMain # 818F cxPPutAway? # 8191 cxPutAway? # 8193 cxRedisp? # 8195 cxErrorEP? 8197 cxSizeWind 8199 cxPage # 819A cxCurApp? 819B cxPrev # 81AA monQH? # 81AB monQT? # 81AC monQueue? 81BC onSP 81BE onCheckSum 81DD menuActive 8333 penCol 8334 penRow # 8335 rclQueue? 8337 errNo 8338 errSP # 833A errOffset? 8346 flags 8364 stCounter # 85E3 XOutDat? # 85E7 YOutDat? # 85EB inputDat? 8629 ES 8641 plotSScreen 8A41 seed1 8A4B seed2 # 8A56 parseVar? 8A5F begPC 8A61 curPC 8A63 endPC 8A6B cmdShadow # 8B27 editDat? 8B2D modePtr 8B2F winTop 8B30 winBtm 8B31 winLeftEdge 8B32 winLeft 8B34 winAbove 8B36 winRow # 8B38 winCol? 8B3A fmtDigits # 8B96 fmtMatMem? # 8B98 EQS? 8BD2 delAdjAmt 8BDD tempMem 8BDF fpBase 8BE1 FPS 8BE3 OPBase 8BE5 OPS # 8BE7 pTempCnt? # 8BE9 cleanTmp? 8BEB pTemp 8BF7 userMem 0FA6F symTable 0FC00 videoRAM ## ZShell 8C3C PROGRAM_ADDR 8C3E ROM_VERS 8C3F ZSHELL_VER 8C40 ZS_BITS ## Usgard 8E8B ORGSP 8EA2 USGSHELL 8EAB VATName 8EB4 DEST_ADDR 8EB4 PAGE1ADDR 8EB6 PAGE2ADDR 8C08 PROG_BYTE 8C41 TX_CHARPUT 8C44 D_LT_STR 8C47 M_CHARPUT 8C4A D_ZM_STR 8C4D D_LM_STR # 8C50 SCROLL_UP # 8C53 TR_CHARPUT # 8C56 CLEARLCD # 8C59 D_HL_DECI # 8C5C CLEARTEXT # 8C5F D_ZT_STR # 8C62 BUSY_OFF # 8C65 BUSY_ON # 8C68 RANDOM 8C6B FIND_PIXEL 8C77 FREEMEM 8C7A VAR_LENGTH 8C7D ASCIIZ_LEN 8C80 NEG_BC 8C83 MUL_HL 8C8C COPY_STRING 8C9B USGARD_INT_INSTALL 8C9E USGARD_INT_REMOVE 8CA1 USGARD_INT_CLEAN 8C95 APPEND 8C98 UNAPPEND 8CCB CHECK_APPEND 8CA4 VAR_NEW 8CA7 VAR_DELETE 8CAA VAR_EXEC 8CAD VAR_GET 8CB0 VAR_RESIZE 8CCE RELOC 8CD1 DERELOC 8CD7 RELOC_TAB 8CB3 SEARCH_VAT 8CB6 OTH_SHUTDOWN 8CB9 DM_HL_DECI 8CBC OTH_PAUSE 8CBF OTH_CLEAR 8CC2 OTH_EXIT 8CC5 OTH_ARROW 8CD4 OTH_FILL ## Rigel # 8C50 GET_T_CUR # 8C53 SCROLL_UP # 8C56 TR_CHARPUT # 8C59 CLEARLCD # 8C5C D_HL_DECI # 8C5F CLEARTEXT # 8C62 D_ZT_STR # 8C65 BUSY_OFF # 8C68 BUSY_ON 8C6E RIGEL_INT_INSTALL 8C71 RIGEL_INT_REMOVE 8C06 VAR_SEARCH [flags] 00 kbdFlags 2,00 trigDeg,trigFlags 3,00 kbdSCR,kbdFlags 4,00 kbdKeyPress,kbdFlags 05 textFlags 2,05 textScrolled,textFlags 3,05 textInverse,textFlags 4,05 textInsMode,textFlags 08 apdFlags 2,08 apdAble,apdFlags 3,08 apdRunning,apdFlags 09 onFlags 3,09 onRunning,onFlags 4,09 onInterrupt,onFlags 0C curFlags 2,0C curAble,curFlags 3,0C curOn,curFlags 4,0C curLock,curFlags 0D appFlags 1,0D appTextSave,appFlags 5,0D appCurGraphic,appFlags 6,0D appCurWord,appFlags 12 indicFlags 0,12 indicRun,indicFlags 2,12 indicOnly,indicFlags 3,12 shift2nd,shiftFlags 4,12 shiftAlpha,shiftFlags 5,12 shiftLwrAlph,shiftFlags 6,12 shiftALock,shiftFlags 7,12 shiftKeepAlph,shiftFlags tilem-2.0/data/symbols/ti86.sym000066400000000000000000000443601220200411600164050ustar00rootroot00000000000000[labels] 0008 rOP1TOOP2 0010 rFINDSYM 0018 rPUSHOP1 0020 rMOV10TOOP1 0028 rFPMULT 0030 rFPADD 4010 _ldhlind 4028 _chkON 402C _bitgrffuncm 4030 _bitgrfpolarm 4034 _bitgrfparamm 4038 _bitgrfrecurm 403C _cphlde 4040 _put_colon 4044 _divHLby10 4048 _divHLbyA 404C _divAHLby10 4058 _timeout 4060 _resetAPD 4064 _scan_code 4068 _get_key 409C _jforcecmdnochar 40B5 _pPutAwayPrompt 40BD _call_cxPPutAway 40C1 _call_cxPutAway 40C5 _call_cxSizeWind 40C9 _call_cxErrorEP 40CD _call_cxMain 40D1 _cxNull 40D2 _p_cxNull 40DD _err_handler 40E1 _set_cx_100 40E5 _set_cx_50 40E9 _set_cx_dec 40ED _set_context 4101 _off 4109 _reset 4119 _removTok 412D _errAxes 4130 _errFldOrder 4133 _errStatPlot 4136 _errOverflow 4139 _errDivBy0 413c _errSingularMat 413f _errDomain 4142 _errIncrement 4145 _errSyntax 4148 _errNumberBase 414B _errMode 414e _errDataType 4151 _errArgument 4154 _errDimMismatch 4157 _errDimension 415A _errUndefined 4169 _errReserved 416c _errInvalid 416f _errIllegalNest 4172 _errBound 4175 _errGraphWindow 4178 _errZoom 417b _errBreak 417e _errStat 4181 _errConversion 4184 _errSolver 4187 _errIterations 418a _errBadGuess 418d _errDifEqSetup 4190 _errPoly 4193 _errTolNotMet 4196 _errLink 4199 _errorA 419C _error 41A1 _instError 41A4 _removError 41B7 _ld_de_fp0 41BB _ld_de_fp1 41BF _mulHL10 41C3 _ckop1cplx 41C7 _ckcplx 41CB _ckop1real 41FB _cpop1op2 4203 _op3toop4 4207 _op1toop4 420B _op2toop4 420F _movtoop4 4213 _op4toop2 4217 _op4toop3 421B _op3toop2 421F _op1toop3 4223 _movfrop1 4227 _op5toop2 422B _op5toop6 422F _op5toop4 4233 _op1toop2 4237 _movtoop2 423B _op6toop2 423F _op6toop1 4243 _op4toop1 4247 _op5toop1 424B _op3toop1 424F _op4toop5 4253 _op3toop5 4257 _op2toop5 425B _movtoop5 425F _op2toop6 4263 _op1toop6 4267 _movtoop6 426B _op1toop5 426F _op2toop1 4273 _movtoop1 4277 _mov11b 427B _mov10b 427F _mov9b 4283 _mov9b_ 4287 _mov8b 428B _mov7b 428F _mov7b_ 4293 _mov6b 4297 _mov5b 429B _mov4b 429F _mov3b 42A3 _mov2b 42A7 _op4toop2m 42CB _op2toop3 42CF _movtoop3 42D3 _op4toop6 42D7 _mov10toop1 42DB _mov10toop1op2 42DF _mov10toop2 42E3 _movfroop1 42E7 _op4set1 42EB _op3set1 42EF _op2set8 42F7 _op2set5 42FB _op2set4 4303 _op2set3 430F _op1set1 4313 _op1set4 4317 _op1set3 431B _op3set2 431F _op1set2 4323 _op2set2 432F _op2set1 4343 _ld_hl_8z 4347 _ld_hl_8a 434B _ld_hlplus1_7a 434F _ld_hl_7a 4353 _op4set0 4357 _op3set0 435B _op2set0 435F _op1set0 4363 _ld_hl_fp0 4367 _zeroop1m 436B _zeroop1 436F _zeroop2 4373 _zeroop3 4377 _ld_hl_11z 437B _ld_hl_bz 4383 _shracc 438B _shlacc 446F _ex_op2_op6 4473 _ex_op5_op6 4477 _ex_op1_op5 447B _ex_op1_op6 447F _ex_op2_op4 4483 _ex_op2_op5 4487 _ex_op1_op3 448B _ex_op1_op4 448F _ex_op1_op2 449B _ckop1fp0 44A3 _ckop2fp0 44B3 _ckop1int 44B7 _ckint 44BB _ckop1odd 44BF _ckodd 450B _ckop2pos 450F _ckop1pos 4513 _absop2 4527 _inco1exp 4547 _HtimesL 458F _findsym_error 45E3 _invsub 45EB _PLUS1 45EF _inc_ptr_ade 45F3 _ex_ahl_bde 460B _get_size_word 4613 _setXXop1 4617 _setXXop2 461B _setXXXXop2 462F _load_ram_ahl 4633 _conv_ahl 4637 _inc_ptr_ahl 463B _dec_ptr_ahl 463F _inc_ptr_bde 4643 _dec_ptr_bde 4647 _set_abs_src_addr 464B _get_free_mem 464F _set_mm_num_bytes 4657 _round_OP1 46AF _check_asm 46B7 _jump_table 46BB _memchk 46BF _dec_ptr_ade 46C3 _getb_ahl 46C7 _cp_ahl_bde 46CB _findsym 46D3 _copy_fwd 46D7 _del_temp_vars 46EB _createreal 46EF _createrconst 46F3 _createcconst 46F7 _createcplx 46FB _creatervect_temp 46FF _creatervect 4703 _createcvect_temp 4707 _createcvect 470B _createrlist_temp 470F _createrlist 4713 _createclist_temp 4717 _createclist 471B _creatermat_temp 471F _creatermat 4723 _createcmat_temp 4727 _createcmat 472B _createstrng_temp 472F _createstrng 4733 _createequ_temp 4737 _createequ 473B _createpict 474F _createprog 475B _copy_bkwd 475F _delvar 476F _update_VAT_ptrs 477B _get_size 477F _get_var_size 4783 _push_bc_OPS 4787 _check_STACK_mem 478B _pop_bc_OPS 478F _push_a_OPS 4793 _pop_a_OPS 479F _popop1 47A3 _poprealo6 47A7 _poprealo5 47AB _poprealo4 47AF _poprealo3 47A3 _poprealo2 47A7 _poprealo1 47CB _sub_FPS_20 47CF _sub_FPS_10 47D3 _sub_FPS_bc 47DB _deallocfps1 47E3 _ram_page_1 47E7 _load_ram_OPS 47EB _load_ram_ES 47EF _load_ram_FPS 47F3 _ram_page_7 4813 _pushrealo1 4893 _cpyto2fpst 4897 _cpyto1fpst 48AF _cpyto2fps1 48C3 _cpyto2fps2 48D7 _cpyo2tofpst 48DB _cpyo6tofpst 48DF _cpyo1tofpst 48E3 _cpydetofpst 48E7 _cpydetohlt 48EB _cpydetohlc 48EF _cpyo5tofps2 48F3 _cpyo2tofpsto1tofps1 48F7 _cpyo1tofps1 48FB _cpydetofps1 48FF _cpydetohl1 4903 _cpyo2tofps2 4907 _cpyo3tofps2 490B _cpyo6tofps2 490F _cpyo1tofps2 4913 _cpydetofps2 4917 _cpydetohl2 491B _cpyo5tofps3 491F _cpyo2tofps2o1tofps3 4923 _cpyo1tofps3 4927 _cpydetofps3 492B _cpydetohl3 492F _cpyo1tofps4 4933 _cpydetofps4 4937 _cpydetohl4 493B _cpyo1tofps6 493F _cpyo1tofps7 4943 _cpyo1tofps8 494F _ask_self_test 4953 _self_test 4957 _strlen 495B _strcpy 495F _strcat 4963 _strcmp 496B _find_bit 498C _cursorOff 4994 _cursorOn 49A0 _reset_MATH 49B0 _disp_GRAPH 49DC _flushallmenus 49E8 _disp_menu 4A0A _exec_pg1 4A27 _putmap 4A2B _putc 4A33 _dispAHL 4A37 _puts 4A3B _putps 4A5F _newline 4A7E _clrLCD 4A82 _clrScrn 4A86 _clrWindow 4A8A _clrLine 4A95 _homeup 4AA1 _vputmap 4AA5 _vputs 4AA9 _vputsn 4AAD _runindicon 4AB1 _runindicoff 4AB5 _clrText 4B1B _exec_pg2 4B1F _binopexec1 4B93 _tofrac 4B9F _gfudydx 4C2F _INTOP1 4C3F _ahl_plus_2_pg3 4C47 _exec_basic 4C9F _stoAns 4CB3 _stoY 4CBB _stoX 4CBF _stoOther 4CDF _rclY 4CE3 _rclX 4CE7 _rclVarSym 4D13 _get_token 4D1B _get_varname 4D3F _disp 4D43 _pause 4D6F _PDspGrph 4D73 _horizCmd 4D77 _vertCmd 4DAF _unpack_hex 4E39 _grbufcpy 4E51 _ILine 4E59 _IPoint 4E71 _geqnamea 4FA8 _set_app_title 514B _FindAlphaUp 514F _FindAlphaDn 515B _dispOP1 515F _dispDone 5191 _formReal 51E9 _CLine 5209 _get_abs_src_addr 521D _get_word_ahl 5221 _set_word_ahl 5235 _abs_mov10toop1 5239 _abs_mov10toop1_noset 523D _abs_mov10b_set_d 5249 _abs_mov10b 5241 _abs_movfrop1_set_d 5245 _abs_movfrop1 5285 _set_abs_dest_addr 52B5 _RcPicGrph 52ED _mm_ldir 52F1 _mm_lddr 5369 _get_statvar 5371 _getky 5398 _low_battery 5464 _mov10op2add 5468 _INTGR 5470 _MINUS1 5474 _FPSUB 5478 _FPADD 5484 _TIMESPT5 5488 _FPSQUARE 548C _FPMULT 5490 _invop1op2 5494 _invop1s 5498 _invop2s 549C _FRAC 54A4 _FPRECIP 54A8 _FPDIV 54AC _SQROOT 54B0 _SQROOTP 54BC _RNDGUARD 54C0 _ROUND 54C4 _LNX 54C8 _LNXP 54CC _LOGXP 54D0 _LOGX 54D4 _ETOX 54D8 _TENX 54E0 _SIN 54E4 _COS 54E8 _TAN 54F0 _TANH 54F4 _COSH 54F8 _SINH 5508 _ACOS 550C _ACOSP 5510 _ATAN 5514 _ASIN 551C _ATANH 5524 _ASINH 5528 _ACOSH 5538 _YTOX 5544 _randint 5567 _writeb_inc_ahl 5577 _convop1 557B _set_mode 55a3 _asmComp 55AA _getkey 55DA _random 5643 _vputspace 569D _get_char 56A1 _get_vchar 56EA _call_user_on 56ED _call_user_off 56F0 _call_sqrtexpr 56F3 _call_sqrtparse 56F6 _call_sqrtexec 56F9 _call_sqrtform 56FC _call_sqrtcmdtok 56FF _call_sqrthome 5702 _call_sqrtkey 5705 _call_sqrtgrf 5718 _exec_pg4 5714 _exec_pg3 571C _linkExec 5730 _exec_assembly 5732 _errNoSignChng 575C _instTok 0C000 _kbdScanCode 0C001 _kbdLGSC 0C002 _kbdPSC 0C003 _kbdWUR 0C004 _kbdDebncCnt 0C005 _kbdkey 0C006 _kbdGetKy 0C007 _keyextend 0C008 _contrast 0C009 _APDSubTimer 0C00A _APDTimer 0C00B _APDWarmUp 0C00C _viet 0C00E _curTime 0C00F _curRow 0C010 _curCol 0C011 _curUnder 0C012 _undelBufLen 0C013 _undelBuf 0C077 _P_tokVarPtr 0C07A _toklen 0C07C _TOK_B3 0C07D _DETOK_H3 0C07E _MEMPRE_H3 0C07F _indicMem 0C087 _indicCounter 0C088 _indicBusy 0C089 _OP1 0C08A _OP1EXPM 0C08B _OP1EXPL 0C08C _OP1M 0C093 _OP1EXT 0C094 _LOGKP 0C094 _OP2 0C095 _OP2EXPM 0C096 _OP2EXPL 0C097 _OP2M 0C09E _OP2EXT 0C09F _OP3 0C09F _LOGKM 0C0A0 _OP3EXPM 0C0A1 _OP3EXPL 0C0A2 _OP3M 0C0A9 _OP3EXT 0C0AA _CORDFLG1 0C0AA _OP4 0C0AB _OP4EXPM 0C0AC _OP4EXPL 0C0AD _OP4M 0C0B4 _OP4EXT 0C0B5 _EK 0C0B5 _CORDFLG 0C0B5 _OP5 0C0B6 _OP5EXPM 0C0B6 _SF 0C0B6 _EL 0C0B7 _OP5EXPL 0C0B7 _EM 0C0B8 _OP5M 0C0B8 _EMM1 0C0B9 _EITS 0C0BA _ENM2 0C0BB _ENA 0C0BC _EEN 0C0BF _OP5EXT 0C0C0 _EN 0C0C0 _OP6 0C0C1 _EJ 0C0C1 _OP6EXPM 0C0C2 _OP6EXPL 0C0C2 _EEI 0C0C3 _OP6M 0C0C5 _ELOW 0C0C6 _EIGH 0C0CA _OP6EXT 0C0CC _OP7 0C0D7 _CPLXTRG 0C0D7 _IOFLAG 0C0D8 _P_IMATHPTR1 0C0DB _P_IMATHPTR2 0C0DE _P_IMATHPTR3 0C0E1 _P_IMATHPTR4 0C0E4 _P_IMATHPTR5 0C0E7 _CHKDELPTR1 0C0E7 _P_CHKDELPTR1 0C0EA _P_CHKDELPTR2 0C0ED _P_INSDELPTR 0C0F0 _P_UPDOWNPTR 0C0F3 _STDRNGSGN 0C0F4 _POLRNGSGN 0C0F5 _PARRNGSGN 0C0F6 _DIFRNDSGN 0C0F7 _USRRNGSGN 0C0F8 _STATSGN 0C0F9 _textShadow 0C1A1 _textShadCur 0C1A3 _textShadTop 0C1A4 _textShadAlph 0C1A5 _textShadIns 0C1A6 _textAccent 0C1A7 _cxMain 0C1A9 _cxPPutAway 0C1AB _cxPutAway 0C1AD _cxRedisp 0C1AF _cxErrorEP 0C1B1 _cxSizeWind 0C1B3 _cxPage 0C1B4 _CXCURAPP 0C1B5 _cxPrev 0C1C4 _monQH 0C1C5 _monQT 0C1C6 _monQueue 0C1D6 _onSP 0C1D8 _onCheckSum 0C1DA _promptRow 0C1DB _promptCol 0C1DC _promptIns 0C1DD _promptShift 0C1DE _promptRet 0C1E0 _promptValid 0C1E2 _P_promptTop 0C1E5 _P_promptCursor 0C1E8 _P_promptTail 0C1EB _P_promptBtm 0C1EE _varType 0C1EF _varCurrent 0C1F8 _varFAFlags 0C1FA _varClass 0C1FB _catCurrent 0C1FD _menuActive 0C1FE _menu2Hilite 0C1FF _menuSingle 0C201 _menuAppStack 0C20D _menuAppPtr 0C20F _menuAppDepth 0C210 _menuSysStack 0C21C _menuSysPtr 0C21E _menuSysDepth 0C21F _menuPrvStack 0C22B _menuPrvPtr 0C22D _menuPrvDepth 0C22E _m2i 0C242 _menuDyn1 0C26A _menuDyn5 0C274 _userMenu1 0C275 _userMenuTitle 0C27C _userMenu2 0C284 _userMenu3 0C28C _userMenu4 0C294 _userMenu5 0C29C _userMenuSA 0C31C _XSTATSAV 0C324 _ioPrompt 0C326 _YSTATSAV 0C330 _FSTATSAV 0C33A _IOSNDTYP 0C33B _SNDRECSTATE 0C33C _IOERRSTATE 0C33D _HEADER 0C346 _IODATA 0C352 _BAKHEADER 0C35B _TBLRNGSGN 0C35C _calc_id 0C37C _penCol 0C37D _penRow 0C37E _P_RCLQUEUE 0C381 _ERRNO 0C382 _ERRSP 0C384 _errOffset 0C386 _ram_to_use 0C390 _offerr_sav_bc 0C392 _ABS_SRC_ADDR 0C395 _ABS_DEST_ADDR 0C398 _MM_NUM_BYTES 0C39B _mm_tmp1 0C39D _mm_tmp2 0C39F _mm_tmp3 0C3A1 _mm_tmp4 0C3A3 _mm_tmp5 0C3A5 _ram_cache 0C3E5 _Flags 0C40A _ram_to_use1 0C414 _statReg 0C415 _STATVARS 0C555 _STCounter 0C555 _curgstyle 0C556 _curGY 0C557 _curGX 0C558 _curGY2 0C559 _curGX2 0C55A _curgstyle_save 0C55B _curgstylesave 0C55C _plotflagsave 0C55D _XMINPTR 0C55F _XMAXPTR 0C561 _XSCLPTR 0C563 _YMINPTR 0C565 _YMAXPTR 0C567 _YSCLPTR 0C569 _DIF1STCURINC 0C56B _TRACEPLOT 0C56C _BOXPLOTINFO 0C56D _SCURINC 0C56F _CURINC 0C571 _YPIXEL 0C572 _ORGXMIN 0C57C _PANSHIFT 0C586 _USRRNGSIZE 0C588 _UTHETMIN 0C58D _STSP 0C58D _STRAMStart 0C592 _UTHETMAX 0C59C _UTHETSTEP 0C5A6 _UTPLOT 0C5B0 _UTMIN 0C5BA _UTMAX 0C5C4 _UTSTEP 0C5CE _UXMIN 0C5D8 _UXMAX 0C5E2 _UXSCL 0C5EC _UYMIN 0C5F6 _UYMAX 0C600 _UYSCL 0C60A _UXRES 0C614 _XRES_INT 0C615 _HDERIV 0C61F _TOL 0C629 _XFACT 0C633 _YFACT 0C63D _DELTAX 0C647 _DELTAY 0C651 _SHORTX 0C65B _SHORTY 0C665 _FUNRNGSIZE 0C667 _FLAGSF 0C668 _XMINF 0C672 _XMAXF 0C67C _XSCLF 0C686 _YMINF 0C690 _YMAXF 0C69A _YSCLF 0C6A4 _LOWER 0C6AE _UPPER 0C6B8 _XRES 0C6C2 _POLRNGSIZE 0C6C4 _FLAGSPOL 0C6C5 _THETAMIN 0C6CF _THETAMAX 0C6D9 _THETASTEP 0C6E3 _XMINPOL 0C6ED _XMAXPOL 0C6F7 _XSCLPOL 0C701 _YMINPOL 0C70B _YMAXPOL 0C715 _YSCLPOL 0C71F _PARRNGSIZE 0C721 _FLAGSPAR 0C722 _TMINPAR 0C72C _TMAXPAR 0C736 _TSTEPPAR 0C740 _XMINPAR 0C74A _XMAXPAR 0C754 _XSCLPAR 0C75E _YMINPAR 0C768 _YMAXPAR 0C772 _YSCLPAR 0C77C _DIFRNGSIZE 0C77E _FLAGSDIF 0C77F _TOLERDIF 0C789 _TPLOTDIF 0C793 _TMINDIF 0C79D _TMAXDIF 0C7A7 _TSTEPDIF 0C7B1 _XMINDIF 0C7BB _XMAXDIF 0C7C5 _XSCLDIF 0C7CF _YMINDIF 0C7D9 _YMAXDIF 0C7E3 _YSCLDIF 0C7ED _XAXISDIF 0C7EE _YAXISDIF 0C7EF _SLOPEF_EQU 0C7F0 _DIRF_X 0C7F1 _DIRF_Y 0C7F2 _DIRF_TIME 0C7FC _FRES 0C806 _INTS 0C810 _DNEQ 0C811 _P_XOUTSYM 0C814 _P_XOUTDAT 0C817 _P_YOUTSYM 0C81A _P_YOUTDAT 0C81D _P_INPUTSYM 0C820 _P_INPUTDAT 0C823 _P_FOUTDAT 0C826 _PREVDATA 0C862 _PREVDATA_EXT 0C86C _P1TYPE 0C86D _SavX1List 0C876 _SavY1List 0C87F _SavF1List 0C888 _P1FRQONOFF 0C889 _P2TYPE 0C88A _SavX2List 0C893 _SavY2List 0C89C _SavF2List 0C8A5 _P2FRQONOFF 0C8A6 _P3TYPE 0C8A7 _SavX3List 0C8B0 _SavY3List 0C8B9 _SavF3List 0C8C2 _P3FRQONOFF 0C8C3 _oldtype 0C8C4 _oldxlist 0C8CD _oldylist 0C8D6 _oldflist 0C8D6 _uppery 0C8DF _oldonoff 0C8E0 _tblpsrow 0C8E1 _tblscroll 0C8E3 _INPUTDAT_PG0 0C8ED _TblLine 0C8F7 _OldTblMin 0C901 _TBLRNGSIZE 0C903 _TblMin 0C90D _TblStep 0C917 _TABLESGN 0C918 _TableYPtr 0C919 _curTblcol 0C91A _curTblrow 0C91B _dspTblcol 0C91C _dspTblrow 0C91D _higTblcol 0C91E _higTblrow 0C920 _TABLEXDATA 0C920 _TBLMATRIX 0C95C _TABLEYDATA 0C9D4 _TABLETEMPLATE 0C9D5 _SavedEqTok 0C9D7 _SavedEqNum1 0C9D8 _SavedEqTok1 0C9DA _SaveAppFlags 0C9DB _SaveCurFlags 0C9DC _SaveCurGstyle 0C9DD _SaveGraphFlags 0C9DE _evalflevel 0C9DF _TmpMatCols 0C9DF _ES 0C9E0 _TmpMatRows 0C9E1 _P_DERIVPTR 0C9E4 _DTMPThresh 0C9E6 _ELCPLXLCNT 0C9E8 _DERIVLEVEL 0C9E9 _P_DIFFEQPTR 0C9EB _P_DSOLVPTR 0C9EE _SOLVAR 0C9F7 _P_QUADPTR 0C9FA _plotSScreen 0CDFA _SEED1 0CE04 _SEED2 0CE0E _PARSEVAR 0CE18 _P_BEGPC 0CE1B _P_CURPC 0CE1E _P_ENDPC 0CE21 _ELCNT 0CE23 _COLCNT 0CE24 _ROWCNT 0CE25 _LCOUNT 0CE27 _EOS_ASAP_2ND 0CE28 _EXEC_CONV_SAVE 0CE2A _LASTENTRYPTR 0CE2C _LASTENTRYSTK 0CEAC _numlastentries 0CEAD _currlastentry 0CEAE _FREESAVEY 0CEAF _FREESAVEX 0CEB0 _STRACESAVE_TYPE 0CEB1 _STRACESAVE 0CEB3 _TRACESAVE 0CEB5 _DIF_T_SAVE 0CEBF _A_B_SAVE 0CEC0 _A_B_TYPE 0CEC1 _GS_DELX 0CEC2 _GS_D1_YINC 0CEC3 _GS_D2_YINC 0CEC4 _GS_DELY 0CEC5 _GS_MAX_Y_PIX 0CEC6 _CURRENT_STYLE 0CEC7 _CL_X1 0CEC8 _CL_X2 0CEC9 _CL_Y_DAT 0CECB _PREV_POINT 0CECD _RESSAVE 0CECE _DREQU_X 0CECF _DREQU_XINIT 0CED9 _DREQU_Y 0CEDA _DREQU_YINIT 0CEE4 _DREQU_XLIST 0CEE7 _DREQU_YLIST 0CEEA _DREQU_tLIST 0CEED _DREQU_COUNT 0CEEF _GY1 0CF21 _GX1 0CF53 _GR1 0CF85 _GQ1 0CF8A _EQU_EDIT_SAVE 0CF8B _FORMULA_BITMAP 0CFAB _MENUCMD_M2I 0CFAB _cmdShadow 0CFC9 _MENUCMD_ITEMS 0D041 _MENUCMD_NUMROWS 0D042 _MENUCMD_CURROW 0D053 _cmdShadCur 0D055 _cmdShadAlph 0D056 _cmdShadIns 0D057 _cmdCursor 0D059 _P_editTop 0D05C _P_EDITCURSOR 0D05F _P_editTail 0D062 _P_editBtm 0D065 _curmatcol 0D066 _curmatrow 0D067 _curlstrow 0D069 _numedTbl 0D069 _curlistel 0D06A _curlstrowh 0D06B _higmatcol 0D06C _higmatrow 0D06D _higlstrow 0D06F _maxdsprow 0D070 _ForCurMat 0D070 _higlstrowh 0D072 _ForDspCol 0D074 _forerrornum 0D075 _P_editSym 0D078 _P_editDat 0D07B _DspMatCol 0D07C _DspMatRow 0D07D _TmpMatCol 0D07E _TmpMatRow 0D07F _numoflist 0D080 _num1stlist 0D081 _NumCurList 0D082 _STATED_CUT_COL 0D083 _listnamebuffer 0D12E _LastName 0D137 _modeRoot 0D139 _modeCount 0D13A _modeItem 0D13B _modePtr 0D13D _winTop 0D13E _winBtm 0D13F _winLeftEdge 0D140 _winLeft 0D142 _winAbove 0D144 _winRow 0D146 _winCol 0D148 _fmtDigits 0D149 _fmtString 0D18A _fmtConv 0D19E _fmtLeft 0D1A0 _fmtIndex 0D1A2 _P_fmtMatSym 0D1A5 _P_fmtMatMem 0D1A8 _EQS 0D1AA _LSTINDEX 0D1AC _LSTSIZE 0D1AE _EQUINDEX 0D1B0 _order 0D1B1 _xnamesav 0D1BA _ynamesav 0D1C3 _CustMType 0D1C3 _MCustM 0D1C4 _CustMLen 0D1C5 _CustMSav 0D1E3 _custmnames 0D279 _VARSAVECNT 0D27A _DELADJAMT 0D27D _TEMPINPUT 0D27E _TSYMPTR1 0D280 _TSYMPTR2 0D282 _P_CHKDELPTR3 0D285 _P_CHKDELPTR4 0D288 _P_TEMPMEM 0D28B _FPBASE 0D28D _FPS 0D28F _OPBASE 0D291 _OPS 0D293 _PTempCnt 0D295 _CLEANTMP 0D297 _P_PTEMP 0D29A _PTEMP_END 0D29D _FREE_MEM 0D2A0 _newdataptr 0D2A3 _SavBotRow 0D2B8 _curstatplot 0D2B9 _curstatplotprompt 0D2BA _difeqfieldmode 0D2BB _matedoldtype 0D2BC _modesave1 0D2BD _statansfirst 0D2BF _statanslast 0D2C1 _statanscur 0D2C3 _charmap 0D2CB _altcharmap 0D2D3 _toktmp1 0D2D4 _toktmp2 0D2D5 _IOSAVOP1 0D2DF _DELVAR_SAV_F 0D2E0 _DEL_SAV_OP1 0D2EB _alt_asm_exec_btm 0D2ED _altlfontptr 0D2F0 _altsfontptr 0D2F3 _altonptr 0D2F6 _altslinkptr 0D2F9 _alt_ret_status 0D2FA _alt_ret_jmp_page 0D2FB _alt_ret_jmp_addr 0D2FD _alt_int_chksum 0D2FE _alt_interrupt_exec 0D3C6 _alt_slink_chksum 0D3C7 _alt_slink_exec 0D48F _alt_on_chksum 0D490 _alt_on_exec 0D558 _alt_off_chksum 0D559 _alt_off_exec 0D621 _altram_end 0D621 _asm_exec_btm 0D623 _ASAP_IND 0D624 _asm_reg_af 0D625 _asm_reg_a 0D626 _asm_reg_l 0D626 _asm_reg_hl 0D627 _asm_reg_h 0D628 _asm_reg_bc 0D628 _asm_reg_c 0D629 _asm_reg_b 0D62A _asm_reg_de 0D62A _asm_reg_e 0D62B _asm_reg_d 0D62C _mPrgmMATH 0D64C _mMath 0D65A _mMath_asap1 0D65C _mMath_asap2 0D65E _mMath_asap3 0D66C _iASAP1 0D678 _iASAP2 0D684 _iASAP3 0D690 _iASAP4 0D69C _iASAP5 0D6A8 _iASAP6 0D6B4 _iASAP7 0D6C0 _iASAP8 0D6CC _iASAP9 0D6D8 _asapnames 0D6D8 _asap_nl1 0D6E1 _asap_nl2 0D6EA _asap_nl3 0D6FC _asapvar 0D706 _tokspell_asap1 0D706 _tokspelltblptr 0D708 _tokspell_asap2 0D70A _tokspell_asap3 0D70E _numtokens 0D70E _numtok_asap1 0D70F _numtok_asap2 0D710 _numtok_asap3 0D712 _eostblptr 0D712 _eostbl_asap1 0D714 _eostbl_asap2 0D716 _eostbl_asap3 0D71A _Amenu_offset 0D722 _reinstall_asap1 0D722 _reinstall_vec 0D724 _reinstall_asap2 0D726 _reinstall_asap3 0D72A _asap1_ram 0D734 _asap2_ram 0D73E _asap3_ram 0D748 _checkStart 0D748 _asm_exec_ram [flags] 00 trigflags 2,00 trigdeg,trigflags 00 doneflags 5,00 donePrgm,doneflags 02 plotflags 1,02 plotloc,plotflags 2,02 plotdisp,plotflags 02 grfmodeflags 4,02 grffuncm,grfmodeflags 5,02 grfpolarm,grfmodeflags 6,02 grfparamm,grfmodeflags 7,02 grfrecurm,grfmodeflags 03 graphflags 0,03 graphdraw,graphflags 2,03 graphcursor,graphflags 04 grfdbflags 0,04 grfdot,grfdbflags 1,04 grfsimul,grfdbflags 2,04 grfgrid,grfdbflags 3,04 grfpolar,grfdbflags 4,04 grfnocoord,grfdbflags 5,04 grfnoaxis,grfdbflags 6,04 grflabel,grfdbflags 05 textflags 1,05 textEraseBelow,textflags 2,05 textScrolled,textflags 3,05 textInverse,textflags 06 parsflag 07 parsflag2 0,06 numop1,parsflag2 08 apdflags 2,08 apdable,apdflags 3,08 apdlock,apdflags 4,08 apdwarmstart,apdflags 09 onflags 3,09 onRunning,onflags 4,09 onInterrupt,onflags 0A fmtflags 0,0A fmtExponent,fmtflags 1,0A fmtEng,fmtflags 2,0A fmtHex,fmtflags 3,0A fmtOct,fmtflags 4,0A fmtBin,fmtflags 0C curflags 2,0C curAble,curflags 3,0C curOn,curflags 4,0C curLock,curflags 0D appflags 1,0D appTextSave,appflags 2,0D appAutoScroll,appflags 12 indicflags 0,12 indicRun,indicflags 2,12 indicOnly,indicflags 12 shiftflags 3,12 shift2nd,shiftflags 4,12 shiftAlpha,shiftflags 5,12 shiftLwrAlph,shiftflags 6,12 shiftALock,shiftflags 16 asap_cmd_flag 7,16 ex_asap_cmd,asap_cmd_flag 17 NewDispf 6,17 ProgramExecuting,NewDispf 18 new_grf_flgs 6,18 textwrite,new_grf_flgs 1D statflags 6,1D statsvalid,statflags 1F anumeditflgs 2,1F ex_asm_module,anumeditflgs 23 exceptionflg 0,23 alt_font,exceptionflg 1,23 alt_vfont,exceptionflg 2,23 alt_int,exceptionflg 3,23 alt_on,exceptionflg 4,23 alt_link,exceptionflg 5,23 alt_sqrt,exceptionflg 6,23 alt_grphexpr,exceptionflg 7,23 alt_off,exceptionflg 24 exceptionflg2 0,24 alt_parse,exceptionflg2 1,24 alt_form,exceptionflg2 2,24 alt_exec,exceptionflg2 4,24 alt_home,exceptionflg2 5,24 alt_cmdtok,exceptionflg2 6,24 alt_key,exceptionflg2 7,24 alt_grf,exceptionflg2 28 asm_flag1 29 asm_flag2 2A asm_flag3 2B asm_flag4 2C asm_flag5 2D asm_flag6 2E asm_flag7 tilem-2.0/db/000077500000000000000000000000001220200411600130365ustar00rootroot00000000000000tilem-2.0/db/Makefile.in000066400000000000000000000023541220200411600151070ustar00rootroot00000000000000prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = @bindir@ datadir = @datadir@ pkgdatadir = @datadir@/tilem2 mandir = @mandir@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ AR = @AR@ CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ RANLIB = @RANLIB@ SHELL = @SHELL@ objects = disasm.o listing.o lstfile.o compile = $(CC) -I$(top_builddir) -I$(top_srcdir)/emu -I$(srcdir) $(CFLAGS) $(CPPFLAGS) $(DEFS) all: libtilemdb.a libtilemdb.a: $(objects) $(AR) cru libtilemdb.a $(objects) $(RANLIB) libtilemdb.a # Disassembler disasm.o: disasm.c tilemdb.h ../emu/tilem.h ../config.h $(compile) -c $(srcdir)/disasm.c # Listing file management listing.o: listing.c tilemdb.h ../emu/tilem.h ../config.h $(compile) -c $(srcdir)/listing.c lstfile.o: lstfile.c tilemdb.h ../emu/tilem.h ../config.h $(compile) -c $(srcdir)/lstfile.c clean: rm -f *.o rm -f libtilemdb.a Makefile: Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && $(SHELL) ./config.status --recheck .PRECIOUS: Makefile $(top_builddir)/config.status .PHONY: all clean tilem-2.0/db/disasm.c000066400000000000000000001051121220200411600144620ustar00rootroot00000000000000/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "tilemdb.h" typedef struct _TilemDisasmSymbol { char* name; dword value; } TilemDisasmSymbol; typedef struct _TilemDisasmSymTable { int nsyms; int nsyms_a; TilemDisasmSymbol* syms; } TilemDisasmSymTable; struct _TilemDisasm { TilemDisasmSymTable labels; TilemDisasmSymTable romcalls; TilemDisasmSymTable flags; TilemDisasmSymTable macros; }; TilemDisasm* tilem_disasm_new() { TilemDisasm* dasm = tilem_new0(TilemDisasm, 1); dasm->labels.syms = NULL; dasm->romcalls.syms = NULL; dasm->flags.syms = NULL; dasm->macros.syms = NULL; return dasm; } static void tilem_disasm_sym_table_free(TilemDisasmSymTable* stab) { int i; for (i = 0; i < stab->nsyms; i++) tilem_free(stab->syms[i].name); tilem_free(stab->syms); } void tilem_disasm_free(TilemDisasm* dasm) { if (!dasm) return; tilem_disasm_sym_table_free(&dasm->labels); tilem_disasm_sym_table_free(&dasm->romcalls); tilem_disasm_sym_table_free(&dasm->flags); tilem_disasm_sym_table_free(&dasm->macros); tilem_free(dasm); } /* Find symbol in the given table, if any */ static TilemDisasmSymbol* find_symbol(const TilemDisasmSymTable* stab, dword value) { int start, end, i; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value == value) return &stab->syms[i]; else if (stab->syms[i].value <= value) start = i + 1; else end = i; } return NULL; } /* Find previous symbol in the given table, if any */ static TilemDisasmSymbol* find_prev_symbol(const TilemDisasmSymTable* stab, dword value) { int start, end, i; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value <= value) start = i + 1; else end = i; } if (start > 0) return &stab->syms[start - 1]; else return NULL; } /* Find symbol with given name */ static TilemDisasmSymbol* find_symbol_by_name(const TilemDisasmSymTable* stab, const char* name) { int i; for (i = 0; i < stab->nsyms; i++) if (!strcmp(stab->syms[i].name, name)) return &stab->syms[i]; return NULL; } /* Find a given symbol in the table, or create a new one */ static TilemDisasmSymbol* add_symbol(TilemDisasmSymTable* stab, dword value) { int start, end, i; TilemDisasmSymbol* syms; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value == value) return &stab->syms[i]; else if (stab->syms[i].value < value) start = i + 1; else end = i; } /* insert new label into the array */ if (stab->nsyms < stab->nsyms_a) { if (start < stab->nsyms) memmove(&stab->syms[start + 1], &stab->syms[start], ((stab->nsyms - start) * sizeof(TilemDisasmSymbol))); } else { stab->nsyms_a = (stab->nsyms + 1) * 2; syms = tilem_new(TilemDisasmSymbol, stab->nsyms_a); if (start > 0) memcpy(syms, stab->syms, start * sizeof(TilemDisasmSymbol)); if (start < stab->nsyms) memcpy(syms + start + 1, stab->syms + start, ((stab->nsyms - start) * sizeof(TilemDisasmSymbol))); tilem_free(stab->syms); stab->syms = syms; } stab->nsyms++; stab->syms[start].value = value; stab->syms[start].name = NULL; return &stab->syms[start]; } /* Remove a symbol from the table */ static void del_symbol(TilemDisasmSymTable* stab, TilemDisasmSymbol* sym) { int n = sym - stab->syms; tilem_free(sym->name); if (n < stab->nsyms - 1) { memmove(sym, sym + 1, (stab->nsyms - n - 1) * sizeof(TilemDisasmSymbol)); } stab->nsyms--; } static void set_symbol(TilemDisasmSymTable* stab, const char* name, dword value) { TilemDisasmSymbol* sym; if ((sym = find_symbol_by_name(stab, name))) { if (sym->value == value) return; else del_symbol(stab, sym); } sym = add_symbol(stab, value); tilem_free(sym->name); sym->name = tilem_new_atomic(char, strlen(name) + 1); strcpy(sym->name, name); } static char* skipws(char* p) { while (*p == ' ' || *p == '\t') p++; return p; } static char* skipwc(char* p) { while ((unsigned char) *p > ' ') p++; return p; } static int parse_sym_value(const char* text, dword* value) { char* p; dword x; if (text[0] >= '0' && text[0] <= '7' && text[1] == ',') { x = strtol(text + 2, &p, 16); *value = 0x1000 + (x << 4) + (text[0] - '0'); } else { *value = strtol(text, &p, 16); } return (p != text && *p == 0); } static int parse_sym_line(TilemDisasmSymTable* stab, char* line) { char *w1end, *w2start, *w2end, *name; dword value; if (line[0] == '#' || line[0] == ';') return 1; w1end = skipwc(line); w2start = skipws(w1end); w2end = skipwc(w2start); if (w1end == line || w2start == w1end || w2end == w2start) return 1; if (*w2end) return 1; *w1end = *w2end = 0; if (*line >= '0' && *line <= '9') { name = w2start; if (!parse_sym_value(line, &value)) return 1; } else { name = line; if (!parse_sym_value(w2start, &value)) return 1; } set_symbol(stab, name, value); return 0; } int tilem_disasm_read_symbol_file(TilemDisasm* dasm, FILE* symfile) { char buf[1024]; char* p; TilemDisasmSymTable* curtbl; int status = 1; curtbl = &dasm->labels; while (fgets(buf, sizeof(buf), symfile)) { p = buf + strlen(buf); while (p != buf && (p[-1] == '\n' || p[-1] == '\r')) p--; *p = 0; if (!strcmp(buf, "[labels]")) curtbl = &dasm->labels; else if (!strcmp(buf, "[romcalls]")) curtbl = &dasm->romcalls; else if (!strcmp(buf, "[flags]")) curtbl = &dasm->flags; else if (!strcmp(buf, "[macros]")) curtbl = &dasm->macros; else if (!parse_sym_line(curtbl, buf)) status = 0; } return status; } void tilem_disasm_set_label(TilemDisasm* dasm, const char* name, dword value) { set_symbol(&dasm->labels, name, value); } int tilem_disasm_get_label(const TilemDisasm* dasm, const char* name, dword* value) { TilemDisasmSymbol* sym = find_symbol_by_name(&dasm->labels, name); if (!sym) return 0; else if (value) *value = sym->value; return 1; } const char* tilem_disasm_get_label_at_address(const TilemDisasm* dasm, dword addr) { TilemDisasmSymbol* sym = find_symbol(&dasm->labels, addr); if (sym) return sym->name; else return NULL; } typedef struct _TilemDisasmInstruction { int length; const char* pattern; } TilemDisasmInstruction; static const TilemDisasmInstruction insts_main[256] = { {1,"NOP"}, {3,"LD~BC,%w"}, {1,"LD~(BC),A"}, {1,"INC~BC"}, {1,"INC~B"}, {1,"DEC~B"}, {2,"LD~B,%b"}, {1,"RLCA"}, {1,"EX~AF,AF'"}, {1,"ADD~HL,BC"}, {1,"LD~A,(BC)"}, {1,"DEC~BC"}, {1,"INC~C"}, {1,"DEC~C"}, {2,"LD~C,%b"}, {1,"RRCA"}, {2,"DJNZ~%r"}, {3,"LD~DE,%w"}, {1,"LD~(DE),A"}, {1,"INC~DE"}, {1,"INC~D"}, {1,"DEC~D"}, {2,"LD~D,%b"}, {1,"RLA"}, {2,"JR~%r"}, {1,"ADD~HL,DE"}, {1,"LD~A,(DE)"}, {1,"DEC~DE"}, {1,"INC~E"}, {1,"DEC~E"}, {2,"LD~E,%b"}, {1,"RRA"}, {2,"JR~NZ,%r"}, {3,"LD~HL,%w"}, {3,"LD~(%a),HL"}, {1,"INC~HL"}, {1,"INC~H"}, {1,"DEC~H"}, {2,"LD~H,%b"}, {1,"DAA"}, {2,"JR~Z,%r"}, {1,"ADD~HL,HL"}, {3,"LD~HL,(%a)"}, {1,"DEC~HL"}, {1,"INC~L"}, {1,"DEC~L"}, {2,"LD~L,%b"}, {1,"CPL"}, {2,"JR~NC,%r"}, {3,"LD~SP,%w"}, {3,"LD~(%a),A"}, {1,"INC~SP"}, {1,"INC~(HL)"}, {1,"DEC~(HL)"}, {2,"LD~(HL),%b"}, {1,"SCF"}, {2,"JR~C,%r"}, {1,"ADD~HL,SP"}, {3,"LD~A,(%a)"}, {1,"DEC~SP"}, {1,"INC~A"}, {1,"DEC~A"}, {2,"LD~A,%b"}, {1,"CCF"}, {1,"LD~B,B"}, {1,"LD~B,C"}, {1,"LD~B,D"}, {1,"LD~B,E"}, {1,"LD~B,H"}, {1,"LD~B,L"}, {1,"LD~B,(HL)"}, {1,"LD~B,A"}, {1,"LD~C,B"}, {1,"LD~C,C"}, {1,"LD~C,D"}, {1,"LD~C,E"}, {1,"LD~C,H"}, {1,"LD~C,L"}, {1,"LD~C,(HL)"}, {1,"LD~C,A"}, {1,"LD~D,B"}, {1,"LD~D,C"}, {1,"LD~D,D"}, {1,"LD~D,E"}, {1,"LD~D,H"}, {1,"LD~D,L"}, {1,"LD~D,(HL)"}, {1,"LD~D,A"}, {1,"LD~E,B"}, {1,"LD~E,C"}, {1,"LD~E,D"}, {1,"LD~E,E"}, {1,"LD~E,H"}, {1,"LD~E,L"}, {1,"LD~E,(HL)"}, {1,"LD~E,A"}, {1,"LD~H,B"}, {1,"LD~H,C"}, {1,"LD~H,D"}, {1,"LD~H,E"}, {1,"LD~H,H"}, {1,"LD~H,L"}, {1,"LD~H,(HL)"}, {1,"LD~H,A"}, {1,"LD~L,B"}, {1,"LD~L,C"}, {1,"LD~L,D"}, {1,"LD~L,E"}, {1,"LD~L,H"}, {1,"LD~L,L"}, {1,"LD~L,(HL)"}, {1,"LD~L,A"}, {1,"LD~(HL),B"}, {1,"LD~(HL),C"}, {1,"LD~(HL),D"}, {1,"LD~(HL),E"}, {1,"LD~(HL),H"}, {1,"LD~(HL),L"}, {1,"HALT"}, {1,"LD~(HL),A"}, {1,"LD~A,B"}, {1,"LD~A,C"}, {1,"LD~A,D"}, {1,"LD~A,E"}, {1,"LD~A,H"}, {1,"LD~A,L"}, {1,"LD~A,(HL)"}, {1,"LD~A,A"}, {1,"ADD~A,B"}, {1,"ADD~A,C"}, {1,"ADD~A,D"}, {1,"ADD~A,E"}, {1,"ADD~A,H"}, {1,"ADD~A,L"}, {1,"ADD~A,(HL)"}, {1,"ADD~A,A"}, {1,"ADC~A,B"}, {1,"ADC~A,C"}, {1,"ADC~A,D"}, {1,"ADC~A,E"}, {1,"ADC~A,H"}, {1,"ADC~A,L"}, {1,"ADC~A,(HL)"}, {1,"ADC~A,A"}, {1,"SUB~B"}, {1,"SUB~C"}, {1,"SUB~D"}, {1,"SUB~E"}, {1,"SUB~H"}, {1,"SUB~L"}, {1,"SUB~(HL)"}, {1,"SUB~A"}, {1,"SBC~A,B"}, {1,"SBC~A,C"}, {1,"SBC~A,D"}, {1,"SBC~A,E"}, {1,"SBC~A,H"}, {1,"SBC~A,L"}, {1,"SBC~A,(HL)"}, {1,"SBC~A,A"}, {1,"AND~B"}, {1,"AND~C"}, {1,"AND~D"}, {1,"AND~E"}, {1,"AND~H"}, {1,"AND~L"}, {1,"AND~(HL)"}, {1,"AND~A"}, {1,"XOR~B"}, {1,"XOR~C"}, {1,"XOR~D"}, {1,"XOR~E"}, {1,"XOR~H"}, {1,"XOR~L"}, {1,"XOR~(HL)"}, {1,"XOR~A"}, {1,"OR~B"}, {1,"OR~C"}, {1,"OR~D"}, {1,"OR~E"}, {1,"OR~H"}, {1,"OR~L"}, {1,"OR~(HL)"}, {1,"OR~A"}, {1,"CP~B"}, {1,"CP~C"}, {1,"CP~D"}, {1,"CP~E"}, {1,"CP~H"}, {1,"CP~L"}, {1,"CP~(HL)"}, {1,"CP~A"}, {1,"RET~NZ"}, {1,"POP~BC"}, {3,"JP~NZ,%j"}, {3,"JP~%j"}, {3,"CALL~NZ,%j"}, {1,"PUSH~BC"}, {2,"ADD~A,%b"}, {1,"RST~%z"}, {1,"RET~Z"}, {1,"RET"}, {3,"JP~Z,%j"}, {1,0}, {3,"CALL~Z,%j"}, {3,"CALL~%j"}, {2,"ADC~A,%b"}, {1,"RST~%z"}, {1,"RET~NC"}, {1,"POP~DE"}, {3,"JP~NC,%j"}, {2,"OUT~(%b),A"}, {3,"CALL~NC,%j"}, {1,"PUSH~DE"}, {2,"SUB~%b"}, {1,"RST~%z"}, {1,"RET~C"}, {1,"EXX"}, {3,"JP~C,%j"}, {2,"IN~A,(%b)"}, {3,"CALL~C,%j"}, {1,0}, {2,"SBC~A,%b"}, {1,"RST~%z"}, {1,"RET~PO"}, {1,"POP~HL"}, {3,"JP~PO,%j"}, {1,"EX~(SP),HL"}, {3,"CALL~PO,%j"}, {1,"PUSH~HL"}, {2,"AND~%b"}, {1,"RST~%z"}, {1,"RET~PE"}, {1,"JP~(HL)"}, {3,"JP~PE,%j"}, {1,"EX~DE,HL"}, {3,"CALL~PE,%j"}, {1,0}, {2,"XOR~%b"}, {1,"RST~%z"}, {1,"RET~P"}, {1,"POP~AF"}, {3,"JP~P,%j"}, {1,"DI"}, {3,"CALL~P,%j"}, {1,"PUSH~AF"}, {2,"OR~%b"}, {1,"RST~%z"}, {1,"RET~M"}, {1,"LD~SP,HL"}, {3,"JP~M,%j"}, {1,"EI"}, {3,"CALL~M,%j"}, {1,0}, {2,"CP~%b"}, {1,"RST~%z"}}; static const TilemDisasmInstruction insts_ddfd[256] = { {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~%i,BC"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~%i,DE"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {4,"LD~%i,%w"}, {4,"LD~(%a),%i"}, {2,"INC~%i"}, {2,"INC~%iH"}, {2,"DEC~%iH"}, {3,"LD~%iH,%b"}, {1,0}, {1,0}, {2,"ADD~%i,%i"}, {4,"LD~%i,(%a)"}, {2,"DEC~%i"}, {2,"INC~%iL"}, {2,"DEC~%iL"}, {3,"LD~%iL,%b"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {3,"INC~(%i%s)"}, {3,"DEC~(%i%s)"}, {4,"LD~(%i%s),%b"}, {1,0}, {1,0}, {2,"ADD~%i,SP"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~B,%iH"}, {2,"LD~B,%iL"}, {3,"LD~B,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~C,%iH"}, {2,"LD~C,%iL"}, {3,"LD~C,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~D,%iH"}, {2,"LD~D,%iL"}, {3,"LD~D,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~E,%iH"}, {2,"LD~E,%iL"}, {3,"LD~E,(%i%s)"}, {1,0}, {2,"LD~%iH,B"}, {2,"LD~%iH,C"}, {2,"LD~%iH,D"}, {2,"LD~%iH,E"}, {2,"LD~%iH,%iH"}, {2,"LD~%iH,%iL"}, {3,"LD~H,(%i%s)"}, {2,"LD~%iH,A"}, {2,"LD~%iL,B"}, {2,"LD~%iL,C"}, {2,"LD~%iL,D"}, {2,"LD~%iL,E"}, {2,"LD~%iL,%iH"}, {2,"LD~%iL,%iL"}, {3,"LD~L,(%i%s)"}, {2,"LD~%iL,A"}, {3,"LD~(%i%s),B"}, {3,"LD~(%i%s),C"}, {3,"LD~(%i%s),D"}, {3,"LD~(%i%s),E"}, {3,"LD~(%i%s),H"}, {3,"LD~(%i%s),L"}, {1,0}, {3,"LD~(%i%s),A"}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~A,%iH"}, {2,"LD~A,%iL"}, {3,"LD~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~A,%iH"}, {2,"ADD~A,%iL"}, {3,"ADD~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADC~A,%iH"}, {2,"ADC~A,%iL"}, {3,"ADC~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"SUB~%iH"}, {2,"SUB~%iL"}, {3,"SUB~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"SBC~A,%iH"}, {2,"SBC~A,%iL"}, {3,"SBC~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"AND~%iH"}, {2,"AND~%iL"}, {3,"AND~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"XOR~%iH"}, {2,"XOR~%iL"}, {3,"XOR~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"OR~%iH"}, {2,"OR~%iL"}, {3,"OR~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"CP~%iH"}, {2,"CP~%iL"}, {3,"CP~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"POP~%i"}, {1,0}, {2,"EX~(SP),%i"}, {1,0}, {2,"PUSH~%i"}, {1,0}, {1,0}, {1,0}, {2,"JP~(%i)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~SP,%i"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}}; static const TilemDisasmInstruction insts_cb[256] = { {2,"RLC~B"}, {2,"RLC~C"}, {2,"RLC~D"}, {2,"RLC~E"}, {2,"RLC~H"}, {2,"RLC~L"}, {2,"RLC~(HL)"}, {2,"RLC~A"}, {2,"RRC~B"}, {2,"RRC~C"}, {2,"RRC~D"}, {2,"RRC~E"}, {2,"RRC~H"}, {2,"RRC~L"}, {2,"RRC~(HL)"}, {2,"RRC~A"}, {2,"RL~B"}, {2,"RL~C"}, {2,"RL~D"}, {2,"RL~E"}, {2,"RL~H"}, {2,"RL~L"}, {2,"RL~(HL)"}, {2,"RL~A"}, {2,"RR~B"}, {2,"RR~C"}, {2,"RR~D"}, {2,"RR~E"}, {2,"RR~H"}, {2,"RR~L"}, {2,"RR~(HL)"}, {2,"RR~A"}, {2,"SLA~B"}, {2,"SLA~C"}, {2,"SLA~D"}, {2,"SLA~E"}, {2,"SLA~H"}, {2,"SLA~L"}, {2,"SLA~(HL)"}, {2,"SLA~A"}, {2,"SRA~B"}, {2,"SRA~C"}, {2,"SRA~D"}, {2,"SRA~E"}, {2,"SRA~H"}, {2,"SRA~L"}, {2,"SRA~(HL)"}, {2,"SRA~A"}, {2,"SLIA~B"}, {2,"SLIA~C"}, {2,"SLIA~D"}, {2,"SLIA~E"}, {2,"SLIA~H"}, {2,"SLIA~L"}, {2,"SLIA~(HL)"}, {2,"SLIA~A"}, {2,"SRL~B"}, {2,"SRL~C"}, {2,"SRL~D"}, {2,"SRL~E"}, {2,"SRL~H"}, {2,"SRL~L"}, {2,"SRL~(HL)"}, {2,"SRL~A"}, {2,"BIT~0,B"}, {2,"BIT~0,C"}, {2,"BIT~0,D"}, {2,"BIT~0,E"}, {2,"BIT~0,H"}, {2,"BIT~0,L"}, {2,"BIT~0,(HL)"}, {2,"BIT~0,A"}, {2,"BIT~1,B"}, {2,"BIT~1,C"}, {2,"BIT~1,D"}, {2,"BIT~1,E"}, {2,"BIT~1,H"}, {2,"BIT~1,L"}, {2,"BIT~1,(HL)"}, {2,"BIT~1,A"}, {2,"BIT~2,B"}, {2,"BIT~2,C"}, {2,"BIT~2,D"}, {2,"BIT~2,E"}, {2,"BIT~2,H"}, {2,"BIT~2,L"}, {2,"BIT~2,(HL)"}, {2,"BIT~2,A"}, {2,"BIT~3,B"}, {2,"BIT~3,C"}, {2,"BIT~3,D"}, {2,"BIT~3,E"}, {2,"BIT~3,H"}, {2,"BIT~3,L"}, {2,"BIT~3,(HL)"}, {2,"BIT~3,A"}, {2,"BIT~4,B"}, {2,"BIT~4,C"}, {2,"BIT~4,D"}, {2,"BIT~4,E"}, {2,"BIT~4,H"}, {2,"BIT~4,L"}, {2,"BIT~4,(HL)"}, {2,"BIT~4,A"}, {2,"BIT~5,B"}, {2,"BIT~5,C"}, {2,"BIT~5,D"}, {2,"BIT~5,E"}, {2,"BIT~5,H"}, {2,"BIT~5,L"}, {2,"BIT~5,(HL)"}, {2,"BIT~5,A"}, {2,"BIT~6,B"}, {2,"BIT~6,C"}, {2,"BIT~6,D"}, {2,"BIT~6,E"}, {2,"BIT~6,H"}, {2,"BIT~6,L"}, {2,"BIT~6,(HL)"}, {2,"BIT~6,A"}, {2,"BIT~7,B"}, {2,"BIT~7,C"}, {2,"BIT~7,D"}, {2,"BIT~7,E"}, {2,"BIT~7,H"}, {2,"BIT~7,L"}, {2,"BIT~7,(HL)"}, {2,"BIT~7,A"}, {2,"RES~0,B"}, {2,"RES~0,C"}, {2,"RES~0,D"}, {2,"RES~0,E"}, {2,"RES~0,H"}, {2,"RES~0,L"}, {2,"RES~0,(HL)"}, {2,"RES~0,A"}, {2,"RES~1,B"}, {2,"RES~1,C"}, {2,"RES~1,D"}, {2,"RES~1,E"}, {2,"RES~1,H"}, {2,"RES~1,L"}, {2,"RES~1,(HL)"}, {2,"RES~1,A"}, {2,"RES~2,B"}, {2,"RES~2,C"}, {2,"RES~2,D"}, {2,"RES~2,E"}, {2,"RES~2,H"}, {2,"RES~2,L"}, {2,"RES~2,(HL)"}, {2,"RES~2,A"}, {2,"RES~3,B"}, {2,"RES~3,C"}, {2,"RES~3,D"}, {2,"RES~3,E"}, {2,"RES~3,H"}, {2,"RES~3,L"}, {2,"RES~3,(HL)"}, {2,"RES~3,A"}, {2,"RES~4,B"}, {2,"RES~4,C"}, {2,"RES~4,D"}, {2,"RES~4,E"}, {2,"RES~4,H"}, {2,"RES~4,L"}, {2,"RES~4,(HL)"}, {2,"RES~4,A"}, {2,"RES~5,B"}, {2,"RES~5,C"}, {2,"RES~5,D"}, {2,"RES~5,E"}, {2,"RES~5,H"}, {2,"RES~5,L"}, {2,"RES~5,(HL)"}, {2,"RES~5,A"}, {2,"RES~6,B"}, {2,"RES~6,C"}, {2,"RES~6,D"}, {2,"RES~6,E"}, {2,"RES~6,H"}, {2,"RES~6,L"}, {2,"RES~6,(HL)"}, {2,"RES~6,A"}, {2,"RES~7,B"}, {2,"RES~7,C"}, {2,"RES~7,D"}, {2,"RES~7,E"}, {2,"RES~7,H"}, {2,"RES~7,L"}, {2,"RES~7,(HL)"}, {2,"RES~7,A"}, {2,"SET~0,B"}, {2,"SET~0,C"}, {2,"SET~0,D"}, {2,"SET~0,E"}, {2,"SET~0,H"}, {2,"SET~0,L"}, {2,"SET~0,(HL)"}, {2,"SET~0,A"}, {2,"SET~1,B"}, {2,"SET~1,C"}, {2,"SET~1,D"}, {2,"SET~1,E"}, {2,"SET~1,H"}, {2,"SET~1,L"}, {2,"SET~1,(HL)"}, {2,"SET~1,A"}, {2,"SET~2,B"}, {2,"SET~2,C"}, {2,"SET~2,D"}, {2,"SET~2,E"}, {2,"SET~2,H"}, {2,"SET~2,L"}, {2,"SET~2,(HL)"}, {2,"SET~2,A"}, {2,"SET~3,B"}, {2,"SET~3,C"}, {2,"SET~3,D"}, {2,"SET~3,E"}, {2,"SET~3,H"}, {2,"SET~3,L"}, {2,"SET~3,(HL)"}, {2,"SET~3,A"}, {2,"SET~4,B"}, {2,"SET~4,C"}, {2,"SET~4,D"}, {2,"SET~4,E"}, {2,"SET~4,H"}, {2,"SET~4,L"}, {2,"SET~4,(HL)"}, {2,"SET~4,A"}, {2,"SET~5,B"}, {2,"SET~5,C"}, {2,"SET~5,D"}, {2,"SET~5,E"}, {2,"SET~5,H"}, {2,"SET~5,L"}, {2,"SET~5,(HL)"}, {2,"SET~5,A"}, {2,"SET~6,B"}, {2,"SET~6,C"}, {2,"SET~6,D"}, {2,"SET~6,E"}, {2,"SET~6,H"}, {2,"SET~6,L"}, {2,"SET~6,(HL)"}, {2,"SET~6,A"}, {2,"SET~7,B"}, {2,"SET~7,C"}, {2,"SET~7,D"}, {2,"SET~7,E"}, {2,"SET~7,H"}, {2,"SET~7,L"}, {2,"SET~7,(HL)"}, {2,"SET~7,A"}}; static const TilemDisasmInstruction insts_ddfdcb[256] = { {4,"RLC~B,(%i%s)"}, {4,"RLC~C,(%i%s)"}, {4,"RLC~D,(%i%s)"}, {4,"RLC~E,(%i%s)"}, {4,"RLC~H,(%i%s)"}, {4,"RLC~L,(%i%s)"}, {4,"RLC~(%i%s)"}, {4,"RLC~A,(%i%s)"}, {4,"RRC~B,(%i%s)"}, {4,"RRC~C,(%i%s)"}, {4,"RRC~D,(%i%s)"}, {4,"RRC~E,(%i%s)"}, {4,"RRC~H,(%i%s)"}, {4,"RRC~L,(%i%s)"}, {4,"RRC~(%i%s)"}, {4,"RRC~A,(%i%s)"}, {4,"RL~B,(%i%s)"}, {4,"RL~C,(%i%s)"}, {4,"RL~D,(%i%s)"}, {4,"RL~E,(%i%s)"}, {4,"RL~H,(%i%s)"}, {4,"RL~L,(%i%s)"}, {4,"RL~(%i%s)"}, {4,"RL~A,(%i%s)"}, {4,"RR~B,(%i%s)"}, {4,"RR~C,(%i%s)"}, {4,"RR~D,(%i%s)"}, {4,"RR~E,(%i%s)"}, {4,"RR~H,(%i%s)"}, {4,"RR~L,(%i%s)"}, {4,"RR~(%i%s)"}, {4,"RR~A,(%i%s)"}, {4,"SLA~B,(%i%s)"}, {4,"SLA~C,(%i%s)"}, {4,"SLA~D,(%i%s)"}, {4,"SLA~E,(%i%s)"}, {4,"SLA~H,(%i%s)"}, {4,"SLA~L,(%i%s)"}, {4,"SLA~(%i%s)"}, {4,"SLA~A,(%i%s)"}, {4,"SRA~B,(%i%s)"}, {4,"SRA~C,(%i%s)"}, {4,"SRA~D,(%i%s)"}, {4,"SRA~E,(%i%s)"}, {4,"SRA~H,(%i%s)"}, {4,"SRA~L,(%i%s)"}, {4,"SRA~(%i%s)"}, {4,"SRA~A,(%i%s)"}, {4,"SLIA~B,(%i%s)"}, {4,"SLIA~C,(%i%s)"}, {4,"SLIA~D,(%i%s)"}, {4,"SLIA~E,(%i%s)"}, {4,"SLIA~H,(%i%s)"}, {4,"SLIA~L,(%i%s)"}, {4,"SLIA~(%i%s)"}, {4,"SLIA~A,(%i%s)"}, {4,"SRL~B,(%i%s)"}, {4,"SRL~C,(%i%s)"}, {4,"SRL~D,(%i%s)"}, {4,"SRL~E,(%i%s)"}, {4,"SRL~H,(%i%s)"}, {4,"SRL~L,(%i%s)"}, {4,"SRL~(%i%s)"}, {4,"SRL~A,(%i%s)"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"RES~0,B,(%i%s)"}, {4,"RES~0,C,(%i%s)"}, {4,"RES~0,D,(%i%s)"}, {4,"RES~0,E,(%i%s)"}, {4,"RES~0,H,(%i%s)"}, {4,"RES~0,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~0,A,(%i%s)"}, {4,"RES~1,B,(%i%s)"}, {4,"RES~1,C,(%i%s)"}, {4,"RES~1,D,(%i%s)"}, {4,"RES~1,E,(%i%s)"}, {4,"RES~1,H,(%i%s)"}, {4,"RES~1,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~1,A,(%i%s)"}, {4,"RES~2,B,(%i%s)"}, {4,"RES~2,C,(%i%s)"}, {4,"RES~2,D,(%i%s)"}, {4,"RES~2,E,(%i%s)"}, {4,"RES~2,H,(%i%s)"}, {4,"RES~2,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~2,A,(%i%s)"}, {4,"RES~3,B,(%i%s)"}, {4,"RES~3,C,(%i%s)"}, {4,"RES~3,D,(%i%s)"}, {4,"RES~3,E,(%i%s)"}, {4,"RES~3,H,(%i%s)"}, {4,"RES~3,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~3,A,(%i%s)"}, {4,"RES~4,B,(%i%s)"}, {4,"RES~4,C,(%i%s)"}, {4,"RES~4,D,(%i%s)"}, {4,"RES~4,E,(%i%s)"}, {4,"RES~4,H,(%i%s)"}, {4,"RES~4,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~4,A,(%i%s)"}, {4,"RES~5,B,(%i%s)"}, {4,"RES~5,C,(%i%s)"}, {4,"RES~5,D,(%i%s)"}, {4,"RES~5,E,(%i%s)"}, {4,"RES~5,H,(%i%s)"}, {4,"RES~5,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~5,A,(%i%s)"}, {4,"RES~6,B,(%i%s)"}, {4,"RES~6,C,(%i%s)"}, {4,"RES~6,D,(%i%s)"}, {4,"RES~6,E,(%i%s)"}, {4,"RES~6,H,(%i%s)"}, {4,"RES~6,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~6,A,(%i%s)"}, {4,"RES~7,B,(%i%s)"}, {4,"RES~7,C,(%i%s)"}, {4,"RES~7,D,(%i%s)"}, {4,"RES~7,E,(%i%s)"}, {4,"RES~7,H,(%i%s)"}, {4,"RES~7,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~7,A,(%i%s)"}, {4,"SET~0,B,(%i%s)"}, {4,"SET~0,C,(%i%s)"}, {4,"SET~0,D,(%i%s)"}, {4,"SET~0,E,(%i%s)"}, {4,"SET~0,H,(%i%s)"}, {4,"SET~0,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~0,A,(%i%s)"}, {4,"SET~1,B,(%i%s)"}, {4,"SET~1,C,(%i%s)"}, {4,"SET~1,D,(%i%s)"}, {4,"SET~1,E,(%i%s)"}, {4,"SET~1,H,(%i%s)"}, {4,"SET~1,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~1,A,(%i%s)"}, {4,"SET~2,B,(%i%s)"}, {4,"SET~2,C,(%i%s)"}, {4,"SET~2,D,(%i%s)"}, {4,"SET~2,E,(%i%s)"}, {4,"SET~2,H,(%i%s)"}, {4,"SET~2,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~2,A,(%i%s)"}, {4,"SET~3,B,(%i%s)"}, {4,"SET~3,C,(%i%s)"}, {4,"SET~3,D,(%i%s)"}, {4,"SET~3,E,(%i%s)"}, {4,"SET~3,H,(%i%s)"}, {4,"SET~3,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~3,A,(%i%s)"}, {4,"SET~4,B,(%i%s)"}, {4,"SET~4,C,(%i%s)"}, {4,"SET~4,D,(%i%s)"}, {4,"SET~4,E,(%i%s)"}, {4,"SET~4,H,(%i%s)"}, {4,"SET~4,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~4,A,(%i%s)"}, {4,"SET~5,B,(%i%s)"}, {4,"SET~5,C,(%i%s)"}, {4,"SET~5,D,(%i%s)"}, {4,"SET~5,E,(%i%s)"}, {4,"SET~5,H,(%i%s)"}, {4,"SET~5,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~5,A,(%i%s)"}, {4,"SET~6,B,(%i%s)"}, {4,"SET~6,C,(%i%s)"}, {4,"SET~6,D,(%i%s)"}, {4,"SET~6,E,(%i%s)"}, {4,"SET~6,H,(%i%s)"}, {4,"SET~6,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~6,A,(%i%s)"}, {4,"SET~7,B,(%i%s)"}, {4,"SET~7,C,(%i%s)"}, {4,"SET~7,D,(%i%s)"}, {4,"SET~7,E,(%i%s)"}, {4,"SET~7,H,(%i%s)"}, {4,"SET~7,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~7,A,(%i%s)"}}; static const TilemDisasmInstruction insts_ed[256] = { {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"IN~B,(C)"}, {2,"OUT~(C),B"}, {2,"SBC~HL,BC"}, {4,"LD~(%a),BC"}, {2,"NEG"}, {2,"RETN"}, {2,"IM~0"}, {2,"LD~I,A"}, {2,"IN~C,(C)"}, {2,"OUT~(C),C"}, {2,"ADC~HL,BC"}, {4,"LD~BC,(%a)"}, {2,"NEG*"}, {2,"RETI"}, {2,"IM~0*"}, {2,"LD~R,A"}, {2,"IN~D,(C)"}, {2,"OUT~(C),D"}, {2,"SBC~HL,DE"}, {4,"LD~(%a),DE"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1"}, {2,"LD~A,I"}, {2,"IN~E,(C)"}, {2,"OUT~(C),E"}, {2,"ADC~HL,DE"}, {4,"LD~DE,(%a)"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2"}, {2,"LD~A,R"}, {2,"IN~H,(C)"}, {2,"OUT~(C),H"}, {2,"SBC~HL,HL"}, {4,"LD~(%a),HL*"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RRD"}, {2,"IN~L,(C)"}, {2,"OUT~(C),L"}, {2,"ADC~HL,HL"}, {4,"LD~HL,(%a)*"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RLD"}, {2,"IN~(C)"}, {2,"OUT~(C),0"}, {2,"SBC~HL,SP"}, {4,"LD~(%a),SP"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1*"}, {2,0}, {2,"IN~A,(C)"}, {2,"OUT~(C),A"}, {2,"ADC~HL,SP"}, {4,"LD~SP,(%a)"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2*"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDI"}, {2,"CPI"}, {2,"INI"}, {2,"OUTI"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDD"}, {2,"CPD"}, {2,"IND"}, {2,"OUTD"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDIR"}, {2,"CPIR"}, {2,"INIR"}, {2,"OTIR"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDDR"}, {2,"CPDR"}, {2,"INDR"}, {2,"OTDR"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}}; /* Count number of bytes of arguments for a given instruction/macro pattern */ static int pattern_arg_size(const char* pattern) { char* p; int count = 0, offs; while (*pattern) { if (*pattern != '%') pattern++; else { pattern++; if (*pattern >= '0' && *pattern <= '9') { offs = strtol(pattern, &p, 10); pattern = p; } else { offs = count; } switch (*pattern) { case 0: pattern--; break; case 'b': case 'C': case 'r': case 's': offs++; break; case 'a': case 'c': case 'f': case 'j': case 'w': offs += 2; break; } pattern++; if (offs > count) count = offs; } } return count; } static void get_instruction_info(const TilemDisasm* dasm, const byte* instr, int* length, int* argbase, const char** pattern) { const TilemDisasmSymbol* sym; const TilemDisasmInstruction* ii; dword mvalue; int i; mvalue = 0; for (i = 0; i < 4; i++) { mvalue = (mvalue << 8) | instr[i]; if ((sym = find_symbol(&dasm->macros, mvalue))) { *pattern = sym->name; *length = i + 1 + pattern_arg_size(sym->name); *argbase = i + 1; return; } } if (instr[0] == 0xed) { ii = &insts_ed[instr[1]]; *argbase = 2; } else if (instr[0] == 0xdd || instr[0] == 0xfd) { if (instr[1] == 0xcb) { ii = &insts_ddfdcb[instr[3]]; } else { ii = &insts_ddfd[instr[1]]; } *argbase = 2; } else if (instr[0] == 0xcb) { ii = &insts_cb[instr[1]]; *argbase = 2; } else { ii = &insts_main[instr[0]]; *argbase = 1; } *length = ii->length; if (ii->pattern) { *pattern = ii->pattern; } else { *argbase = 0; if (ii->length == 1) *pattern = "DB~%b"; else *pattern = "DB~%b,%b"; } } static void TILEM_ATTR_PRINTF(3, 4) printv(char** buf, int* bsize, const char* fmt, ...) { va_list ap; int n; if (*bsize == 0) return; va_start(ap, fmt); n = vsnprintf(*buf, *bsize, fmt, ap); va_end(ap); if (n >= *bsize) { *buf += *bsize - 1; **buf = 0; *bsize = 0; } else { *buf += n; **buf = 0; *bsize -= n; } } static void print_byte(char** buf, int* bsize, unsigned int b) { printv(buf, bsize, "$%02X", b); } static void print_word(const TilemDisasm* dasm, char** buf, int* bsize, dword w, int autonum, int autodiff) { TilemDisasmSymbol* sym; if (autonum && w < 0x100) { printv(buf, bsize, "$%04X", w); return; } sym = find_prev_symbol(&dasm->labels, w); if (sym && !strcmp(sym->name, "flags")) { w -= sym->value; sym = find_symbol(&dasm->flags, w); if (sym) { printv(buf, bsize, "flags + %s", sym->name); } else { printv(buf, bsize, "flags + $%02X", w); } } else if (sym && w == sym->value) { printv(buf, bsize, "%s", sym->name); } else if (sym && autodiff && w > 0x8000 && w - sym->value < 64) { printv(buf, bsize, "%s + %d", sym->name, w - sym->value); } else { printv(buf, bsize, "$%04X", w); } } static void print_romcall(const TilemDisasm* dasm, char** buf, int* bsize, dword w) { TilemDisasmSymbol* sym; sym = find_symbol(&dasm->romcalls, w); if (sym) { printv(buf, bsize, "%s", sym->name); } else { printv(buf, bsize, "$%04X", w); } } static void print_flag(const TilemDisasm* dasm, char** buf, int* bsize, unsigned int bit, unsigned int offset, unsigned int prefix) { TilemDisasmSymbol* sym; int i; if (prefix == 0xfd) { sym = find_symbol(&dasm->flags, 0x1000 + (offset << 4) + bit); if (sym) { for (i = 0; sym->name[i]; i++) { printv(buf, bsize, "%c", sym->name[i]); if (sym->name[i] == ',') printv(buf, bsize, " (IY + "); } printv(buf, bsize, ")"); return; } sym = find_symbol(&dasm->flags, offset); if (sym) { printv(buf, bsize, "%d, (IY + %s)", bit, sym->name); return; } } printv(buf, bsize, "%d, (%s", bit, (prefix == 0xfd ? "IY" : "IX")); if (offset & 0x80) { printv(buf, bsize, " - $%02X", 0x100 - offset); } else if (offset) { printv(buf, bsize, " + $%02X", offset); } printv(buf, bsize, ")"); } static void disassemble_pattern(const TilemDisasm* dasm, const char* pattern, const byte* ibuf, dword pc, int argbase, char** buf, int* bsize) { int argidx, offs; char* p; dword w; TilemDisasmSymbol* sym; argidx = argbase; while (*bsize && *pattern) { if (*pattern == '~') printv(buf, bsize, "\t"); else if (*pattern == ',') { printv(buf, bsize, ", "); } else if (*pattern != '%') { printv(buf, bsize, "%c", *pattern); } else { pattern++; if (*pattern >= '0' && *pattern <= '9') { offs = argbase + strtol(pattern, &p, 10); pattern = p; } else { offs = argidx; } switch (*pattern) { case 0: pattern--; break; case '%': printv(buf, bsize, "%%"); break; case 'a': /* %a: word value, always an address */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 0, 1); offs += 2; break; case 'b': /* %b: byte value */ print_byte(buf, bsize, ibuf[offs]); offs++; break; case 'c': /* %c: word value, always a ROM call number */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_romcall(dasm, buf, bsize, w); offs += 2; break; case 'C': /* %C: byte value, always a ROM call number */ print_romcall(dasm, buf, bsize, ibuf[offs]); offs++; break; case 'f': /* %f: flag value */ print_flag(dasm, buf, bsize, (ibuf[offs + 1] >> 3) & 7, ibuf[offs], ibuf[0]); offs += 2; break; case 'i': /* %i: IX or IY by instruction prefix */ if (ibuf[0] == 0xdd) printv(buf, bsize, "IX"); else printv(buf, bsize, "IY"); break; case 'j': /* %j: word value, always a jump address */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 0, 0); offs += 2; break; case 'r': /* %r: one-byte PC-relative value */ if (ibuf[offs] & 0x80) w = pc + offs - 0xff + ibuf[offs]; else w = pc + offs + 1 + ibuf[offs]; print_word(dasm, buf, bsize, w, 0, 0); offs++; break; case 's': /* %s: one-byte signed displacement */ if (ibuf[0] == 0xfd && (sym = find_symbol(&dasm->flags, ibuf[offs]))) { printv(buf, bsize, " + %s", sym->name); } else if (ibuf[offs] & 0x80) { printv(buf, bsize, " - "); print_byte(buf, bsize, 0x100 - ibuf[offs]); } else if (ibuf[offs]) { printv(buf, bsize, " + "); print_byte(buf, bsize, ibuf[offs]); } offs++; break; case 'w': /* %w: word value */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 1, 1); offs += 2; break; case 'z': /* %z: RST target address */ print_word(dasm, buf, bsize, ibuf[0] & 0x38, 0, 0); break; } if (offs > argidx) argidx = offs; } pattern++; } } void tilem_disasm_disassemble(const TilemDisasm* dasm, TilemCalc* calc, int phys, dword addr, dword* nextaddr, char* buffer, int bufsize) { byte ibuf[64]; dword a, addr_l, max; int length, argbase, i; const char* pattern; if (phys) { max = calc->hw.romsize + calc->hw.ramsize; for (i = 0; i < 4; i++) { a = (addr + i) % max; ibuf[i] = calc->mem[a]; } addr_l = (*calc->hw.mem_ptol)(calc, addr); if (addr_l == 0xffffffff) addr_l = (addr & 0x3fff) | 0x4000; } else { max = 0x10000; for (i = 0; i < 4; i++) { a = (addr + i) & 0xffff; ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, a)]; } addr_l = addr; } get_instruction_info(dasm, ibuf, &length, &argbase, &pattern); if (phys) { for (i = 0; i < length; i++) { ibuf[i] = calc->mem[addr]; addr = (addr + 1) % max; } } else { for (i = 0; i < length; i++) { ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, addr)]; addr = (addr + 1) & 0xffff; } } if (nextaddr) *nextaddr = addr; if (buffer) { disassemble_pattern(dasm, pattern, ibuf, addr_l, argbase, &buffer, &bufsize); } } tilem-2.0/db/listing.c000066400000000000000000000202311220200411600146510ustar00rootroot00000000000000/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "tilemdb.h" struct _TilemListingLineCache { dword minaddr; dword maxaddr; int* order; }; static void sort_lines(TilemListing* lst, int start, int end) { int pivot, ncstart, ncend, n; dword addr, pivotaddr; int* order = lst->linecache->order; pivot = order[start]; pivotaddr = lst->lines[pivot].address; ncstart = start + 1; ncend = end; while (ncstart < ncend) { n = order[ncstart]; addr = lst->lines[n].address; if (addr < pivotaddr) { ncstart++; } else { order[ncstart] = order[ncend - 1]; order[ncend - 1] = n; ncend--; } } ncstart--; order[start] = order[ncstart]; order[ncstart] = pivot; if (ncstart > start + 1) sort_lines(lst, start, ncstart); if (end > ncend + 1) sort_lines(lst, ncend, end); } static void ensure_order(TilemListing* lst) { int i; if (lst->nlines == 0) { lst->linecache->minaddr = 0xffff; lst->linecache->maxaddr = 0; } else if (!lst->linecache->order) { lst->linecache->order = tilem_new_atomic(int, lst->nlines); for (i = 0; i < lst->nlines; i++) lst->linecache->order[i] = i; sort_lines(lst, 0, lst->nlines); i = lst->linecache->order[0]; lst->linecache->minaddr = lst->lines[i].address; i = lst->linecache->order[lst->nlines - 1]; lst->linecache->maxaddr = lst->lines[i].address; } } static void order_destroyed(TilemListing* lst) { tilem_free(lst->linecache->order); lst->linecache->order = NULL; } static int first_at_addr(TilemListing* lst, dword addr) { int start, end, i; start = 0; end = lst->nlines; while (start < end) { i = (start + end) / 2; if (lst->lines[lst->linecache->order[i]].address < addr) start = i + 1; else end = i; } return start; } TilemListing* tilem_listing_new() { TilemListing* lst = tilem_new0(TilemListing, 1); lst->lines = NULL; lst->linecache = tilem_new0(TilemListingLineCache, 1); lst->linecache->order = NULL; return lst; } void tilem_listing_free(TilemListing* lst) { int i; if (!lst) return; for (i = 0; i < lst->nlines; i++) tilem_free(lst->lines[i].text); tilem_free(lst->lines); tilem_free(lst->linecache->order); tilem_free(lst->linecache); tilem_free(lst); } void tilem_listing_file_clear(TilemListing* lst) { order_destroyed(lst); lst->nlines = 0; lst->nlines_a = 0; tilem_free(lst->lines); lst->lines = NULL; } void tilem_listing_append_line(TilemListing* lst, int srclinenum, dword address, int depth, int datasize, const byte* data, const char* text, int is_expansion) { TilemListingLine* line; int i; order_destroyed(lst); lst->nlines++; if (lst->nlines >= lst->nlines_a) { lst->nlines_a = lst->nlines * 2; lst->lines = tilem_renew(TilemListingLine, lst->lines, lst->nlines_a); } line = &lst->lines[lst->nlines - 1]; line->listing = lst; line->srclinenum = srclinenum; line->address = address & 0xffff; line->depth = depth; if (datasize > TILEM_MAX_LINE_BYTES) datasize = TILEM_MAX_LINE_BYTES; line->datasize = datasize; for (i = 0; i < datasize; i++) line->data[i] = data[i]; if (text) { line->text = tilem_new_atomic(char, strlen(text) + 1); strcpy(line->text, text); if ((text[0] >= 'A' && text[0] <= 'Z') || (text[0] >= 'a' && text[0] <= 'z') || (text[0] & 0x80)) line->is_label = 1; else line->is_label = 0; } else { line->text = NULL; line->is_label = 0; } line->is_expansion = is_expansion; } void tilem_listing_get_address_range(TilemListing* lst, dword* min, dword* max) { ensure_order(lst); if (min) *min = lst->linecache->minaddr; if (max) *max = lst->linecache->maxaddr; } TilemListingLine* tilem_listing_line_get_next(TilemListingLine* line) { if (!line) return NULL; if (line != line->listing->lines + line->listing->nlines) return line + 1; else return NULL; } TilemListingLine* tilem_listing_line_get_prev(TilemListingLine* line) { if (!line) return NULL; if (line != line->listing->lines) return line - 1; else return NULL; } TilemListingLine* tilem_listing_get_loaded_line_at_addr(TilemListing* lst, dword address, TilemCalc* calc, int match_internal) { int i; TilemListingLine *line; ensure_order(lst); i = first_at_addr(lst, address + 1); while (--i >= 0) { line = &lst->lines[lst->linecache->order[i]]; if (match_internal) { if (line->address + TILEM_MAX_LINE_BYTES <= address) return NULL; else if (line->address + line->datasize <= address) continue; } else { if (line->address != address) return NULL; } if (tilem_listing_line_is_loaded(line, calc)) return line; } return NULL; } static inline unsigned int getbyte(TilemCalc* calc, dword addr) { dword pa = (*calc->hw.mem_ltop)(calc, addr & 0xffff); return calc->mem[pa]; } static inline int line_load_count(const TilemListingLine* line, TilemCalc* calc) { int i, n; for (i = n = 0; i < line->datasize; i++) if (getbyte(calc, line->address + i) == line->data[i]) n++; return n; } static inline TilemListingLine* get_next_local(TilemListingLine* line) { TilemListingLine* nline = tilem_listing_line_get_next(line); if (nline && nline->address != line->address + line->datasize) return NULL; else return nline; } static inline TilemListingLine* get_prev_local(TilemListingLine* line) { TilemListingLine* nline = tilem_listing_line_get_prev(line); if (nline && nline->address != line->address + line->datasize) return NULL; else return nline; } int tilem_listing_line_is_loaded(TilemListingLine* line, TilemCalc* calc) { int nbytes, ngood; TilemListingLine *nline; while (line->datasize == 0 && (nline = get_next_local(line))) line = nline; if (line_load_count(line, calc) != line->datasize) return 0; else { nbytes = ngood = line->datasize; nline = line; while ((nline = get_next_local(nline)) && nline->address < line->address + 32) { nbytes += nline->datasize; ngood += line_load_count(nline, calc); } nline = line; while ((nline = get_prev_local(nline)) && line->address < nline->address + 32) { nbytes += nline->datasize; ngood += line_load_count(nline, calc); } return (ngood > nbytes / 2); } } static int bptest_listing_line(TilemCalc* calc, dword addr TILEM_ATTR_UNUSED, void* data) { return tilem_listing_line_is_loaded(data, calc); } int tilem_listing_line_add_breakpoint(TilemListingLine* line, TilemCalc* calc, int bptype, int match_internal) { dword max; if (match_internal && line->datasize > 0) max = line->address + line->datasize - 1; else max = line->address; return tilem_z80_add_breakpoint(calc, bptype, line->address, max, 0xffff, &bptest_listing_line, (void*) line); } static int bptest_listing_int(TilemCalc* calc, dword addr, void* data) { TilemListing* lst = data; if (tilem_listing_get_loaded_line_at_addr(lst, addr, calc, 1)) return 1; else return 0; } static int bptest_listing_top(TilemCalc* calc, dword addr, void* data) { TilemListing* lst = data; if (tilem_listing_get_loaded_line_at_addr(lst, addr, calc, 0)) return 1; else return 0; } int tilem_listing_add_breakpoint(TilemListing* lst, TilemCalc* calc, int bptype, int match_internal) { dword min, max; tilem_listing_get_address_range(lst, &min, &max); return tilem_z80_add_breakpoint(calc, bptype, min, max, 0xffff, (match_internal ? &bptest_listing_int : &bptest_listing_top), lst); } tilem-2.0/db/lstfile.c000066400000000000000000000233141220200411600146470ustar00rootroot00000000000000/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "tilemdb.h" /* Test if TEXT contains a correctly-formatted number WIDTH characters wide. If PAD = 0, number is padded on left with zeroes; if PAD = 1, number is padded on left with spaces; if PAD = -1, number is padded on right with spaces. */ static int match_num(const char* text, int width, int pad, int base, int* value) { int start, end; char* p; if ((int) strlen(text) < width) return 0; start = 0; while (start < width && text[start] == ' ') start++; end = width; while (end > start && text[end - 1] == ' ') end--; if (start == end) return 0; if (pad != 1 && start != 0) return 0; if (pad != -1 && end != width) return 0; if (pad != 0 && text[start] == '0' && start != end - 1) return 0; *value = strtol(text + start, &p, base); return (p == text + end); } /* Test if string exactly matches a printf-like format string. %d, %x match decimal and hex integers; %s matches any string of exactly that width. */ static int match_pattern(const char* text, const char* pattern, int* datasize, byte* data, ...) { int width, pad, value, *ip; char **sp; char *end; va_list ap; int failed = 0, lastdb = 0; va_start(ap, data); *datasize = 0; while (!failed && *pattern) { if (*pattern != '%') { if (*text == *pattern) text++; else failed = 1; pattern++; } else { pattern++; if (*pattern == '0') { pad = 0; pattern++; } else if (*pattern == '-') { pad = -1; pattern++; } else pad = 1; width = strtol(pattern, &end, 10); pattern = end; if (!width) width = strlen(text); else if (width > (int) strlen(text)) { failed = 1; break; } switch (*pattern) { case '%': if (*text == '%') text++; else failed = 1; break; case 'B': if (text[0] == ' ' && text[1] == ' ') { lastdb = 1; text += 2; break; } case 'b': if (match_num(text, width, pad, 16, &value) && !lastdb) { data[*datasize] = value; (*datasize)++; text += width; } else { failed = 1; } break; case 'd': ip = va_arg(ap, int *); if (match_num(text, width, pad, 10, ip)) { text += width; } else { failed = 1; } break; case 'x': ip = va_arg(ap, int *); if (match_num(text, width, pad, 16, ip)) { text += width; } else { failed = 1; } break; case 's': sp = va_arg(ap, char **); *sp = (char*) text; text += width; break; } pattern++; } } va_end(ap); return (!failed && *text == 0); } static int get_tasm_depth(const char* s) { if (!strncmp(s, "+++", 3)) return 4; else if (!strncmp(s, "++ ", 3)) return 3; else if (!strncmp(s, "+ ", 3)) return 2; else if (!strncmp(s, " ", 3)) return 1; else return 0; } static int parse_listing(const char* line, int* linenum, int* addr, int* depth, int* datasize, byte* data, char** text, int* isexp, const TilemListingLine* prevline) { int dummy; char *p, *q; /* tasm */ if (match_pattern(line, "%04d%3s%04x%1s%02B %02B %02B %02B %s", datasize, data, linenum, &p, addr, &q, text)) { *depth = get_tasm_depth(p); *isexp = 0; return 1; } if (match_pattern(line, "%04d%3s%04x%1s%02b %02b %02b ", datasize, data, linenum, &p, addr, &q) || match_pattern(line, "%04d%3s%04x%1s%02b %02b ", datasize, data, linenum, &p, addr, &q) || match_pattern(line, "%04d%3s%04x%1s%02b ", datasize, data, linenum, &p, addr, &q)) { *depth = get_tasm_depth(p); *text = NULL; *isexp = 0; return 1; } /* zmasm */ if (match_pattern(line, "%08x %02B %02B %02B %02B %02B %02B %4s %5d %s", datasize, data, addr, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, "%08x %02B %02B %02B %02B %02B %02B %4s %5d", datasize, data, addr, &p, linenum) && p[0] >= 'A' && p[0] <= 'Z') { *text = NULL; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, " %4s %5d %s", datasize, data, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *addr = prevline->address + prevline->datasize; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, " %08x %4s %5d %s", datasize, data, &dummy, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *addr = prevline->address + prevline->datasize; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } /* spasm - old and new versions */ if (match_pattern(line, "%5d %04x: %02b %02b %02b %02b %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b %02b %02b - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b %02b - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b - - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: - - - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b %02b %02b %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b %02b - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b - - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b - - - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x - - - - %s", datasize, data, linenum, &dummy, addr, text)) { *depth = *isexp = 0; return 1; } if (match_pattern(line, " %02b %02b %02b %02b %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b - %s", datasize, data, text) || match_pattern(line, " %02b %02b - - %s", datasize, data, text) || match_pattern(line, " %02b - - - %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b %02b %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b - %s", datasize, data, text) || match_pattern(line, " %02b %02b - - %s", datasize, data, text) || match_pattern(line, " %02b - - - %s", datasize, data, text)) { *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = *isexp = 0; return 1; } /* tpasm or miniasm */ if (match_pattern(line, "%-5d %08x %02B %02B %02B %02B %02B %2s%s", datasize, data, linenum, addr, &p, text) || match_pattern(line, "%5d %08x %02B %02B %02B %02B %02B %2s%s", datasize, data, linenum, addr, &p, text)) { *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, "%-5d %08x (%08x) %2s%s", datasize, data, linenum, addr, &dummy, &p, text) || match_pattern(line, "%5d %08x (%08x) %2s%s", datasize, data, linenum, addr, &dummy, &p, text)) { *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, " %02B %02B %02B %02B %02B %1s", datasize, data, &p)) { *text = NULL; *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, " %02b %02b %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b", datasize, data) || match_pattern(line, " %02b", datasize, data)) { *text = NULL; *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = *isexp = 0; return 1; } printf("***\t%s\n", line); return 0; } int tilem_listing_read_file(TilemListing* lst, FILE* lstfile) { char buf[1024]; int linenum, addr, depth, isexp, datasize; byte data[TILEM_MAX_LINE_BYTES]; char *text; int i, status = 1; TilemListingLine prevline; prevline.text = NULL; prevline.srclinenum = 0; prevline.address = 0xffffffff; prevline.depth = 0; prevline.datasize = 0; while (fgets(buf, sizeof(buf), lstfile)) { i = strlen(buf); while (i > 0 && (buf[i - 1] == '\r' || buf[i - 1] == '\n')) i--; buf[i] = 0; if (parse_listing(buf, &linenum, &addr, &depth, &datasize, data, &text, &isexp, &prevline)) { if (linenum) status = 0; tilem_listing_append_line(lst, linenum, addr, depth, datasize, data, text, isexp); prevline = lst->lines[lst->nlines - 1]; } } return status; } tilem-2.0/db/tilemdb.h000066400000000000000000000112541220200411600146320ustar00rootroot00000000000000/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEMDB_H #define _TILEMDB_H #include #ifdef __cplusplus extern "C" { #endif /* Disassembler */ typedef struct _TilemDisasm TilemDisasm; /* Create a new disassembly context. */ TilemDisasm* tilem_disasm_new(void); /* Free a disassembly context. */ void tilem_disasm_free(TilemDisasm* dasm); /* Read symbols from SYMFILE. */ int tilem_disasm_read_symbol_file(TilemDisasm* dasm, FILE* symfile); /* Set symbol NAME to value VALUE. */ void tilem_disasm_set_label(TilemDisasm* dasm, const char* name, dword value); /* Check if symbol NAME is defined. If symbol is defined and VALUE is non-null, set *VALUE to symbol's value. */ int tilem_disasm_get_label(const TilemDisasm* dasm, const char* name, dword* value); /* Check if a label is defined at the given address. */ const char* tilem_disasm_get_label_at_address(const TilemDisasm* dasm, dword addr); /* Disassemble a line starting at address ADDR. Store text (up to BUFSIZE characters) in BUFFER, and set *NEXTADDR to the address of the following line. If PHYS is 0, use logical addresses; otherwise use physical addresses. */ void tilem_disasm_disassemble(const TilemDisasm* dasm, TilemCalc* calc, int phys, dword addr, dword* nextaddr, char* buffer, int bufsize); /* Assembly listing files */ typedef struct _TilemListing TilemListing; typedef struct _TilemListingLine TilemListingLine; typedef struct _TilemListingLineCache TilemListingLineCache; #define TILEM_MAX_LINE_BYTES 6 struct _TilemListingLine { TilemListing* listing; /* Listing to which this line belongs */ char* text; /* Text of source line */ int srclinenum; /* Line number in original source file */ dword address; /* Address */ int depth; /* Source file inclusion depth */ byte datasize; /* Number of data bytes */ unsigned is_label : 1; /* = 1 if line appears to contain a label */ unsigned is_expansion : 1; /* = 1 if line is part of a macro expansion */ byte data[TILEM_MAX_LINE_BYTES]; /* Data bytes on this line */ }; struct _TilemListing { int nlines; int nlines_a; TilemListingLine* lines; TilemListingLineCache* linecache; }; /* Create new assembly listing. */ TilemListing* tilem_listing_new(void); /* Free listing data. */ void tilem_listing_free(TilemListing* lst); /* Clear listing file contents. */ void tilem_listing_clear(TilemListing* lst); /* Add a line to the end of the listing file. */ void tilem_listing_append_line(TilemListing* lst, int srclinenum, dword address, int depth, int datasize, const byte* data, const char* text, int is_expansion); /* Calculate minimum and maximum address used by a listing file. */ void tilem_listing_get_address_range(TilemListing* lst, dword* min, dword* max); /* Get next line, if any. */ TilemListingLine* tilem_listing_line_get_next(TilemListingLine* line); /* Get previous line, if any. */ TilemListingLine* tilem_listing_line_get_prev(TilemListingLine* line); /* Find the line (if any) currently loaded at the given address. If MATCH_INTERNAL = 0, find only lines that begin at that address. */ TilemListingLine* tilem_listing_get_loaded_line_at_addr(TilemListing* lst, dword address, TilemCalc* calc, int match_internal); /* Check if given line is currently loaded (and mapped into Z80 memory space.) */ int tilem_listing_line_is_loaded(TilemListingLine* line, TilemCalc* calc); /* Set a breakpoint to be triggered on the given line. */ int tilem_listing_line_add_breakpoint(TilemListingLine* line, TilemCalc* calc, int bptype, int match_internal); /* Set a breakpoint to be triggered on any line in the listing. */ int tilem_listing_add_breakpoint(TilemListing* lst, TilemCalc* calc, int bptype, int match_internal); /* Read assembly listing from LSTFILE. */ int tilem_listing_read_file(TilemListing* lst, FILE* lstfile); #ifdef __cplusplus } #endif #endif tilem-2.0/emu/000077500000000000000000000000001220200411600132375ustar00rootroot00000000000000tilem-2.0/emu/Makefile.in000066400000000000000000000161501220200411600153070ustar00rootroot00000000000000prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = @bindir@ datadir = @datadir@ pkgdatadir = @datadir@/tilem2 mandir = @mandir@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ AR = @AR@ CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ OPT_CFLAGS = @OPT_CFLAGS@ RANLIB = @RANLIB@ SHELL = @SHELL@ core_objects = calcs.o z80.o state.o rom.o flash.o link.o keypad.o lcd.o \ cert.o md5.o timers.o monolcd.o graylcd.o grayimage.o graycolor.o x7_objects = x7_init.o x7_io.o x7_memory.o x7_subcore.o x1_objects = x1_init.o x1_io.o x1_memory.o x1_subcore.o x2_objects = x2_init.o x2_io.o x2_memory.o x2_subcore.o x3_objects = x3_init.o x3_io.o x3_memory.o x3_subcore.o xp_objects = xp_init.o xp_io.o xp_memory.o xp_subcore.o xs_objects = xs_init.o xs_io.o xs_memory.o xs_subcore.o x4_objects = x4_init.o x4_io.o x4_memory.o x4_subcore.o xz_objects = xz_init.o xz_io.o xz_memory.o xz_subcore.o xn_objects = xn_init.o xn_io.o xn_memory.o xn_subcore.o x5_objects = x5_init.o x5_io.o x5_memory.o x5_subcore.o x6_objects = x6_init.o x6_io.o x6_memory.o x6_subcore.o objects = $(core_objects) $(x7_objects) $(x1_objects) $(x2_objects) \ $(x3_objects) $(xp_objects) $(xs_objects) $(x4_objects) $(xz_objects) \ $(xn_objects) $(x5_objects) $(x6_objects) compile = $(CC) -I$(top_builddir) -I$(srcdir) $(CFLAGS) $(CPPFLAGS) $(DEFS) $(OPT_CFLAGS) all: libtilemcore.a libtilemcore.a: $(objects) $(AR) cru libtilemcore.a $(objects) $(RANLIB) libtilemcore.a # Main emulator core calcs.o: calcs.c tilem.h z80.h ../config.h $(compile) -c $(srcdir)/calcs.c z80.o: z80.c z80.h z80cmds.h z80main.h z80cb.h z80ddfd.h z80ed.h tilem.h ../config.h $(compile) -c $(srcdir)/z80.c state.o: state.c tilem.h z80.h ../config.h $(compile) -c $(srcdir)/state.c rom.o: rom.c tilem.h ../config.h $(compile) -c $(srcdir)/rom.c flash.o: flash.c tilem.h ../config.h $(compile) -c $(srcdir)/flash.c link.o: link.c tilem.h ../config.h $(compile) -c $(srcdir)/link.c keypad.o: keypad.c tilem.h scancodes.h ../config.h $(compile) -c $(srcdir)/keypad.c lcd.o: lcd.c tilem.h ../config.h $(compile) -c $(srcdir)/lcd.c cert.o: cert.c tilem.h ../config.h $(compile) -c $(srcdir)/cert.c md5.o: md5.c tilem.h ../config.h $(compile) -c $(srcdir)/md5.c timers.o: timers.c tilem.h ../config.h $(compile) -c $(srcdir)/timers.c monolcd.o: monolcd.c tilem.h ../config.h $(compile) -c $(srcdir)/monolcd.c graylcd.o: graylcd.c tilem.h graylcd.h ../config.h $(compile) -c $(srcdir)/graylcd.c grayimage.o: grayimage.c tilem.h graylcd.h ../config.h $(compile) -c $(srcdir)/grayimage.c graycolor.o: graycolor.c tilem.h ../config.h $(compile) -c $(srcdir)/graycolor.c # TI-73 x7_init.o: x7/x7_init.c x7/x7.h tilem.h ../config.h $(compile) -c $(srcdir)/x7/x7_init.c x7_io.o: x7/x7_io.c x7/x7.h tilem.h ../config.h $(compile) -c $(srcdir)/x7/x7_io.c x7_memory.o: x7/x7_memory.c x7/x7.h tilem.h ../config.h $(compile) -c $(srcdir)/x7/x7_memory.c x7_subcore.o: x7/x7_subcore.c x7/x7.h tilem.h ../config.h $(compile) -c $(srcdir)/x7/x7_subcore.c # TI-81 x1_init.o: x1/x1_init.c x1/x1.h tilem.h ../config.h $(compile) -c $(srcdir)/x1/x1_init.c x1_io.o: x1/x1_io.c x1/x1.h tilem.h ../config.h $(compile) -c $(srcdir)/x1/x1_io.c x1_memory.o: x1/x1_memory.c x1/x1.h tilem.h ../config.h $(compile) -c $(srcdir)/x1/x1_memory.c x1_subcore.o: x1/x1_subcore.c x1/x1.h tilem.h ../config.h $(compile) -c $(srcdir)/x1/x1_subcore.c # TI-82 x2_init.o: x2/x2_init.c x2/x2.h tilem.h ../config.h $(compile) -c $(srcdir)/x2/x2_init.c x2_io.o: x2/x2_io.c x2/x2.h tilem.h ../config.h $(compile) -c $(srcdir)/x2/x2_io.c x2_memory.o: x2/x2_memory.c x2/x2.h tilem.h ../config.h $(compile) -c $(srcdir)/x2/x2_memory.c x2_subcore.o: x2/x2_subcore.c x2/x2.h tilem.h ../config.h $(compile) -c $(srcdir)/x2/x2_subcore.c # TI-83 x3_init.o: x3/x3_init.c x3/x3.h tilem.h ../config.h $(compile) -c $(srcdir)/x3/x3_init.c x3_io.o: x3/x3_io.c x3/x3.h tilem.h ../config.h $(compile) -c $(srcdir)/x3/x3_io.c x3_memory.o: x3/x3_memory.c x3/x3.h tilem.h ../config.h $(compile) -c $(srcdir)/x3/x3_memory.c x3_subcore.o: x3/x3_subcore.c x3/x3.h tilem.h ../config.h $(compile) -c $(srcdir)/x3/x3_subcore.c # TI-83 Plus xp_init.o: xp/xp_init.c xp/xp.h tilem.h ../config.h $(compile) -c $(srcdir)/xp/xp_init.c xp_io.o: xp/xp_io.c xp/xp.h tilem.h ../config.h $(compile) -c $(srcdir)/xp/xp_io.c xp_memory.o: xp/xp_memory.c xp/xp.h tilem.h ../config.h $(compile) -c $(srcdir)/xp/xp_memory.c xp_subcore.o: xp/xp_subcore.c xp/xp.h tilem.h ../config.h $(compile) -c $(srcdir)/xp/xp_subcore.c # TI-83 Plus SE xs_init.o: xs/xs_init.c xs/xs.h tilem.h ../config.h $(compile) -c $(srcdir)/xs/xs_init.c xs_io.o: xs/xs_io.c xs/xs.h tilem.h ../config.h $(compile) -c $(srcdir)/xs/xs_io.c xs_memory.o: xs/xs_memory.c xs/xs.h tilem.h ../config.h $(compile) -c $(srcdir)/xs/xs_memory.c xs_subcore.o: xs/xs_subcore.c xs/xs.h tilem.h ../config.h $(compile) -c $(srcdir)/xs/xs_subcore.c # TI-84 Plus x4_init.o: x4/x4_init.c x4/x4.h tilem.h ../config.h $(compile) -c $(srcdir)/x4/x4_init.c x4_io.o: x4/x4_io.c x4/x4.h tilem.h ../config.h $(compile) -c $(srcdir)/x4/x4_io.c x4_memory.o: x4/x4_memory.c x4/x4.h tilem.h ../config.h $(compile) -c $(srcdir)/x4/x4_memory.c x4_subcore.o: x4/x4_subcore.c x4/x4.h tilem.h ../config.h $(compile) -c $(srcdir)/x4/x4_subcore.c # TI-84 Plus SE xz_init.o: xz/xz_init.c xz/xz.h tilem.h ../config.h $(compile) -c $(srcdir)/xz/xz_init.c xz_io.o: xz/xz_io.c xz/xz.h tilem.h ../config.h $(compile) -c $(srcdir)/xz/xz_io.c xz_memory.o: xz/xz_memory.c xz/xz.h tilem.h ../config.h $(compile) -c $(srcdir)/xz/xz_memory.c xz_subcore.o: xz/xz_subcore.c xz/xz.h tilem.h ../config.h $(compile) -c $(srcdir)/xz/xz_subcore.c # TI-Nspire 84 Plus emulator xn_init.o: xn/xn_init.c xn/xn.h tilem.h ../config.h $(compile) -c $(srcdir)/xn/xn_init.c xn_io.o: xn/xn_io.c xn/xn.h tilem.h ../config.h $(compile) -c $(srcdir)/xn/xn_io.c xn_memory.o: xn/xn_memory.c xn/xn.h tilem.h ../config.h $(compile) -c $(srcdir)/xn/xn_memory.c xn_subcore.o: xn/xn_subcore.c xn/xn.h tilem.h ../config.h $(compile) -c $(srcdir)/xn/xn_subcore.c # TI-85 x5_init.o: x5/x5_init.c x5/x5.h tilem.h ../config.h $(compile) -c $(srcdir)/x5/x5_init.c x5_io.o: x5/x5_io.c x5/x5.h tilem.h ../config.h $(compile) -c $(srcdir)/x5/x5_io.c x5_memory.o: x5/x5_memory.c x5/x5.h tilem.h ../config.h $(compile) -c $(srcdir)/x5/x5_memory.c x5_subcore.o: x5/x5_subcore.c x5/x5.h tilem.h ../config.h $(compile) -c $(srcdir)/x5/x5_subcore.c # TI-86 x6_init.o: x6/x6_init.c x6/x6.h tilem.h ../config.h $(compile) -c $(srcdir)/x6/x6_init.c x6_io.o: x6/x6_io.c x6/x6.h tilem.h ../config.h $(compile) -c $(srcdir)/x6/x6_io.c x6_memory.o: x6/x6_memory.c x6/x6.h tilem.h ../config.h $(compile) -c $(srcdir)/x6/x6_memory.c x6_subcore.o: x6/x6_subcore.c x6/x6.h tilem.h ../config.h $(compile) -c $(srcdir)/x6/x6_subcore.c clean: rm -f *.o rm -f libtilemcore.a Makefile: Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && $(SHELL) ./config.status --recheck .PRECIOUS: Makefile $(top_builddir)/config.status .PHONY: clean all tilem-2.0/emu/calcs.c000066400000000000000000000111151220200411600144670ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" #include "z80.h" extern const TilemHardware hardware_ti73, hardware_ti76, hardware_ti81, hardware_ti82, hardware_ti83, hardware_ti83p, hardware_ti83pse, hardware_ti84p, hardware_ti84pse, hardware_ti84pns, hardware_ti85, hardware_ti86; const TilemHardware* hwmodels[] = { &hardware_ti73, &hardware_ti76, &hardware_ti81, &hardware_ti82, &hardware_ti83, &hardware_ti83p, &hardware_ti83pse, &hardware_ti84p, &hardware_ti84pse, &hardware_ti84pns, &hardware_ti85, &hardware_ti86 }; #define NUM_MODELS (sizeof(hwmodels) / sizeof(TilemHardware*)) void tilem_get_supported_hardware(const TilemHardware*** models, int* nmodels) { *models = hwmodels; *nmodels = NUM_MODELS; } void tilem_calc_reset(TilemCalc* calc) { tilem_z80_reset(calc); tilem_lcd_reset(calc); tilem_linkport_reset(calc); tilem_keypad_reset(calc); tilem_flash_reset(calc); tilem_md5_assist_reset(calc); tilem_user_timers_reset(calc); if (calc->hw.reset) (*calc->hw.reset)(calc); } TilemCalc* tilem_calc_new(char id) { int i; TilemCalc* calc; dword msize; for (i = 0; i < (int) NUM_MODELS; i++) { if (hwmodels[i]->model_id == id) { calc = tilem_try_new0(TilemCalc, 1); if (!calc) { return NULL; } calc->hw = *hwmodels[i]; calc->poweronhalt = 1; calc->battery = 60; calc->hwregs = tilem_try_new_atomic(dword, calc->hw.nhwregs); if (!calc->hwregs) { tilem_free(calc); return NULL; } memset(calc->hwregs, 0, calc->hw.nhwregs * sizeof(dword)); msize = (calc->hw.romsize + calc->hw.ramsize + calc->hw.lcdmemsize); calc->mem = tilem_try_new_atomic(byte, msize); if (!calc->mem) { tilem_free(calc->hwregs); tilem_free(calc); return NULL; } calc->ram = calc->mem + calc->hw.romsize; calc->lcdmem = calc->ram + calc->hw.ramsize; memset(calc->ram, 0, msize - calc->hw.romsize); calc->lcd.emuflags = TILEM_LCD_REQUIRE_DELAY; calc->flash.emuflags = TILEM_FLASH_REQUIRE_DELAY; tilem_calc_reset(calc); return calc; } } fprintf(stderr, "INTERNAL ERROR: invalid model ID '%c'\n", id); return NULL; } TilemCalc* tilem_calc_copy(TilemCalc* calc) { TilemCalc* newcalc; dword msize; newcalc = tilem_try_new(TilemCalc, 1); if (!newcalc) return NULL; memcpy(newcalc, calc, sizeof(TilemCalc)); newcalc->hwregs = tilem_try_new_atomic(dword, calc->hw.nhwregs); if (!newcalc->hwregs) { tilem_free(newcalc); return NULL; } memcpy(newcalc->hwregs, calc->hwregs, calc->hw.nhwregs * sizeof(dword)); newcalc->z80.timers = tilem_try_new(TilemZ80Timer, newcalc->z80.ntimers); if (!newcalc->z80.timers) { tilem_free(newcalc->hwregs); tilem_free(newcalc); return NULL; } memcpy(newcalc->z80.timers, calc->z80.timers, newcalc->z80.ntimers * sizeof(TilemZ80Timer)); newcalc->z80.breakpoints = tilem_try_new(TilemZ80Breakpoint, newcalc->z80.nbreakpoints); if (!newcalc->z80.breakpoints) { tilem_free(newcalc->z80.timers); tilem_free(newcalc->hwregs); tilem_free(newcalc); return NULL; } memcpy(newcalc->z80.breakpoints, calc->z80.breakpoints, newcalc->z80.nbreakpoints * sizeof(TilemZ80Breakpoint)); msize = (calc->hw.romsize + calc->hw.ramsize + calc->hw.lcdmemsize); newcalc->mem = tilem_try_new_atomic(byte, msize); if (!newcalc->mem) { tilem_free(newcalc->z80.breakpoints); tilem_free(newcalc->z80.timers); tilem_free(newcalc->hwregs); tilem_free(newcalc); return NULL; } memcpy(newcalc->mem, calc->mem, msize * sizeof(byte)); newcalc->ram = newcalc->mem + calc->hw.romsize; newcalc->lcdmem = newcalc->ram + calc->hw.ramsize; return newcalc; } void tilem_calc_free(TilemCalc* calc) { tilem_free(calc->mem); tilem_free(calc->hwregs); tilem_free(calc->z80.breakpoints); tilem_free(calc->z80.timers); tilem_free(calc); } tilem-2.0/emu/cert.c000066400000000000000000000062551220200411600143500ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" static int certificate_valid(byte* cert) { int i, n; if (cert[0] != 0) return 0; i = 1; /* check that the actual certificate area consists of valid certificate fields */ while (cert[i] <= 0x0F) { switch (cert[i + 1] & 0x0F) { case 0x0D: n = cert[i + 2] + 3; break; case 0x0E: n = (cert[i + 2] << 8) + cert[i + 3] + 4; break; case 0x0F: n = 6; break; default: n = (cert[i + 1] & 0xf) + 2; } i += n; if (i >= 0x2000) return 0; } /* check that the fields end with FF */ if (cert[i] != 0xFF) return 0; /* if there are fields present, assume the certificate is OK */ if (i > 1) return 1; /* no fields present -> this could be an incompletely-patched certificate from an older version of TilEm; verify that the next 4k bytes are truly empty */ while (i < 0x1000) { if (cert[i] != 0xFF) return 0; i++; } return 1; } void tilem_calc_fix_certificate(TilemCalc* calc, byte* cert, int app_start, int app_end, unsigned exptab_offset) { int i, base, max_apps, page; unsigned insttab_offset = 0x1fe0; /* If the ROM was dumped from an unpatched OS, the certificate needs to be patched for some calculator functions to work. */ /* First, check if the certificate is already valid */ if (cert[0x2000] == 0) base = 0x2000; else base = 0; if (certificate_valid(cert + base)) { return; } tilem_message(calc, "Repairing certificate area..."); memset(cert, 0xff, 16384); cert[0] = 0; cert[insttab_offset] = 0xfe; if (app_start < app_end) max_apps = app_end - app_start + 1; else max_apps = app_start - app_end + 1; for (i = 0; i < max_apps; i++) { if (app_start < app_end) page = app_start + i; else page = app_start - i; /* Clear installed bit / set expiration count for existing apps. (If this incorrectly detects pages that aren't really apps, don't worry about it; better to err on the side of caution.) */ if (calc->mem[page << 14] != 0x80 || calc->mem[(page << 14) + 1] != 0x0f) continue; tilem_message(calc, "Found application at page %02x (index %d)", page, i); cert[insttab_offset + ((i + 1) / 8)] &= ~(1 << ((i + 1) % 8)); cert[exptab_offset + 2 * i] = 0x80; cert[exptab_offset + 2 * i + 1] = 0x00; } } tilem-2.0/emu/flash.c000066400000000000000000000173631220200411600145120ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" #define FLASH_READ 0 #define FLASH_AA 1 #define FLASH_55 2 #define FLASH_PROG 3 #define FLASH_ERASE 4 #define FLASH_ERAA 5 #define FLASH_ER55 6 #define FLASH_ERROR 7 #define FLASH_FASTMODE 8 #define FLASH_FASTPROG 9 #define FLASH_FASTEXIT 10 #define FLASH_BUSY_PROGRAM 1 #define FLASH_BUSY_ERASE_WAIT 2 #define FLASH_BUSY_ERASE 3 /* Still to do: - autoselect - erase suspend - fast program - CFI */ #define WARN(xxx) \ tilem_warning(calc, "Flash error (" xxx ")") #define WARN2(xxx, yyy, zzz) \ tilem_warning(calc, "Flash error (" xxx ")", (yyy), (zzz)) void tilem_flash_reset(TilemCalc* calc) { calc->flash.unlock = 0; calc->flash.state = FLASH_READ; calc->flash.busy = 0; } void tilem_flash_delay_timer(TilemCalc* calc, void* data TILEM_ATTR_UNUSED) { if (calc->flash.busy == FLASH_BUSY_ERASE_WAIT) { calc->flash.busy = FLASH_BUSY_ERASE; tilem_z80_set_timer(calc, TILEM_TIMER_FLASH_DELAY, 200000, 0, 1); } else { calc->flash.busy = 0; } } #ifdef DISABLE_FLASH_DELAY # define set_busy(fl, bm, t) #else static inline void set_busy(TilemCalc* calc, int busymode, int time) { if (!(calc->flash.emuflags & TILEM_FLASH_REQUIRE_DELAY)) return; calc->flash.busy = busymode; tilem_z80_set_timer(calc, TILEM_TIMER_FLASH_DELAY, time, 0, 1); } #endif static inline void program_byte(TilemCalc* calc, dword a, byte v) { calc->mem[a] &= v; calc->flash.progaddr = a; calc->flash.progbyte = v; if (calc->mem[a] != v) { WARN2("bad program %02x over %02x", v, calc->mem[a]); calc->flash.state = FLASH_ERROR; } else { calc->flash.state = FLASH_READ; } set_busy(calc, FLASH_BUSY_PROGRAM, 7); } static inline void erase_sector(TilemCalc* calc, dword a, dword l) { dword i; calc->flash.progaddr = a; for (i = 0; i < l; i++) calc->mem[a + i]=0xFF; calc->flash.state = FLASH_READ; set_busy(calc, FLASH_BUSY_ERASE_WAIT, 50); } static const TilemFlashSector* get_sector(TilemCalc* calc, dword pa) { int i; const TilemFlashSector* sec; for (i = 0; i < calc->hw.nflashsectors; i++) { sec = &calc->hw.flashsectors[i]; if (pa >= sec->start && pa < sec->start + sec->size) return sec; } return NULL; } static int sector_writable(TilemCalc* calc, const TilemFlashSector* sec) { return !(sec->protectgroup & ~calc->flash.overridegroup); } byte tilem_flash_read_byte(TilemCalc* calc, dword pa) { byte value; if (calc->flash.busy == FLASH_BUSY_PROGRAM) { if (pa != calc->flash.progaddr) WARN("reading from Flash while programming"); value = (~calc->flash.progbyte & 0x80); value |= calc->flash.toggles; calc->flash.toggles ^= 0x40; return (value); } else if (calc->flash.busy == FLASH_BUSY_ERASE) { if ((pa >> 16) != (calc->flash.progaddr >> 16)) WARN("reading from Flash while erasing"); value = calc->flash.toggles | 0x08; calc->flash.toggles ^= 0x44; return (value); } else if (calc->flash.busy == FLASH_BUSY_ERASE_WAIT) { if ((pa >> 16) != (calc->flash.progaddr >> 16)) WARN("reading from Flash while erasing"); value = calc->flash.toggles; calc->flash.toggles ^= 0x44; return (value); } if (calc->flash.state == FLASH_ERROR) { value = ((~calc->flash.progbyte & 0x80) | 0x20); value |= calc->flash.toggles; calc->flash.toggles ^= 0x40; return (value); } else if (calc->flash.state == FLASH_FASTMODE) { return (calc->mem[pa]); } else if (calc->flash.state == FLASH_READ) { return (calc->mem[pa]); } else { WARN("reading during program/erase sequence"); calc->flash.state = FLASH_READ; return (calc->mem[pa]); } } void tilem_flash_erase_address(TilemCalc* calc, dword pa) { const TilemFlashSector* sec = get_sector(calc, pa); if (sector_writable(calc, sec)) { tilem_message(calc, "Erasing Flash sector at %06x", pa); erase_sector(calc, sec->start, sec->size); } else { WARN("erasing protected sector"); } } void tilem_flash_write_byte(TilemCalc* calc, dword pa, byte v) { int oldstate; int i; const TilemFlashSector* sec; if (!calc->flash.unlock) return; #ifndef DISABLE_FLASH_DELAY if (calc->flash.busy == FLASH_BUSY_PROGRAM || calc->flash.busy == FLASH_BUSY_ERASE) return; #endif oldstate = calc->flash.state; calc->flash.state = FLASH_READ; switch (oldstate) { case FLASH_READ: if (((pa&0xFFF) == 0xAAA) && (v == 0xAA)) calc->flash.state = FLASH_AA; return; case FLASH_AA: if (((pa&0xFFF) == 0x555) && (v == 0x55)) calc->flash.state = FLASH_55; else if (v != 0xF0) { WARN2("undefined command %02x->%06x after AA", v, pa); } return; case FLASH_55: if ((pa&0xFFF) == 0xAAA) { switch (v) { case 0x10: case 0x30: WARN("attempt to erase without pre-erase"); return; case 0x20: //WARN("entering fast mode"); calc->flash.state = FLASH_FASTMODE; return; case 0x80: calc->flash.state = FLASH_ERASE; return; case 0x90: WARN("autoselect is not implemented"); return; case 0xA0: calc->flash.state = FLASH_PROG; return; } } if (v != 0xF0) WARN2("undefined command %02x->%06x after AA,55", v, pa); return; case FLASH_PROG: sec = get_sector(calc, pa); if (!sector_writable(calc, sec)) WARN("programming protected sector"); else program_byte(calc, pa, v); return; case FLASH_FASTMODE: //WARN2("fast mode cmd %02x->%06x", v, pa); if ( v == 0x90 ) calc->flash.state = FLASH_FASTEXIT; else if ( v == 0xA0 ) calc->flash.state = FLASH_FASTPROG; else // TODO : figure out whether mixing is allowed on real HW WARN2("mixing fast programming with regular programming : %02x->%06x", v, pa); return; case FLASH_FASTPROG: //WARN2("fast prog %02x->%06x", v, pa); sec = get_sector(calc, pa); if (!sector_writable(calc, sec)) WARN("programming protected sector"); else program_byte(calc, pa, v); calc->flash.state = FLASH_FASTMODE; return; case FLASH_FASTEXIT: //WARN("leaving fast mode"); if ( v != 0xF0 ) { WARN2("undefined command %02x->%06x after fast mode pre-exit 90", v, pa); // TODO : figure out whether fast mode remains in such a case calc->flash.state = FLASH_FASTMODE; } return; case FLASH_ERASE: if (((pa&0xFFF) == 0xAAA) && (v == 0xAA)) calc->flash.state = FLASH_ERAA; else if (v != 0xF0) WARN2("undefined command %02x->%06x after pre-erase", v, pa); return; case FLASH_ERAA: if (((pa&0xFFF) == 0x555) && (v == 0x55)) calc->flash.state = FLASH_ER55; else if (v != 0xF0) WARN2("undefined command %02x->%06x after pre-erase AA", v, pa); return; case FLASH_ER55: if (((pa&0xFFF) == 0xAAA) && v==0x10) { tilem_message(calc, "Erasing entire Flash chip"); for (i = 0; i < calc->hw.nflashsectors; i++) { sec = &calc->hw.flashsectors[i]; if (sector_writable(calc, sec)) erase_sector(calc, sec->start, sec->size); } } else if (v == 0x30) { tilem_flash_erase_address(calc, pa); } else if (v != 0xF0) WARN2("undefined command %02x->%06x after pre-erase AA,55", v, pa); return; } } tilem-2.0/emu/graycolor.c000066400000000000000000000046001220200411600154040ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" dword* tilem_color_palette_new(int rlight, int glight, int blight, int rdark, int gdark, int bdark, double gamma) { dword* pal = tilem_new_atomic(dword, 256); double r0, g0, b0, dr, dg, db; double igamma = 1.0 / gamma; double s = (1.0 / 255.0); int r, g, b, i; r0 = pow(rlight * s, gamma); g0 = pow(glight * s, gamma); b0 = pow(blight * s, gamma); dr = (pow(rdark * s, gamma) - r0) * s; dg = (pow(gdark * s, gamma) - g0) * s; db = (pow(bdark * s, gamma) - b0) * s; pal[0] = (rlight << 16) | (glight << 8) | blight; for (i = 1; i < 255; i++) { r = pow(r0 + i * dr, igamma) * 255.0 + 0.5; if (r < 0) r = 0; if (r > 255) r = 255; g = pow(g0 + i * dg, igamma) * 255.0 + 0.5; if (g < 0) g = 0; if (g > 255) g = 255; b = pow(b0 + i * db, igamma) * 255.0 + 0.5; if (b < 0) b = 0; if (b > 255) b = 255; pal[i] = (r << 16) | (g << 8) | b; } pal[255] = (rdark << 16) | (gdark << 8) | bdark; return pal; } byte* tilem_color_palette_new_packed(int rlight, int glight, int blight, int rdark, int gdark, int bdark, double gamma) { dword* palette; byte* packed; int i; palette = tilem_color_palette_new(rlight, glight, blight, rdark, gdark, bdark, gamma); packed = tilem_new_atomic(byte, 256 * 3); for (i = 0; i < 256; i++) { packed[i * 3] = palette[i] >> 16; packed[i * 3 + 1] = palette[i] >> 8; packed[i * 3 + 2] = palette[i]; } tilem_free(palette); return packed; } tilem-2.0/emu/grayimage.c000066400000000000000000000173551220200411600153630ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2010-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" /* Scale the input buffer, multiply by F * INCOUNT, and add to the output buffer (which must be an exact multiple of the size of the input buffer.) */ static inline void add_scale1d_exact(const byte * restrict in, int incount, unsigned int * restrict out, int outcount, int f) { int i, j; for (i = 0; i < incount; i++) { for (j = 0; j < outcount / incount; j++) { *out += *in * f * incount; out++; } in++; } } /* Scale a 1-dimensional buffer, multiply by F * INCOUNT, and add to the output buffer. */ static inline void add_scale1d_smooth(const byte * restrict in, int incount, unsigned int * restrict out, int outcount, int f) { int in_rem, out_rem; unsigned int outv; int i; in_rem = outcount; out_rem = incount; outv = 0; i = outcount; while (i > 0) { if (in_rem < out_rem) { out_rem -= in_rem; outv += in_rem * *in * f; in++; in_rem = outcount; } else { in_rem -= out_rem; outv += out_rem * *in * f; *out += outv; outv = 0; out++; out_rem = incount; i--; } } } /* Scale a 2-dimensional buffer, multiply by INWIDTH * INHEIGHT, and store in the output buffer. */ static void scale2d_smooth(const byte * restrict in, int inwidth, int inheight, int inrowstride, unsigned int * restrict out, int outwidth, int outheight, int outrowstride) { int in_rem, out_rem; int i; memset(out, 0, outrowstride * outheight * sizeof(int)); in_rem = outheight; out_rem = inheight; i = outheight; while (i > 0) { if (in_rem < out_rem) { if (in_rem) { if (outwidth % inwidth) add_scale1d_smooth(in, inwidth, out, outwidth, in_rem); else add_scale1d_exact(in, inwidth, out, outwidth, in_rem); } out_rem -= in_rem; in += inrowstride; in_rem = outheight; } else { in_rem -= out_rem; if (outwidth % inwidth) add_scale1d_smooth(in, inwidth, out, outwidth, out_rem); else add_scale1d_exact(in, inwidth, out, outwidth, out_rem); out += outrowstride; out_rem = inheight; i--; } } } /* Quickly scale a 1-dimensional buffer and store in the output buffer. */ static inline void scale1d_fast(const byte * restrict in, int incount, byte * restrict out, int outcount) { int i, e; e = outcount - incount / 2; i = outcount; while (i > 0) { if (e >= 0) { *out = *in; out++; e -= incount; i--; } else { e += outcount; in++; } } } /* Quickly scale a 2-dimensional buffer and store in the output buffer. */ static void scale2d_fast(const byte * restrict in, int inwidth, int inheight, int inrowstride, byte * restrict out, int outwidth, int outheight, int outrowstride) { int i, e; e = outheight - inheight / 2; i = outheight; while (i > 0) { if (e >= 0) { scale1d_fast(in, inwidth, out, outwidth); out += outrowstride; e -= inheight; i--; } else { e += outheight; in += inrowstride; } } } /* Determine range of linear pixel values corresponding to a given contrast level. */ static void get_contrast_settings(unsigned int contrast, int *cbase, int *cfact) { if (contrast < 32) { *cbase = 0; *cfact = contrast * 8; } else { *cbase = (contrast - 32) * 8; *cfact = 255 - *cbase; } } #define GETSCALEBUF(ttt, www, hhh) \ ((ttt *) alloc_scalebuf(buf, (www) * (hhh) * sizeof(ttt))) static void* alloc_scalebuf(TilemLCDBuffer *buf, unsigned int size) { if (TILEM_UNLIKELY(size > buf->tmpbufsize)) { buf->tmpbufsize = size; tilem_free(buf->tmpbuf); buf->tmpbuf = tilem_malloc_atomic(size); } return buf->tmpbuf; } void tilem_draw_lcd_image_indexed(TilemLCDBuffer * restrict buf, byte * restrict buffer, int imgwidth, int imgheight, int rowstride, int scaletype) { int dwidth = buf->width; int dheight = buf->height; int i, j, v; unsigned int * restrict ibuf; int cbase, cfact; byte cindex[129]; if (dwidth == 0 || dheight == 0 || buf->contrast == 0) { for (i = 0; i < imgheight; i++) { for (j = 0; j < imgwidth; j++) buffer[j] = 0; buffer += rowstride; } return; } get_contrast_settings(buf->contrast, &cbase, &cfact); for (i = 0; i <= 128; i++) cindex[i] = ((i * cfact) >> 7) + cbase; if (scaletype == TILEM_SCALE_FAST || (imgwidth % dwidth == 0 && imgheight % dheight == 0)) { scale2d_fast(buf->data, dwidth, dheight, buf->rowstride, buffer, imgwidth, imgheight, rowstride); for (i = 0; i < imgwidth * imgheight; i++) buffer[i] = cindex[buffer[i]]; } else { ibuf = GETSCALEBUF(unsigned int, imgwidth, imgheight); scale2d_smooth(buf->data, dwidth, dheight, buf->rowstride, ibuf, imgwidth, imgheight, imgwidth); for (i = 0; i < imgheight; i++) { for (j = 0; j < imgwidth; j++) { v = ibuf[j] / (dwidth * dheight); buffer[j] = cindex[v]; } ibuf += imgwidth; buffer += rowstride; } } } void tilem_draw_lcd_image_rgb(TilemLCDBuffer * restrict buf, byte * restrict buffer, int imgwidth, int imgheight, int rowstride, int pixbytes, const dword * restrict palette, int scaletype) { int dwidth = buf->width; int dheight = buf->height; int i, j, v; int padbytes = rowstride - (imgwidth * pixbytes); byte * restrict bbuf; unsigned int * restrict ibuf; int cbase, cfact; dword cpalette[129]; if (dwidth == 0 || dheight == 0 || buf->contrast == 0) { for (i = 0; i < imgheight; i++) { for (j = 0; j < imgwidth; j++) { buffer[0] = palette[0] >> 16; buffer[1] = palette[0] >> 8; buffer[2] = palette[0]; buffer += pixbytes; } buffer += padbytes; } return; } get_contrast_settings(buf->contrast, &cbase, &cfact); for (i = 0; i <= 128; i++) { v = ((i * cfact) >> 7) + cbase; cpalette[i] = palette[v]; } if (scaletype == TILEM_SCALE_FAST || (imgwidth % dwidth == 0 && imgheight % dheight == 0)) { bbuf = GETSCALEBUF(byte, imgwidth, imgheight); scale2d_fast(buf->data, dwidth, dheight, buf->rowstride, bbuf, imgwidth, imgheight, imgwidth); for (i = 0; i < imgheight; i++) { for (j = 0; j < imgwidth; j++) { v = bbuf[j]; buffer[0] = cpalette[v] >> 16; buffer[1] = cpalette[v] >> 8; buffer[2] = cpalette[v]; buffer += pixbytes; } bbuf += imgwidth; buffer += padbytes; } } else { ibuf = GETSCALEBUF(unsigned int, imgwidth, imgheight); scale2d_smooth(buf->data, dwidth, dheight, buf->rowstride, ibuf, imgwidth, imgheight, imgwidth); for (i = 0; i < imgheight; i++) { for (j = 0; j < imgwidth; j++) { v = (ibuf[j] / (dwidth * dheight)); buffer[0] = cpalette[v] >> 16; buffer[1] = cpalette[v] >> 8; buffer[2] = cpalette[v]; buffer += pixbytes; } ibuf += imgwidth; buffer += padbytes; } } } tilem-2.0/emu/graylcd.c000066400000000000000000000161141220200411600150330ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2010-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" #include "graylcd.h" /* Read screen contents and update pixels that have changed */ static void tmr_screen_update(TilemCalc *calc, void *data) { TilemGrayLCD *glcd = data; byte *np, *op, nb, ob, d; int i, j, n; dword delta; glcd->t++; if (calc->z80.lastlcdwrite == glcd->lcdupdatetime) return; glcd->lcdupdatetime = calc->z80.lastlcdwrite; (*calc->hw.get_lcd)(calc, glcd->newbits); np = glcd->newbits; op = glcd->oldbits; glcd->oldbits = np; glcd->newbits = op; n = 0; for (i = 0; i < glcd->bwidth * glcd->height; i++) { nb = *np; ob = *op; d = nb ^ ob; for (j = 0; j < 8; j++) { if (d & (0x80 >> j)) { delta = glcd->t - glcd->tchange[n]; glcd->tchange[n] = glcd->t; if (ob & (0x80 >> j)) { glcd->curpixels[n].ndark += delta; glcd->curpixels[n].ndarkseg++; } else { glcd->curpixels[n].nlight += delta; glcd->curpixels[n].nlightseg++; } } n++; } np++; op++; } } TilemGrayLCD* tilem_gray_lcd_new(TilemCalc *calc, int windowsize, int sampleint) { TilemGrayLCD *glcd = tilem_new(TilemGrayLCD, 1); int nbytes, npixels, i; glcd->bwidth = (calc->hw.lcdwidth + 7) / 8; glcd->height = calc->hw.lcdheight; nbytes = glcd->bwidth * glcd->height; npixels = nbytes * 8; glcd->oldbits = tilem_new_atomic(byte, nbytes); glcd->newbits = tilem_new_atomic(byte, nbytes); glcd->tchange = tilem_new_atomic(dword, npixels); glcd->tframestart = tilem_new_atomic(dword, windowsize); glcd->framestamp = tilem_new_atomic(dword, windowsize); glcd->curpixels = tilem_new_atomic(TilemGrayLCDPixel, npixels); glcd->framebasepixels = tilem_new_atomic(TilemGrayLCDPixel, npixels * windowsize); memset(glcd->oldbits, 0, nbytes); memset(glcd->tchange, 0, npixels * sizeof(dword)); memset(glcd->tframestart, 0, windowsize * sizeof(dword)); memset(glcd->curpixels, 0, npixels * sizeof(TilemGrayLCDPixel)); memset(glcd->framebasepixels, 0, (npixels * windowsize * sizeof(TilemGrayLCDPixel))); glcd->calc = calc; glcd->timer_id = tilem_z80_add_timer(calc, sampleint / 2, sampleint, 1, &tmr_screen_update, glcd); /* assign arbitrary but unique timestamps to the initial n frames */ for (i = 0; i < windowsize; i++) glcd->framestamp[i] = calc->z80.lastlcdwrite - i; glcd->lcdupdatetime = calc->z80.lastlcdwrite - 1; glcd->t = 0; glcd->windowsize = windowsize; glcd->sampleint = sampleint; glcd->framenum = 0; return glcd; } void tilem_gray_lcd_free(TilemGrayLCD *glcd) { tilem_z80_remove_timer(glcd->calc, glcd->timer_id); tilem_free(glcd->oldbits); tilem_free(glcd->newbits); tilem_free(glcd->tchange); tilem_free(glcd->tframestart); tilem_free(glcd->framestamp); tilem_free(glcd->curpixels); tilem_free(glcd->framebasepixels); tilem_free(glcd); } /* Update levelbuf with values based on the accumulated grayscale data */ void tilem_gray_lcd_get_frame(TilemGrayLCD * restrict glcd, TilemLCDBuffer * restrict buf) { int i, j, n; unsigned int current, delta, fd, fl; word ndark, nlight, ndarkseg, nlightseg; dword tbase, tlimit; dword lastwrite; byte * restrict bp; byte * restrict op; TilemGrayLCDPixel * restrict pix; TilemGrayLCDPixel * restrict basepix; dword * restrict tchange; if (TILEM_UNLIKELY(buf->height != glcd->height || buf->rowstride != glcd->bwidth * 8)) { /* reallocate data buffer */ tilem_free(buf->data); buf->data = tilem_new_atomic(byte, glcd->height * glcd->bwidth * 8); buf->rowstride = glcd->bwidth * 8; buf->height = glcd->height; } buf->width = glcd->calc->hw.lcdwidth; if (!glcd->calc->lcd.active || (glcd->calc->z80.halted && !glcd->calc->poweronhalt)) { /* screen is turned off */ buf->stamp = glcd->calc->z80.lastlcdwrite; buf->contrast = 0; return; } buf->contrast = glcd->calc->lcd.contrast; /* If LCD remains unchanged throughout the window, set timestamp to the time when the LCD was last changed, so that consecutive frames have the same timestamp. If LCD has changed during the window, values of gray pixels will vary from one frame to another, so use a unique timestamp for each frame */ lastwrite = glcd->calc->z80.lastlcdwrite; if (glcd->framestamp[glcd->framenum] == lastwrite) buf->stamp = lastwrite; else buf->stamp = glcd->calc->z80.clock + 0x80000000; glcd->framestamp[glcd->framenum] = lastwrite; /* set tbase to the sample number where the window began; this is used to limit the weight of unchanging pixels */ tbase = glcd->tframestart[glcd->framenum]; glcd->tframestart[glcd->framenum] = glcd->t; tlimit = glcd->t - tbase; /* number of samples per window */ bp = glcd->newbits; op = buf->data; pix = glcd->curpixels; basepix = glcd->framebasepixels + (glcd->framenum * glcd->height * glcd->bwidth * 8); tchange = glcd->tchange; (*glcd->calc->hw.get_lcd)(glcd->calc, bp); n = 0; for (i = 0; i < glcd->bwidth * glcd->height; i++) { for (j = 0; j < 8; j++) { /* check if pixel is currently set */ current = *bp & (0x80 >> j); /* compute number of dark and light samples within the window */ ndark = pix[n].ndark - basepix[n].ndark; nlight = pix[n].nlight - basepix[n].nlight; /* compute number of dark and light segments within the window */ ndarkseg = pix[n].ndarkseg - basepix[n].ndarkseg; nlightseg = pix[n].nlightseg - basepix[n].nlightseg; /* average light segment in this window is (nlight / nlightseg); average dark segment is (ndark / ndarkseg) */ /* ensure tchange is later than or equal to tbase */ if (tchange[n] - tbase > tlimit) { tchange[n] = tbase; } /* if current segment is longer than average, count it as well */ delta = glcd->t - tchange[n]; if (current) { if (delta * ndarkseg >= ndark) { ndark += delta; ndarkseg++; } } else { if (delta * nlightseg >= nlight) { nlight += delta; nlightseg++; } } fd = ndark * nlightseg; fl = nlight * ndarkseg; if (fd + fl == 0) *op = (ndark ? 128 : 0); else *op = ((fd * 128) / (fd + fl)); n++; op++; } bp++; } memcpy(basepix, pix, (glcd->height * glcd->bwidth * 8 * sizeof(TilemGrayLCDPixel))); glcd->framenum = (glcd->framenum + 1) % glcd->windowsize; } tilem-2.0/emu/graylcd.h000066400000000000000000000037261220200411600150450ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2010-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_GRAYLCD_H #define _TILEM_GRAYLCD_H typedef struct _TilemGrayLCDPixel { word ndark; /* Sum of lengths of dark intervals */ word nlight; /* Sum of lengths of light intervals */ word ndarkseg; /* Number of dark intervals */ word nlightseg; /* Number of light intervals */ } TilemGrayLCDPixel; struct _TilemGrayLCD { TilemCalc *calc; /* Calculator */ int timer_id; /* Screen update timer */ dword lcdupdatetime; /* CPU time of last known LCD update */ dword t; /* Time counter */ int windowsize; /* Number of frames in the sampling window */ int framenum; /* Current frame number */ int sampleint; /* Microseconds per sample */ int bwidth; /* Width of LCD, bytes */ int height; /* Height of LCD, pixels */ byte *oldbits; /* Original pixel values (current buffer) */ byte *newbits; /* Original pixel values (alternate buffer) */ dword *tchange; /* Time when pixels changed */ dword *tframestart; /* Time at start of frame */ dword *framestamp; /* LCD update time at start of frame */ TilemGrayLCDPixel *curpixels; /* Current pixel counters */ TilemGrayLCDPixel *framebasepixels; /* Pixel counters as of the start of each frame */ }; #endif tilem-2.0/emu/keypad.c000066400000000000000000000043321220200411600146620ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" #include "scancodes.h" void tilem_keypad_reset(TilemCalc* calc) { int i; calc->keypad.group = 0xff; calc->keypad.onkeydown = 0; calc->keypad.onkeyint = 0; for (i = 0; i < 8; i++) calc->keypad.keysdown[i] = 0; } void tilem_keypad_set_group(TilemCalc* calc, byte group) { calc->keypad.group = group; } byte tilem_keypad_read_keys(TilemCalc* calc) { int i; byte keys, old; keys = 0; for (i = 0; i < 8; i++) { if (!(calc->keypad.group & (1 << i))) keys |= calc->keypad.keysdown[i]; } do { old = keys; for (i = 0; i < 8; i++) { if (keys & calc->keypad.keysdown[i]) keys |= calc->keypad.keysdown[i]; } } while (keys != old); return ~keys; } void tilem_keypad_press_key(TilemCalc* calc, int scancode) { if (scancode == TILEM_KEY_ON) { if (!calc->keypad.onkeydown && calc->keypad.onkeyint) calc->z80.interrupts |= TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeydown = 1; } else if (scancode > 0 && scancode < 65) { scancode--; calc->keypad.keysdown[scancode / 8] |= (1 << (scancode % 8)); } } void tilem_keypad_release_key(TilemCalc* calc, int scancode) { if (scancode == TILEM_KEY_ON) { if (calc->keypad.onkeydown && calc->keypad.onkeyint) calc->z80.interrupts |= TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeydown = 0; } else if (scancode > 0 && scancode < 65) { scancode--; calc->keypad.keysdown[scancode / 8] &= ~(1 << (scancode % 8)); } } tilem-2.0/emu/lcd.c000066400000000000000000000132101220200411600141420ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" #ifdef DISABLE_LCD_DRIVER_DELAY # define BUSY 0 # define SET_BUSY 0 #else # define BUSY check_delay_timer(calc) # define SET_BUSY set_delay_timer(calc) static inline int check_delay_timer(TilemCalc* calc) { int t; if (!calc->lcd.busy) return 0; t = tilem_z80_get_timer_clocks(calc, TILEM_TIMER_LCD_DELAY); return (t > 0); } static inline void set_delay_timer(TilemCalc* calc) { int delay; if (!(calc->lcd.emuflags & TILEM_LCD_REQUIRE_DELAY)) return; if (calc->lcd.emuflags & TILEM_LCD_REQUIRE_LONG_DELAY) delay = 70; else delay = 50; calc->lcd.busy = 1; tilem_z80_set_timer(calc, TILEM_TIMER_LCD_DELAY, delay, 0, 0); } #endif void tilem_lcd_reset(TilemCalc* calc) { calc->lcd.active = 0; calc->lcd.contrast = 32; calc->lcd.addr = 0; calc->lcd.mode = 1; calc->lcd.nextbyte = 0; calc->lcd.x = calc->lcd.y = 0; calc->lcd.inc = 7; calc->lcd.rowshift = 0; calc->lcd.busy = 0; if (calc->hw.lcdmemsize) calc->lcd.rowstride = (calc->hw.lcdmemsize / calc->hw.lcdheight); else calc->lcd.rowstride = (calc->hw.lcdwidth / 8); } void tilem_lcd_delay_timer(TilemCalc* calc, void* data TILEM_ATTR_UNUSED) { calc->lcd.busy = 0; } byte tilem_lcd_t6a04_status(TilemCalc* calc) { return (calc->lcd.busy << 7 | calc->lcd.mode << 6 | calc->lcd.active << 5 | (calc->lcd.inc & 3)); } void tilem_lcd_t6a04_control(TilemCalc* calc, byte val) { if (BUSY) return; if (val <= 1) { calc->lcd.mode = val; } else if (val == 2) { calc->lcd.active = 0; } else if (val == 3) { calc->lcd.active = 1; } else if (val <= 7) { calc->lcd.inc = val; } else if ((val >= 0x20) && (val <= 0x3F)){ calc->lcd.x = val - 0x20; } else if ((val >= 0x80) && (val <= 0xBF)) { calc->lcd.y = val - 0x80; } else if ((val >= 0x40) && (val <= 0x7F)) { calc->lcd.rowshift = val - 0x40; } else if (val >= 0xc0) { calc->lcd.contrast = val - 0xc0; } calc->z80.lastlcdwrite = calc->z80.clock; SET_BUSY; } byte tilem_lcd_t6a04_read(TilemCalc* calc) { byte retv = calc->lcd.nextbyte; byte* lcdbuf = calc->lcdmem; int stride = calc->lcd.rowstride; int xlimit; if (BUSY) return(0); if (calc->lcd.mode) xlimit = stride; else xlimit = (stride * 8 + 5) / 6; if (calc->lcd.x >= xlimit) calc->lcd.x = 0; else if (calc->lcd.x < 0) calc->lcd.x = xlimit - 1; if (calc->lcd.y >= 0x40) calc->lcd.y = 0; else if (calc->lcd.y < 0) calc->lcd.y = 0x3F; if (calc->lcd.mode) { calc->lcd.nextbyte = *(lcdbuf + calc->lcd.x + stride * calc->lcd.y); } else { int col = 0x06 * calc->lcd.x; int ofs = calc->lcd.y * stride + (col >> 3); int shift = 0x0A - (col & 0x07); calc->lcd.nextbyte = ((*(lcdbuf + ofs) << 8) | *(lcdbuf + ofs + 1)) >> shift; } switch (calc->lcd.inc) { case 4: calc->lcd.y--; break; case 5: calc->lcd.y++; break; case 6: calc->lcd.x--; break; case 7: calc->lcd.x++; break; } SET_BUSY; return(retv); } void tilem_lcd_t6a04_write(TilemCalc* calc, byte sprite) { byte* lcdbuf = calc->lcdmem; int stride = calc->lcd.rowstride; int xlimit; if (BUSY) return; if (calc->lcd.mode) xlimit = stride; else xlimit = (stride * 8 + 5) / 6; if (calc->lcd.x >= xlimit) calc->lcd.x = 0; else if (calc->lcd.x < 0) calc->lcd.x = xlimit - 1; if (calc->lcd.y >= 0x40) calc->lcd.y = 0; else if (calc->lcd.y < 0) calc->lcd.y = 0x3F; if (calc->lcd.mode) { *(lcdbuf + calc->lcd.x + stride * calc->lcd.y) = sprite; } else { int col = 0x06 * calc->lcd.x; int ofs = calc->lcd.y * stride + (col >> 3); int shift = col & 0x07; int mask; sprite <<= 2; mask = ~(0xFC >> shift); *(lcdbuf + ofs) = (*(lcdbuf + ofs) & mask) | (sprite >> shift); if (shift > 2 && (col >> 3) < (stride - 1)) { ofs++; shift = 8 - shift; mask = ~(0xFC << shift); *(lcdbuf + ofs) = (*(lcdbuf + ofs) & mask) | (sprite << shift); } } switch (calc->lcd.inc) { case 4: calc->lcd.y--; break; case 5: calc->lcd.y++; break; case 6: calc->lcd.x--; break; case 7: calc->lcd.x++; break; } calc->z80.lastlcdwrite = calc->z80.clock; SET_BUSY; return; } void tilem_lcd_t6a04_get_data(TilemCalc* calc, byte* data) { int width = calc->hw.lcdwidth / 8; byte* lcdbuf = calc->lcdmem; int stride = calc->lcd.rowstride; int i, j, k; for (i = 0; i < calc->hw.lcdheight; i++) { j = (i + calc->lcd.rowshift) % 64; for (k = 0; k < width; k++) data[k] = lcdbuf[j * stride + k]; data += width; } } void tilem_lcd_t6a43_get_data(TilemCalc* calc, byte* data) { int width = calc->hw.lcdwidth / 8; byte* lcdbuf = calc->ram + calc->lcd.addr; int stride = calc->lcd.rowstride; int i, j; for (i = 0; i < calc->hw.lcdheight; i++) { for (j = 0; j < 10; j++) data[j] = lcdbuf[j]; for (; j < 10 + width - stride; j++) data[j] = 0; for (; j < width; j++) data[j] = lcdbuf[j + stride - width]; data += width; lcdbuf += stride; } } tilem-2.0/emu/link.c000066400000000000000000000274221220200411600143470ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" /* Internal link port control */ static inline void dbus_interrupt(TilemCalc* calc, dword inttype, dword mask) { if (!(calc->linkport.mode & mask)) return; calc->z80.interrupts |= inttype; } static inline void dbus_set_lines(TilemCalc* calc, byte lines) { if (lines != calc->linkport.lines) { calc->linkport.lines = lines; if (calc->linkport.linkemu == TILEM_LINK_EMULATOR_BLACK) { tilem_z80_stop(calc, TILEM_STOP_LINK_STATE); } } } static inline void dbus_set_extlines(TilemCalc* calc, byte lines) { if ((lines ^ calc->linkport.extlines) & ~calc->linkport.lines) { dbus_interrupt(calc, TILEM_INTERRUPT_LINK_ACTIVE, TILEM_LINK_MODE_INT_ON_ACTIVE); } calc->linkport.extlines = lines; } void tilem_linkport_assist_timer(TilemCalc* calc, void* data TILEM_ATTR_UNUSED) { TilemLinkport* lp = &calc->linkport; if (lp->assistflags & TILEM_LINK_ASSIST_WRITE_BUSY) { lp->assistflags &= ~TILEM_LINK_ASSIST_WRITE_BUSY; lp->assistflags |= TILEM_LINK_ASSIST_WRITE_ERROR; } else if (lp->assistflags & TILEM_LINK_ASSIST_READ_BUSY) { lp->assistflags &= ~TILEM_LINK_ASSIST_READ_BUSY; lp->assistflags |= TILEM_LINK_ASSIST_READ_ERROR; } else return; dbus_interrupt(calc, TILEM_INTERRUPT_LINK_ERROR, TILEM_LINK_MODE_INT_ON_ERROR); } static inline void assist_set_timeout(TilemCalc* calc) { if (calc->linkport.mode & TILEM_LINK_MODE_NO_TIMEOUT) return; tilem_z80_set_timer(calc, TILEM_TIMER_LINK_ASSIST, 2000000, 0, 1); } static inline void assist_clear_timeout(TilemCalc* calc) { tilem_z80_set_timer(calc, TILEM_TIMER_LINK_ASSIST, 0, 0, 0); } static void assist_update_write(TilemCalc* calc) { switch (calc->linkport.extlines) { case 0: if (calc->linkport.lines == 0 && calc->linkport.assistoutbits > 0) { /* Ready to send next bit */ if (calc->linkport.assistout & 1) dbus_set_lines(calc, 2); else dbus_set_lines(calc, 1); calc->linkport.assistout >>= 1; calc->linkport.assistoutbits--; assist_set_timeout(calc); /* other device must respond within 2 seconds */ } else if (calc->linkport.lines == 0) { /* Finished sending a byte */ calc->linkport.assistflags &= ~TILEM_LINK_ASSIST_WRITE_BUSY; assist_clear_timeout(calc); } break; case 1: case 2: if (calc->linkport.extlines == (calc->linkport.lines ^ 3)) { /* Other device acknowledged our bit. Note that the timeout is NOT set at this point. My experiments indicate that the assist will wait, apparently indefinitely, for the other device to bring its lines high. */ dbus_set_lines(calc, 0); assist_clear_timeout(calc); } break; case 3: /* illegal line state; flag error */ calc->linkport.assistflags &= ~TILEM_LINK_ASSIST_WRITE_BUSY; calc->linkport.assistflags |= TILEM_LINK_ASSIST_WRITE_ERROR; dbus_set_lines(calc, 0); assist_clear_timeout(calc); dbus_interrupt(calc, TILEM_INTERRUPT_LINK_ERROR, TILEM_LINK_MODE_INT_ON_ERROR); break; } } static void assist_update_read(TilemCalc* calc) { switch (calc->linkport.extlines) { case 0: /* Finished receiving a bit */ if (calc->linkport.lines == 1) { calc->linkport.assistin >>= 1; calc->linkport.assistin |= 0x80; calc->linkport.assistinbits++; } else if (calc->linkport.lines == 2) { calc->linkport.assistin >>= 1; calc->linkport.assistinbits++; } if (calc->linkport.assistinbits >= 8) { /* finished receiving a byte */ calc->linkport.assistlastbyte = calc->linkport.assistin; calc->linkport.assistflags &= ~TILEM_LINK_ASSIST_READ_BUSY; calc->linkport.assistflags |= TILEM_LINK_ASSIST_READ_BYTE; assist_clear_timeout(calc); } else { assist_set_timeout(calc); /* other device must send next bit within 2 seconds */ } dbus_set_lines(calc, 0); /* indicate we're ready to receive */ break; case 1: /* other device sent a zero; acknowledge it */ calc->linkport.assistflags |= TILEM_LINK_ASSIST_READ_BUSY; dbus_set_lines(calc, 2); assist_set_timeout(calc); /* other device must bring both lines high again within 2 seconds */ break; case 2: /* same as above, but other device sent a one */ calc->linkport.assistflags |= TILEM_LINK_ASSIST_READ_BUSY; dbus_set_lines(calc, 1); assist_set_timeout(calc); /* other device must bring both lines high again within 2 seconds */ break; case 3: /* illegal line state; flag error */ calc->linkport.assistflags &= ~TILEM_LINK_ASSIST_READ_BUSY; calc->linkport.assistflags |= TILEM_LINK_ASSIST_READ_ERROR; dbus_set_lines(calc, 0); assist_clear_timeout(calc); dbus_interrupt(calc, TILEM_INTERRUPT_LINK_ERROR, TILEM_LINK_MODE_INT_ON_ERROR); break; } } static void graylink_update_write(TilemCalc* calc) { switch (calc->linkport.lines) { case 0: if (calc->linkport.extlines == 0 && calc->linkport.graylinkoutbits > 1) { /* Ready to send next bit */ if (calc->linkport.graylinkout & 1) dbus_set_extlines(calc, 2); else dbus_set_extlines(calc, 1); calc->linkport.graylinkout >>= 1; calc->linkport.graylinkoutbits--; } else if (calc->linkport.extlines == 0) { /* Finished sending a byte */ calc->linkport.graylinkoutbits = 0; tilem_z80_stop(calc, TILEM_STOP_LINK_WRITE_BYTE); } break; case 1: case 2: if (calc->linkport.extlines == (calc->linkport.lines ^ 3)) /* Other device acknowledged our bit */ dbus_set_extlines(calc, 0); break; case 3: /* illegal line state; flag error */ dbus_set_extlines(calc, 0); calc->linkport.graylinkoutbits = 0; tilem_z80_stop(calc, TILEM_STOP_LINK_ERROR); break; } } static void graylink_update_read(TilemCalc* calc) { switch (calc->linkport.lines) { case 0: /* Finished receiving a bit */ if (calc->linkport.extlines == 1) { calc->linkport.graylinkin >>= 1; calc->linkport.graylinkin |= 0x80; calc->linkport.graylinkinbits++; } else if (calc->linkport.extlines == 2) { calc->linkport.graylinkin >>= 1; calc->linkport.graylinkinbits++; } if (calc->linkport.graylinkinbits >= 8) { /* finished receiving a byte */ tilem_z80_stop(calc, TILEM_STOP_LINK_READ_BYTE); } dbus_set_extlines(calc, 0); break; case 1: /* other device sent a zero; acknowledge it */ dbus_set_extlines(calc, 2); break; case 2: /* same as above, but other device sent a one */ dbus_set_extlines(calc, 1); break; case 3: /* illegal line state; flag error */ dbus_set_extlines(calc, 0); calc->linkport.graylinkinbits = 0; tilem_z80_stop(calc, TILEM_STOP_LINK_ERROR); break; } } static void dbus_update(TilemCalc* calc) { byte oldlines; do { if (calc->linkport.linkemu == TILEM_LINK_EMULATOR_GRAY) { if (calc->linkport.graylinkoutbits) { graylink_update_write(calc); } else if (calc->linkport.graylinkinbits != 8) { graylink_update_read(calc); } } oldlines = calc->linkport.lines; if (calc->linkport.assistflags & TILEM_LINK_ASSIST_WRITE_BUSY) { assist_update_write(calc); } else if (calc->linkport.mode & TILEM_LINK_MODE_ASSIST && !(calc->linkport.assistflags & TILEM_LINK_ASSIST_READ_BYTE)) { assist_update_read(calc); } } while (oldlines != calc->linkport.lines); if ((calc->linkport.assistflags & TILEM_LINK_ASSIST_READ_BYTE) && (calc->linkport.mode & TILEM_LINK_MODE_INT_ON_READ)) calc->z80.interrupts |= TILEM_INTERRUPT_LINK_READ; else calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_READ; if (!(calc->linkport.assistflags & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) && (calc->linkport.mode & TILEM_LINK_MODE_INT_ON_IDLE)) calc->z80.interrupts |= TILEM_INTERRUPT_LINK_IDLE; else calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_IDLE; } void tilem_linkport_reset(TilemCalc* calc) { dbus_set_lines(calc, 0); assist_clear_timeout(calc); calc->linkport.mode = 0; calc->linkport.assistflags = 0; calc->linkport.assistin = 0; calc->linkport.assistinbits = 0; calc->linkport.assistout = 0; calc->linkport.assistoutbits = 0; calc->linkport.assistlastbyte = 0; } byte tilem_linkport_get_lines(TilemCalc* calc) { //dbus_update(calc); return (~calc->linkport.lines & ~calc->linkport.extlines & 3); } void tilem_linkport_set_lines(TilemCalc* calc, byte lines) { if (!(calc->linkport.mode & TILEM_LINK_MODE_ASSIST) && !(calc->linkport.assistflags & TILEM_LINK_ASSIST_WRITE_BUSY)) dbus_set_lines(calc, lines & 3); dbus_update(calc); } byte tilem_linkport_read_byte(TilemCalc* calc) { byte value = calc->linkport.assistin; calc->linkport.assistflags &= ~(TILEM_LINK_ASSIST_READ_BYTE | TILEM_LINK_ASSIST_READ_BUSY); calc->linkport.assistinbits = 0; dbus_update(calc); return value; } void tilem_linkport_write_byte(TilemCalc* calc, byte data) { if (calc->linkport.assistflags & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) return; dbus_set_lines(calc, 0); calc->linkport.assistout = data; calc->linkport.assistoutbits = 8; calc->linkport.assistflags |= TILEM_LINK_ASSIST_WRITE_BUSY; dbus_update(calc); } unsigned int tilem_linkport_get_assist_flags(TilemCalc* calc) { //dbus_update(calc); return calc->linkport.assistflags; } void tilem_linkport_set_mode(TilemCalc* calc, unsigned int mode) { if ((mode ^ calc->linkport.mode) & TILEM_LINK_MODE_ASSIST) { dbus_set_lines(calc, 0); calc->linkport.assistflags &= ~(TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY); assist_clear_timeout(calc); } if (!(mode & TILEM_LINK_MODE_INT_ON_ACTIVE)) calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ACTIVE; if (!(mode & TILEM_LINK_MODE_INT_ON_ERROR)) calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR; calc->linkport.mode = mode; dbus_update(calc); } /* External BlackLink emulation */ void tilem_linkport_blacklink_set_lines(TilemCalc* calc, byte lines) { dbus_set_extlines(calc, lines & 3); dbus_update(calc); } byte tilem_linkport_blacklink_get_lines(TilemCalc* calc) { dbus_update(calc); return (~calc->linkport.lines & ~calc->linkport.extlines & 3); } /* External GrayLink emulation */ void tilem_linkport_graylink_reset(TilemCalc* calc) { calc->linkport.graylinkin = 0; calc->linkport.graylinkinbits = 0; calc->linkport.graylinkout = 0; calc->linkport.graylinkoutbits = 0; dbus_set_extlines(calc, 0); dbus_update(calc); } int tilem_linkport_graylink_ready(TilemCalc* calc) { if (calc->linkport.graylinkoutbits || calc->linkport.graylinkinbits) return 0; else return 1; } int tilem_linkport_graylink_send_byte(TilemCalc* calc, byte value) { if (!tilem_linkport_graylink_ready(calc)) return -1; dbus_set_extlines(calc, 0); /* set to 9 because we want to wait for the calc to bring both link lines low before we send the first bit, and also after we send the last bit */ calc->linkport.graylinkoutbits = 9; calc->linkport.graylinkout = value; dbus_update(calc); return 0; } int tilem_linkport_graylink_get_byte(TilemCalc* calc) { dbus_update(calc); if (calc->linkport.graylinkinbits != 8) return -1; calc->linkport.graylinkinbits = 0; return calc->linkport.graylinkin; } tilem-2.0/emu/md5.c000066400000000000000000000041701220200411600140720ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" void tilem_md5_assist_reset(TilemCalc* calc) { int i; for (i = 0; i < 6; i++) calc->md5assist.regs[i] = 0; calc->md5assist.shift = 0; calc->md5assist.mode = 0; } dword tilem_md5_assist_get_value(TilemCalc* calc) { /* Return the result of a complete MD5 operation: b + ((a + f(b,c,d) + X + T) <<< s) */ dword a, b, c, d, x, t, result; byte mode, s; mode = calc->md5assist.mode; a = calc->md5assist.regs[TILEM_MD5_REG_A]; b = calc->md5assist.regs[TILEM_MD5_REG_B]; c = calc->md5assist.regs[TILEM_MD5_REG_C]; d = calc->md5assist.regs[TILEM_MD5_REG_D]; x = calc->md5assist.regs[TILEM_MD5_REG_X]; t = calc->md5assist.regs[TILEM_MD5_REG_T]; s = calc->md5assist.shift; switch (mode) { case TILEM_MD5_FUNC_FF: /* F(X,Y,Z) = XY v not(X) Z */ result = (b & c) | ((~b) & d); break; case TILEM_MD5_FUNC_GG: /* G(X,Y,Z) = XZ v Y not(Z) */ result = (b & d) | (c & (~d)); break; case TILEM_MD5_FUNC_HH: /* H(X,Y,Z) = X xor Y xor Z */ result = b ^ c ^ d; break; case TILEM_MD5_FUNC_II: /* I(X,Y,Z) = Y xor (X v not(Z)) */ result = c ^ (b | (~d)); break; default: tilem_internal(calc, "Invalid MD5 mode %d", mode); return 0; } result += a + x + t; result &= 0xffffffff; result = (result << s) | (result >> (32 - s)); result += b; return result; } tilem-2.0/emu/monolcd.c000066400000000000000000000070571220200411600150470ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" TilemLCDBuffer* tilem_lcd_buffer_new() { return tilem_new0(TilemLCDBuffer, 1); } void tilem_lcd_buffer_free(TilemLCDBuffer *buf) { tilem_free(buf->data); tilem_free(buf->tmpbuf); tilem_free(buf); } void tilem_lcd_get_frame(TilemCalc * restrict calc, TilemLCDBuffer * restrict buf) { byte * restrict bp; byte * restrict op; int dwidth = calc->hw.lcdwidth; int dheight = calc->hw.lcdheight; unsigned int size; int bwidth = ((calc->hw.lcdwidth + 7) / 8); int i, j; if (TILEM_UNLIKELY(buf->height != dheight || buf->rowstride != bwidth * 8)) { /* reallocate data buffer */ tilem_free(buf->data); buf->data = tilem_new_atomic(byte, dwidth * bwidth * 8); buf->rowstride = bwidth * 8; buf->height = dheight; } size = bwidth * dheight * sizeof(byte); if (TILEM_UNLIKELY(buf->tmpbufsize < size)) { /* reallocate temp buffer */ tilem_free(buf->tmpbuf); buf->tmpbuf = tilem_malloc_atomic(size); buf->tmpbufsize = size; } buf->width = dwidth; buf->stamp = calc->z80.lastlcdwrite; if (!calc->lcd.active || (calc->z80.halted && !calc->poweronhalt)) { /* screen is turned off */ buf->contrast = 0; return; } buf->contrast = calc->lcd.contrast; bp = buf->tmpbuf; op = buf->data; (*calc->hw.get_lcd)(calc, bp); for (i = 0; i < bwidth * dheight; i++) { for (j = 0; j < 8; j++) { *op = (*bp << j) & 0x80; op++; } bp++; } } /* Do the same thing as tilem_lcd_get_frame, but output is only 0 and 1 */ void tilem_lcd_get_frame1(TilemCalc * restrict calc, TilemLCDBuffer * restrict buf) { byte * restrict bp; byte * restrict op; int dwidth = calc->hw.lcdwidth; int dheight = calc->hw.lcdheight; unsigned int size; int bwidth = ((calc->hw.lcdwidth + 7) / 8); int i, j; if (TILEM_UNLIKELY(buf->height != dheight || buf->rowstride != bwidth * 8)) { /* reallocate data buffer */ tilem_free(buf->data); buf->data = tilem_new_atomic(byte, dwidth * bwidth * 8); buf->rowstride = bwidth * 8; buf->height = dheight; } size = bwidth * dheight * sizeof(byte); if (TILEM_UNLIKELY(buf->tmpbufsize < size)) { /* reallocate temp buffer */ tilem_free(buf->tmpbuf); buf->tmpbuf = tilem_malloc_atomic(size); buf->tmpbufsize = size; } buf->width = dwidth; buf->stamp = calc->z80.lastlcdwrite; if (!calc->lcd.active || (calc->z80.halted && !calc->poweronhalt)) { /* screen is turned off */ buf->contrast = 0; return; } buf->contrast = calc->lcd.contrast; bp = buf->tmpbuf; op = buf->data; (*calc->hw.get_lcd)(calc, bp); for (i = 0; i < bwidth * dheight; i++) { for (j = 0; j < 8; j++) { *op = (*bp << j) & 0x80; if(*op != 0) *op = 1; op++; } bp++; } } tilem-2.0/emu/rom.c000066400000000000000000000055761220200411600142150ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" static int find_string(const char *str, FILE *romfile, dword start, dword limit) { char buf[256]; int pos = 0; int len, i; len = strlen(str); fseek(romfile, (long int) start, SEEK_SET); for (i = 0; i < len-1; i++) { buf[pos] = fgetc(romfile); pos = (pos+1)%256; limit--; } while (limit > 0 && !feof(romfile) && !ferror(romfile)) { buf[pos] = fgetc(romfile); pos = (pos+1)%256; limit--; for (i = 0; i < len; i++) { if (str[i] != buf[(pos + 256 - len + i)%256]) break; } if (i == len) return 1; } return 0; } char tilem_guess_rom_type(FILE* romfile) { unsigned long initpos; dword size; char result; initpos = ftell(romfile); fseek(romfile, 0L, SEEK_END); size = ftell(romfile); if (size >= 0x8000 && size < 0x9000) { /* 32k: TI-81 (old or new) */ result = TILEM_CALC_TI81; } else if (size >= 0x20000 && size < 0x2C000) { /* 128k: TI-82 or TI-86 */ if (find_string("CATALOG", romfile, 0, 0x20000)) result = TILEM_CALC_TI85; else result = TILEM_CALC_TI82; } else if (size >= 0x40000 && size < 0x4C000) { /* 256k: TI-83 (or a variant) or TI-86 */ if (!find_string("TI82", romfile, 0, 0x40000)) result = TILEM_CALC_TI86; else if (find_string("Termin\x96", romfile, 0, 0x40000)) result = TILEM_CALC_TI76; else result = TILEM_CALC_TI83; } else if (size >= 0x80000 && size < 0x8C000) { /* 512k: TI-83 Plus or TI-73 */ if (find_string("TI-83 Plus", romfile, 0, 8 * 0x4000)) result = TILEM_CALC_TI83P; else result = TILEM_CALC_TI73; } else if (size >= 0x100000 && size < 0x124000) { /* 1024k: TI-84 Plus */ result = TILEM_CALC_TI84P; } else if (size >= 0x200000 && size < 0x224000) { /* 2048k: TI-83 Plus SE, TI-84 Plus SE */ if (find_string("\xed\xef", romfile, 0x1FC000, 0x4000)) result = TILEM_CALC_TI84P_NSPIRE; else if (find_string("Operating", romfile, 0x1FC000, 0x4000)) result = TILEM_CALC_TI84P_SE; else result = TILEM_CALC_TI83P_SE; } else { result = 0; } fseek(romfile, initpos, SEEK_SET); return result; } tilem-2.0/emu/scancodes.h000066400000000000000000000044171220200411600153600ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_SCANCODES_H #define _TILEM_SCANCODES_H #ifdef __cplusplus extern "C" { #endif enum { TILEM_KEY_DOWN = 0x01, TILEM_KEY_LEFT = 0x02, TILEM_KEY_RIGHT = 0x03, TILEM_KEY_UP = 0x04, TILEM_KEY_ENTER = 0x09, TILEM_KEY_ADD = 0x0A, TILEM_KEY_SUB = 0x0B, TILEM_KEY_MUL = 0x0C, TILEM_KEY_DIV = 0x0D, TILEM_KEY_POWER = 0x0E, TILEM_KEY_CLEAR = 0x0F, TILEM_KEY_CHS = 0x11, TILEM_KEY_3 = 0x12, TILEM_KEY_6 = 0x13, TILEM_KEY_9 = 0x14, TILEM_KEY_RPAREN = 0x15, TILEM_KEY_TAN = 0x16, TILEM_KEY_VARS = 0x17, TILEM_KEY_DECPNT = 0x19, TILEM_KEY_2 = 0x1A, TILEM_KEY_5 = 0x1B, TILEM_KEY_8 = 0x1C, TILEM_KEY_LPAREN = 0x1D, TILEM_KEY_COS = 0x1E, TILEM_KEY_PRGM = 0x1F, TILEM_KEY_STAT = 0x20, TILEM_KEY_0 = 0x21, TILEM_KEY_1 = 0x22, TILEM_KEY_4 = 0x23, TILEM_KEY_7 = 0x24, TILEM_KEY_COMMA = 0x25, TILEM_KEY_SIN = 0x26, TILEM_KEY_MATRIX = 0x27, TILEM_KEY_GRAPHVAR = 0x28, TILEM_KEY_ON = 0x29, TILEM_KEY_STORE = 0x2A, TILEM_KEY_LN = 0x2B, TILEM_KEY_LOG = 0x2C, TILEM_KEY_SQUARE = 0x2D, TILEM_KEY_RECIP = 0x2E, TILEM_KEY_MATH = 0x2F, TILEM_KEY_ALPHA = 0x30, TILEM_KEY_GRAPH = 0x31, TILEM_KEY_TRACE = 0x32, TILEM_KEY_ZOOM = 0x33, TILEM_KEY_WINDOW = 0x34, TILEM_KEY_YEQU = 0x35, TILEM_KEY_2ND = 0x36, TILEM_KEY_MODE = 0x37, TILEM_KEY_DEL = 0x38 }; #ifdef __cplusplus } #endif #endif tilem-2.0/emu/state.c000066400000000000000000000551231220200411600145310ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "tilem.h" #include "z80.h" static void set_hw_reg(TilemCalc* calc, const char* name, dword value) { int i; for (i = 0; i < calc->hw.nhwregs; i++) { if (!strcmp(name, calc->hw.hwregnames[i])) { calc->hwregs[i] = value; return; } } tilem_warning(calc, "Unknown hwreg %s", name); } static const char* get_timer_name(TilemCalc* calc, int id) { if (id == TILEM_TIMER_LCD_DELAY) return "lcddelay"; else if (id == TILEM_TIMER_FLASH_DELAY) return "flashdelay"; else if (id == TILEM_TIMER_LINK_ASSIST) return "linkassist"; else if (id == TILEM_TIMER_USER1) return "user1"; else if (id == TILEM_TIMER_USER2) return "user2"; else if (id == TILEM_TIMER_USER3) return "user3"; else if (id <= TILEM_NUM_SYS_TIMERS) abort(); id -= TILEM_NUM_SYS_TIMERS + 1; if (id < calc->hw.nhwtimers) return calc->hw.hwtimernames[id]; else return NULL; } static void set_ptimer(TilemCalc* calc, const char* name, dword value, dword period, int rt) { int i; const char* tname; for (i = 1; i <= calc->z80.ntimers; i++) { tname = get_timer_name(calc, i); if (tname && !strcmp(name, tname)) { tilem_z80_set_timer(calc, i, value, period, rt); return; } } tilem_warning(calc, "Unknown timer %s", name); } static int load_old_sav_file(TilemCalc* calc, FILE* savfile) { byte b[76]; dword regs[19]; int i, le, be, c; unsigned int pageA, pageB; /* Read memory mapping */ if (fread(calc->mempagemap, 1, 4, savfile) < 4) return 1; /* Read CPU registers */ if (fread(b, 1, 76, savfile) < 76) return 1; be = le = 0; /* determine if file is in big-endian or little-endian format */ for (i = 0; i < 19; i++) { if (b[i * 4] || b[i * 4 + 1]) le++; if (b[i * 4 + 2] || b[i * 4 + 3]) be++; } if (le > be) { for (i = 0; i < 19; i++) { regs[i] = b[i * 4] + (b[i * 4 + 1] << 8); } } else { for (i = 0; i < 19; i++) { regs[i] = b[i * 4 + 3] + (b[i * 4 + 2] << 8); } } calc->z80.r.af.d = regs[0]; calc->z80.r.bc.d = regs[1]; calc->z80.r.de.d = regs[2]; calc->z80.r.hl.d = regs[3]; calc->z80.r.ix.d = regs[4]; calc->z80.r.iy.d = regs[5]; calc->z80.r.pc.d = regs[6]; calc->z80.r.sp.d = regs[7]; calc->z80.r.af2.d = regs[8]; calc->z80.r.bc2.d = regs[9]; calc->z80.r.de2.d = regs[10]; calc->z80.r.hl2.d = regs[11]; calc->z80.r.iff1 = regs[12] ? 1 : 0; calc->z80.r.iff2 = regs[13] ? 1 : 0; calc->z80.r.im = regs[15]; calc->z80.r.ir.b.h = regs[16]; calc->z80.r.ir.b.l = regs[17]; calc->z80.r.r7 = regs[18] & 0x80; if (calc->hw.model_id == '2' || calc->hw.model_id == '3') { if (fread(b, 1, 5, savfile) < 5) return 1; if (calc->hw.model_id == '3') set_hw_reg(calc, "rom_bank", calc->mempagemap[1] & 0x08); calc->hw.z80_out(calc, 0x02, b[4]); } /* Read RAM contents: old save files for TI-82/83/85 store RAM pages in logical rather than physical order */ if (calc->hw.model_id == '2' || calc->hw.model_id == '3' || calc->hw.model_id == '5') { if (fread(calc->mem + calc->hw.romsize + 0x4000, 1, 0x4000, savfile) < 0x4000) return 1; if (fread(calc->mem + calc->hw.romsize, 1, 0x4000, savfile) < 0x4000) return 1; } else { if (fread(calc->mem + calc->hw.romsize, 1, calc->hw.ramsize, savfile) < calc->hw.ramsize) return 1; } /* Read LCD contents */ if (calc->hw.flags & TILEM_CALC_HAS_T6A04) { calc->lcd.rowstride = 12; /* old save files only support the visible portion of the screen */ if (fread(calc->lcdmem, 1, 768, savfile) < 768) return 1; } /* Read additional HW state */ switch (calc->hw.model_id) { case '1': break; case '2': case '3': if ((c = fgetc(savfile)) != EOF) calc->lcd.mode = c; if ((c = fgetc(savfile)) != EOF) calc->lcd.x = c; if ((c = fgetc(savfile)) != EOF) calc->lcd.y = c; break; case '5': pageA = calc->mempagemap[1]; if (pageA >= 0x08) pageA += 0x38; calc->hw.z80_out(calc, 0x05, pageA); if ((c = fgetc(savfile)) != EOF) calc->hw.z80_out(calc, 0x06, c); break; case '6': pageA = calc->mempagemap[1]; pageB = calc->mempagemap[2]; if (pageA >= 0x10) pageA += 0x30; if (pageB >= 0x10) pageB += 0x30; calc->hw.z80_out(calc, 0x05, pageA); calc->hw.z80_out(calc, 0x06, pageB); break; default: /* TI-73/83+ series */ if ((c = fgetc(savfile)) != EOF) calc->lcd.mode = c; if ((c = fgetc(savfile)) != EOF) calc->lcd.x = c; if ((c = fgetc(savfile)) != EOF) calc->lcd.y = c; if ((c = fgetc(savfile)) != EOF) calc->lcd.inc = c; if ((c = fgetc(savfile)) == EOF) c = 0; if (c) { pageA = calc->mempagemap[2]; pageB = calc->mempagemap[3]; calc->hw.z80_out(calc, 0x04, 0x77); } else { pageA = calc->mempagemap[1]; pageB = calc->mempagemap[2]; calc->hw.z80_out(calc, 0x04, 0x76); } if (pageA >= (calc->hw.romsize >> 14)) pageA = ((pageA & 0x1f) | calc->hw.rampagemask); if (pageB >= (calc->hw.romsize >> 14)) pageB = ((pageB & 0x1f) | calc->hw.rampagemask); calc->hw.z80_out(calc, 0x06, pageA); calc->hw.z80_out(calc, 0x07, pageB); if ((c = fgetc(savfile)) != EOF) calc->flash.state = c; if ((c = fgetc(savfile)) != EOF) calc->flash.unlock = c; if ((c = fgetc(savfile)) != EOF) calc->hw.z80_out(calc, 0x20, c); if ((c = fgetc(savfile)) != EOF) set_hw_reg(calc, "port21", c); if ((c = fgetc(savfile)) != EOF) set_hw_reg(calc, "port22", c); if ((c = fgetc(savfile)) != EOF) set_hw_reg(calc, "port23", c); if ((c = fgetc(savfile)) != EOF) calc->hw.z80_out(calc, 0x27, c); if ((c = fgetc(savfile)) != EOF) calc->hw.z80_out(calc, 0x28, c); break; } calc->poweronhalt = calc->lcd.active = 1; return 0; } static int read_sav_line(FILE* savfile, char **buf) { int c, n, na; tilem_free(*buf); na = 100; *buf = tilem_malloc_atomic(na); n = 0; while ((c = fgetc(savfile)) != EOF) { if (c == '\r' || c == '\n') break; n++; if (n >= na) { na = n * 2; *buf = tilem_realloc(*buf, na); } if (c == '#') c = 0; (*buf)[n - 1] = c; } if (n == 0 && c == EOF) { tilem_free(*buf); *buf = NULL; return 0; } else { (*buf)[n] = 0; return 1; } } static int parse_sav_definition(char* line, char** value) { char *p; p = strchr(line, '='); if (!p) return 0; while (p != line && p[-1] == ' ') p--; *p = 0; p++; while (*p == ' ' || *p == '=') p++; *value = p; return 1; } static int load_new_sav_file(TilemCalc* calc, FILE* savfile) { char *buf = NULL; char *p, *q; dword value, length; byte *data; int ok = 0; byte digit; int firstdigit; dword period; int rt; while (read_sav_line(savfile, &buf)) { if (!parse_sav_definition(buf, &p)) continue; if (*p == '{') { p++; if (!strcmp(buf, "RAM")) { length = calc->hw.ramsize; data = calc->ram; } else if (!strcmp(buf, "LCD")) { length = calc->hw.lcdmemsize; data = calc->lcdmem; } else { length = 0; data = NULL; } value = 0; firstdigit = 1; while (*p != '}') { if (*p == 0 || *p == '#') { if (!read_sav_line(savfile, &buf)) return 1; p = buf; continue; } if (*p >= '0' && *p <= '9') { digit = *p - '0'; p++; } else if (*p >= 'A' && *p <= 'F') { digit = *p + 10 - 'A'; p++; } else if (*p >= 'a' && *p <= 'f') { digit = *p + 10 - 'a'; p++; } else { p++; continue; } if (firstdigit) { value = digit << 4; firstdigit = 0; } else { value |= digit; if (length != 0) { *data = value; data++; length--; } firstdigit = 1; } } continue; } if (!strcmp(buf, "MODEL")) { q = p; while (*q >= ' ') q++; *q = 0; if (strcmp(p, calc->hw.name)) { tilem_free(buf); return 1; } ok = 1; continue; } value = strtol(p, &q, 16); /* Persistent timers */ if (!strncmp(buf, "timer:", 6)) { while (*q == ' ') q++; if (*q != ',') continue; q++; while (*q == ' ') q++; period = strtol(q, &q, 16); while (*q == ' ') q++; if (*q != ',') continue; q++; while (*q == ' ') q++; rt = strtol(q, &q, 16); set_ptimer(calc, buf + 6, value, period, rt); continue; } /* Z80 */ if (!strcmp(buf, "af")) calc->z80.r.af.d = value; else if (!strcmp(buf, "bc")) calc->z80.r.bc.d = value; else if (!strcmp(buf, "de")) calc->z80.r.de.d = value; else if (!strcmp(buf, "hl")) calc->z80.r.hl.d = value; else if (!strcmp(buf, "af'")) calc->z80.r.af2.d = value; else if (!strcmp(buf, "bc'")) calc->z80.r.bc2.d = value; else if (!strcmp(buf, "de'")) calc->z80.r.de2.d = value; else if (!strcmp(buf, "hl'")) calc->z80.r.hl2.d = value; else if (!strcmp(buf, "ix")) calc->z80.r.ix.d = value; else if (!strcmp(buf, "iy")) calc->z80.r.iy.d = value; else if (!strcmp(buf, "pc")) calc->z80.r.pc.d = value; else if (!strcmp(buf, "sp")) calc->z80.r.sp.d = value; else if (!strcmp(buf, "ir")) { calc->z80.r.ir.d = value; calc->z80.r.r7 = value & 0x80; } else if (!strcmp(buf, "wz")) calc->z80.r.wz.d = value; else if (!strcmp(buf, "wz'")) calc->z80.r.wz2.d = value; else if (!strcmp(buf, "iff1")) calc->z80.r.iff1 = value; else if (!strcmp(buf, "iff2")) calc->z80.r.iff2 = value; else if (!strcmp(buf, "im")) calc->z80.r.im = value; else if (!strcmp(buf, "interrupts")) calc->z80.interrupts = value; else if (!strcmp(buf, "clockspeed")) calc->z80.clockspeed = value; else if (!strcmp(buf, "halted")) calc->z80.halted = value; /* LCD */ else if (!strcmp(buf, "lcd.active")) calc->lcd.active = value; else if (!strcmp(buf, "lcd.addr")) calc->lcd.addr = value; else if (!strcmp(buf, "lcd.rowshift")) calc->lcd.rowshift = value; else if (!strcmp(buf, "lcd.contrast")) calc->lcd.contrast = value; else if (!strcmp(buf, "lcd.inc")) calc->lcd.inc = value; else if (!strcmp(buf, "lcd.mode")) calc->lcd.mode = value; else if (!strcmp(buf, "lcd.x")) calc->lcd.x = value; else if (!strcmp(buf, "lcd.y")) calc->lcd.y = value; else if (!strcmp(buf, "lcd.nextbyte")) calc->lcd.nextbyte = value; else if (!strcmp(buf, "lcd.rowstride")) calc->lcd.rowstride = value; else if (!strcmp(buf, "lcd.busy")) calc->lcd.busy = value; /* Link port */ else if (!strcmp(buf, "linkport.lines")) calc->linkport.lines = value; else if (!strcmp(buf, "linkport.mode")) calc->linkport.mode = value; else if (!strcmp(buf, "linkport.assistflags")) calc->linkport.assistflags = value; else if (!strcmp(buf, "linkport.assistin")) calc->linkport.assistin = value; else if (!strcmp(buf, "linkport.assistinbits")) calc->linkport.assistinbits = value; else if (!strcmp(buf, "linkport.assistout")) calc->linkport.assistout = value; else if (!strcmp(buf, "linkport.assistoutbits")) calc->linkport.assistoutbits = value; else if (!strcmp(buf, "linkport.assistlastbyte")) calc->linkport.assistlastbyte = value; /* Keypad */ else if (!strcmp(buf, "keypad.group")) calc->keypad.group = value; else if (!strcmp(buf, "keypad.onkeyint")) calc->keypad.onkeyint = value; /* MD5 assist */ else if (!strcmp(buf, "md5assist.a")) calc->md5assist.regs[0] = value; else if (!strcmp(buf, "md5assist.b")) calc->md5assist.regs[1] = value; else if (!strcmp(buf, "md5assist.c")) calc->md5assist.regs[2] = value; else if (!strcmp(buf, "md5assist.d")) calc->md5assist.regs[3] = value; else if (!strcmp(buf, "md5assist.x")) calc->md5assist.regs[4] = value; else if (!strcmp(buf, "md5assist.t")) calc->md5assist.regs[5] = value; else if (!strcmp(buf, "md5assist.shift")) calc->md5assist.shift = value; else if (!strcmp(buf, "md5assist.mode")) calc->md5assist.mode = value; /* Programmable timers */ else if (!strcmp(buf, "usertimer0.frequency")) calc->usertimers[0].frequency = value; else if (!strcmp(buf, "usertimer0.loopvalue")) calc->usertimers[0].loopvalue = value; else if (!strcmp(buf, "usertimer0.status")) calc->usertimers[0].status = value; else if (!strcmp(buf, "usertimer1.frequency")) calc->usertimers[1].frequency = value; else if (!strcmp(buf, "usertimer1.loopvalue")) calc->usertimers[1].loopvalue = value; else if (!strcmp(buf, "usertimer1.status")) calc->usertimers[1].status = value; else if (!strcmp(buf, "usertimer2.frequency")) calc->usertimers[2].frequency = value; else if (!strcmp(buf, "usertimer2.loopvalue")) calc->usertimers[2].loopvalue = value; else if (!strcmp(buf, "usertimer2.status")) calc->usertimers[2].status = value; /* Main power */ else if (!strcmp(buf, "poweronhalt")) calc->poweronhalt = value; /* Battery */ else if (!strcmp(buf, "battery")) calc->battery = value; /* Memory */ else if (!strcmp(buf, "mempagemap0")) calc->mempagemap[0] = value; else if (!strcmp(buf, "mempagemap1")) calc->mempagemap[1] = value; else if (!strcmp(buf, "mempagemap2")) calc->mempagemap[2] = value; else if (!strcmp(buf, "mempagemap3")) calc->mempagemap[3] = value; else if (!strcmp(buf, "flash.unlock")) calc->flash.unlock = value; else if (!strcmp(buf, "flash.state")) calc->flash.state = value; else if (!strcmp(buf, "flash.busy")) calc->flash.busy = value; else if (!strcmp(buf, "flash.progaddr")) calc->flash.progaddr = value; else if (!strcmp(buf, "flash.progbyte")) calc->flash.progbyte = value; else if (!strcmp(buf, "flash.toggles")) calc->flash.toggles = value; else if (!strcmp(buf, "flash.overridegroup")) calc->flash.overridegroup = value; else set_hw_reg(calc, buf, value); } tilem_free(buf); return !ok; } int tilem_calc_load_state(TilemCalc* calc, FILE* romfile, FILE* savfile) { int b; int savtype = 0; if (romfile) { if (fread(calc->mem, 1, calc->hw.romsize, romfile) != calc->hw.romsize) return 1; } tilem_calc_reset(calc); if (savfile) { /* first byte of old save files is always zero */ b = fgetc(savfile); fseek(savfile, 0L, SEEK_SET); if (b == 0) { if (load_old_sav_file(calc, savfile)) { tilem_calc_reset(calc); return 1; } else savtype = 1; } else { if (load_new_sav_file(calc, savfile)) { tilem_calc_reset(calc); return 1; } else savtype = 2; } } if (calc->hw.stateloaded) (*calc->hw.stateloaded)(calc, savtype); return 0; } char tilem_get_sav_type(FILE* savfile) { int b; char *buf = NULL, *p, *q; const TilemHardware **models; int nmodels, i; char id = 0; tilem_get_supported_hardware(&models, &nmodels); /* first byte of old save files is always zero */ b = fgetc(savfile); fseek(savfile, 0L, SEEK_SET); if (b == 0) return 0; /* old files give no way to detect model */ while (read_sav_line(savfile, &buf)) { if (parse_sav_definition(buf, &p) && !strcmp(buf, "MODEL")) { q = p; while (*q >= ' ') q++; *q = 0; for (i = 0; i < nmodels; i++) if (!strcmp(p, models[i]->name)) id = models[i]->model_id; break; } } fseek(savfile, 0L, SEEK_SET); tilem_free(buf); return id; } int tilem_calc_save_state(TilemCalc* calc, FILE* romfile, FILE* savfile) { dword i; dword t; int j; const char* tname; unsigned int rowstride; if (romfile) { if (fwrite(calc->mem, 1, calc->hw.romsize, romfile) != calc->hw.romsize) return 1; } if (savfile) { fprintf(savfile, "# Tilem II State File\n# Version: %s\n", PACKAGE_VERSION); fprintf(savfile, "MODEL = %s\n", calc->hw.name); fprintf(savfile, "\n## CPU ##\n"); fprintf(savfile, "af = %04X\n", calc->z80.r.af.w.l); fprintf(savfile, "bc = %04X\n", calc->z80.r.bc.w.l); fprintf(savfile, "de = %04X\n", calc->z80.r.de.w.l); fprintf(savfile, "hl = %04X\n", calc->z80.r.hl.w.l); fprintf(savfile, "af' = %04X\n", calc->z80.r.af2.w.l); fprintf(savfile, "bc' = %04X\n", calc->z80.r.bc2.w.l); fprintf(savfile, "de' = %04X\n", calc->z80.r.de2.w.l); fprintf(savfile, "hl' = %04X\n", calc->z80.r.hl2.w.l); fprintf(savfile, "ix = %04X\n", calc->z80.r.ix.w.l); fprintf(savfile, "iy = %04X\n", calc->z80.r.iy.w.l); fprintf(savfile, "pc = %04X\n", calc->z80.r.pc.w.l); fprintf(savfile, "sp = %04X\n", calc->z80.r.sp.w.l); fprintf(savfile, "ir = %04X\n", ((calc->z80.r.ir.w.l & ~0x80) | calc->z80.r.r7)); fprintf(savfile, "wz = %04X\n", calc->z80.r.wz.w.l); fprintf(savfile, "wz' = %04X\n", calc->z80.r.wz2.w.l); fprintf(savfile, "iff1 = %X\n", calc->z80.r.iff1); fprintf(savfile, "iff2 = %X\n", calc->z80.r.iff2); fprintf(savfile, "im = %X\n", calc->z80.r.im); fprintf(savfile, "interrupts = %08X\n", calc->z80.interrupts); fprintf(savfile, "clockspeed = %X\n", calc->z80.clockspeed); fprintf(savfile, "halted = %X\n", calc->z80.halted); fprintf(savfile, "\n## LCD Driver ##\n"); fprintf(savfile, "lcd.active = %X\n", calc->lcd.active); fprintf(savfile, "lcd.contrast = %X\n", calc->lcd.contrast); fprintf(savfile, "lcd.rowstride = %X\n", calc->lcd.rowstride); if (calc->hw.flags & TILEM_CALC_HAS_T6A04) { fprintf(savfile, "lcd.rowshift = %X\n", calc->lcd.rowshift); fprintf(savfile, "lcd.inc = %X\n", calc->lcd.inc); fprintf(savfile, "lcd.mode = %X\n", calc->lcd.mode); fprintf(savfile, "lcd.x = %02X\n", calc->lcd.x); fprintf(savfile, "lcd.y = %02X\n", calc->lcd.y); fprintf(savfile, "lcd.nextbyte = %02X\n", calc->lcd.nextbyte); fprintf(savfile, "lcd.busy = %X\n", calc->lcd.busy); } fprintf(savfile, "lcd.addr = %X\n", calc->lcd.addr); if (calc->hw.flags & TILEM_CALC_HAS_LINK) { fprintf(savfile, "\n## Link Port ##\n"); fprintf(savfile, "linkport.lines = %X\n", calc->linkport.lines); fprintf(savfile, "linkport.mode = %08X\n", calc->linkport.mode); } if (calc->hw.flags & TILEM_CALC_HAS_LINK_ASSIST) { fprintf(savfile, "linkport.assistflags = %08X\n", calc->linkport.assistflags); fprintf(savfile, "linkport.assistin = %02X\n", calc->linkport.assistin); fprintf(savfile, "linkport.assistinbits = %X\n", calc->linkport.assistinbits); fprintf(savfile, "linkport.assistout = %02X\n", calc->linkport.assistout); fprintf(savfile, "linkport.assistoutbits = %X\n", calc->linkport.assistoutbits); fprintf(savfile, "linkport.assistlastbyte = %02X\n", calc->linkport.assistlastbyte); } fprintf(savfile, "\n## Keypad ##\n"); fprintf(savfile, "keypad.group = %X\n", calc->keypad.group); fprintf(savfile, "keypad.onkeyint = %X\n", calc->keypad.onkeyint); fprintf(savfile, "\n## Memory mapping ##\n"); fprintf(savfile, "mempagemap0 = %X\n", calc->mempagemap[0]); fprintf(savfile, "mempagemap1 = %X\n", calc->mempagemap[1]); fprintf(savfile, "mempagemap2 = %X\n", calc->mempagemap[2]); fprintf(savfile, "mempagemap3 = %X\n", calc->mempagemap[3]); fprintf(savfile, "\n## Power ##\n"); fprintf(savfile, "poweronhalt = %X\n", calc->poweronhalt); fprintf(savfile, "battery = %X\n", calc->battery); if (calc->hw.flags & TILEM_CALC_HAS_FLASH) { fprintf(savfile, "\n## Flash ##\n"); fprintf(savfile, "flash.unlock = %X\n", calc->flash.unlock); fprintf(savfile, "flash.state = %X\n", calc->flash.state); fprintf(savfile, "flash.busy = %X\n", calc->flash.busy); fprintf(savfile, "flash.progaddr = %X\n", calc->flash.progaddr); fprintf(savfile, "flash.progbyte = %X\n", calc->flash.progbyte); fprintf(savfile, "flash.toggles = %X\n", calc->flash.toggles); fprintf(savfile, "flash.overridegroup = %X\n", calc->flash.overridegroup); } if (calc->hw.flags & TILEM_CALC_HAS_MD5_ASSIST) { fprintf(savfile, "\n## MD5 assist ##\n"); fprintf(savfile, "md5assist.a = %X\n", calc->md5assist.regs[0]); fprintf(savfile, "md5assist.b = %X\n", calc->md5assist.regs[1]); fprintf(savfile, "md5assist.c = %X\n", calc->md5assist.regs[2]); fprintf(savfile, "md5assist.d = %X\n", calc->md5assist.regs[3]); fprintf(savfile, "md5assist.x = %X\n", calc->md5assist.regs[4]); fprintf(savfile, "md5assist.t = %X\n", calc->md5assist.regs[5]); fprintf(savfile, "md5assist.shift = %X\n", calc->md5assist.shift); fprintf(savfile, "md5assist.mode = %X\n", calc->md5assist.mode); } for (j = 0; j < calc->hw.nusertimers; j++) { fprintf(savfile, "\n## Programmable timer %d ##\n", j); fprintf(savfile, "usertimer%d.frequency = %X\n", j, calc->usertimers[j].frequency); fprintf(savfile, "usertimer%d.loopvalue = %X\n", j, calc->usertimers[j].loopvalue); fprintf(savfile, "usertimer%d.status = %X\n", j, calc->usertimers[j].status); } fprintf(savfile, "\n## Model-specific ##\n"); for (j = 0; j < calc->hw.nhwregs; j++) { fprintf(savfile, "%s = %X\n", calc->hw.hwregnames[j], calc->hwregs[j]); } fprintf(savfile, "\n## Timers ##\n"); for (j = calc->z80.timer_cpu; j; j = calc->z80.timers[j].next) { tname = get_timer_name(calc, j); if (tname) { t = tilem_z80_get_timer_clocks(calc, j); fprintf(savfile, "timer:%s = %X, %X, 0\n", tname, t, calc->z80.timers[j].period); } } for (j = calc->z80.timer_rt; j; j = calc->z80.timers[j].next) { tname = get_timer_name(calc, j); if (tname) { t = tilem_z80_get_timer_microseconds(calc, j); fprintf(savfile, "timer:%s = %X, %X, 1\n", tname, t, calc->z80.timers[j].period); } } fprintf(savfile, "\n## RAM contents ##\n"); fprintf(savfile, "RAM = {\n"); for (i = 0; i < calc->hw.ramsize; i++) { if (i % 256 == 0) { fprintf(savfile, "# %02X:%04X\n", (i >> 14), (i & 0x3fff)); } fprintf(savfile, "%02X", calc->mem[i + calc->hw.romsize]); if (i % 32 == 31) fprintf(savfile, "\n"); } fprintf(savfile, "}\n## End of RAM contents ##\n"); if (calc->hw.lcdmemsize) { fprintf(savfile, "\n## LCD contents ##\n"); fprintf(savfile, "LCD = {\n"); rowstride = calc->lcd.rowstride; if (rowstride == 0) rowstride = 32; for (i = 0; i < calc->hw.lcdmemsize; i++) { fprintf(savfile, "%02X", calc->lcdmem[i]); if (i % rowstride == (rowstride - 1)) fprintf(savfile, "\n"); } fprintf(savfile, "}\n## End of LCD contents ##\n"); } } return 0; } tilem-2.0/emu/tilem.h000066400000000000000000000754221220200411600145340ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_H #define _TILEM_H #include "tilemint.h" #ifdef __cplusplus extern "C" { #endif /* Basic integer types */ typedef uint8_t byte; typedef uint16_t word; typedef uint32_t dword; typedef uint64_t qword; /* Structure types */ typedef struct _TilemHardware TilemHardware; typedef struct _TilemCalc TilemCalc; /* Useful macros */ #if __GNUC__ >= 3 # define TILEM_ATTR_PURE __attribute__((__pure__)) # define TILEM_ATTR_UNUSED __attribute__((__unused__)) # define TILEM_ATTR_MALLOC __attribute__((__malloc__)) # define TILEM_ATTR_PRINTF(x,y) __attribute__((__format__(__printf__,x,y))) # define TILEM_LIKELY(xxx) (__builtin_expect((xxx), 1)) # define TILEM_UNLIKELY(xxx) (__builtin_expect((xxx), 0)) #else # define TILEM_ATTR_PURE # define TILEM_ATTR_UNUSED # define TILEM_ATTR_MALLOC # define TILEM_ATTR_PRINTF(x,y) # define TILEM_LIKELY(xxx) (xxx) # define TILEM_UNLIKELY(xxx) (xxx) #endif #define TILEM_DWORD_TO_PTR(xxx) ((void*)(uintptr_t)(xxx)) #define TILEM_PTR_TO_DWORD(xxx) ((dword)(uintptr_t)(xxx)) /* Memory allocation */ void* tilem_malloc(size_t size) TILEM_ATTR_MALLOC; void* tilem_malloc0(size_t size) TILEM_ATTR_MALLOC; void* tilem_malloc_atomic(size_t size) TILEM_ATTR_MALLOC; void* tilem_try_malloc(size_t size) TILEM_ATTR_MALLOC; void* tilem_try_malloc0(size_t size) TILEM_ATTR_MALLOC; void* tilem_try_malloc_atomic(size_t size) TILEM_ATTR_MALLOC; void* tilem_realloc(void* ptr, size_t size) TILEM_ATTR_MALLOC; void tilem_free(void* ptr); #define tilem_new(ttt, nnn) ((ttt*) tilem_malloc((nnn) * sizeof(ttt))); #define tilem_new0(ttt, nnn) ((ttt*) tilem_malloc0((nnn) * sizeof(ttt))); #define tilem_new_atomic(ttt, nnn) ((ttt*) tilem_malloc_atomic((nnn) * sizeof(ttt))); #define tilem_try_new(ttt, nnn) ((ttt*) tilem_try_malloc((nnn) * sizeof(ttt))); #define tilem_try_new0(ttt, nnn) ((ttt*) tilem_try_malloc0((nnn) * sizeof(ttt))); #define tilem_try_new_atomic(ttt, nnn) ((ttt*) tilem_try_malloc_atomic((nnn) * sizeof(ttt))); #define tilem_renew(ttt, ppp, nnn) ((ttt*) tilem_realloc((ppp), (nnn) * sizeof(ttt))) /* Message/error logging */ /* Write an informative message. This can be used to notify the user of major occurences, such as changes in the Flash protection. These messages can occur regularly in normal operation and are provided chiefly to aid in debugging. */ void tilem_message(TilemCalc* calc, const char* msg, ...) TILEM_ATTR_PRINTF(2, 3); /* Write a warning message. These messages occur when the calculator software (either the OS or a user program) performs an invalid operation; these messages often indicate a bug in the calculator software, but are otherwise harmless. */ void tilem_warning(TilemCalc* calc, const char* msg, ...) TILEM_ATTR_PRINTF(2, 3); /* Write a warning about an internal error. These messages should never occur and indicate a bug in TilEm. */ void tilem_internal(TilemCalc* calc, const char* msg, ...) TILEM_ATTR_PRINTF(2, 3); /* Z80 CPU */ /* This union allows us to manipulate register pairs as either byte or word values. It may need to be modified for really unusual host CPUs. */ typedef union _TilemZ80Reg { #ifdef WORDS_BIGENDIAN struct { byte h3, h2, h, l; } b; struct { word h, l; } w; dword d; #else struct { byte l, h, h2, h3; } b; struct { word l, h; } w; dword d; #endif } TilemZ80Reg; typedef struct _TilemZ80Regs { TilemZ80Reg af, bc, de, hl; TilemZ80Reg ix, iy, pc, sp; TilemZ80Reg ir, wz, wz2; TilemZ80Reg af2, bc2, de2, hl2; int iff1, iff2, im; byte r7; } TilemZ80Regs; /* Breakpoint types */ enum { TILEM_BREAK_MEM_READ = 1, /* Break after reading from memory */ TILEM_BREAK_MEM_EXEC, /* Break prior to executing from memory */ TILEM_BREAK_MEM_WRITE, /* Break after writing to memory */ TILEM_BREAK_PORT_READ, /* Break after reading from port */ TILEM_BREAK_PORT_WRITE, /* Break after writing to port */ TILEM_BREAK_EXECUTE, /* Break after executing opcode */ TILEM_BREAK_TYPE_MASK = 0xffff, TILEM_BREAK_PHYSICAL = 0x10000, /* Use physical addresses */ TILEM_BREAK_DISABLED = 0x20000 /* Disabled breakpoint */ }; /* Emulation flags */ enum { TILEM_Z80_BREAK_INVALID = 1, /* Break on invalid instructions */ TILEM_Z80_BREAK_UNDOCUMENTED = 2, /* Break on undocumented instructions */ TILEM_Z80_SKIP_UNDOCUMENTED = 4, /* Ignore undocumented instructions entirely (act as two NOPs) */ TILEM_Z80_RESET_UNDOCUMENTED = 8, /* Reset CPU following undocumented instructions */ TILEM_Z80_BREAK_EXCEPTIONS = 16, /* Break on hardware exceptions */ TILEM_Z80_IGNORE_EXCEPTIONS = 32 /* Ignore hardware exceptions */ }; /* Reasons for stopping emulation */ enum { TILEM_STOP_TIMEOUT = 0, /* stopped due to timeout */ TILEM_STOP_BREAKPOINT = 1, /* stopped due to breakpoint */ TILEM_STOP_INVALID_INST = 2, /* invalid instruction */ TILEM_STOP_UNDOCUMENTED_INST = 4, /* undocumented instruction */ TILEM_STOP_EXCEPTION = 8, /* hardware exception */ TILEM_STOP_LINK_STATE = 16, /* blacklink state change */ TILEM_STOP_LINK_READ_BYTE = 32, /* graylink finished reading byte */ TILEM_STOP_LINK_WRITE_BYTE = 64, /* graylink finished writing byte */ TILEM_STOP_LINK_ERROR = 128 /* graylink encountered error */ }; /* Types of interrupt */ enum { TILEM_INTERRUPT_ON_KEY = 1, /* ON key pressed */ TILEM_INTERRUPT_TIMER1 = 2, /* Main interrupt timer */ TILEM_INTERRUPT_TIMER2 = 4, /* Alt. interrupt timer (83/83+) */ TILEM_INTERRUPT_USER_TIMER1 = 8, /* Programmable timers (83+SE) */ TILEM_INTERRUPT_USER_TIMER2 = 16, TILEM_INTERRUPT_USER_TIMER3 = 32, TILEM_INTERRUPT_LINK_ACTIVE = 512, /* Link port state changed */ TILEM_INTERRUPT_LINK_READ = 1024, /* Link assist read a byte */ TILEM_INTERRUPT_LINK_IDLE = 2048, /* Link assist is idle */ TILEM_INTERRUPT_LINK_ERROR = 4096 /* Link assist failed */ }; /* Types of hardware exception */ enum { TILEM_EXC_RAM_EXEC = 1, /* Executing at invalid RAM address */ TILEM_EXC_FLASH_EXEC = 2, /* Executing at invalid Flash address */ TILEM_EXC_FLASH_WRITE = 4, /* Writing to invalid Flash address */ TILEM_EXC_INSTRUCTION = 8 /* Invalid instruction */ }; /* Constant hardware timer IDs */ enum { TILEM_TIMER_NONE = 0, TILEM_TIMER_LCD_DELAY, TILEM_TIMER_FLASH_DELAY, TILEM_TIMER_LINK_ASSIST, TILEM_TIMER_USER1, TILEM_TIMER_USER2, TILEM_TIMER_USER3, TILEM_TIMER_HW }; #define TILEM_NUM_SYS_TIMERS (TILEM_TIMER_HW - 1) /* Type of a timer callback function. Second arg is the callback data passed to tilem_z80_add_timer(). */ typedef void (*TilemZ80TimerFunc)(TilemCalc*, void*); /* Type of a breakpoint test function. Second arg is the memory address (or opcode in the case of TILEM_BREAK_EXECUTE breakpoints.) Third arg is the callback data passed to tilem_z80_add_breakpoint(). */ typedef int (*TilemZ80BreakpointFunc)(TilemCalc*, dword, void*); typedef struct _TilemZ80Timer TilemZ80Timer; typedef struct _TilemZ80Breakpoint TilemZ80Breakpoint; typedef struct _TilemZ80 { TilemZ80Regs r; unsigned int interrupts; /* Currently active interrupts */ int clockspeed; /* Current CPU speed (kHz) */ int halted; unsigned int exception; dword clock; dword lastwrite; dword lastlcdwrite; unsigned int emuflags; int ntimers; TilemZ80Timer* timers; int timer_cpu; /* Sorted list of timers (CPU-based) */ int timer_rt; /* Sorted list of timers (realtime) */ int timer_free; /* List of free timer structs */ int nbreakpoints; TilemZ80Breakpoint* breakpoints; int breakpoint_mr; /* Memory read breakpoints */ int breakpoint_mx; /* Memory exec breakpoints */ int breakpoint_mw; /* Memory write breakpoints */ int breakpoint_pr; /* Port read breakpoints */ int breakpoint_pw; /* Port write breakpoints */ int breakpoint_op; /* Opcode breakpoints */ int breakpoint_mpr; /* Physical mem read breakpoints */ int breakpoint_mpx; /* Physical mem exec breakpoints */ int breakpoint_mpw; /* Physical mem write breakpoints */ int breakpoint_disabled; /* Disabled breakpoints */ int breakpoint_free; /* List of free bp structs */ int stopping; dword stop_reason; dword stop_mask; int stop_breakpoint; } TilemZ80; /* Reset CPU */ void tilem_z80_reset(TilemCalc* calc); /* Halt simulation */ void tilem_z80_stop(TilemCalc* calc, dword reason); /* Set CPU speed (kHz) */ void tilem_z80_set_speed(TilemCalc* calc, int speed); /* Raise a hardware exception */ void tilem_z80_exception(TilemCalc* calc, unsigned type); /* Add a timer with the given callback function and data. The callback function will be called after 'count' time units, and every 'period' time units thereafter. If rt = 0, the time units are CPU clock cycles; if rt = 1, time units are microseconds. Note that if a timer is set in response to a memory read or write, the length of the delay may be off by as much as 19 clock cycles; the precise timings for these are not (yet) properly emulated. Timers set in response to port I/O events will be accurate to the nearest CPU clock cycle. The timer is considered to have "fired" as soon as the specified amount of time has elapsed. The callback function, however, may not be called until after the instruction finishes. If multiple timers fire during the same instruction, the order in which the callback functions will be called is undefined. If you create a timer using this function (either repeating or non-repeating), you must call tilem_z80_remove_timer() when the timer is no longer needed. */ int tilem_z80_add_timer(TilemCalc* calc, dword count, dword period, int rt, TilemZ80TimerFunc func, void* data); /* Change settings for an existing timer. Arguments are the same as above. If count = 0, the timer is disabled. */ void tilem_z80_set_timer(TilemCalc* calc, int id, dword count, dword period, int rt); /* Change period for an existing timer without affecting the current interval. */ void tilem_z80_set_timer_period(TilemCalc* calc, int id, dword period); /* Delete a timer. */ void tilem_z80_remove_timer(TilemCalc* calc, int id); /* Check whether a timer is currently running. */ int tilem_z80_timer_running(TilemCalc* calc, int id) TILEM_ATTR_PURE; /* Get the number of clock ticks from now until the next time the given timer fires. (This may be negative, if the timer has already fired during this instruction.) NOTE: If the timer is disabled, the return value is undefined. */ int tilem_z80_get_timer_clocks(TilemCalc* calc, int id) TILEM_ATTR_PURE; /* Get the number of microseconds from now until the next time the given timer fires. */ int tilem_z80_get_timer_microseconds(TilemCalc* calc, int id) TILEM_ATTR_PURE; /* Add a breakpoint. The breakpoint will be triggered if the address, ANDed with the given mask, falls between the given start and end inclusive. If a callback function is specified it acts as an additional filter, to determine whether the simulation should be halted. */ int tilem_z80_add_breakpoint(TilemCalc* calc, int type, dword start, dword end, dword mask, TilemZ80BreakpointFunc func, void* data); /* Remove the given breakpoint. */ void tilem_z80_remove_breakpoint(TilemCalc* calc, int id); /* Enable the given breakpoint. */ void tilem_z80_enable_breakpoint(TilemCalc* calc, int id); /* Disable the given breakpoint. */ void tilem_z80_disable_breakpoint(TilemCalc* calc, int id); /* Check whether the given breakpoint is currently enabled. */ int tilem_z80_breakpoint_enabled(TilemCalc* calc, int id); /* Get the type of the given breakpoint. */ int tilem_z80_get_breakpoint_type(TilemCalc* calc, int id); /* Get the start address of the given breakpoint. */ dword tilem_z80_get_breakpoint_address_start(TilemCalc* calc, int id); /* Get the start address of the given breakpoint. */ dword tilem_z80_get_breakpoint_address_end(TilemCalc* calc, int id); /* Get the start address of the given breakpoint. */ dword tilem_z80_get_breakpoint_address_mask(TilemCalc* calc, int id); /* Get the callback/filter function associated to the given breakpoint. */ TilemZ80BreakpointFunc tilem_z80_get_breakpoint_callback(TilemCalc* calc, int id); /* Get the data associated to the given breakpoint. */ void* tilem_z80_get_breakpoint_data(TilemCalc* calc, int id); /* Set the type of the given breakpoint. */ void tilem_z80_set_breakpoint_type(TilemCalc* calc, int id, int type); /* Set the start address of the given breakpoint. */ void tilem_z80_set_breakpoint_address_start(TilemCalc* calc, int id, dword start); /* Set the start address of the given breakpoint. */ void tilem_z80_set_breakpoint_address_end(TilemCalc* calc, int id, dword end); /* Set the start address of the given breakpoint. */ void tilem_z80_set_breakpoint_address_mask(TilemCalc* calc, int id, dword mask); /* Set the callback/filter function associated to the given breakpoint. */ void tilem_z80_set_breakpoint_callback(TilemCalc* calc, int id, TilemZ80BreakpointFunc func); /* Set the data associated to the given breakpoint. */ void tilem_z80_set_breakpoint_data(TilemCalc* calc, int id, void* data); /* Run the simulated CPU for the given number of clock ticks/microseconds, or until a breakpoint is hit or tilem_z80_stop() is called. */ dword tilem_z80_run(TilemCalc* calc, int clocks, int* remaining); dword tilem_z80_run_time(TilemCalc* calc, int microseconds, int* remaining); /* LCD driver */ /* Emulation flags */ enum { TILEM_LCD_REQUIRE_DELAY = 1, /* Emulate required delay between commands */ TILEM_LCD_REQUIRE_LONG_DELAY = 2 /* Require extra-long delay */ }; typedef struct _TilemLCD { /* Common settings */ byte active; /* LCD driver active */ byte contrast; /* Contrast value (0-63) */ int rowstride; /* Number of bytes per row */ unsigned int emuflags; /* T6A43 internal driver */ word addr; /* Memory address */ /* T6A04 external driver */ byte mode; /* I/O mode (0 = 6bit, 1 = 8bit) */ byte inc; /* Increment mode (4-7) */ byte nextbyte; /* Output register */ int x, y; /* Current position */ int rowshift; /* Starting row for display */ byte busy; } TilemLCD; /* Reset LCD driver */ void tilem_lcd_reset(TilemCalc* calc); /* Get LCD driver status (port 10 input) */ byte tilem_lcd_t6a04_status(TilemCalc* calc); /* Send command to LCD driver (port 10 output) */ void tilem_lcd_t6a04_control(TilemCalc* calc, byte val); /* Read data from LCD driver (port 11 input) */ byte tilem_lcd_t6a04_read(TilemCalc* calc); /* Write data to LCD driver (port 11 output) */ void tilem_lcd_t6a04_write(TilemCalc* calc, byte val); /* Get screen image (T6A04 style) */ void tilem_lcd_t6a04_get_data(TilemCalc* calc, byte* data); /* Get screen image (T6A43 style) */ void tilem_lcd_t6a43_get_data(TilemCalc* calc, byte* data); /* Callback for TILEM_TIMER_LCD_DELAY */ void tilem_lcd_delay_timer(TilemCalc* calc, void* data); /* DBUS link port driver */ /* Link port / assist mode flags */ enum { TILEM_LINK_MODE_ASSIST = 1, /* Enable link assist */ TILEM_LINK_MODE_NO_TIMEOUT = 2, /* Assist doesn't time out (xp) */ TILEM_LINK_MODE_INT_ON_ACTIVE = 4, /* Interrupt on state change */ TILEM_LINK_MODE_INT_ON_READ = 8, /* Interrupt on asst. read */ TILEM_LINK_MODE_INT_ON_IDLE = 16, /* Interrupt when asst. idle */ TILEM_LINK_MODE_INT_ON_ERROR = 32 /* Interrupt on asst. error */ }; /* Link port state flags */ enum { TILEM_LINK_ASSIST_READ_BYTE = 1, /* Assisted read finished */ TILEM_LINK_ASSIST_READ_BUSY = 2, /* Assisted read in progress */ TILEM_LINK_ASSIST_READ_ERROR = 4, /* Assisted read failed */ TILEM_LINK_ASSIST_WRITE_BUSY = 8, /* Assisted write in progress */ TILEM_LINK_ASSIST_WRITE_ERROR = 16 /* Assisted write failed */ }; /* Link emulation mode */ enum { TILEM_LINK_EMULATOR_NONE = 0, /* Link port disconnected */ TILEM_LINK_EMULATOR_BLACK = 1, /* Connected to virtual BlackLink (exit emulation on state change) */ TILEM_LINK_EMULATOR_GRAY = 2 /* Connected to virtual GrayLink (auto send/receive bytes) */ }; typedef struct _TilemLinkport { byte lines, extlines; /* Link line state for TI/PC 0 = both lines high 1 = red wire low 2 = white wire low 3 = both wires low */ unsigned int mode; /* Mode flags */ /* Internal link assist */ unsigned int assistflags; /* Assist state */ byte assistin; /* Input buffer (recv from PC) */ byte assistinbits; /* Input bit count */ byte assistout; /* Output buffer (send to PC) */ byte assistoutbits; /* Output bit count */ byte assistlastbyte; /* Last byte received */ /* External link emulator */ byte linkemu; byte graylinkin; /* Input buffer (recv from TI) */ byte graylinkinbits; /* Input bit count */ byte graylinkout; /* Output buffer (send to TI) */ byte graylinkoutbits; /* Output bit count */ } TilemLinkport; /* Reset link port */ void tilem_linkport_reset(TilemCalc* calc); /* Read link port lines */ byte tilem_linkport_get_lines(TilemCalc* calc); /* Set link port lines */ void tilem_linkport_set_lines(TilemCalc* calc, byte lines); /* Read from, and clear, link assist input buffer */ byte tilem_linkport_read_byte(TilemCalc* calc); /* Write to link assist output buffer */ void tilem_linkport_write_byte(TilemCalc* calc, byte data); /* Get assist state */ unsigned int tilem_linkport_get_assist_flags(TilemCalc* calc); /* Set link port mode */ void tilem_linkport_set_mode(TilemCalc* calc, unsigned int mode); /* Set line states for virtual BlackLink */ void tilem_linkport_blacklink_set_lines(TilemCalc* calc, byte lines); /* Get line states from virtual BlackLink */ byte tilem_linkport_blacklink_get_lines(TilemCalc* calc); /* Reset GrayLink */ void tilem_linkport_graylink_reset(TilemCalc* calc); /* Check if GrayLink is ready to send data */ int tilem_linkport_graylink_ready(TilemCalc* calc); /* Send a byte via virtual GrayLink */ int tilem_linkport_graylink_send_byte(TilemCalc* calc, byte value); /* Get byte received by virtual GrayLink (-1 = none available) */ int tilem_linkport_graylink_get_byte(TilemCalc* calc); /* Callback for TILEM_TIMER_LINK_ASSIST */ void tilem_linkport_assist_timer(TilemCalc* calc, void* data); /* Keypad */ typedef struct _TilemKeypad { byte group; byte onkeydown; byte onkeyint; byte keysdown[8]; } TilemKeypad; /* Reset keypad */ void tilem_keypad_reset(TilemCalc* calc); /* Set current group (port 1 output) */ void tilem_keypad_set_group(TilemCalc* calc, byte group); /* Read keys from current group (port 1 input) */ byte tilem_keypad_read_keys(TilemCalc* calc); /* Press a key */ void tilem_keypad_press_key(TilemCalc* calc, int scancode); /* Release a key */ void tilem_keypad_release_key(TilemCalc* calc, int scancode); /* Flash */ /* Emulation flags */ enum { TILEM_FLASH_REQUIRE_DELAY = 1 /* Require delay after program/erase */ }; typedef struct _TilemFlashSector { dword start; dword size; byte protectgroup; } TilemFlashSector; typedef struct _TilemFlash { byte unlock; byte state; unsigned int emuflags; byte busy; dword progaddr; byte progbyte; byte toggles; byte overridegroup; } TilemFlash; /* Reset Flash */ void tilem_flash_reset(TilemCalc* calc); /* Read a byte from the Flash chip */ byte tilem_flash_read_byte(TilemCalc* calc, dword pa); /* Erase a Flash sector */ void tilem_flash_erase_address(TilemCalc* calc, dword pa); /* Write a byte to the Flash chip */ void tilem_flash_write_byte(TilemCalc* calc, dword pa, byte v); /* Callback for TILEM_TIMER_FLASH_DELAY */ void tilem_flash_delay_timer(TilemCalc* calc, void* data); /* MD5 assist */ enum { TILEM_MD5_REG_A = 0, /* initial 'a' value */ TILEM_MD5_REG_B = 1, /* 'b' value */ TILEM_MD5_REG_C = 2, /* 'c' value */ TILEM_MD5_REG_D = 3, /* 'd' value */ TILEM_MD5_REG_X = 4, /* 'X' (or 'T') value */ TILEM_MD5_REG_T = 5 /* 'T' (or 'X') value */ }; enum { TILEM_MD5_FUNC_FF = 0, TILEM_MD5_FUNC_GG = 1, TILEM_MD5_FUNC_HH = 2, TILEM_MD5_FUNC_II = 3 }; typedef struct _TilemMD5Assist { dword regs[6]; byte shift; byte mode; } TilemMD5Assist; /* Reset MD5 assist */ void tilem_md5_assist_reset(TilemCalc* calc); /* Get output value */ dword tilem_md5_assist_get_value(TilemCalc* calc); /* Programmable timers */ #define TILEM_MAX_USER_TIMERS 3 enum { TILEM_USER_TIMER_LOOP = 1, /* loop when counter reaches 0 */ TILEM_USER_TIMER_INTERRUPT = 2, /* generate interrupt when finished */ TILEM_USER_TIMER_OVERFLOW = 4, /* timer has expired at least twice since last mode setting */ TILEM_USER_TIMER_FINISHED = 256, /* timer has expired at least once since last mode setting (port 4 status bit) */ TILEM_USER_TIMER_NO_HALT_INT = 512 /* suppress interrupt if CPU is halted */ }; typedef struct _TilemUserTimer { byte frequency; byte loopvalue; unsigned int status; } TilemUserTimer; /* Reset timers */ void tilem_user_timers_reset(TilemCalc* calc); /* Set frequency control register */ void tilem_user_timer_set_frequency(TilemCalc* calc, int n, byte value); /* Set status flags */ void tilem_user_timer_set_mode(TilemCalc* calc, int n, byte mode); /* Start timer */ void tilem_user_timer_start(TilemCalc* calc, int n, byte value); /* Get timer value */ byte tilem_user_timer_get_value(TilemCalc* calc, int n); /* Callback function */ void tilem_user_timer_expired(TilemCalc* calc, void* data); /* Calculators */ /* Model IDs */ enum { TILEM_CALC_TI73 = '7', /* TI-73 / TI-73 Explorer */ TILEM_CALC_TI76 = 'f', /* TI-76.fr */ TILEM_CALC_TI81 = '1', /* TI-81 */ TILEM_CALC_TI82 = '2', /* TI-82 */ TILEM_CALC_TI83 = '3', /* TI-83 / TI-82 STATS [.fr] */ TILEM_CALC_TI83P = 'p', /* TI-83 Plus */ TILEM_CALC_TI83P_SE = 's', /* TI-83 Plus Silver Edition */ TILEM_CALC_TI84P = '4', /* TI-84 Plus */ TILEM_CALC_TI84P_SE = 'z', /* TI-84 Plus Silver Edition */ TILEM_CALC_TI84P_NSPIRE = 'n', /* TI-Nspire 84 Plus emulator */ TILEM_CALC_TI85 = '5', /* TI-85 */ TILEM_CALC_TI86 = '6' /* TI-86 */ }; /* Calculator flags */ enum { TILEM_CALC_HAS_LINK = 1, /* Has link port */ TILEM_CALC_HAS_LINK_ASSIST = 2, /* Has hardware link assist */ TILEM_CALC_HAS_USB = 4, /* Has USB controller */ TILEM_CALC_HAS_FLASH = 8, /* Has (writable) Flash */ TILEM_CALC_HAS_T6A04 = 16, /* Has separate LCD driver */ TILEM_CALC_HAS_MD5_ASSIST = 32 /* Has hardware MD5 assist */ }; /* Calculator hardware description */ struct _TilemHardware { char model_id; /* Single character identifying model */ const char* name; /* Short name (e.g. ti83p) */ const char* desc; /* Full name (e.g. TI-83 Plus) */ unsigned int flags; int lcdwidth, lcdheight; /* Size of LCD */ dword romsize, ramsize; /* Size of ROM and RAM */ dword lcdmemsize; /* Size of external LCD memory */ byte rampagemask; /* Bit mask used for RAM page */ int nflashsectors; const TilemFlashSector* flashsectors; int nusertimers; int nhwregs; /* Number of hardware registers */ const char** hwregnames; /* Harware register names */ int nhwtimers; /* Number of hardware timers */ const char** hwtimernames; /* Hardware timer names*/ const char** keynames; /* Reset calculator */ void (*reset) (TilemCalc*); /* Reinitialize after loading state */ void (*stateloaded) (TilemCalc*, int); /* Z80 ports and memory */ byte (*z80_in) (TilemCalc*, dword); void (*z80_out) (TilemCalc*, dword, byte); void (*z80_wrmem) (TilemCalc*, dword, byte); byte (*z80_rdmem) (TilemCalc*, dword); byte (*z80_rdmem_m1) (TilemCalc*, dword); /* Evaluate a non-standard instruction */ void (*z80_instr) (TilemCalc*, dword); /* Persistent timer callback */ void (*z80_ptimer) (TilemCalc*, int); /* Retrieve LCD contents */ void (*get_lcd) (TilemCalc*, byte*); /* Convert physical <-> logical addresses */ dword (*mem_ltop) (TilemCalc*, dword); dword (*mem_ptol) (TilemCalc*, dword); }; /* Current state of the calculator */ struct _TilemCalc { TilemHardware hw; TilemZ80 z80; byte* mem; byte* ram; byte* lcdmem; byte mempagemap[4]; TilemLCD lcd; TilemLinkport linkport; TilemKeypad keypad; TilemFlash flash; TilemMD5Assist md5assist; TilemUserTimer usertimers[TILEM_MAX_USER_TIMERS]; byte poweronhalt; /* System power control. If this is zero, turn off LCD, timers, etc. when CPU halts */ byte battery; /* Battery level (units of 0.1 V) */ dword* hwregs; }; /* Get a list of supported hardware models */ void tilem_get_supported_hardware(const TilemHardware*** models, int* nmodels); /* Create a new calculator. This function returns NULL if insufficient memory is available. */ TilemCalc* tilem_calc_new(char id); /* Make an exact copy of an existing calculator (including both internal and external state.) Be careful when using this in conjunction with custom timer/breakpoint callback functions. This function returns NULL if insufficient memory is available. */ TilemCalc* tilem_calc_copy(TilemCalc* calc); /* Free a calculator that was previously created by tilem_calc_new() or tilem_calc_copy(). */ void tilem_calc_free(TilemCalc* calc); /* Reset calculator (essentially, remove and replace batteries.) */ void tilem_calc_reset(TilemCalc* calc); /* Load calculator state from ROM and/or save files. */ int tilem_calc_load_state(TilemCalc* calc, FILE* romfile, FILE* savfile); /* Save calculator state to ROM and/or save files. */ int tilem_calc_save_state(TilemCalc* calc, FILE* romfile, FILE* savfile); /* LCD image conversion/scaling */ /* Scaling algorithms */ enum { TILEM_SCALE_FAST = 0, /* Fast scaling (nearest neighbor) - looks lousy unless the scaling factor is fairly large */ TILEM_SCALE_SMOOTH /* Smooth scaling - slower and looks better at small sizes; note that this falls back to using the "fast" algorithm if we are scaling up by an integer factor */ }; /* Buffer representing a snapshot of the LCD state */ typedef struct _TilemLCDBuffer { byte width; /* Width of LCD */ byte height; /* Height of LCD */ byte rowstride; /* Offset between rows in buffer */ byte contrast; /* Contrast value (0-63) */ dword stamp; /* Timestamp */ dword tmpbufsize; /* Size of temporary buffer */ byte *data; /* Image data (rowstride*height bytes) */ void *tmpbuf; /* Temporary buffer used for scaling */ } TilemLCDBuffer; /* Create new TilemLCDBuffer. */ TilemLCDBuffer* tilem_lcd_buffer_new(void) TILEM_ATTR_MALLOC; /* Free a TilemLCDBuffer. */ void tilem_lcd_buffer_free(TilemLCDBuffer *buf); /* Convert current LCD memory contents to a TilemLCDBuffer (i.e., a monochrome snapshot.) */ void tilem_lcd_get_frame(TilemCalc * restrict calc, TilemLCDBuffer * restrict buf); /* Convert current LCD memory contents to a TilemLCDBuffer (i.e., a monochrome snapshot.) Output is only 0 and 1 */ void tilem_lcd_get_frame1(TilemCalc * restrict calc, TilemLCDBuffer * restrict buf); /* Convert and scale image to an 8-bit indexed image buffer. IMGWIDTH and IMGHEIGHT are the width and height of the output image, ROWSTRIDE the number of bytes from the start of one row to the next (often equal to IMGWIDTH), and SCALETYPE the scaling algorithm to use. */ void tilem_draw_lcd_image_indexed(TilemLCDBuffer * restrict frm, byte * restrict buffer, int imgwidth, int imgheight, int rowstride, int scaletype); /* Convert and scale image to a 24-bit RGB or 32-bit RGBA image buffer. IMGWIDTH and IMGHEIGHT are the width and height of the output image, ROWSTRIDE the number of bytes from the start of one row to the next (often equal to 3 * IMGWIDTH), PIXBYTES the number of bytes per pixel (3 or 4), and SCALETYPE the scaling algorithm to use. PALETTE is an array of 256 color values. */ void tilem_draw_lcd_image_rgb(TilemLCDBuffer * restrict frm, byte * restrict buffer, int imgwidth, int imgheight, int rowstride, int pixbytes, const dword * restrict palette, int scaletype); /* Calculate a color palette for use with the above functions. RLIGHT, GLIGHT, BLIGHT are the RGB components (0 to 255) of the lightest possible color; RDARK, GDARK, BDARK are the RGB components of the darkest possible color. GAMMA is the gamma value for the output device (2.2 for most current computer displays and image file formats.) */ dword* tilem_color_palette_new(int rlight, int glight, int blight, int rdark, int gdark, int bdark, double gamma); /* Calculate a color palette, as above, and convert it to a packed array of bytes (R, G, B) */ byte* tilem_color_palette_new_packed(int rlight, int glight, int blight, int rdark, int gdark, int bdark, double gamma); /* Grayscale LCD simulation */ typedef struct _TilemGrayLCD TilemGrayLCD; /* Create a new LCD and attach to a calculator. Sampling for grayscale is done across WINDOWSIZE frames, with samples taken every SAMPLEINT microseconds. */ TilemGrayLCD* tilem_gray_lcd_new(TilemCalc *calc, int windowsize, int sampleint); /* Detach and free an LCD. */ void tilem_gray_lcd_free(TilemGrayLCD *glcd); /* Generate a grayscale image for the next frame, based on current calculator state. This function also updates the frame counter and internal state; for proper grayscale behavior, this function needs to be called at regular intervals. */ void tilem_gray_lcd_get_frame(TilemGrayLCD * restrict glcd, TilemLCDBuffer * restrict frm); /* Miscellaneous functions */ /* Guess calculator type for a ROM file */ char tilem_guess_rom_type(FILE* romfile); /* Get calculator type for a SAV file */ char tilem_get_sav_type(FILE* savfile); /* Check validity of calculator certificate; repair if necessary */ void tilem_calc_fix_certificate(TilemCalc* calc, byte* cert, int app_start, int app_end, unsigned exptab_offset); #ifdef __cplusplus } #endif #endif tilem-2.0/emu/tilemint.h000066400000000000000000000002671220200411600152420ustar00rootroot00000000000000#ifndef _TILEMINT_H #define _TILEMINT_H #ifdef HAVE_STDINTS1_H # include #elif defined(HAVE_STDINTS2_H) # include #else # include #endif #endif tilem-2.0/emu/timers.c000066400000000000000000000132631220200411600147130ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "tilem.h" void tilem_user_timers_reset(TilemCalc* calc) { int i; for (i = 0; i < TILEM_MAX_USER_TIMERS; i++) { tilem_z80_set_timer(calc, TILEM_TIMER_USER1 + i, 0, 0, 0); calc->usertimers[i].frequency = 0; calc->usertimers[i].loopvalue = 0; calc->usertimers[i].status = 0; } } static inline dword get_duration(int fvalue, int nticks) { qword t=0; if (fvalue & 0x80) { if (fvalue & 0x20) return 64 * nticks; else if (fvalue & 0x10) return 32 * nticks; else if (fvalue & 0x08) return 16 * nticks; else if (fvalue & 0x04) return 8 * nticks; else if (fvalue & 0x02) return 4 * nticks; else if (fvalue & 0x01) return 2 * nticks; else return nticks; } else if (fvalue & 0x40) { switch (fvalue & 7) { case 0: t = 3000000; break; case 1: t = 33000000; break; case 2: t = 328000000; break; case 3: t = 0xC3530D40; //3277000000; break; case 4: t = 1000000; break; case 5: t = 16000000; break; case 6: t = 256000000; break; case 7: t = 0xF4240000; //4096000000; break; } return ((t * nticks + 16384) / 32768); } return 0; } static dword get_normal_duration(const TilemUserTimer* tmr) { if (tmr->loopvalue) return get_duration(tmr->frequency, tmr->loopvalue); else return get_duration(tmr->frequency, 256); } static dword get_overflow_duration(const TilemUserTimer* tmr) { return get_duration(tmr->frequency, 256); } void tilem_user_timer_set_frequency(TilemCalc* calc, int n, byte value) { TilemUserTimer* tmr = &calc->usertimers[n]; /* writing to frequency control port stops timer; set loopvalue to the current value of the counter */ tmr->loopvalue = tilem_user_timer_get_value(calc, n); tilem_z80_set_timer(calc, TILEM_TIMER_USER1 + n, 0, 0, 0); tmr->frequency = value; } void tilem_user_timer_set_mode(TilemCalc* calc, int n, byte mode) { TilemUserTimer* tmr = &calc->usertimers[n]; /* setting mode clears "finished" and "overflow" flags */ tmr->status = ((tmr->status & TILEM_USER_TIMER_NO_HALT_INT) | (mode & 3)); calc->z80.interrupts &= ~(TILEM_INTERRUPT_USER_TIMER1 << n); /* if timer is currently running, it will not overflow the next time it expires -> set period to normal */ if ((mode & TILEM_USER_TIMER_LOOP) || tmr->loopvalue == 0) { tilem_z80_set_timer_period(calc, TILEM_TIMER_USER1 + n, get_normal_duration(tmr)); } else { tilem_z80_set_timer_period(calc, TILEM_TIMER_USER1 + n, 0); } } void tilem_user_timer_start(TilemCalc* calc, int n, byte value) { TilemUserTimer* tmr = &calc->usertimers[n]; dword count, period; tmr->loopvalue = value; /* if a valid frequency is set, then writing to value port starts timer */ count = get_normal_duration(tmr); if (!count) return; if (!value) { /* input value 0 means loop indefinitely */ period = get_overflow_duration(tmr); } else if (tmr->status & TILEM_USER_TIMER_FINISHED) { /* timer has already expired once -> it will overflow the next time it expires (note that this happens even if the loop flag isn't set) */ period = get_overflow_duration(tmr); } else if (!(tmr->status & TILEM_USER_TIMER_LOOP)) { /* don't loop */ period = 0; } else { /* timer hasn't expired yet; second iteration starts from the same counter value as the first */ period = count; } tilem_z80_set_timer(calc, TILEM_TIMER_USER1 + n, count, period, (calc->usertimers[n].frequency & 0x80 ? 0 : 1)); } byte tilem_user_timer_get_value(TilemCalc* calc, int n) { TilemUserTimer* tmr = &calc->usertimers[n]; dword period; if (!tilem_z80_timer_running(calc, TILEM_TIMER_USER1 + n)) return tmr->loopvalue; period = get_overflow_duration(tmr); if (tmr->frequency & 0x80) { dword t = tilem_z80_get_timer_clocks (calc, TILEM_TIMER_USER1 + n); return ((t * 256) / period) % 256; } else { qword t = tilem_z80_get_timer_microseconds (calc, TILEM_TIMER_USER1 + n); return ((t * 256) / period) % 256; } } void tilem_user_timer_expired(TilemCalc* calc, void* data) { int n = TILEM_PTR_TO_DWORD(data); TilemUserTimer* tmr = &calc->usertimers[n]; /* input value 0 means loop indefinitely (don't set flags) */ if (!tmr->loopvalue) { return; } /* if timer has already finished, set "overflow" flag */ if (tmr->status & TILEM_USER_TIMER_FINISHED) { tmr->status |= TILEM_USER_TIMER_OVERFLOW; } /* set "finished" flag */ tmr->status |= TILEM_USER_TIMER_FINISHED; /* generate interrupt if appropriate */ if ((tmr->status & TILEM_USER_TIMER_INTERRUPT) && (!(tmr->status & TILEM_USER_TIMER_NO_HALT_INT) || !calc->z80.halted)) { calc->z80.interrupts |= (TILEM_INTERRUPT_USER_TIMER1 << n); } if (tmr->status & TILEM_USER_TIMER_LOOP) { /* timer will overflow the next time it expires (unless user writes to the mode port before then) */ tilem_z80_set_timer_period(calc, TILEM_TIMER_USER1 + n, get_overflow_duration(tmr)); } } tilem-2.0/emu/x1/000077500000000000000000000000001220200411600135675ustar00rootroot00000000000000tilem-2.0/emu/x1/x1.h000066400000000000000000000034231220200411600142720ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X1_H #define _TILEM_X1_H enum { HW_VERSION, /* HW version: 0 = unknown 1 = original HW (1990-1992) 2 = revised HW (1992-1996) */ PORT2, /* memory mapping control (new HW) */ PORT3, /* mask of enabled interrupts */ PORT4, /* mapping mode, timer control */ PORT5, /* memory mapping bank A (old HW) */ PORT6, /* memory mapping bank B (old HW) */ NUM_HW_REGS }; #define HW_REG_NAMES { "hw_version", "port2", "port3", "port4", "port5", "port6" } #define TIMER_INT (TILEM_NUM_SYS_TIMERS + 1) #define NUM_HW_TIMERS 1 #define HW_TIMER_NAMES { "int" } void x1_reset(TilemCalc* calc); byte x1_z80_in(TilemCalc* calc, dword port); void x1_z80_out(TilemCalc* calc, dword port, byte value); void x1_z80_ptimer(TilemCalc* calc, int id); void x1_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x1_z80_rdmem(TilemCalc* calc, dword addr); dword x1_mem_ltop(TilemCalc* calc, dword addr); dword x1_mem_ptol(TilemCalc* calc, dword addr); void x1_get_lcd(TilemCalc* calc, byte* data); #endif tilem-2.0/emu/x1/x1_init.c000066400000000000000000000025561220200411600153160ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x1.h" void x1_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x08; calc->hwregs[PORT2] = 0x00; calc->hwregs[PORT5] = 0x00; calc->hwregs[PORT6] = 0x00; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x01; calc->mempagemap[2] = 0x00; calc->mempagemap[3] = 0x02; if (calc->hwregs[HW_VERSION] != 2) calc->lcd.rowstride = 12; tilem_z80_set_speed(calc, 2000); /* FIXME: measure actual frequency */ tilem_z80_set_timer(calc, TIMER_INT, 6000, 6000, 1); } tilem-2.0/emu/x1/x1_io.c000066400000000000000000000110101220200411600147430ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x1.h" byte x1_z80_in(TilemCalc* calc, dword port) { byte v; if (calc->hwregs[HW_VERSION] == 1) port &= 7; switch(port&0x1f) { case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: return(calc->hwregs[PORT2]); case 0x03: v = (calc->keypad.onkeydown ? 0x00: 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; return(v); case 0x05: return(calc->hwregs[PORT5]); case 0x06: return(calc->hwregs[PORT6]); case 0x10: return(tilem_lcd_t6a04_status(calc)); case 0x11: return(tilem_lcd_t6a04_read(calc)); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { int pageA, pageB; switch (calc->hwregs[HW_VERSION]) { case 1: if (calc->hwregs[PORT5] & 0x40) pageA = 2; else if (calc->hwregs[PORT5] & 1) pageA = 1; else pageA = 0; if (calc->hwregs[PORT6] & 0x40) pageB = 2; else if (calc->hwregs[PORT6] & 1) pageB = 1; else pageB = 0; break; case 2: if (calc->hwregs[PORT2] & 0x40) pageA = 2; else if (calc->hwregs[PORT2] & 1) pageA = 1; else pageA = 0; if (calc->hwregs[PORT2] & 0x80) pageB = 2; else if (calc->hwregs[PORT2] & 8) pageB = 1; else pageB = 0; break; default: /* unknown HW version - ignore all output values and use standard mapping */ pageA = 1; pageB = 0; } calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 2; } void x1_z80_out(TilemCalc* calc, dword port, byte value) { if (!calc->hwregs[HW_VERSION] && calc->z80.r.pc.d < 0x8000) { /* detect version */ if (port == 0x05 || port == 0x06) { calc->hwregs[HW_VERSION] = 1; setup_mapping(calc); } else if (port == 0x10 || port == 0x11) { calc->lcd.rowstride = 15; calc->hwregs[HW_VERSION] = 2; setup_mapping(calc); } } if (calc->hwregs[HW_VERSION] == 1) port &= 7; switch(port&0x1f) { case 0x00: calc->lcd.addr = ((value & 0x1f) << 8); calc->z80.lastlcdwrite = calc->z80.clock; break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x02: calc->hwregs[PORT2] = value; if (calc->hwregs[HW_VERSION] != 2) calc->lcd.contrast = 16 + (value & 0x1f); setup_mapping(calc); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) { calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; } calc->hwregs[PORT3] = value; calc->lcd.active = calc->poweronhalt = ((value & 8) >> 3); break; case 0x04: calc->hwregs[PORT4] = value; if (calc->hwregs[HW_VERSION] == 1) { switch (value & 0x18) { case 0x00: calc->lcd.rowstride = 10; break; case 0x08: calc->lcd.rowstride = 12; break; case 0x10: calc->lcd.rowstride = 16; break; case 0x18: calc->lcd.rowstride = 20; break; } calc->z80.lastlcdwrite = calc->z80.clock; } break; case 0x05: calc->hwregs[PORT5] = value; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x10: tilem_lcd_t6a04_control(calc, value); break; case 0x11: tilem_lcd_t6a04_write(calc, value); break; } return; } void x1_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; } } void x1_get_lcd(TilemCalc* calc, byte* data) { if (calc->hwregs[HW_VERSION] == 2) tilem_lcd_t6a04_get_data(calc, data); else tilem_lcd_t6a43_get_data(calc, data); } tilem-2.0/emu/x1/x1_memory.c000066400000000000000000000034621220200411600156600ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x1.h" void x1_z80_wrmem(TilemCalc* calc, dword A, byte v) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x8000) { *(calc->mem + 0x8000 + (pa & 0x1fff)) = v; if ((((pa - 0x8000 - calc->lcd.addr) >> 6) < (unsigned) calc->lcd.rowstride) && calc->hwregs[HW_VERSION] < 2) calc->z80.lastlcdwrite = calc->z80.clock; } } byte x1_z80_rdmem(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x8000) return (*(calc->mem + 0x8000 + (pa & 0x1fff))); else return (*(calc->mem + (pa & 0x7fff))); } dword x1_mem_ltop(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x8000) return (0x8000 + (pa & 0x1fff)); else return (pa); } dword x1_mem_ptol(TilemCalc* calc TILEM_ATTR_UNUSED, dword A) { if (A & 0x8000) return (0xE000 + (A & 0x1fff)); else return (A); } tilem-2.0/emu/x1/x1_subcore.c000066400000000000000000000035111220200411600160050ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x1.h" static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Vars", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Mode", "0", "1", "4", "7", "EE", "Sin", "Matrix", "Graphvar", "On", "Store", "Ln", "Log", "Square", "Recip", "Math", "Alpha", "Graph", "Trace", "Zoom", "Range", "YEqu", "2nd", "Ins", "Del", 0, 0, 0, 0, 0, 0, 0, 0}; const TilemHardware hardware_ti81 = { '1', "ti81", "TI-81", TILEM_CALC_HAS_T6A04, 96, 64, 0x8000, 0x2000, 15 * 64, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x1_reset, NULL, x1_z80_in, x1_z80_out, x1_z80_wrmem, x1_z80_rdmem, x1_z80_rdmem, NULL, x1_z80_ptimer, x1_get_lcd, x1_mem_ltop, x1_mem_ptol }; tilem-2.0/emu/x2/000077500000000000000000000000001220200411600135705ustar00rootroot00000000000000tilem-2.0/emu/x2/x2.h000066400000000000000000000032401220200411600142710ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X2_H #define _TILEM_X2_H enum { HW_VERSION, /* HW version: 0 = unknown 1 = original HW (1993-2000) 2 = revised HW (2001-2003) */ PORT0, /* port 0 (link port control) */ PORT2, /* port 2 (memory mapping) */ PORT3, /* mask of enabled interrupts */ PORT4, /* mapping mode + timer speed */ NUM_HW_REGS }; #define HW_REG_NAMES { "hw_version", "port0", "port2", "port3", "port4" } #define TIMER_INT (TILEM_NUM_SYS_TIMERS + 1) #define NUM_HW_TIMERS 1 #define HW_TIMER_NAMES { "int" } void x2_reset(TilemCalc* calc); byte x2_z80_in(TilemCalc* calc, dword port); void x2_z80_out(TilemCalc* calc, dword port, byte value); void x2_z80_ptimer(TilemCalc* calc, int id); void x2_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x2_z80_rdmem(TilemCalc* calc, dword addr); dword x2_mem_ltop(TilemCalc* calc, dword addr); dword x2_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x2/x2_init.c000066400000000000000000000024201220200411600153060ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x2.h" void x2_reset(TilemCalc* calc) { calc->hwregs[PORT2] = 0xF8; calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x00; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x00; calc->mempagemap[2] = 0x09; calc->mempagemap[3] = 0x08; tilem_z80_set_speed(calc, 6000); /* FIXME: measure actual frequency */ tilem_z80_set_timer(calc, TIMER_INT, 1000, 9259, 1); } tilem-2.0/emu/x2/x2_io.c000066400000000000000000000110331220200411600147520ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x2.h" byte x2_z80_in(TilemCalc* calc, dword port) { static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v, b; switch(port&0xff) { case 0x00: v = tilem_linkport_get_lines(calc); if (calc->hwregs[HW_VERSION] == 1) { /* HW version 1 uses separate PCR/PDR, as the TI-85 does. */ b = (calc->hwregs[PORT0] >> 4) | 0xf0; return ((calc->hwregs[PORT0] & b) | (v & ~b)); } else { /* HW version 2 uses a TI-83-like interface. (Do the same if version is unknown, because most code written for HW version 1 will work fine with these values.) */ return (0xc0 | (v * 5)); } case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: return(calc->hwregs[PORT2]); case 0x03: v = (calc->keypad.onkeydown ? 0x00: 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; return(v); case 0x10: return(tilem_lcd_t6a04_status(calc)); case 0x11: return(tilem_lcd_t6a04_read(calc)); case 0x14: /* FIXME: determine value of this port on old hardware, and the values of bits 1-7. (As on TI-83, probably mirrors port 0 in both cases.) */ b = battlevel[calc->hwregs[PORT4] >> 6]; return(calc->battery >= b ? 1 : 0); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; /* FIXME: this is all rather hypothetical and untested, but it makes sense based on how the TI-83 works */ if (calc->hwregs[PORT2] & 0x40) { pageA = (0x08 | (calc->hwregs[PORT2] & 1)); } else { pageA = (calc->hwregs[PORT2] & 7); } if (calc->hwregs[PORT2] & 0x80) { pageB = (0x08 | ((calc->hwregs[PORT2] >> 3) & 1)); } else { pageB = ((calc->hwregs[PORT2] >> 3) & 7); } if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x08; } } void x2_z80_out(TilemCalc* calc, dword port, byte value) { switch(port&0xff) { case 0x00: calc->hwregs[PORT0] = value; if (calc->hwregs[HW_VERSION] == 1) { /* HW version 1 */ value = (((value >> 6) & (value >> 2)) | ((value >> 4) & ~value)); } else if (calc->hwregs[HW_VERSION] == 0) { /* HW version unknown: auto-detect */ if ((value & 0xc3) == 0xc0) { value = ((value >> 2) | (value >> 4)); } } tilem_linkport_set_lines(calc, value); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x02: calc->hwregs[PORT2] = value; setup_mapping(calc); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) { calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; } calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; /* Detect hardware version */ if (calc->z80.r.pc.d < 0x4000) { if (value & 0x10) calc->hwregs[HW_VERSION] = 1; else calc->hwregs[HW_VERSION] = 2; } /* FIXME: implement changing interrupt frequencies -- somebody needs to measure them. Also check if bit 4 works as on 83. */ setup_mapping(calc); break; case 0x10: tilem_lcd_t6a04_control(calc, value); break; case 0x11: tilem_lcd_t6a04_write(calc, value); break; } return; } void x2_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; } } tilem-2.0/emu/x2/x2_memory.c000066400000000000000000000031401220200411600156530ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x2.h" #include void x2_z80_wrmem(TilemCalc* calc, dword A, byte v) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x28000) abort(); if (pa >= 0x20000) { *(calc->mem + pa) = v; } } byte x2_z80_rdmem(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); return (*(calc->mem + pa)); } dword x2_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword x2_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/x2/x2_subcore.c000066400000000000000000000035711220200411600160150ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x2.h" static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Vars", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Stat", "0", "1", "4", "7", "Comma", "Sin", "Matrix", "Graphvar", "On", "Store", "Ln", "Log", "Square", "Recip", "Math", "Alpha", "Graph", "Trace", "Zoom", "Window", "YEqu", "2nd", "Mode", "Del", 0, 0, 0, 0, 0, 0, 0, 0}; const TilemHardware hardware_ti82 = { '2', "ti82", "TI-82", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_T6A04), 96, 64, 8 * 0x4000, 0x8000, 15 * 64, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x2_reset, NULL, x2_z80_in, x2_z80_out, x2_z80_wrmem, x2_z80_rdmem, x2_z80_rdmem, NULL, x2_z80_ptimer, tilem_lcd_t6a04_get_data, x2_mem_ltop, x2_mem_ptol }; tilem-2.0/emu/x3/000077500000000000000000000000001220200411600135715ustar00rootroot00000000000000tilem-2.0/emu/x3/x3.h000066400000000000000000000032411220200411600142740ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X3_H #define _TILEM_X3_H enum { PORT2, /* port 2 (memory mapping) */ PORT3, /* mask of enabled interrupts */ PORT4, /* mapping mode + timer speed */ ROM_BANK, /* current ROM bank for port 2 mapping */ NUM_HW_REGS }; #define HW_REG_NAMES { "port2", "port3", "port4", "rom_bank" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define NUM_HW_TIMERS 3 #define HW_TIMER_NAMES { "int1", "int2a", "int2b" } void x3_reset(TilemCalc* calc); byte x3_z80_in(TilemCalc* calc, dword port); void x3_z80_out(TilemCalc* calc, dword port, byte value); void x3_z80_ptimer(TilemCalc* calc, int id); void x3_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x3_z80_rdmem(TilemCalc* calc, dword addr); dword x3_mem_ltop(TilemCalc* calc, dword addr); dword x3_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x3/x3_init.c000066400000000000000000000025711220200411600153170ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x3.h" void x3_reset(TilemCalc* calc) { calc->hwregs[PORT2] = 0xF8; calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x00; calc->hwregs[ROM_BANK] = 0x00; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x00; calc->mempagemap[2] = 0x11; calc->mempagemap[3] = 0x10; tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 9259, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 9259, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 9259, 1); } tilem-2.0/emu/x3/x3_io.c000066400000000000000000000105011220200411600147530ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x3.h" byte x3_z80_in(TilemCalc* calc, dword port) { static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v, b; switch(port&0x1f) { case 0x00: case 0x04: case 0x08: case 0x0C: v = tilem_linkport_get_lines(calc); return((calc->hwregs[ROM_BANK] << 1) | (v * 5)); case 0x01: case 0x05: case 0x09: case 0x0D: return(tilem_keypad_read_keys(calc)); case 0x02: case 0x06: case 0x0A: case 0x0E: case 0x16: case 0x1E: return(calc->hwregs[PORT2]); case 0x03: case 0x07: case 0x0B: case 0x0F: case 0x17: case 0x1F: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; return(v); case 0x10: case 0x12: case 0x18: case 0x1A: return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: case 0x19: case 0x1B: return(tilem_lcd_t6a04_read(calc)); case 0x14: case 0x1C: b = battlevel[calc->hwregs[PORT4] >> 6]; v = tilem_linkport_get_lines(calc); return((calc->battery >= b ? 1 : 0) | (calc->hwregs[ROM_BANK] << 1) | (v << 2)); case 0x15: case 0x1D: return(tilem_keypad_read_keys(calc) & ~1); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; if (calc->hwregs[PORT2] & 0x40) { pageA = (0x10 | (calc->hwregs[PORT2] & 1)); } else { pageA = (calc->hwregs[ROM_BANK] | (calc->hwregs[PORT2] & 7)); } if (calc->hwregs[PORT2] & 0x80) { pageB = (0x10 | ((calc->hwregs[PORT2] >> 3) & 1)); } else { pageB = (calc->hwregs[ROM_BANK] | ((calc->hwregs[PORT2] >> 3) & 7)); } if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x10; } } void x3_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[8] = { 1667, 1852, 3889, 4321, 6111, 6790, 8333, 9259 }; int t; switch(port&0x1f) { case 0x00: calc->hwregs[ROM_BANK] = ((value & 0x10) >> 1); tilem_linkport_set_lines(calc, value); setup_mapping(calc); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x02: calc->hwregs[PORT2] = value; setup_mapping(calc); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; t = tmrvalues[((value >> 4) & 1) | (value & 6)]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x10: tilem_lcd_t6a04_control(calc, value); break; case 0x11: tilem_lcd_t6a04_write(calc, value); break; } return; } void x3_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; } } tilem-2.0/emu/x3/x3_memory.c000066400000000000000000000030521220200411600156570ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x3.h" void x3_z80_wrmem(TilemCalc* calc, dword A, byte v) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x40000) { *(calc->mem + pa) = v; } } byte x3_z80_rdmem(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); return (*(calc->mem + pa)); } dword x3_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword x3_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/x3/x3_subcore.c000066400000000000000000000044261220200411600160170ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x3.h" static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Vars", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Stat", "0", "1", "4", "7", "Comma", "Sin", "Matrix", "Graphvar", "On", "Store", "Ln", "Log", "Square", "Recip", "Math", "Alpha", "Graph", "Trace", "Zoom", "Window", "YEqu", "2nd", "Mode", "Del", 0, 0, 0, 0, 0, 0, 0, 0}; const TilemHardware hardware_ti83 = { '3', "ti83", "TI-83 / TI-82 STATS", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_T6A04), 96, 64, 16 * 0x4000, 0x8000, 15 * 64, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x3_reset, NULL, x3_z80_in, x3_z80_out, x3_z80_wrmem, x3_z80_rdmem, x3_z80_rdmem, NULL, x3_z80_ptimer, tilem_lcd_t6a04_get_data, x3_mem_ltop, x3_mem_ptol }; const TilemHardware hardware_ti76 = { 'f', "ti76", "TI-76.fr", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_T6A04), 96, 64, 16 * 0x4000, 0x8000, 15 * 64, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x3_reset, NULL, x3_z80_in, x3_z80_out, x3_z80_wrmem, x3_z80_rdmem, x3_z80_rdmem, NULL, x3_z80_ptimer, tilem_lcd_t6a04_get_data, x3_mem_ltop, x3_mem_ptol }; tilem-2.0/emu/x4/000077500000000000000000000000001220200411600135725ustar00rootroot00000000000000tilem-2.0/emu/x4/x4.h000066400000000000000000000071701220200411600143030ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X4_H #define _TILEM_X4_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT5, /* memory mapping bank C */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ PORT8, /* link assist mode flags */ PORT9, /* unknown (link assist settings?) */ PORTA, /* unknown (timeout value?) */ PORTB, /* unknown (timeout value?) */ PORTC, /* unknown (timeout value?) */ PORTD, /* unknown */ PORTE, /* unknown */ PORTF, /* unknown */ PORT20, /* CPU speed control */ PORT21, /* hardware type / RAM no-exec control */ PORT22, /* Flash no-exec lower limit */ PORT23, /* Flash no-exec upper limit */ PORT25, /* RAM no-exec lower limit */ PORT26, /* RAM no-exec upper limit */ PORT27, /* bank C forced-page-0 limit */ PORT28, /* bank B forced-page-1 limit */ PORT29, /* LCD port delay (6 MHz) */ PORT2A, /* LCD port delay (mode 1) */ PORT2B, /* LCD port delay (mode 2) */ PORT2C, /* LCD port delay (mode 3) */ PORT2D, /* unknown */ PORT2E, /* memory delay */ PORT2F, /* Duration of LCD wait timer */ CLOCK_MODE, /* clock mode */ CLOCK_INPUT, /* clock input register */ CLOCK_DIFF, /* clock value minus actual time */ RAM_READ_DELAY, RAM_WRITE_DELAY, RAM_EXEC_DELAY, FLASH_READ_DELAY, FLASH_WRITE_DELAY, FLASH_EXEC_DELAY, LCD_PORT_DELAY, NO_EXEC_RAM_MASK, NO_EXEC_RAM_LOWER, NO_EXEC_RAM_UPPER, LCD_WAIT, /* LCD wait timer active */ PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port5", "port6", "port7", "port8", "port9", \ "portA", "portB", "portC", "portD", "portE", "portF", "port20", \ "port21", "port22", "port23", "port25", "port26", "port27", \ "port28", "port29", "port2A", "port2B", "port2C", "port2D", \ "port2E", "port2F", "clock_mode", "clock_input", "clock_diff", \ "ram_read_delay", "ram_write_delay", "ram_exec_delay", \ "flash_read_delay", "flash_write_delay", "flash_exec_delay", \ "lcd_port_delay", "no_exec_ram_mask", "no_exec_ram_lower", \ "no_exec_ram_upper", "lcd_wait", "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define TIMER_LCD_WAIT (TILEM_NUM_SYS_TIMERS + 4) #define NUM_HW_TIMERS 4 #define HW_TIMER_NAMES { "int1", "int2a", "int2b", "lcd_wait" } void x4_reset(TilemCalc* calc); void x4_stateloaded(TilemCalc* calc, int savtype); byte x4_z80_in(TilemCalc* calc, dword port); void x4_z80_out(TilemCalc* calc, dword port, byte value); void x4_z80_ptimer(TilemCalc* calc, int id); void x4_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x4_z80_rdmem(TilemCalc* calc, dword addr); byte x4_z80_rdmem_m1(TilemCalc* calc, dword addr); dword x4_mem_ltop(TilemCalc* calc, dword addr); dword x4_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x4/x4_init.c000066400000000000000000000047021220200411600153170ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x4.h" void x4_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x07; calc->hwregs[PORT6] = 0x3F; calc->hwregs[PORT7] = 0x3F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x3E; calc->mempagemap[2] = 0x3F; calc->mempagemap[3] = 0x3F; calc->z80.r.pc.d = 0x8000; calc->hwregs[PORT8] = 0x80; calc->hwregs[PORT20] = 0; calc->hwregs[PORT21] = 0; calc->hwregs[PORT22] = 0x08; calc->hwregs[PORT23] = 0x29; calc->hwregs[PORT25] = 0x10; calc->hwregs[PORT26] = 0x20; calc->hwregs[PORT27] = 0; calc->hwregs[PORT28] = 0; calc->hwregs[PORT29] = 0x14; calc->hwregs[PORT2A] = 0x27; calc->hwregs[PORT2B] = 0x2F; calc->hwregs[PORT2C] = 0x3B; calc->hwregs[PORT2D] = 0x01; calc->hwregs[PORT2E] = 0x44; calc->hwregs[PORT2F] = 0x4A; calc->hwregs[FLASH_READ_DELAY] = 0; calc->hwregs[FLASH_WRITE_DELAY] = 0; calc->hwregs[FLASH_EXEC_DELAY] = 0; calc->hwregs[RAM_READ_DELAY] = 0; calc->hwregs[RAM_WRITE_DELAY] = 0; calc->hwregs[RAM_EXEC_DELAY] = 0; calc->hwregs[LCD_PORT_DELAY] = 5; calc->hwregs[NO_EXEC_RAM_MASK] = 0x7C00; calc->hwregs[NO_EXEC_RAM_LOWER] = 0x4000; calc->hwregs[NO_EXEC_RAM_UPPER] = 0x8000; calc->hwregs[PROTECTSTATE] = 0; tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 9277, 1); } void x4_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x3E * 0x4000L), 0x29, 0x0c, 0x1e50); } tilem-2.0/emu/x4/x4_io.c000066400000000000000000000353061220200411600147670ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "x4.h" static void set_lcd_wait_timer(TilemCalc* calc) { static const int delaytime[8] = { 48, 112, 176, 240, 304, 368, 432, 496 }; int i; switch (calc->hwregs[PORT20] & 3) { case 0: return; case 1: i = (calc->hwregs[PORT2F] & 3); break; case 2: i = ((calc->hwregs[PORT2F] >> 2) & 7); break; default: i = ((calc->hwregs[PORT2F] >> 5) & 7); break; } tilem_z80_set_timer(calc, TIMER_LCD_WAIT, delaytime[i], 0, 0); calc->hwregs[LCD_WAIT] = 1; } byte x4_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; unsigned int f; time_t curtime; switch(port&0xff) { case 0x00: v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); return(v); case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: v = battlevel[calc->hwregs[PORT4] >> 6]; return ((calc->battery >= v ? 0xe1 : 0xe0) | (calc->hwregs[LCD_WAIT] ? 0 : 2) | (calc->flash.unlock << 2)); case 0x03: return(calc->hwregs[PORT3]); case 0x04: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; if (calc->usertimers[0].status & TILEM_USER_TIMER_FINISHED) v |= 0x20; if (calc->usertimers[1].status & TILEM_USER_TIMER_FINISHED) v |= 0x40; if (calc->usertimers[2].status & TILEM_USER_TIMER_FINISHED) v |= 0x80; return(v); case 0x05: return(calc->hwregs[PORT5] & 0x0f); case 0x06: return(calc->hwregs[PORT6]); case 0x07: return(calc->hwregs[PORT7]); case 0x08: return(calc->hwregs[PORT8]); case 0x09: f = tilem_linkport_get_assist_flags(calc); if (f & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) v = 0x00; else v = 0x20; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_READ) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_IDLE) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ERROR) v |= 0x04; if (f & TILEM_LINK_ASSIST_READ_BUSY) v |= 0x08; if (f & TILEM_LINK_ASSIST_READ_BYTE) v |= 0x10; if (f & (TILEM_LINK_ASSIST_READ_ERROR | TILEM_LINK_ASSIST_WRITE_ERROR)) v |= 0x40; if (f & TILEM_LINK_ASSIST_WRITE_BUSY) v |= 0x80; calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR; return(v); case 0x0A: v = calc->linkport.assistlastbyte; tilem_linkport_read_byte(calc); return(v); case 0x0E: return(calc->hwregs[PORTE] & 3); case 0x0F: return(calc->hwregs[PORTF] & 3); case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_read(calc)); case 0x15: return(0x45); /* ??? */ case 0x1C: return(tilem_md5_assist_get_value(calc)); case 0x1D: return(tilem_md5_assist_get_value(calc) >> 8); case 0x1E: return(tilem_md5_assist_get_value(calc) >> 16); case 0x1F: return(tilem_md5_assist_get_value(calc) >> 24); case 0x20: return(calc->hwregs[PORT20] & 3); case 0x21: return(calc->hwregs[PORT21] & 0x33); case 0x22: return(calc->hwregs[PORT22]); case 0x23: return(calc->hwregs[PORT23]); case 0x25: return(calc->hwregs[PORT25]); case 0x26: return(calc->hwregs[PORT26]); case 0x27: return(calc->hwregs[PORT27]); case 0x28: return(calc->hwregs[PORT28]); case 0x29: return(calc->hwregs[PORT29]); case 0x2A: return(calc->hwregs[PORT2A]); case 0x2B: return(calc->hwregs[PORT2B]); case 0x2C: return(calc->hwregs[PORT2C]); case 0x2D: return(calc->hwregs[PORT2D] & 3); case 0x2E: return(calc->hwregs[PORT2E]); case 0x2F: return(calc->hwregs[PORT2F]); case 0x30: return(calc->usertimers[0].frequency); case 0x31: return(calc->usertimers[0].status); case 0x32: return(tilem_user_timer_get_value(calc, 0)); case 0x33: return(calc->usertimers[1].frequency); case 0x34: return(calc->usertimers[1].status); case 0x35: return(tilem_user_timer_get_value(calc, 1)); case 0x36: return(calc->usertimers[2].frequency); case 0x37: return(calc->usertimers[2].status); case 0x38: return(tilem_user_timer_get_value(calc, 2)); case 0x39: return(0xf0); /* ??? */ case 0x40: return calc->hwregs[CLOCK_MODE]; case 0x41: return calc->hwregs[CLOCK_INPUT]&0xff; case 0x42: return (calc->hwregs[CLOCK_INPUT]>>8)&0xff; case 0x43: return (calc->hwregs[CLOCK_INPUT]>>16)&0xff; case 0x44: return (calc->hwregs[CLOCK_INPUT]>>24)&0xff; case 0x45: case 0x46: case 0x47: case 0x48: if (calc->hwregs[CLOCK_MODE] & 1) { time(&curtime); } else { curtime = 0; } curtime += calc->hwregs[CLOCK_DIFF]; return (curtime >> ((port - 0x45) * 8)); case 0x4C: return(0x22); case 0x4D: /* USB port - not emulated, calculator should recognize that the USB cable is disconnected. Thanks go to Dan Englender for these values. */ return(0xA5); case 0x55: return(0x1F); case 0x56: return(0x00); case 0x57: return(0x50); case 0x0B: case 0x0C: case 0x0D: case 0x14: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: return(0); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB, pageC; if (calc->hwregs[PORT6] & 0x80) pageA = (0x40 | (calc->hwregs[PORT6] & 7)); else pageA = (calc->hwregs[PORT6] & 0x3f); if (calc->hwregs[PORT7] & 0x80) pageB = (0x40 | (calc->hwregs[PORT7] & 7)); else pageB = (calc->hwregs[PORT7] & 0x3f); pageC = (0x40 | (calc->hwregs[PORT5] & 7)); if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = pageC; } } static void setup_clockdelays(TilemCalc* calc) { byte lcdport = calc->hwregs[PORT29 + (calc->hwregs[PORT20] & 3)]; byte memport = calc->hwregs[PORT2E]; if (!(lcdport & 1)) memport &= ~0x07; if (!(lcdport & 2)) memport &= ~0x70; calc->hwregs[FLASH_EXEC_DELAY] = (memport & 1); calc->hwregs[FLASH_READ_DELAY] = ((memport >> 1) & 1); calc->hwregs[FLASH_WRITE_DELAY] = ((memport >> 2) & 1); calc->hwregs[RAM_EXEC_DELAY] = ((memport >> 4) & 1); calc->hwregs[RAM_READ_DELAY] = ((memport >> 5) & 1); calc->hwregs[RAM_WRITE_DELAY] = ((memport >> 6) & 1); calc->hwregs[LCD_PORT_DELAY] = (lcdport >> 2); } void x4_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1953, 4395, 6836, 9277 }; int t, r; unsigned int mode; time_t curtime; switch(port&0xff) { case 0x00: tilem_linkport_set_lines(calc, value); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; if (value & 0x06) { calc->usertimers[0].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status &= ~TILEM_USER_TIMER_NO_HALT_INT; } else { calc->usertimers[0].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status |= TILEM_USER_TIMER_NO_HALT_INT; } mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x05: calc->hwregs[PORT5] = value & 0x0f; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: calc->hwregs[PORT7] = value; setup_mapping(calc); break; case 0x08: calc->hwregs[PORT8] = value; mode = calc->linkport.mode; if (value & 0x01) mode |= TILEM_LINK_MODE_INT_ON_READ; else mode &= ~TILEM_LINK_MODE_INT_ON_READ; if (value & 0x02) mode |= TILEM_LINK_MODE_INT_ON_IDLE; else mode &= ~TILEM_LINK_MODE_INT_ON_IDLE; if (value & 0x04) mode |= TILEM_LINK_MODE_INT_ON_ERROR; else mode &= ~TILEM_LINK_MODE_INT_ON_ERROR; if (value & 0x80) mode &= ~TILEM_LINK_MODE_ASSIST; else mode |= TILEM_LINK_MODE_ASSIST; tilem_linkport_set_mode(calc, mode); break; case 0x09: calc->hwregs[PORT9] = value; break; case 0x0A: calc->hwregs[PORTA] = value; break; case 0x0B: calc->hwregs[PORTB] = value; break; case 0x0C: calc->hwregs[PORTC] = value; break; case 0x0D: if (!(calc->hwregs[PORT8] & 0x80)) tilem_linkport_write_byte(calc, value); break; case 0x0E: calc->hwregs[PORTE] = value; break; case 0x0F: calc->hwregs[PORTF] = value; break; case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_write(calc, value); break; case 0x14: if (calc->hwregs[PROTECTSTATE] == 7) { if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); calc->flash.unlock = value&1; } else { tilem_warning(calc, "Writing to protected port 14"); } break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: r = (port & 0xff) - 0x18; calc->md5assist.regs[r] >>= 8; calc->md5assist.regs[r] |= (value << 24); break; case 0x1E: calc->md5assist.shift = value & 0x1f; break; case 0x1F: calc->md5assist.mode = value & 3; break; case 0x20: calc->hwregs[PORT20] = value; if (value & 3) { tilem_z80_set_speed(calc, 15000); } else { tilem_z80_set_speed(calc, 6000); } setup_clockdelays(calc); break; case 0x21: if (calc->flash.unlock) { calc->hwregs[PORT21] = value; t = (value >> 4) & 3; calc->hwregs[NO_EXEC_RAM_MASK] = (0x8000 << t) - 0x400; calc->flash.overridegroup = value & 3; } else { tilem_warning(calc, "Writing to protected port 21"); } break; case 0x22: if (calc->flash.unlock) { calc->hwregs[PORT22] = value; } else { tilem_warning(calc, "Writing to protected port 22"); } break; case 0x23: if (calc->flash.unlock) { calc->hwregs[PORT23] = value; } else { tilem_warning(calc, "Writing to protected port 23"); } break; case 0x25: if (calc->flash.unlock) { calc->hwregs[PORT25] = value; calc->hwregs[NO_EXEC_RAM_LOWER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 25"); } break; case 0x26: if (calc->flash.unlock) { calc->hwregs[PORT26] = value; calc->hwregs[NO_EXEC_RAM_UPPER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 26"); } break; case 0x27: calc->hwregs[PORT27] = value; break; case 0x28: calc->hwregs[PORT28] = value; break; case 0x29: calc->hwregs[PORT29] = value; setup_clockdelays(calc); break; case 0x2A: calc->hwregs[PORT2A] = value; setup_clockdelays(calc); break; case 0x2B: calc->hwregs[PORT2B] = value; setup_clockdelays(calc); break; case 0x2C: calc->hwregs[PORT2C] = value; setup_clockdelays(calc); break; case 0x2D: calc->hwregs[PORT2D] = value; break; case 0x2E: calc->hwregs[PORT2E] = value; setup_clockdelays(calc); break; case 0x2F: calc->hwregs[PORT2F] = value; break; case 0x30: tilem_user_timer_set_frequency(calc, 0, value); break; case 0x31: tilem_user_timer_set_mode(calc, 0, value); break; case 0x32: tilem_user_timer_start(calc, 0, value); break; case 0x33: tilem_user_timer_set_frequency(calc, 1, value); break; case 0x34: tilem_user_timer_set_mode(calc, 1, value); break; case 0x35: tilem_user_timer_start(calc, 1, value); break; case 0x36: tilem_user_timer_set_frequency(calc, 2, value); break; case 0x37: tilem_user_timer_set_mode(calc, 2, value); break; case 0x38: tilem_user_timer_start(calc, 2, value); break; case 0x40: time(&curtime); if ((calc->hwregs[CLOCK_MODE] & 1) != (value & 1)) { if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; else calc->hwregs[CLOCK_DIFF] += curtime; } if (!(calc->hwregs[CLOCK_MODE] & 2) && (value & 2)) { calc->hwregs[CLOCK_DIFF] = calc->hwregs[CLOCK_INPUT]; if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; } calc->hwregs[CLOCK_MODE] = value & 3; break; case 0x41: calc->hwregs[CLOCK_INPUT] &= 0xffffff00; calc->hwregs[CLOCK_INPUT] |= value; break; case 0x42: calc->hwregs[CLOCK_INPUT] &= 0xffff00ff; calc->hwregs[CLOCK_INPUT] |= (value << 8); break; case 0x43: calc->hwregs[CLOCK_INPUT] &= 0xff00ffff; calc->hwregs[CLOCK_INPUT] |= (value << 16); break; case 0x44: calc->hwregs[CLOCK_INPUT] &= 0x00ffffff; calc->hwregs[CLOCK_INPUT] |= (value << 24); break; } return; } void x4_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; case TIMER_LCD_WAIT: calc->hwregs[LCD_WAIT] = 0; break; } } tilem-2.0/emu/x4/x4_memory.c000066400000000000000000000115071220200411600156650ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x4.h" void x4_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; byte page; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x40; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x41; } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x100000) { calc->z80.clock += calc->hwregs[FLASH_WRITE_DELAY]; tilem_flash_write_byte(calc, pa, v); } else if (pa < 0x120000) { calc->z80.clock += calc->hwregs[RAM_WRITE_DELAY]; *(calc->mem+pa) = v; } } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; if (pa < 0x100000 && (calc->flash.state || calc->flash.busy)) value = tilem_flash_read_byte(calc, pa); else value = *(calc->mem + pa); if (pa < 0xB0000 || pa >= 0x100000 || (pa >= 0xC0000 && pa < 0xF0000)) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte x4_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x40; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x41; } if (TILEM_UNLIKELY(page == 0x3E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x100000) calc->z80.clock += calc->hwregs[FLASH_READ_DELAY]; else calc->z80.clock += calc->hwregs[RAM_READ_DELAY]; value = readbyte(calc, pa); return (value); } byte x4_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa, m; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x40; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x41; } if (TILEM_UNLIKELY(page == 0x3E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x100000) { calc->z80.clock += calc->hwregs[FLASH_EXEC_DELAY]; if (TILEM_UNLIKELY(page >= calc->hwregs[PORT22] && page <= calc->hwregs[PORT23])) { tilem_warning(calc, "Executing in restricted Flash area"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } } else { calc->z80.clock += calc->hwregs[RAM_EXEC_DELAY]; m = pa & calc->hwregs[NO_EXEC_RAM_MASK]; if (TILEM_UNLIKELY(m < calc->hwregs[NO_EXEC_RAM_LOWER] || m > calc->hwregs[NO_EXEC_RAM_UPPER])) { tilem_warning(calc, "Executing in restricted RAM area"); tilem_z80_exception(calc, TILEM_EXC_RAM_EXEC); } } value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword x4_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x40; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x41; } return ((page << 14) | (A & 0x3fff)); } dword x4_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; if (!page) return (A & 0x3fff); if (page == calc->mempagemap[1]) return (0x4000 | (A & 0x3fff)); if ((A & 0x3fff) < 64 * calc->hwregs[PORT28]) { if (page == 0x41) return (0x8000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[2]) return (0x8000 | (A & 0x3fff)); } if ((A & 0x3fff) >= (0x4000 - 64 * calc->hwregs[PORT27])) { if (page == 0x40) return (0xC000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[3]) return (0xC000 | (A & 0x3fff)); } return (0xffffffff); } tilem-2.0/emu/x4/x4_subcore.c000066400000000000000000000042351220200411600160170ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x4.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x10000, 0}, {0x080000, 0x10000, 0}, {0x090000, 0x10000, 0}, {0x0A0000, 0x10000, 0}, {0x0B0000, 0x10000, 1}, {0x0C0000, 0x10000, 0}, {0x0D0000, 0x10000, 0}, {0x0E0000, 0x10000, 0}, {0x0F0000, 0x08000, 0}, {0x0F8000, 0x02000, 0}, {0x0FA000, 0x02000, 0}, {0x0FC000, 0x04000, 1}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; extern const char* xp_keynames[]; TilemHardware hardware_ti84p = { '4', "ti84p", "TI-84 Plus", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_LINK_ASSIST | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH | TILEM_CALC_HAS_MD5_ASSIST), 96, 64, 64 * 0x4000, 8 * 0x4000, 16 * 64, 0x80, NUM_FLASH_SECTORS, flashsectors, 3, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, xp_keynames, x4_reset, x4_stateloaded, x4_z80_in, x4_z80_out, x4_z80_wrmem, x4_z80_rdmem, x4_z80_rdmem_m1, NULL, x4_z80_ptimer, tilem_lcd_t6a04_get_data, x4_mem_ltop, x4_mem_ptol }; tilem-2.0/emu/x5/000077500000000000000000000000001220200411600135735ustar00rootroot00000000000000tilem-2.0/emu/x5/x5.h000066400000000000000000000031061220200411600143000ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X5_H #define _TILEM_X5_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* mapping mode, timer control */ PORT5, /* memory mapping bank A */ PORT6, /* memory mapping bank B */ PORT7, /* link port control */ NUM_HW_REGS }; #define HW_REG_NAMES { "port3", "port4", "port5", "port6", "port7" } #define TIMER_INT (TILEM_NUM_SYS_TIMERS + 1) #define NUM_HW_TIMERS 1 #define HW_TIMER_NAMES { "int" } void x5_reset(TilemCalc* calc); byte x5_z80_in(TilemCalc* calc, dword port); void x5_z80_out(TilemCalc* calc, dword port, byte value); void x5_z80_ptimer(TilemCalc* calc, int id); void x5_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x5_z80_rdmem(TilemCalc* calc, dword addr); dword x5_mem_ltop(TilemCalc* calc, dword addr); dword x5_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x5/x5_init.c000066400000000000000000000025071220200411600153220ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x5.h" void x5_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x16; calc->hwregs[PORT5] = 0x00; calc->hwregs[PORT6] = 0x40; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x00; calc->mempagemap[2] = 0x08; calc->mempagemap[3] = 0x08; calc->lcd.addr = 0x3c00; tilem_z80_set_speed(calc, 6000); /* FIXME: measure actual frequency */ tilem_z80_set_timer(calc, TIMER_INT, 1000, 5000, 1); } tilem-2.0/emu/x5/x5_io.c000066400000000000000000000070541220200411600147700ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x5.h" byte x5_z80_in(TilemCalc* calc, dword port) { byte v, b; switch(port&0xff) { case 0x01: return(tilem_keypad_read_keys(calc)); case 0x03: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; return(v); case 0x04: return(0x01); case 0x05: return(calc->hwregs[PORT5]); case 0x06: return(calc->hwregs[PORT6]); case 0x07: v = tilem_linkport_get_lines(calc); b = (calc->hwregs[PORT7] >> 4) | 0xf0; return ((calc->hwregs[PORT7] & b) | (v & ~b)); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; if (calc->hwregs[PORT5] & 0x40) { pageA = (0x08 | (calc->hwregs[PORT5] & 1)); } else { pageA = (calc->hwregs[PORT5] & 7); } if (calc->hwregs[PORT6] & 0x40) { pageB = (0x08 | (calc->hwregs[PORT6] & 1)); } else { pageB = (calc->hwregs[PORT6] & 7); } calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x08; } void x5_z80_out(TilemCalc* calc, dword port, byte value) { switch(port&0xff) { case 0x00: calc->lcd.addr = ((value & 0x3f) << 8); calc->z80.lastlcdwrite = calc->z80.clock; break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x02: /* Contrast */ calc->lcd.contrast = 16 + (value & 0x1f); break; case 0x03: /* Interrupts / LCD power */ if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) { calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; } calc->hwregs[PORT3] = value; calc->lcd.active = calc->poweronhalt = ((value & 8) >> 3); break; case 0x04: /* LCD control */ calc->hwregs[PORT4] = value; switch (value & 0x18) { case 0x00: calc->lcd.rowstride = 10; break; case 0x08: calc->lcd.rowstride = 12; break; case 0x10: calc->lcd.rowstride = 16; break; case 0x18: calc->lcd.rowstride = 20; break; } calc->z80.lastlcdwrite = calc->z80.clock; break; case 0x05: calc->hwregs[PORT5] = value; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: /* Link */ calc->hwregs[PORT7] = value; value = (((value >> 6) & (value >> 2)) | ((value >> 4) & ~value)); tilem_linkport_set_lines(calc, value); break; } return; } void x5_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; } } tilem-2.0/emu/x5/x5_memory.c000066400000000000000000000032551220200411600156700ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x5.h" void x5_z80_wrmem(TilemCalc* calc, dword A, byte v) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x20000) { *(calc->mem + pa) = v; if (((pa - 0x20000 - calc->lcd.addr) >> 6) < (unsigned) calc->lcd.rowstride) calc->z80.lastlcdwrite = calc->z80.clock; } } byte x5_z80_rdmem(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); return (*(calc->mem + pa)); } dword x5_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword x5_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/x5/x5_subcore.c000066400000000000000000000035101220200411600160140ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x5.h" static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Custom", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Del", "0", "1", "4", "7", "EE", "Sin", "Stat", "XVar", "On", "Store", "Comma", "Square", "Ln", "Log", "Graph", "Alpha", "F5", "F4", "F3", "F2", "F1", "2nd", "Exit", "More", 0, 0, 0, 0, 0, 0, 0, 0}; const TilemHardware hardware_ti85 = { '5', "ti85", "TI-85", TILEM_CALC_HAS_LINK, 128, 64, 8 * 0x4000, 0x8000, 0, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x5_reset, NULL, x5_z80_in, x5_z80_out, x5_z80_wrmem, x5_z80_rdmem, x5_z80_rdmem, NULL, x5_z80_ptimer, tilem_lcd_t6a43_get_data, x5_mem_ltop, x5_mem_ptol }; tilem-2.0/emu/x6/000077500000000000000000000000001220200411600135745ustar00rootroot00000000000000tilem-2.0/emu/x6/x6.h000066400000000000000000000031061220200411600143020ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X6_H #define _TILEM_X6_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* mapping mode, timer control */ PORT5, /* memory mapping bank A */ PORT6, /* memory mapping bank B */ PORT7, /* link port control */ NUM_HW_REGS }; #define HW_REG_NAMES { "port3", "port4", "port5", "port6", "port7" } #define TIMER_INT (TILEM_NUM_SYS_TIMERS + 1) #define NUM_HW_TIMERS 1 #define HW_TIMER_NAMES { "int" } void x6_reset(TilemCalc* calc); byte x6_z80_in(TilemCalc* calc, dword port); void x6_z80_out(TilemCalc* calc, dword port, byte value); void x6_z80_ptimer(TilemCalc* calc, int id); void x6_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x6_z80_rdmem(TilemCalc* calc, dword addr); dword x6_mem_ltop(TilemCalc* calc, dword addr); dword x6_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x6/x6_init.c000066400000000000000000000025161220200411600153240ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x6.h" void x6_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x56; calc->hwregs[PORT5] = 0x00; calc->hwregs[PORT6] = 0x00; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x00; calc->mempagemap[2] = 0x00; calc->mempagemap[3] = 0x10 + 0x00; calc->lcd.addr = 0x3c00; tilem_z80_set_speed(calc, 6000); /* FIXME: measure actual frequency */ tilem_z80_set_timer(calc, TIMER_INT, 1000, 5000, 1); } tilem-2.0/emu/x6/x6_io.c000066400000000000000000000070431220200411600147700ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x6.h" byte x6_z80_in(TilemCalc* calc, dword port) { byte v, b; switch(port&0xff) { case 0x01: return(tilem_keypad_read_keys(calc)); case 0x03: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; return(v); case 0x04: return(0x01); case 0x05: return(calc->hwregs[PORT5]); case 0x06: return(calc->hwregs[PORT6]); case 0x07: v = tilem_linkport_get_lines(calc); b = (calc->hwregs[PORT7] >> 4) | 0xf0; return (calc->hwregs[PORT7] & b) | (v & ~b); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; if (calc->hwregs[PORT5] & 0x40) { pageA = (0x10 | (calc->hwregs[PORT5] & 7)); } else { pageA = (calc->hwregs[PORT5] & 0x0f); } if (calc->hwregs[PORT6] & 0x40) { pageB = (0x10 | (calc->hwregs[PORT6] & 7)); } else { pageB = (calc->hwregs[PORT6] & 0x0f); } calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x10; } void x6_z80_out(TilemCalc* calc, dword port, byte value) { switch(port&0xff) { case 0x00: calc->lcd.addr = ((value & 0x3f) << 8); calc->z80.lastlcdwrite = calc->z80.clock; break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x02: /* contrast */ calc->lcd.contrast = 16 + (value & 0x1f); break; case 0x03: /* Lcd Power */ if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) { calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; } calc->hwregs[PORT3] = value; calc->lcd.active = calc->poweronhalt = ((value & 8) >> 3); break; case 0x04: /* LCD control */ calc->hwregs[PORT4] = value; switch (value & 0x18) { case 0x00: calc->lcd.rowstride = 10; break; case 0x08: calc->lcd.rowstride = 12; break; case 0x10: calc->lcd.rowstride = 16; break; case 0x18: calc->lcd.rowstride = 20; break; } calc->z80.lastlcdwrite = calc->z80.clock; break; case 0x05: calc->hwregs[PORT5] = value; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: /* Link */ calc->hwregs[PORT7] = value; value = (((value >> 6) & (value >> 2)) | ((value >> 4) & ~value)); tilem_linkport_set_lines(calc, value); break; } return; } void x6_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; } } tilem-2.0/emu/x6/x6_memory.c000066400000000000000000000032551220200411600156720ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x6.h" void x6_z80_wrmem(TilemCalc* calc, dword A, byte v) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); if (pa >= 0x40000) { *(calc->mem + pa) = v; if (((pa - 0x40000 - calc->lcd.addr) >> 6) < (unsigned) calc->lcd.rowstride) calc->z80.lastlcdwrite = calc->z80.clock; } } byte x6_z80_rdmem(TilemCalc* calc, dword A) { dword pa = 0x4000 * calc->mempagemap[(A)>>14] + (A & 0x3FFF); return (*(calc->mem + pa)); } dword x6_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword x6_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/x6/x6_subcore.c000066400000000000000000000035221220200411600160210ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x6.h" static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Custom", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Del", "0", "1", "4", "7", "EE", "Sin", "Table", "XVar", "On", "Store", "Comma", "Square", "Ln", "Log", "Graph", "Alpha", "F5", "F4", "F3", "F2", "F1", "2nd", "Exit", "More", 0, 0, 0, 0, 0, 0, 0, 0}; const TilemHardware hardware_ti86 = { '6', "ti86", "TI-86", TILEM_CALC_HAS_LINK, 128, 64, 0x10 * 0x4000, 0x08 * 0x4000, 0, 0x40, 0, NULL, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x6_reset, NULL, x6_z80_in, x6_z80_out, x6_z80_wrmem, x6_z80_rdmem, x6_z80_rdmem, NULL, x6_z80_ptimer, tilem_lcd_t6a43_get_data, x6_mem_ltop, x6_mem_ptol }; tilem-2.0/emu/x7/000077500000000000000000000000001220200411600135755ustar00rootroot00000000000000tilem-2.0/emu/x7/x7.h000066400000000000000000000035431220200411600143110ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_X7_H #define _TILEM_X7_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ NOEXEC, /* no-exec sector map */ PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port6", "port7", "noexec", \ "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define NUM_HW_TIMERS 3 #define HW_TIMER_NAMES { "int1", "int2a", "int2b" } void x7_reset(TilemCalc* calc); void x7_stateloaded(TilemCalc* calc, int savtype); byte x7_z80_in(TilemCalc* calc, dword port); void x7_z80_out(TilemCalc* calc, dword port, byte value); void x7_z80_ptimer(TilemCalc* calc, int id); void x7_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte x7_z80_rdmem(TilemCalc* calc, dword addr); byte x7_z80_rdmem_m1(TilemCalc* calc, dword addr); dword x7_mem_ltop(TilemCalc* calc, dword addr); dword x7_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/x7/x7_init.c000066400000000000000000000032121220200411600153200ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x7.h" void x7_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x77; calc->hwregs[PORT6] = 0x1F; calc->hwregs[PORT7] = 0x1F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x1E; calc->mempagemap[2] = 0x1F; calc->mempagemap[3] = 0x1F; calc->z80.r.pc.d = 0x8000; calc->hwregs[NOEXEC] = 0; calc->hwregs[PROTECTSTATE] = 0; tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 8474, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 8474, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 8474, 1); } void x7_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x1E * 0x4000L), 0x08, 0x13, 0x1f18); } tilem-2.0/emu/x7/x7_io.c000066400000000000000000000121121220200411600147630ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x7.h" byte x7_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; /* FIXME: confirm that mirror ports are the same as on 83+ - and figure out what, if anything, port 5 does */ switch(port&0x1f) { case 0x00: case 0x08: v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); return(v); case 0x01: case 0x09: return(tilem_keypad_read_keys(calc)); case 0x02: case 0x0A: v = battlevel[calc->hwregs[PORT4] >> 6]; return(calc->battery >= v ? 0x05 : 0x04); case 0x03: case 0x0B: return(calc->hwregs[PORT3]); case 0x04: case 0x0C: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; return(v); case 0x06: case 0x0E: return(calc->hwregs[PORT6]); case 0x07: case 0x0F: return(calc->hwregs[PORT7]); case 0x10: case 0x12: case 0x18: case 0x1A: return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: case 0x19: case 0x1B: return(tilem_lcd_t6a04_read(calc)); } return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; if (calc->hwregs[PORT6] & 0x40) pageA = (0x20 | (calc->hwregs[PORT6] & 1)); else pageA = (calc->hwregs[PORT6] & 0x1f); if (calc->hwregs[PORT7] & 0x40) pageB = (0x20 | (calc->hwregs[PORT7] & 1)); else pageB = (calc->hwregs[PORT7] & 0x1f); if (calc->hwregs[PORT4] & 1) { /* FIXME: confirm this behavior (83+-like rather than 83-like) */ calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = pageA; calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x20; } } void x7_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1786, 4032, 5882, 8474 }; int t; unsigned int mode; switch(port&0x1f) { case 0x00: case 0x08: tilem_linkport_set_lines(calc, value); break; case 0x01: case 0x09: tilem_keypad_set_group(calc, value); break; case 0x03: case 0x0B: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: case 0x0C: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x06: case 0x0E: calc->hwregs[PORT6] = value & 0x7f; setup_mapping(calc); break; case 0x07: case 0x0F: calc->hwregs[PORT7] = value & 0x7f; setup_mapping(calc); break; case 0x10: case 0x12: case 0x18: case 0x1A: tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: case 0x19: case 0x1B: tilem_lcd_t6a04_write(calc, value); break; case 0x14: case 0x15: if (calc->hwregs[PROTECTSTATE] == 7) { if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); calc->flash.unlock = value&1; } break; case 0x16: case 0x17: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { tilem_message(calc, "No-exec mask set to %x", value); calc->hwregs[NOEXEC] = ((value & 0x0f) << 2); } break; } return; } void x7_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; } } tilem-2.0/emu/x7/x7_memory.c000066400000000000000000000061531220200411600156740ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x7.h" void x7_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; pa = (A & 0x3FFF) + 0x4000*calc->mempagemap[(A)>>14]; if (pa<0x80000) tilem_flash_write_byte(calc, pa, v); else if (pa < 0x88000) *(calc->mem+pa) = v; } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; if (pa < 0x80000 && (calc->flash.state || calc->flash.busy)) value = tilem_flash_read_byte(calc, pa); else value = *(calc->mem + pa); if (pa < 0x70000 || pa >= 0x80000) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte x7_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; pa = 0x4000 * page + (A & 0x3FFF); if (TILEM_UNLIKELY(page == 0x1E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } value = readbyte(calc, pa); return(value); } byte x7_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; pa = 0x4000 * page + (A & 0x3FFF); if (TILEM_UNLIKELY(calc->hwregs[NOEXEC] & (1 << (page % 4)))) { tilem_warning(calc, "Executing in restricted Flash area"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } if (TILEM_UNLIKELY(page == 0x1E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); tilem_z80_exception(calc, TILEM_EXC_RAM_EXEC); } value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword x7_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword x7_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/x7/x7_subcore.c000066400000000000000000000045321220200411600160250ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "x7.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x08000, 0}, {0x078000, 0x02000, 0}, {0x07A000, 0x02000, 0}, {0x07C000, 0x04000, 1}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; static const char* keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Const", "Clear", 0, "Chs", "3", "6", "9", "RParen", "MixSimp", "AppsMenu", 0, "DecPnt", "2", "5", "8", "LParen", "FracDec", "Prgm", "StatEd", "0", "1", "4", "7", "Percent", "FracSlash", "Expon", "Draw", "On", "Store", "Comma", "VarX", "Simp", "Unit", "Square", "Math", "Graph", "Trace", "Zoom", "Window", "YEqu", "2nd", "Mode", "Del", 0, 0, 0, 0, 0, 0, 0, 0}; TilemHardware hardware_ti73 = { '7', "ti73", "TI-73", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH), 96, 64, 32 * 0x4000, 2 * 0x4000, 15 * 64, 0x40, NUM_FLASH_SECTORS, flashsectors, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, keynames, x7_reset, x7_stateloaded, x7_z80_in, x7_z80_out, x7_z80_wrmem, x7_z80_rdmem, x7_z80_rdmem_m1, NULL, x7_z80_ptimer, tilem_lcd_t6a04_get_data, x7_mem_ltop, x7_mem_ptol }; tilem-2.0/emu/xn/000077500000000000000000000000001220200411600136645ustar00rootroot00000000000000tilem-2.0/emu/xn/xn.h000066400000000000000000000071751220200411600144740ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_XN_H #define _TILEM_XN_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT5, /* memory mapping bank C */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ PORT8, /* link assist mode flags */ PORT9, /* unknown (link assist settings?) */ PORTA, /* unknown (timeout value?) */ PORTB, /* unknown (timeout value?) */ PORTC, /* unknown (timeout value?) */ PORTD, /* unknown */ PORTE, /* unknown */ PORTF, /* unknown */ PORT20, /* CPU speed control */ PORT21, /* hardware type / RAM no-exec control */ PORT22, /* Flash no-exec lower limit */ PORT23, /* Flash no-exec upper limit */ PORT25, /* unknown */ PORT26, /* unknown */ PORT27, /* bank C forced-page-0 limit */ PORT28, /* bank B forced-page-1 limit */ PORT29, /* LCD port delay (6 MHz) */ PORT2A, /* LCD port delay (mode 1) */ PORT2B, /* LCD port delay (mode 2) */ PORT2C, /* LCD port delay (mode 3) */ PORT2D, /* unknown */ PORT2E, /* memory delay */ PORT2F, /* Duration of LCD wait timer */ CLOCK_MODE, /* clock mode */ CLOCK_INPUT, /* clock input register */ CLOCK_DIFF, /* clock value minus actual time */ RAM_READ_DELAY, RAM_WRITE_DELAY, RAM_EXEC_DELAY, FLASH_READ_DELAY, FLASH_WRITE_DELAY, FLASH_EXEC_DELAY, LCD_PORT_DELAY, NO_EXEC_RAM, LCD_WAIT, /* LCD wait timer active */ PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port5", "port6", "port7", "port8", "port9", \ "portA", "portB", "portC", "portD", "portE", "portF", "port20", \ "port21", "port22", "port23", "port25", "port26", "port27", \ "port28", "port29", "port2A", "port2B", "port2C", "port2D", \ "port2E", "port2F", "clock_mode", "clock_input", "clock_diff", \ "ram_read_delay", "ram_write_delay", "ram_exec_delay", \ "flash_read_delay", "flash_write_delay", "flash_exec_delay", \ "lcd_port_delay", "no_exec_ram", "lcd_wait", "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define TIMER_LCD_WAIT (TILEM_NUM_SYS_TIMERS + 4) #define TIMER_FREEZE_LINK_PORT (TILEM_NUM_SYS_TIMERS + 5) #define NUM_HW_TIMERS 5 #define HW_TIMER_NAMES { "int1", "int2a", "int2b", "lcd_wait", \ "freeze_link_port" } void xn_reset(TilemCalc* calc); void xn_stateloaded(TilemCalc* calc, int savtype); byte xn_z80_in(TilemCalc* calc, dword port); void xn_z80_out(TilemCalc* calc, dword port, byte value); void xn_z80_instr(TilemCalc* calc, dword opcode); void xn_z80_ptimer(TilemCalc* calc, int id); void xn_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte xn_z80_rdmem(TilemCalc* calc, dword addr); byte xn_z80_rdmem_m1(TilemCalc* calc, dword addr); dword xn_mem_ltop(TilemCalc* calc, dword addr); dword xn_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/xn/xn_init.c000066400000000000000000000047161220200411600155100ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xn.h" void xn_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x07; calc->hwregs[PORT6] = 0x7F; calc->hwregs[PORT7] = 0x7F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x7E; calc->mempagemap[2] = 0x7F; calc->mempagemap[3] = 0x7F; calc->z80.r.pc.d = 0x8000; calc->hwregs[PORT8] = 0x80; calc->hwregs[PORT20] = 0; calc->hwregs[PORT21] = 0; calc->hwregs[PORT22] = 0x08; calc->hwregs[PORT23] = 0x69; calc->hwregs[PORT25] = 0x10; calc->hwregs[PORT26] = 0x20; calc->hwregs[PORT27] = 0; calc->hwregs[PORT28] = 0; calc->hwregs[PORT29] = 0x14; calc->hwregs[PORT2A] = 0x27; calc->hwregs[PORT2B] = 0x2F; calc->hwregs[PORT2C] = 0x3B; calc->hwregs[PORT2D] = 0x01; calc->hwregs[PORT2E] = 0x44; calc->hwregs[PORT2F] = 0x4A; calc->hwregs[FLASH_READ_DELAY] = 0; calc->hwregs[FLASH_WRITE_DELAY] = 0; calc->hwregs[FLASH_EXEC_DELAY] = 0; calc->hwregs[RAM_READ_DELAY] = 0; calc->hwregs[RAM_WRITE_DELAY] = 0; calc->hwregs[RAM_EXEC_DELAY] = 0; calc->hwregs[LCD_PORT_DELAY] = 5; calc->hwregs[NO_EXEC_RAM] = 0x5555; calc->hwregs[PROTECTSTATE] = 0; tilem_z80_set_speed(calc, 6000); calc->z80.emuflags |= TILEM_Z80_RESET_UNDOCUMENTED; calc->lcd.emuflags &= ~TILEM_LCD_REQUIRE_DELAY; tilem_z80_set_timer(calc, TIMER_INT1, 1600, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 9277, 1); } void xn_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x7E * 0x4000L), 0x69, 0x0c, 0x1e50); } tilem-2.0/emu/xn/xn_io.c000066400000000000000000000423421220200411600151510ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "xn.h" static void set_lcd_wait_timer(TilemCalc* calc) { static const int delaytime[8] = { 48, 112, 176, 240, 304, 368, 432, 496 }; int i; switch (calc->hwregs[PORT20] & 3) { case 0: return; case 1: i = (calc->hwregs[PORT2F] & 3); break; case 2: i = ((calc->hwregs[PORT2F] >> 2) & 7); break; default: i = ((calc->hwregs[PORT2F] >> 5) & 7); break; } tilem_z80_set_timer(calc, TIMER_LCD_WAIT, delaytime[i], 0, 0); calc->hwregs[LCD_WAIT] = 1; } byte xn_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; unsigned int f; time_t curtime; switch(port&0xff) { case 0x00: if (tilem_z80_timer_running(calc, TIMER_FREEZE_LINK_PORT)) return(3); v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); return(v); case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: v = battlevel[calc->hwregs[PORT4] >> 6]; return ((calc->battery >= v ? 0xe1 : 0xe0) | (calc->hwregs[LCD_WAIT] ? 0 : 2) | (calc->flash.unlock << 2)); case 0x03: return(calc->hwregs[PORT3]); case 0x04: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; if (calc->usertimers[0].status & TILEM_USER_TIMER_FINISHED) v |= 0x20; if (calc->usertimers[1].status & TILEM_USER_TIMER_FINISHED) v |= 0x40; if (calc->usertimers[2].status & TILEM_USER_TIMER_FINISHED) v |= 0x80; return(v); case 0x05: return(calc->hwregs[PORT5] & 0x0f); case 0x06: return(calc->hwregs[PORT6]); case 0x07: return(calc->hwregs[PORT7]); case 0x08: return(calc->hwregs[PORT8]); case 0x09: f = tilem_linkport_get_assist_flags(calc); if (f & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) v = 0x00; else v = 0x20; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_READ) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_IDLE) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ERROR) v |= 0x04; if (f & TILEM_LINK_ASSIST_READ_BUSY) v |= 0x08; if (f & TILEM_LINK_ASSIST_READ_BYTE) v |= 0x10; if (f & (TILEM_LINK_ASSIST_READ_ERROR | TILEM_LINK_ASSIST_WRITE_ERROR)) v |= 0x40; if (f & TILEM_LINK_ASSIST_WRITE_BUSY) v |= 0x80; calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR; return(v); case 0x0A: v = calc->linkport.assistlastbyte; tilem_linkport_read_byte(calc); return(v); case 0x0E: return(calc->hwregs[PORTE] & 3); case 0x0F: return(calc->hwregs[PORTF] & 3); case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_read(calc)); case 0x15: return(0x45); /* ??? */ case 0x1C: return(tilem_md5_assist_get_value(calc)); case 0x1D: return(tilem_md5_assist_get_value(calc) >> 8); case 0x1E: return(tilem_md5_assist_get_value(calc) >> 16); case 0x1F: return(tilem_md5_assist_get_value(calc) >> 24); case 0x20: return(calc->hwregs[PORT20] & 3); case 0x21: return(calc->hwregs[PORT21] & 0x33); case 0x22: return(calc->hwregs[PORT22]); case 0x23: return(calc->hwregs[PORT23]); case 0x25: return(calc->hwregs[PORT25]); case 0x26: return(calc->hwregs[PORT26]); case 0x27: return(calc->hwregs[PORT27]); case 0x28: return(calc->hwregs[PORT28]); case 0x29: return(calc->hwregs[PORT29]); case 0x2A: return(calc->hwregs[PORT2A]); case 0x2B: return(calc->hwregs[PORT2B]); case 0x2C: return(calc->hwregs[PORT2C]); case 0x2D: return(calc->hwregs[PORT2D] & 3); case 0x2E: return(calc->hwregs[PORT2E]); case 0x2F: return(calc->hwregs[PORT2F]); case 0x30: return(calc->usertimers[0].frequency); case 0x31: return(calc->usertimers[0].status); case 0x32: return(tilem_user_timer_get_value(calc, 0)); case 0x33: return(calc->usertimers[1].frequency); case 0x34: return(calc->usertimers[1].status); case 0x35: return(tilem_user_timer_get_value(calc, 1)); case 0x36: return(calc->usertimers[2].frequency); case 0x37: return(calc->usertimers[2].status); case 0x38: return(tilem_user_timer_get_value(calc, 2)); case 0x39: return(0xf0); /* ??? */ case 0x40: return calc->hwregs[CLOCK_MODE]; case 0x41: return calc->hwregs[CLOCK_INPUT]&0xff; case 0x42: return (calc->hwregs[CLOCK_INPUT]>>8)&0xff; case 0x43: return (calc->hwregs[CLOCK_INPUT]>>16)&0xff; case 0x44: return (calc->hwregs[CLOCK_INPUT]>>24)&0xff; case 0x45: case 0x46: case 0x47: case 0x48: if (calc->hwregs[CLOCK_MODE] & 1) { time(&curtime); } else { curtime = 0; } curtime += calc->hwregs[CLOCK_DIFF]; return (curtime >> ((port - 0x45) * 8)); case 0x4C: return(0x22); case 0x4D: /* USB port - not emulated, calculator should recognize that the USB cable is disconnected. Thanks go to Dan Englender for these values. */ return(0xA5); case 0x55: return(0x1F); case 0x56: return(0x00); case 0x57: return(0x50); case 0x0B: case 0x0C: case 0x0D: case 0x14: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: return(0); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB, pageC; if (calc->hwregs[PORT6] & 0x80) pageA = (0x80 | (calc->hwregs[PORT6] & 7)); else pageA = (calc->hwregs[PORT6] & 0x7f); if (calc->hwregs[PORT7] & 0x80) pageB = (0x80 | (calc->hwregs[PORT7] & 7)); else pageB = (calc->hwregs[PORT7] & 0x7f); pageC = (0x80 | (calc->hwregs[PORT5] & 7)); if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = pageC; } } static void setup_clockdelays(TilemCalc* calc) { byte lcdport = calc->hwregs[PORT29 + (calc->hwregs[PORT20] & 3)]; byte memport = calc->hwregs[PORT2E]; if (!(lcdport & 1)) memport &= ~0x07; if (!(lcdport & 2)) memport &= ~0x70; calc->hwregs[FLASH_EXEC_DELAY] = (memport & 1); calc->hwregs[FLASH_READ_DELAY] = ((memport >> 1) & 1); calc->hwregs[FLASH_WRITE_DELAY] = ((memport >> 2) & 1); calc->hwregs[RAM_EXEC_DELAY] = ((memport >> 4) & 1); calc->hwregs[RAM_READ_DELAY] = ((memport >> 5) & 1); calc->hwregs[RAM_WRITE_DELAY] = ((memport >> 6) & 1); calc->hwregs[LCD_PORT_DELAY] = (lcdport >> 2); } void xn_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1953, 4395, 6836, 9277 }; int t, r; unsigned int mode; time_t curtime; switch(port&0xff) { case 0x00: if (value == 0 && calc->linkport.lines != 0 && calc->linkport.extlines == 0) { /* Kludge to work around TI's broken RecAByteIO implementation on 2.46+, which will fail if the sending device is too fast. */ tilem_z80_set_timer(calc, TIMER_FREEZE_LINK_PORT, 100, 0, 0); } tilem_linkport_set_lines(calc, value); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; if (value & 0x06) { calc->usertimers[0].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status &= ~TILEM_USER_TIMER_NO_HALT_INT; } else { calc->usertimers[0].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status |= TILEM_USER_TIMER_NO_HALT_INT; } mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x05: calc->hwregs[PORT5] = value & 0x0f; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: calc->hwregs[PORT7] = value; setup_mapping(calc); break; case 0x08: calc->hwregs[PORT8] = value; mode = calc->linkport.mode; if (value & 0x01) mode |= TILEM_LINK_MODE_INT_ON_READ; else mode &= ~TILEM_LINK_MODE_INT_ON_READ; if (value & 0x02) mode |= TILEM_LINK_MODE_INT_ON_IDLE; else mode &= ~TILEM_LINK_MODE_INT_ON_IDLE; if (value & 0x04) mode |= TILEM_LINK_MODE_INT_ON_ERROR; else mode &= ~TILEM_LINK_MODE_INT_ON_ERROR; if (value & 0x80) mode &= ~TILEM_LINK_MODE_ASSIST; else mode |= TILEM_LINK_MODE_ASSIST; tilem_linkport_set_mode(calc, mode); break; case 0x09: calc->hwregs[PORT9] = value; break; case 0x0A: calc->hwregs[PORTA] = value; break; case 0x0B: calc->hwregs[PORTB] = value; break; case 0x0C: calc->hwregs[PORTC] = value; break; case 0x0D: if (!(calc->hwregs[PORT8] & 0x80)) tilem_linkport_write_byte(calc, value); break; case 0x0E: calc->hwregs[PORTE] = value; break; case 0x0F: calc->hwregs[PORTF] = value; break; case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_write(calc, value); break; case 0x14: if (calc->hwregs[PROTECTSTATE] == 7) { /* if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); */ calc->flash.unlock = value&1; } break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: r = (port & 0xff) - 0x18; calc->md5assist.regs[r] >>= 8; calc->md5assist.regs[r] |= (value << 24); break; case 0x1E: calc->md5assist.shift = value & 0x1f; break; case 0x1F: calc->md5assist.mode = value & 3; break; case 0x20: calc->hwregs[PORT20] = value; if (value & 3) { tilem_z80_set_speed(calc, 15000); } else { tilem_z80_set_speed(calc, 6000); } setup_clockdelays(calc); break; case 0x21: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { calc->hwregs[PORT21] = value; /* FIXME: these restrictions were tested on 83+ SE; someone should confirm them for 84+ */ switch (value & 0x30) { case 0x00: /* restrict pp. 0, 2, 4, 6, 8, A, C, E */ calc->hwregs[NO_EXEC_RAM] = 0x5555; break; case 0x10: /* restrict pp. 0, 3, 4, 7, 8, B, C, F */ calc->hwregs[NO_EXEC_RAM] = 0x9999; break; case 0x20: /* restrict pp. 0, 3-7, 8, B-F */ calc->hwregs[NO_EXEC_RAM] = 0xF9F9; break; case 0x30: /* restrict pp. 0, 3-F */ calc->hwregs[NO_EXEC_RAM] = 0xFFF9; break; } } break; case 0x22: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { calc->hwregs[PORT22] = value; } break; case 0x23: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { calc->hwregs[PORT23] = value; } break; case 0x25: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { calc->hwregs[PORT25] = value; } break; case 0x26: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { calc->hwregs[PORT26] = value; } break; case 0x27: calc->hwregs[PORT27] = value; break; case 0x28: calc->hwregs[PORT28] = value; break; case 0x29: calc->hwregs[PORT29] = value; setup_clockdelays(calc); break; case 0x2A: calc->hwregs[PORT2A] = value; setup_clockdelays(calc); break; case 0x2B: calc->hwregs[PORT2B] = value; setup_clockdelays(calc); break; case 0x2C: calc->hwregs[PORT2C] = value; setup_clockdelays(calc); break; case 0x2D: calc->hwregs[PORT2D] = value; break; case 0x2E: calc->hwregs[PORT2E] = value; setup_clockdelays(calc); break; case 0x2F: calc->hwregs[PORT2F] = value; break; case 0x30: tilem_user_timer_set_frequency(calc, 0, value); break; case 0x31: tilem_user_timer_set_mode(calc, 0, value); break; case 0x32: tilem_user_timer_start(calc, 0, value); break; case 0x33: tilem_user_timer_set_frequency(calc, 1, value); break; case 0x34: tilem_user_timer_set_mode(calc, 1, value); break; case 0x35: tilem_user_timer_start(calc, 1, value); break; case 0x36: tilem_user_timer_set_frequency(calc, 2, value); break; case 0x37: tilem_user_timer_set_mode(calc, 2, value); break; case 0x38: tilem_user_timer_start(calc, 2, value); break; case 0x40: time(&curtime); if ((calc->hwregs[CLOCK_MODE] & 1) != (value & 1)) { if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; else calc->hwregs[CLOCK_DIFF] += curtime; } if (!(calc->hwregs[CLOCK_MODE] & 2) && (value & 2)) { calc->hwregs[CLOCK_DIFF] = calc->hwregs[CLOCK_INPUT]; if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; } calc->hwregs[CLOCK_MODE] = value & 3; break; case 0x41: calc->hwregs[CLOCK_INPUT] &= 0xffffff00; calc->hwregs[CLOCK_INPUT] |= value; break; case 0x42: calc->hwregs[CLOCK_INPUT] &= 0xffff00ff; calc->hwregs[CLOCK_INPUT] |= (value << 8); break; case 0x43: calc->hwregs[CLOCK_INPUT] &= 0xff00ffff; calc->hwregs[CLOCK_INPUT] |= (value << 16); break; case 0x44: calc->hwregs[CLOCK_INPUT] &= 0x00ffffff; calc->hwregs[CLOCK_INPUT] |= (value << 24); break; } return; } void xn_z80_instr(TilemCalc* calc, dword opcode) { dword pa; byte l, h; switch (opcode) { case 0xeded: /* emulator control instruction */ l = xn_z80_rdmem(calc, calc->z80.r.pc.d); h = xn_z80_rdmem(calc, calc->z80.r.pc.d + 1); calc->z80.r.pc.d += 2; opcode = (l | (h << 8)); switch (opcode) { case 0x1000: /* Power off */ case 0x1001: /* Power on */ case 0x1002: /* Prepare for power off */ break; case 0x1003: /* Disable Nspire keypad */ tilem_message(calc, "Keypad locked"); break; case 0x1004: /* Enable Nspire keypad */ tilem_message(calc, "Keypad unlocked"); break; case 0x1005: /* ??? */ break; case 0x1008: /* check if USB data waiting (?) */ calc->z80.r.af.d |= 0x40; break; case 0x100C: /* ??? */ calc->z80.r.af.d &= ~0x40; break; case 0x100D: /* check if USB link should be used (???) */ calc->z80.r.af.d &= ~0x40; break; case 0x100E: case 0x100F: /* ??? */ break; case 0x101C: /* disable USB device (???) */ break; case 0x1020: /* check for something USB-related */ calc->z80.r.af.d |= 0x40; break; case 0x1024: /* check if USB data waiting */ calc->z80.r.af.d |= 0x40; break; case 0x1029: /* check for something USB-related */ calc->z80.r.af.d |= 0x40; break; case 0x1027: /* check for something USB-related */ calc->z80.r.af.d |= 0x40; break; case 0x102E: /* ??? */ break; case 0x102F: /* ??? */ break; default: tilem_warning(calc, "Unknown control instruction %x", opcode); } break; case 0xedee: /* erase Flash at address HL */ if (calc->flash.unlock) { pa = xn_mem_ltop(calc, calc->z80.r.hl.w.l); if (pa < 0x200000) { tilem_flash_erase_address(calc, pa); } } break; case 0xedef: /* enable Flash writing for following instruction */ if (calc->flash.unlock) { calc->flash.state = 3; } break; default: tilem_warning(calc, "Invalid opcode %x", opcode); tilem_z80_exception(calc, TILEM_EXC_INSTRUCTION); break; } } void xn_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; case TIMER_LCD_WAIT: calc->hwregs[LCD_WAIT] = 0; break; } } tilem-2.0/emu/xn/xn_memory.c000066400000000000000000000112341220200411600160460ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xn.h" void xn_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; byte page; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) { calc->z80.clock += calc->hwregs[FLASH_WRITE_DELAY]; if (calc->flash.state == 3) { *(calc->mem+pa) = v; calc->flash.state = 0; } } else if (pa < 0x220000) { calc->z80.clock += calc->hwregs[RAM_WRITE_DELAY]; *(calc->mem+pa) = v; } } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; value = *(calc->mem + pa); if (pa < 0x1B0000 || pa >= 0x200000 || (pa >= 0x1C0000 && pa < 0x1F0000)) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte xn_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) calc->z80.clock += calc->hwregs[FLASH_READ_DELAY]; else calc->z80.clock += calc->hwregs[RAM_READ_DELAY]; value = readbyte(calc, pa); return (value); } byte xn_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY((page & 0x80) && calc->hwregs[NO_EXEC_RAM] & (1 << (page&7)))) { tilem_warning(calc, "Executing in restricted RAM area"); tilem_z80_exception(calc, TILEM_EXC_RAM_EXEC); } if (TILEM_UNLIKELY(page >= calc->hwregs[PORT22] && page <= calc->hwregs[PORT23])) { tilem_warning(calc, "Executing in restricted Flash area"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) calc->z80.clock += calc->hwregs[FLASH_EXEC_DELAY]; else calc->z80.clock += calc->hwregs[RAM_EXEC_DELAY]; value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword xn_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } return ((page << 14) | (A & 0x3fff)); } dword xn_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; if (!page) return (A & 0x3fff); if (page == calc->mempagemap[1]) return (0x4000 | (A & 0x3fff)); if ((A & 0x3fff) < 64 * calc->hwregs[PORT28]) { if (page == 0x81) return (0x8000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[2]) return (0x8000 | (A & 0x3fff)); } if ((A & 0x3fff) >= (0x4000 - 64 * calc->hwregs[PORT27])) { if (page == 0x80) return (0xC000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[3]) return (0xC000 | (A & 0x3fff)); } return (0xffffffff); } tilem-2.0/emu/xn/xn_subcore.c000066400000000000000000000051031220200411600161760ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xn.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x10000, 0}, {0x080000, 0x10000, 0}, {0x090000, 0x10000, 0}, {0x0A0000, 0x10000, 0}, {0x0B0000, 0x10000, 0}, {0x0C0000, 0x10000, 0}, {0x0D0000, 0x10000, 0}, {0x0E0000, 0x10000, 0}, {0x0F0000, 0x10000, 0}, {0x100000, 0x10000, 0}, {0x110000, 0x10000, 0}, {0x120000, 0x10000, 0}, {0x130000, 0x10000, 0}, {0x140000, 0x10000, 0}, {0x150000, 0x10000, 0}, {0x160000, 0x10000, 0}, {0x170000, 0x10000, 0}, {0x180000, 0x10000, 0}, {0x190000, 0x10000, 0}, {0x1A0000, 0x10000, 0}, {0x1B0000, 0x10000, 0}, {0x1C0000, 0x10000, 0}, {0x1D0000, 0x10000, 0}, {0x1E0000, 0x10000, 0}, {0x1F0000, 0x08000, 0}, {0x1F8000, 0x02000, 0}, {0x1FA000, 0x02000, 0}, {0x1FC000, 0x04000, 0}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; extern const char* xp_keynames[]; TilemHardware hardware_ti84pns = { 'n', "ti84pns", "TI-Nspire (TI-84 Plus mode)", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_LINK_ASSIST | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH | TILEM_CALC_HAS_MD5_ASSIST), 96, 64, 128 * 0x4000, 8 * 0x4000, 15 * 64, 0x80, NUM_FLASH_SECTORS, flashsectors, 3, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, xp_keynames, xn_reset, xn_stateloaded, xn_z80_in, xn_z80_out, xn_z80_wrmem, xn_z80_rdmem, xn_z80_rdmem_m1, xn_z80_instr, xn_z80_ptimer, tilem_lcd_t6a04_get_data, xn_mem_ltop, xn_mem_ptol }; tilem-2.0/emu/xp/000077500000000000000000000000001220200411600136665ustar00rootroot00000000000000tilem-2.0/emu/xp/xp.h000066400000000000000000000037421220200411600144740ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_XP_H #define _TILEM_XP_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT5, /* no-exec map index */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ NOEXEC0, /* no-exec map */ NOEXEC1, NOEXEC2, NOEXEC3, NOEXEC4, PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port5", "port6", "port7", \ "noexec0", "noexec1", "noexec2", "noexec3", \ "noexec4", "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define NUM_HW_TIMERS 3 #define HW_TIMER_NAMES { "int1", "int2a", "int2b" } void xp_reset(TilemCalc* calc); void xp_stateloaded(TilemCalc* calc, int savtype); byte xp_z80_in(TilemCalc* calc, dword port); void xp_z80_out(TilemCalc* calc, dword port, byte value); void xp_z80_ptimer(TilemCalc* calc, int id); void xp_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte xp_z80_rdmem(TilemCalc* calc, dword addr); byte xp_z80_rdmem_m1(TilemCalc* calc, dword addr); dword xp_mem_ltop(TilemCalc* calc, dword addr); dword xp_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/xp/xp_init.c000066400000000000000000000035231220200411600155070ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xp.h" void xp_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x77; calc->hwregs[PORT6] = 0x1F; calc->hwregs[PORT7] = 0x1F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x1E; calc->mempagemap[2] = 0x1F; calc->mempagemap[3] = 0x1F; calc->z80.r.pc.d = 0x8000; calc->hwregs[PORT5] = 0; calc->hwregs[NOEXEC0] = 0; calc->hwregs[NOEXEC1] = 0; calc->hwregs[NOEXEC2] = 0; calc->hwregs[NOEXEC3] = 0; calc->hwregs[NOEXEC4] = 0; calc->hwregs[PROTECTSTATE] = 0; tilem_linkport_set_mode(calc, TILEM_LINK_MODE_NO_TIMEOUT); tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 8474, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 8474, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 8474, 1); } void xp_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x1E * 0x4000L), 0x15, 0x0c, 0x1f18); } tilem-2.0/emu/xp/xp_io.c000066400000000000000000000136741220200411600151630ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xp.h" byte xp_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; switch(port&0x1f) { case 0x00: case 0x08: v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); if (calc->linkport.mode & TILEM_LINK_MODE_ASSIST) v |= 0x04; if (calc->linkport.assistflags & TILEM_LINK_ASSIST_READ_BYTE) v |= 0x08; else if (calc->linkport.assistflags & TILEM_LINK_ASSIST_READ_BUSY) v |= 0x40; return(v); case 0x01: case 0x09: return(tilem_keypad_read_keys(calc)); case 0x02: case 0x0A: v = battlevel[calc->hwregs[PORT4] >> 6]; return((calc->battery >= v ? 3 : 2) | (calc->flash.unlock << 2) | (calc->hwregs[PORT5] << 3)); case 0x03: case 0x0B: return(calc->hwregs[PORT3]); case 0x04: case 0x0C: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; return(v); case 0x05: case 0x0D: return(tilem_linkport_read_byte(calc)); case 0x06: case 0x0E: return(calc->hwregs[PORT6]); case 0x07: case 0x0F: return(calc->hwregs[PORT7]); case 0x10: case 0x12: case 0x18: case 0x1A: return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: case 0x19: case 0x1B: return(tilem_lcd_t6a04_read(calc)); } return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB; if (calc->hwregs[PORT6] & 0x40) pageA = (0x20 | (calc->hwregs[PORT6] & 1)); else pageA = (calc->hwregs[PORT6] & 0x1f); if (calc->hwregs[PORT7] & 0x40) pageB = (0x20 | (calc->hwregs[PORT7] & 1)); else pageB = (calc->hwregs[PORT7] & 0x1f); if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = pageA; calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = 0x20; } } void xp_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1786, 4032, 5882, 8474 }; int t; unsigned int mode; switch(port&0x1f) { case 0x00: case 0x08: mode = calc->linkport.mode; if (value & 4) mode |= TILEM_LINK_MODE_ASSIST; else mode &= ~TILEM_LINK_MODE_ASSIST; tilem_linkport_set_mode(calc, mode); tilem_linkport_set_lines(calc, value); break; case 0x01: case 0x09: tilem_keypad_set_group(calc, value); break; case 0x03: case 0x0B: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: case 0x0C: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x05: case 0x0D: calc->hwregs[PORT5] = value & 0x07; break; case 0x06: case 0x0E: calc->hwregs[PORT6] = value & 0x7f; setup_mapping(calc); break; case 0x07: case 0x0F: calc->hwregs[PORT7] = value & 0x7f; setup_mapping(calc); break; case 0x10: case 0x12: case 0x18: case 0x1A: tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: case 0x19: case 0x1B: tilem_lcd_t6a04_write(calc, value); break; case 0x14: case 0x15: if (calc->hwregs[PROTECTSTATE] == 7) { if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); calc->flash.unlock = value&1; } break; case 0x16: case 0x17: if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) { switch(calc->hwregs[PORT5]) { case 0: tilem_message(calc, "No-exec mask for 08-0F set to %x", value); calc->hwregs[NOEXEC1] = value; break; case 1: tilem_message(calc, "No-exec mask for 10-17 set to %x", value); calc->hwregs[NOEXEC2] = value; break; case 2: tilem_message(calc, "No-exec mask for 18-1B set to %x", value); calc->hwregs[NOEXEC3] = value & 0x0f; break; case 7: tilem_message(calc, "No-exec mask for RAM set to %x", value); calc->hwregs[NOEXEC4] = (value & 1) | ((value>>4) & 2); break; } } break; } return; } void xp_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; } } tilem-2.0/emu/xp/xp_memory.c000066400000000000000000000063171220200411600160600ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xp.h" void xp_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; pa = (A & 0x3FFF) + 0x4000*calc->mempagemap[(A)>>14]; if (pa < 0x80000) tilem_flash_write_byte(calc, pa, v); else if (pa < 0x88000) *(calc->mem+pa) = v; } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; if (pa < 0x80000 && (calc->flash.state || calc->flash.busy)) value = tilem_flash_read_byte(calc, pa); else value = *(calc->mem + pa); if (pa < 0x70000 || pa >= 0x80000) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte xp_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; pa = 0x4000 * page + (A & 0x3FFF); if (TILEM_UNLIKELY(page == 0x1E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } value = readbyte(calc, pa); return (value); } byte xp_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; pa = 0x4000 * page + (A & 0x3FFF); if (TILEM_UNLIKELY(calc->hwregs[NOEXEC0+page/8] & (1<<(page%8)))) { tilem_warning(calc, "Executing in restricted %s area", page>0x1f?"RAM":"Flash"); tilem_z80_exception(calc, (page > 0x1f ? TILEM_EXC_RAM_EXEC : TILEM_EXC_FLASH_EXEC)); } if (TILEM_UNLIKELY(page == 0x1E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword xp_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; return ((page << 14) | (A & 0x3fff)); } dword xp_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; int i; for (i = 0; i < 4; i++) { if (calc->mempagemap[i] == page) { return ((i << 14) | (A & 0x3fff)); } } return (0xffffffff); } tilem-2.0/emu/xp/xp_subcore.c000066400000000000000000000045521220200411600162110ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xp.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x08000, 0}, {0x078000, 0x02000, 0}, {0x07A000, 0x02000, 0}, {0x07C000, 0x04000, 1}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; const char* xp_keynames[64] = { "Down", "Left", "Right", "Up", 0, 0, 0, 0, "Enter", "Add", "Sub", "Mul", "Div", "Power", "Clear", 0, "Chs", "3", "6", "9", "RParen", "Tan", "Vars", 0, "DecPnt", "2", "5", "8", "LParen", "Cos", "Prgm", "Stat", "0", "1", "4", "7", "Comma", "Sin", "Apps", "Graphvar", "On", "Store", "Ln", "Log", "Square", "Recip", "Math", "Alpha", "Graph", "Trace", "Zoom", "Window", "YEqu", "2nd", "Mode", "Del", 0, 0, 0, 0, 0, 0, 0, 0}; TilemHardware hardware_ti83p = { 'p', "ti83p", "TI-83 Plus", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_LINK_ASSIST | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH), 96, 64, 32 * 0x4000, 2 * 0x4000, 15 * 64, 0x40, NUM_FLASH_SECTORS, flashsectors, 0, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, xp_keynames, xp_reset, xp_stateloaded, xp_z80_in, xp_z80_out, xp_z80_wrmem, xp_z80_rdmem, xp_z80_rdmem_m1, NULL, xp_z80_ptimer, tilem_lcd_t6a04_get_data, xp_mem_ltop, xp_mem_ptol }; tilem-2.0/emu/xs/000077500000000000000000000000001220200411600136715ustar00rootroot00000000000000tilem-2.0/emu/xs/xs.h000066400000000000000000000067211220200411600145020ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_XS_H #define _TILEM_XS_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT5, /* memory mapping bank C */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ PORT8, /* link assist mode flags */ PORT9, /* unknown (link assist settings?) */ PORTA, /* unknown (timeout value?) */ PORTB, /* unknown (timeout value?) */ PORTC, /* unknown (timeout value?) */ PORTD, /* unknown */ PORTE, /* unknown */ PORTF, /* unknown */ PORT20, /* CPU speed control */ PORT21, /* hardware type / RAM no-exec control */ PORT22, /* Flash no-exec lower limit */ PORT23, /* Flash no-exec upper limit */ PORT25, /* RAM no-exec lower limit */ PORT26, /* RAM no-exec upper limit */ PORT27, /* bank C forced-page-0 limit */ PORT28, /* bank B forced-page-1 limit */ PORT29, /* LCD port delay (6 MHz) */ PORT2A, /* LCD port delay (mode 1) */ PORT2B, /* LCD port delay (mode 2) */ PORT2C, /* LCD port delay (mode 3) */ PORT2D, /* unknown */ PORT2E, /* memory delay */ PORT2F, /* Duration of LCD wait timer */ RAM_READ_DELAY, RAM_WRITE_DELAY, RAM_EXEC_DELAY, FLASH_READ_DELAY, FLASH_WRITE_DELAY, FLASH_EXEC_DELAY, LCD_PORT_DELAY, NO_EXEC_RAM_MASK, NO_EXEC_RAM_LOWER, NO_EXEC_RAM_UPPER, LCD_WAIT, /* LCD wait timer active */ PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port5", "port6", "port7", "port8", "port9", \ "portA", "portB", "portC", "portD", "portE", "portF", "port20", \ "port21", "port22", "port23", "port25", "port26", "port27", \ "port28", "port29", "port2A", "port2B", "port2C", "port2D", \ "port2E", "port2F", "ram_read_delay", "ram_write_delay", \ "ram_exec_delay", "flash_read_delay", "flash_write_delay", \ "flash_exec_delay", "lcd_port_delay", "no_exec_ram_mask", \ "no_exec_ram_lower", "no_exec_ram_upper", \ "lcd_wait", "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define TIMER_LCD_WAIT (TILEM_NUM_SYS_TIMERS + 4) #define NUM_HW_TIMERS 4 #define HW_TIMER_NAMES { "int1", "int2a", "int2b", "lcd_wait" } void xs_reset(TilemCalc* calc); void xs_stateloaded(TilemCalc* calc, int savtype); byte xs_z80_in(TilemCalc* calc, dword port); void xs_z80_out(TilemCalc* calc, dword port, byte value); void xs_z80_ptimer(TilemCalc* calc, int id); void xs_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte xs_z80_rdmem(TilemCalc* calc, dword addr); byte xs_z80_rdmem_m1(TilemCalc* calc, dword addr); dword xs_mem_ltop(TilemCalc* calc, dword addr); dword xs_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/xs/xs_init.c000066400000000000000000000050231220200411600155120ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xs.h" void xp_fix_cert(TilemCalc* calc, byte *cert); void xs_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x77; calc->hwregs[PORT6] = 0x7F; calc->hwregs[PORT7] = 0x7F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x7E; calc->mempagemap[2] = 0x7F; calc->mempagemap[3] = 0x7F; calc->z80.r.pc.d = 0x8000; calc->hwregs[PORT8] = 0x80; calc->hwregs[PORT20] = 0; calc->hwregs[PORT21] = 1; calc->hwregs[PORT22] = 0x08; calc->hwregs[PORT23] = 0x69; calc->hwregs[PORT25] = 0x10; calc->hwregs[PORT26] = 0x20; calc->hwregs[PORT27] = 0; calc->hwregs[PORT28] = 0; calc->hwregs[PORT29] = 0x14; calc->hwregs[PORT2A] = 0x27; calc->hwregs[PORT2B] = 0x2F; calc->hwregs[PORT2C] = 0x3B; calc->hwregs[PORT2D] = 0x01; calc->hwregs[PORT2E] = 0x44; calc->hwregs[PORT2F] = 0x4A; calc->hwregs[FLASH_READ_DELAY] = 0; calc->hwregs[FLASH_WRITE_DELAY] = 0; calc->hwregs[FLASH_EXEC_DELAY] = 0; calc->hwregs[RAM_READ_DELAY] = 0; calc->hwregs[RAM_WRITE_DELAY] = 0; calc->hwregs[RAM_EXEC_DELAY] = 0; calc->hwregs[LCD_PORT_DELAY] = 5; calc->hwregs[NO_EXEC_RAM_MASK] = 0x7C00; calc->hwregs[NO_EXEC_RAM_LOWER] = 0x4000; calc->hwregs[NO_EXEC_RAM_UPPER] = 0x8000; calc->hwregs[PROTECTSTATE] = 0; calc->flash.overridegroup = 1; tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 9277, 1); } void xs_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x7E * 0x4000L), 0x69, 0x0c, 0x1e50); } tilem-2.0/emu/xs/xs_io.c000066400000000000000000000320511220200411600151570ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xs.h" static void set_lcd_wait_timer(TilemCalc* calc) { static const int delaytime[8] = { 48, 112, 176, 240, 304, 368, 432, 496 }; int i; switch (calc->hwregs[PORT20] & 3) { case 0: return; case 1: i = (calc->hwregs[PORT2F] & 3); break; case 2: i = ((calc->hwregs[PORT2F] >> 2) & 7); break; default: i = ((calc->hwregs[PORT2F] >> 5) & 7); break; } tilem_z80_set_timer(calc, TIMER_LCD_WAIT, delaytime[i], 0, 0); calc->hwregs[LCD_WAIT] = 1; } byte xs_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; unsigned int f; switch(port&0xff) { case 0x00: v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); return(v); case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: v = battlevel[calc->hwregs[PORT4] >> 6]; return((calc->battery >= v ? 0xc1 : 0xc0) | (calc->hwregs[LCD_WAIT] ? 0 : 2) | (calc->flash.unlock << 2)); case 0x03: return(calc->hwregs[PORT3]); case 0x04: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; if (calc->usertimers[0].status & TILEM_USER_TIMER_FINISHED) v |= 0x20; if (calc->usertimers[1].status & TILEM_USER_TIMER_FINISHED) v |= 0x40; if (calc->usertimers[2].status & TILEM_USER_TIMER_FINISHED) v |= 0x80; return(v); case 0x05: return(calc->hwregs[PORT5] & 0x0f); case 0x06: return(calc->hwregs[PORT6]); case 0x07: return(calc->hwregs[PORT7]); case 0x08: return(calc->hwregs[PORT8]); case 0x09: f = tilem_linkport_get_assist_flags(calc); if (f & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) v = 0x00; else v = 0x20; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_READ) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_IDLE) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ERROR) v |= 0x04; if (f & TILEM_LINK_ASSIST_READ_BUSY) v |= 0x08; if (f & TILEM_LINK_ASSIST_READ_BYTE) v |= 0x10; if (f & (TILEM_LINK_ASSIST_READ_ERROR | TILEM_LINK_ASSIST_WRITE_ERROR)) v |= 0x40; if (f & TILEM_LINK_ASSIST_WRITE_BUSY) v |= 0x80; calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR; return(v); case 0x0A: v = calc->linkport.assistlastbyte; tilem_linkport_read_byte(calc); return(v); case 0x0E: return(calc->hwregs[PORTE] & 3); case 0x0F: return(calc->hwregs[PORTF] & 3); case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_read(calc)); case 0x15: return(0x33); /* ??? */ case 0x1C: return(tilem_md5_assist_get_value(calc)); case 0x1D: return(tilem_md5_assist_get_value(calc) >> 8); case 0x1E: return(tilem_md5_assist_get_value(calc) >> 16); case 0x1F: return(tilem_md5_assist_get_value(calc) >> 24); case 0x20: return(calc->hwregs[PORT20] & 3); case 0x21: return(calc->hwregs[PORT21] & 0x33); case 0x22: return(calc->hwregs[PORT22]); case 0x23: return(calc->hwregs[PORT23]); case 0x25: return(calc->hwregs[PORT25]); case 0x26: return(calc->hwregs[PORT26]); case 0x27: return(calc->hwregs[PORT27]); case 0x28: return(calc->hwregs[PORT28]); case 0x29: return(calc->hwregs[PORT29]); case 0x2A: return(calc->hwregs[PORT2A]); case 0x2B: return(calc->hwregs[PORT2B]); case 0x2C: return(calc->hwregs[PORT2C]); case 0x2D: return(calc->hwregs[PORT2D] & 3); case 0x2E: return(calc->hwregs[PORT2E]); case 0x2F: return(calc->hwregs[PORT2F]); case 0x30: return(calc->usertimers[0].frequency); case 0x31: return(calc->usertimers[0].status); case 0x32: return(tilem_user_timer_get_value(calc, 0)); case 0x33: return(calc->usertimers[1].frequency); case 0x34: return(calc->usertimers[1].status); case 0x35: return(tilem_user_timer_get_value(calc, 1)); case 0x36: return(calc->usertimers[2].frequency); case 0x37: return(calc->usertimers[2].status); case 0x38: return(tilem_user_timer_get_value(calc, 2)); case 0x0B: case 0x0C: case 0x0D: case 0x14: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: return(0); } return(0xff); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB, pageC; if (calc->hwregs[PORT6] & 0x80) pageA = (0x80 | (calc->hwregs[PORT6] & 7)); else pageA = (calc->hwregs[PORT6] & 0x7f); if (calc->hwregs[PORT7] & 0x80) pageB = (0x80 | (calc->hwregs[PORT7] & 7)); else pageB = (calc->hwregs[PORT7] & 0x7f); pageC = (0x80 | (calc->hwregs[PORT5] & 7)); if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = pageC; } } static void setup_clockdelays(TilemCalc* calc) { byte lcdport = calc->hwregs[PORT29 + (calc->hwregs[PORT20] & 3)]; byte memport = calc->hwregs[PORT2E]; if (!(lcdport & 1)) memport &= ~0x07; if (!(lcdport & 2)) memport &= ~0x70; calc->hwregs[FLASH_EXEC_DELAY] = (memport & 1); calc->hwregs[FLASH_READ_DELAY] = ((memport >> 1) & 1); calc->hwregs[FLASH_WRITE_DELAY] = ((memport >> 2) & 1); calc->hwregs[RAM_EXEC_DELAY] = ((memport >> 4) & 1); calc->hwregs[RAM_READ_DELAY] = ((memport >> 5) & 1); calc->hwregs[RAM_WRITE_DELAY] = ((memport >> 6) & 1); calc->hwregs[LCD_PORT_DELAY] = (lcdport >> 2); } void xs_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1953, 4395, 6836, 9277 }; int t, r; unsigned int mode; switch(port&0xff) { case 0x00: tilem_linkport_set_lines(calc, value); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; if (value & 0x06) { calc->usertimers[0].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status &= ~TILEM_USER_TIMER_NO_HALT_INT; } else { calc->usertimers[0].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status |= TILEM_USER_TIMER_NO_HALT_INT; } mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x05: calc->hwregs[PORT5] = value & 0x0f; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: calc->hwregs[PORT7] = value; setup_mapping(calc); break; case 0x08: calc->hwregs[PORT8] = value; mode = calc->linkport.mode; if (value & 0x01) mode |= TILEM_LINK_MODE_INT_ON_READ; else mode &= ~TILEM_LINK_MODE_INT_ON_READ; if (value & 0x02) mode |= TILEM_LINK_MODE_INT_ON_IDLE; else mode &= ~TILEM_LINK_MODE_INT_ON_IDLE; if (value & 0x04) mode |= TILEM_LINK_MODE_INT_ON_ERROR; else mode &= ~TILEM_LINK_MODE_INT_ON_ERROR; if (value & 0x80) mode &= ~TILEM_LINK_MODE_ASSIST; else mode |= TILEM_LINK_MODE_ASSIST; tilem_linkport_set_mode(calc, mode); break; case 0x09: calc->hwregs[PORT9] = value; break; case 0x0A: calc->hwregs[PORTA] = value; break; case 0x0B: calc->hwregs[PORTB] = value; break; case 0x0C: calc->hwregs[PORTC] = value; break; case 0x0D: if (!(calc->hwregs[PORT8] & 0x80)) tilem_linkport_write_byte(calc, value); break; case 0x0E: calc->hwregs[PORTE] = value; break; case 0x0F: calc->hwregs[PORTF] = value; break; case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_write(calc, value); break; case 0x14: if (calc->hwregs[PROTECTSTATE] == 7) { if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); calc->flash.unlock = value&1; } else { tilem_warning(calc, "Writing to protected port 14"); } break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: r = (port & 0xff) - 0x18; calc->md5assist.regs[r] >>= 8; calc->md5assist.regs[r] |= (value << 24); break; case 0x1E: calc->md5assist.shift = value & 0x1f; break; case 0x1F: calc->md5assist.mode = value & 3; break; case 0x20: calc->hwregs[PORT20] = value; if (value & 3) { tilem_z80_set_speed(calc, 15000); } else { tilem_z80_set_speed(calc, 6000); } setup_clockdelays(calc); break; case 0x21: if (calc->flash.unlock) { calc->hwregs[PORT21] = value; t = (value >> 4) & 3; calc->hwregs[NO_EXEC_RAM_MASK] = (0x8000 << t) - 0x400; calc->flash.overridegroup = value & 3; } else { tilem_warning(calc, "Writing to protected port 21"); } break; case 0x22: if (calc->flash.unlock) { calc->hwregs[PORT22] = value; } else { tilem_warning(calc, "Writing to protected port 22"); } break; case 0x23: if (calc->flash.unlock) { calc->hwregs[PORT23] = value; } else { tilem_warning(calc, "Writing to protected port 23"); } break; case 0x25: if (calc->flash.unlock) { calc->hwregs[PORT25] = value; calc->hwregs[NO_EXEC_RAM_LOWER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 25"); } break; case 0x26: if (calc->flash.unlock) { calc->hwregs[PORT26] = value; calc->hwregs[NO_EXEC_RAM_UPPER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 26"); } break; case 0x27: calc->hwregs[PORT27] = value; break; case 0x28: calc->hwregs[PORT28] = value; break; case 0x29: calc->hwregs[PORT29] = value; setup_clockdelays(calc); break; case 0x2A: calc->hwregs[PORT2A] = value; setup_clockdelays(calc); break; case 0x2B: calc->hwregs[PORT2B] = value; setup_clockdelays(calc); break; case 0x2C: calc->hwregs[PORT2C] = value; setup_clockdelays(calc); break; case 0x2D: calc->hwregs[PORT2D] = value; setup_clockdelays(calc); break; case 0x2E: calc->hwregs[PORT2E] = value; setup_clockdelays(calc); break; case 0x2F: calc->hwregs[PORT2F] = value; break; case 0x30: tilem_user_timer_set_frequency(calc, 0, value); break; case 0x31: tilem_user_timer_set_mode(calc, 0, value); break; case 0x32: tilem_user_timer_start(calc, 0, value); break; case 0x33: tilem_user_timer_set_frequency(calc, 1, value); break; case 0x34: tilem_user_timer_set_mode(calc, 1, value); break; case 0x35: tilem_user_timer_start(calc, 1, value); break; case 0x36: tilem_user_timer_set_frequency(calc, 2, value); break; case 0x37: tilem_user_timer_set_mode(calc, 2, value); break; case 0x38: tilem_user_timer_start(calc, 2, value); break; } return; } void xs_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; case TIMER_LCD_WAIT: calc->hwregs[LCD_WAIT] = 0; break; } } tilem-2.0/emu/xs/xs_memory.c000066400000000000000000000121171220200411600160610ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xs.h" /* FIXME: what effect, if any, do ports 27 and 28 have in memory mapping mode 1? */ void xs_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; byte page; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } pa = (A & 0x3FFF) + 0x4000L*page; if (pa<0x200000) { calc->z80.clock += calc->hwregs[FLASH_WRITE_DELAY]; tilem_flash_write_byte(calc, pa, v); } else if (pa < 0x220000) { calc->z80.clock += calc->hwregs[RAM_WRITE_DELAY]; *(calc->mem+pa) = v; } } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; if (pa < 0x200000 && (calc->flash.state || calc->flash.busy)) value = tilem_flash_read_byte(calc, pa); else value = *(calc->mem + pa); if (pa < 0x1F0000 || pa >= 0x200000) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte xs_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) calc->z80.clock += calc->hwregs[FLASH_READ_DELAY]; else calc->z80.clock += calc->hwregs[RAM_READ_DELAY]; value = readbyte(calc, pa); return (value); } byte xs_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa, m; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) { calc->z80.clock += calc->hwregs[FLASH_EXEC_DELAY]; if (TILEM_UNLIKELY(page >= calc->hwregs[PORT22] && page <= calc->hwregs[PORT23])) { tilem_warning(calc, "Executing in restricted Flash area"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } } else { calc->z80.clock += calc->hwregs[RAM_EXEC_DELAY]; /* Note: this isn't quite strict enough; when port 21 is set to 30h, the "ghost" RAM pages 88-8F are treated as distinct pages for restriction purposes. This detail probably isn't worth emulating. */ m = pa & calc->hwregs[NO_EXEC_RAM_MASK]; if (TILEM_UNLIKELY(m < calc->hwregs[NO_EXEC_RAM_LOWER] || m > calc->hwregs[NO_EXEC_RAM_UPPER])) { tilem_warning(calc, "Executing in restricted RAM area"); tilem_z80_exception(calc, TILEM_EXC_RAM_EXEC); } } value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword xs_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } return ((page << 14) | (A & 0x3fff)); } dword xs_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; if (!page) return (A & 0x3fff); if (page == calc->mempagemap[1]) return (0x4000 | (A & 0x3fff)); if ((A & 0x3fff) < 64 * calc->hwregs[PORT28]) { if (page == 0x81) return (0x8000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[2]) return (0x8000 | (A & 0x3fff)); } if ((A & 0x3fff) >= (0x4000 - 64 * calc->hwregs[PORT27])) { if (page == 0x80) return (0xC000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[3]) return (0xC000 | (A & 0x3fff)); } return (0xffffffff); } tilem-2.0/emu/xs/xs_subcore.c000066400000000000000000000050711220200411600162140ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xs.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x10000, 0}, {0x080000, 0x10000, 0}, {0x090000, 0x10000, 0}, {0x0A0000, 0x10000, 0}, {0x0B0000, 0x10000, 0}, {0x0C0000, 0x10000, 0}, {0x0D0000, 0x10000, 0}, {0x0E0000, 0x10000, 0}, {0x0F0000, 0x10000, 0}, {0x100000, 0x10000, 0}, {0x110000, 0x10000, 0}, {0x120000, 0x10000, 0}, {0x130000, 0x10000, 0}, {0x140000, 0x10000, 0}, {0x150000, 0x10000, 0}, {0x160000, 0x10000, 0}, {0x170000, 0x10000, 0}, {0x180000, 0x10000, 0}, {0x190000, 0x10000, 0}, {0x1A0000, 0x10000, 0}, {0x1B0000, 0x10000, 0}, {0x1C0000, 0x10000, 0}, {0x1D0000, 0x10000, 0}, {0x1E0000, 0x10000, 0}, {0x1F0000, 0x08000, 0}, {0x1F8000, 0x02000, 0}, {0x1FA000, 0x02000, 0}, {0x1FC000, 0x04000, 2}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; extern const char* xp_keynames[]; TilemHardware hardware_ti83pse = { 's', "ti83pse", "TI-83 Plus Silver Edition", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_LINK_ASSIST | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH | TILEM_CALC_HAS_MD5_ASSIST), 96, 64, 128 * 0x4000, 8 * 0x4000, 16 * 64, 0x80, NUM_FLASH_SECTORS, flashsectors, 3, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, xp_keynames, xs_reset, xs_stateloaded, xs_z80_in, xs_z80_out, xs_z80_wrmem, xs_z80_rdmem, xs_z80_rdmem_m1, NULL, xs_z80_ptimer, tilem_lcd_t6a04_get_data, xs_mem_ltop, xs_mem_ptol }; tilem-2.0/emu/xz/000077500000000000000000000000001220200411600137005ustar00rootroot00000000000000tilem-2.0/emu/xz/xz.h000066400000000000000000000071701220200411600145170ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_XZ_H #define _TILEM_XZ_H enum { PORT3, /* mask of enabled interrupts */ PORT4, /* interrupt timer speed */ PORT5, /* memory mapping bank C */ PORT6, /* memory mapping bank A */ PORT7, /* memory mapping bank B */ PORT8, /* link assist mode flags */ PORT9, /* unknown (link assist settings?) */ PORTA, /* unknown (timeout value?) */ PORTB, /* unknown (timeout value?) */ PORTC, /* unknown (timeout value?) */ PORTD, /* unknown */ PORTE, /* unknown */ PORTF, /* unknown */ PORT20, /* CPU speed control */ PORT21, /* hardware type / RAM no-exec control */ PORT22, /* Flash no-exec lower limit */ PORT23, /* Flash no-exec upper limit */ PORT25, /* RAM no-exec lower limit */ PORT26, /* RAM no-exec upper limit */ PORT27, /* bank C forced-page-0 limit */ PORT28, /* bank B forced-page-1 limit */ PORT29, /* LCD port delay (6 MHz) */ PORT2A, /* LCD port delay (mode 1) */ PORT2B, /* LCD port delay (mode 2) */ PORT2C, /* LCD port delay (mode 3) */ PORT2D, /* unknown */ PORT2E, /* memory delay */ PORT2F, /* Duration of LCD wait timer */ CLOCK_MODE, /* clock mode */ CLOCK_INPUT, /* clock input register */ CLOCK_DIFF, /* clock value minus actual time */ RAM_READ_DELAY, RAM_WRITE_DELAY, RAM_EXEC_DELAY, FLASH_READ_DELAY, FLASH_WRITE_DELAY, FLASH_EXEC_DELAY, LCD_PORT_DELAY, NO_EXEC_RAM_MASK, NO_EXEC_RAM_LOWER, NO_EXEC_RAM_UPPER, LCD_WAIT, /* LCD wait timer active */ PROTECTSTATE, /* port protection state */ NUM_HW_REGS }; #define HW_REG_NAMES \ { "port3", "port4", "port5", "port6", "port7", "port8", "port9", \ "portA", "portB", "portC", "portD", "portE", "portF", "port20", \ "port21", "port22", "port23", "port25", "port26", "port27", \ "port28", "port29", "port2A", "port2B", "port2C", "port2D", \ "port2E", "port2F", "clock_mode", "clock_input", "clock_diff", \ "ram_read_delay", "ram_write_delay", "ram_exec_delay", \ "flash_read_delay", "flash_write_delay", "flash_exec_delay", \ "lcd_port_delay", "no_exec_ram_mask", "no_exec_ram_lower", \ "no_exec_ram_upper", "lcd_wait", "protectstate" } #define TIMER_INT1 (TILEM_NUM_SYS_TIMERS + 1) #define TIMER_INT2A (TILEM_NUM_SYS_TIMERS + 2) #define TIMER_INT2B (TILEM_NUM_SYS_TIMERS + 3) #define TIMER_LCD_WAIT (TILEM_NUM_SYS_TIMERS + 4) #define NUM_HW_TIMERS 4 #define HW_TIMER_NAMES { "int1", "int2a", "int2b", "lcd_wait" } void xz_reset(TilemCalc* calc); void xz_stateloaded(TilemCalc* calc, int savtype); byte xz_z80_in(TilemCalc* calc, dword port); void xz_z80_out(TilemCalc* calc, dword port, byte value); void xz_z80_ptimer(TilemCalc* calc, int id); void xz_z80_wrmem(TilemCalc* calc, dword addr, byte value); byte xz_z80_rdmem(TilemCalc* calc, dword addr); byte xz_z80_rdmem_m1(TilemCalc* calc, dword addr); dword xz_mem_ltop(TilemCalc* calc, dword addr); dword xz_mem_ptol(TilemCalc* calc, dword addr); #endif tilem-2.0/emu/xz/xz_init.c000066400000000000000000000047431220200411600155400ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xz.h" void xz_reset(TilemCalc* calc) { calc->hwregs[PORT3] = 0x0B; calc->hwregs[PORT4] = 0x07; calc->hwregs[PORT6] = 0x7F; calc->hwregs[PORT7] = 0x7F; calc->mempagemap[0] = 0x00; calc->mempagemap[1] = 0x7E; calc->mempagemap[2] = 0x7F; calc->mempagemap[3] = 0x7F; calc->z80.r.pc.d = 0x8000; calc->hwregs[PORT8] = 0x80; calc->hwregs[PORT20] = 0; calc->hwregs[PORT21] = 1; calc->hwregs[PORT22] = 0x08; calc->hwregs[PORT23] = 0x69; calc->hwregs[PORT25] = 0x10; calc->hwregs[PORT26] = 0x20; calc->hwregs[PORT27] = 0; calc->hwregs[PORT28] = 0; calc->hwregs[PORT29] = 0x14; calc->hwregs[PORT2A] = 0x27; calc->hwregs[PORT2B] = 0x2F; calc->hwregs[PORT2C] = 0x3B; calc->hwregs[PORT2D] = 0x01; calc->hwregs[PORT2E] = 0x44; calc->hwregs[PORT2F] = 0x4A; calc->hwregs[FLASH_READ_DELAY] = 0; calc->hwregs[FLASH_WRITE_DELAY] = 0; calc->hwregs[FLASH_EXEC_DELAY] = 0; calc->hwregs[RAM_READ_DELAY] = 0; calc->hwregs[RAM_WRITE_DELAY] = 0; calc->hwregs[RAM_EXEC_DELAY] = 0; calc->hwregs[LCD_PORT_DELAY] = 5; calc->hwregs[NO_EXEC_RAM_MASK] = 0x7C00; calc->hwregs[NO_EXEC_RAM_LOWER] = 0x4000; calc->hwregs[NO_EXEC_RAM_UPPER] = 0x8000; calc->hwregs[PROTECTSTATE] = 0; calc->flash.overridegroup = 1; tilem_z80_set_speed(calc, 6000); tilem_z80_set_timer(calc, TIMER_INT1, 1600, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2A, 1300, 9277, 1); tilem_z80_set_timer(calc, TIMER_INT2B, 1000, 9277, 1); } void xz_stateloaded(TilemCalc* calc, int savtype TILEM_ATTR_UNUSED) { tilem_calc_fix_certificate(calc, calc->mem + (0x7E * 0x4000L), 0x69, 0x0c, 0x1e50); } tilem-2.0/emu/xz/xz_io.c000066400000000000000000000353061220200411600152030ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "xz.h" static void set_lcd_wait_timer(TilemCalc* calc) { static const int delaytime[8] = { 48, 112, 176, 240, 304, 368, 432, 496 }; int i; switch (calc->hwregs[PORT20] & 3) { case 0: return; case 1: i = (calc->hwregs[PORT2F] & 3); break; case 2: i = ((calc->hwregs[PORT2F] >> 2) & 7); break; default: i = ((calc->hwregs[PORT2F] >> 5) & 7); break; } tilem_z80_set_timer(calc, TIMER_LCD_WAIT, delaytime[i], 0, 0); calc->hwregs[LCD_WAIT] = 1; } byte xz_z80_in(TilemCalc* calc, dword port) { /* FIXME: measure actual levels */ static const byte battlevel[4] = { 33, 39, 36, 43 }; byte v; unsigned int f; time_t curtime; switch(port&0xff) { case 0x00: v = tilem_linkport_get_lines(calc); v |= (calc->linkport.lines << 4); return(v); case 0x01: return(tilem_keypad_read_keys(calc)); case 0x02: v = battlevel[calc->hwregs[PORT4] >> 6]; return ((calc->battery >= v ? 0xe1 : 0xe0) | (calc->hwregs[LCD_WAIT] ? 0 : 2) | (calc->flash.unlock << 2)); case 0x03: return(calc->hwregs[PORT3]); case 0x04: v = (calc->keypad.onkeydown ? 0x00 : 0x08); if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2) v |= 0x04; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE) v |= 0x10; if (calc->usertimers[0].status & TILEM_USER_TIMER_FINISHED) v |= 0x20; if (calc->usertimers[1].status & TILEM_USER_TIMER_FINISHED) v |= 0x40; if (calc->usertimers[2].status & TILEM_USER_TIMER_FINISHED) v |= 0x80; return(v); case 0x05: return(calc->hwregs[PORT5] & 0x0f); case 0x06: return(calc->hwregs[PORT6]); case 0x07: return(calc->hwregs[PORT7]); case 0x08: return(calc->hwregs[PORT8]); case 0x09: f = tilem_linkport_get_assist_flags(calc); if (f & (TILEM_LINK_ASSIST_READ_BUSY | TILEM_LINK_ASSIST_WRITE_BUSY)) v = 0x00; else v = 0x20; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_READ) v |= 0x01; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_IDLE) v |= 0x02; if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ERROR) v |= 0x04; if (f & TILEM_LINK_ASSIST_READ_BUSY) v |= 0x08; if (f & TILEM_LINK_ASSIST_READ_BYTE) v |= 0x10; if (f & (TILEM_LINK_ASSIST_READ_ERROR | TILEM_LINK_ASSIST_WRITE_ERROR)) v |= 0x40; if (f & TILEM_LINK_ASSIST_WRITE_BUSY) v |= 0x80; calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR; return(v); case 0x0A: v = calc->linkport.assistlastbyte; tilem_linkport_read_byte(calc); return(v); case 0x0E: return(calc->hwregs[PORTE] & 3); case 0x0F: return(calc->hwregs[PORTF] & 3); case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_status(calc)); case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); return(tilem_lcd_t6a04_read(calc)); case 0x15: return(0x45); /* ??? */ case 0x1C: return(tilem_md5_assist_get_value(calc)); case 0x1D: return(tilem_md5_assist_get_value(calc) >> 8); case 0x1E: return(tilem_md5_assist_get_value(calc) >> 16); case 0x1F: return(tilem_md5_assist_get_value(calc) >> 24); case 0x20: return(calc->hwregs[PORT20] & 3); case 0x21: return(calc->hwregs[PORT21] & 0x33); case 0x22: return(calc->hwregs[PORT22]); case 0x23: return(calc->hwregs[PORT23]); case 0x25: return(calc->hwregs[PORT25]); case 0x26: return(calc->hwregs[PORT26]); case 0x27: return(calc->hwregs[PORT27]); case 0x28: return(calc->hwregs[PORT28]); case 0x29: return(calc->hwregs[PORT29]); case 0x2A: return(calc->hwregs[PORT2A]); case 0x2B: return(calc->hwregs[PORT2B]); case 0x2C: return(calc->hwregs[PORT2C]); case 0x2D: return(calc->hwregs[PORT2D] & 3); case 0x2E: return(calc->hwregs[PORT2E]); case 0x2F: return(calc->hwregs[PORT2F]); case 0x30: return(calc->usertimers[0].frequency); case 0x31: return(calc->usertimers[0].status); case 0x32: return(tilem_user_timer_get_value(calc, 0)); case 0x33: return(calc->usertimers[1].frequency); case 0x34: return(calc->usertimers[1].status); case 0x35: return(tilem_user_timer_get_value(calc, 1)); case 0x36: return(calc->usertimers[2].frequency); case 0x37: return(calc->usertimers[2].status); case 0x38: return(tilem_user_timer_get_value(calc, 2)); case 0x39: return(0xf0); /* ??? */ case 0x40: return calc->hwregs[CLOCK_MODE]; case 0x41: return calc->hwregs[CLOCK_INPUT]&0xff; case 0x42: return (calc->hwregs[CLOCK_INPUT]>>8)&0xff; case 0x43: return (calc->hwregs[CLOCK_INPUT]>>16)&0xff; case 0x44: return (calc->hwregs[CLOCK_INPUT]>>24)&0xff; case 0x45: case 0x46: case 0x47: case 0x48: if (calc->hwregs[CLOCK_MODE] & 1) { time(&curtime); } else { curtime = 0; } curtime += calc->hwregs[CLOCK_DIFF]; return (curtime >> ((port - 0x45) * 8)); case 0x4C: return(0x22); case 0x4D: /* USB port - not emulated, calculator should recognize that the USB cable is disconnected. Thanks go to Dan Englender for these values. */ return(0xA5); case 0x55: return(0x1F); case 0x56: return(0x00); case 0x57: return(0x50); case 0x0B: case 0x0C: case 0x0D: case 0x14: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: return(0); } tilem_warning(calc, "Input from port %x", port); return(0x00); } static void setup_mapping(TilemCalc* calc) { unsigned int pageA, pageB, pageC; if (calc->hwregs[PORT6] & 0x80) pageA = (0x80 | (calc->hwregs[PORT6] & 7)); else pageA = (calc->hwregs[PORT6] & 0x7f); if (calc->hwregs[PORT7] & 0x80) pageB = (0x80 | (calc->hwregs[PORT7] & 7)); else pageB = (calc->hwregs[PORT7] & 0x7f); pageC = (0x80 | (calc->hwregs[PORT5] & 7)); if (calc->hwregs[PORT4] & 1) { calc->mempagemap[1] = (pageA & ~1); calc->mempagemap[2] = (pageA | 1); calc->mempagemap[3] = pageB; } else { calc->mempagemap[1] = pageA; calc->mempagemap[2] = pageB; calc->mempagemap[3] = pageC; } } static void setup_clockdelays(TilemCalc* calc) { byte lcdport = calc->hwregs[PORT29 + (calc->hwregs[PORT20] & 3)]; byte memport = calc->hwregs[PORT2E]; if (!(lcdport & 1)) memport &= ~0x07; if (!(lcdport & 2)) memport &= ~0x70; calc->hwregs[FLASH_EXEC_DELAY] = (memport & 1); calc->hwregs[FLASH_READ_DELAY] = ((memport >> 1) & 1); calc->hwregs[FLASH_WRITE_DELAY] = ((memport >> 2) & 1); calc->hwregs[RAM_EXEC_DELAY] = ((memport >> 4) & 1); calc->hwregs[RAM_READ_DELAY] = ((memport >> 5) & 1); calc->hwregs[RAM_WRITE_DELAY] = ((memport >> 6) & 1); calc->hwregs[LCD_PORT_DELAY] = (lcdport >> 2); } void xz_z80_out(TilemCalc* calc, dword port, byte value) { static const int tmrvalues[4] = { 1953, 4395, 6836, 9277 }; int t, r; unsigned int mode; time_t curtime; switch(port&0xff) { case 0x00: tilem_linkport_set_lines(calc, value); break; case 0x01: tilem_keypad_set_group(calc, value); break; case 0x03: if (value & 0x01) { calc->keypad.onkeyint = 1; } else { calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY; calc->keypad.onkeyint = 0; } if (!(value & 0x02)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1; if (!(value & 0x04)) calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2; if (value & 0x06) { calc->usertimers[0].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status &= ~TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status &= ~TILEM_USER_TIMER_NO_HALT_INT; } else { calc->usertimers[0].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[1].status |= TILEM_USER_TIMER_NO_HALT_INT; calc->usertimers[2].status |= TILEM_USER_TIMER_NO_HALT_INT; } mode = calc->linkport.mode; if (value & 0x10) mode |= TILEM_LINK_MODE_INT_ON_ACTIVE; else mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE; tilem_linkport_set_mode(calc, mode); calc->poweronhalt = ((value & 8) >> 3); calc->hwregs[PORT3] = value; break; case 0x04: calc->hwregs[PORT4] = value; t = tmrvalues[(value & 6) >> 1]; tilem_z80_set_timer_period(calc, TIMER_INT1, t); tilem_z80_set_timer_period(calc, TIMER_INT2A, t); tilem_z80_set_timer_period(calc, TIMER_INT2B, t); setup_mapping(calc); break; case 0x05: calc->hwregs[PORT5] = value & 0x0f; setup_mapping(calc); break; case 0x06: calc->hwregs[PORT6] = value; setup_mapping(calc); break; case 0x07: calc->hwregs[PORT7] = value; setup_mapping(calc); break; case 0x08: calc->hwregs[PORT8] = value; mode = calc->linkport.mode; if (value & 0x01) mode |= TILEM_LINK_MODE_INT_ON_READ; else mode &= ~TILEM_LINK_MODE_INT_ON_READ; if (value & 0x02) mode |= TILEM_LINK_MODE_INT_ON_IDLE; else mode &= ~TILEM_LINK_MODE_INT_ON_IDLE; if (value & 0x04) mode |= TILEM_LINK_MODE_INT_ON_ERROR; else mode &= ~TILEM_LINK_MODE_INT_ON_ERROR; if (value & 0x80) mode &= ~TILEM_LINK_MODE_ASSIST; else mode |= TILEM_LINK_MODE_ASSIST; tilem_linkport_set_mode(calc, mode); break; case 0x09: calc->hwregs[PORT9] = value; break; case 0x0A: calc->hwregs[PORTA] = value; break; case 0x0B: calc->hwregs[PORTB] = value; break; case 0x0C: calc->hwregs[PORTC] = value; break; case 0x0D: if (!(calc->hwregs[PORT8] & 0x80)) tilem_linkport_write_byte(calc, value); break; case 0x0E: calc->hwregs[PORTE] = value; break; case 0x0F: calc->hwregs[PORTF] = value; break; case 0x10: case 0x12: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_control(calc, value); break; case 0x11: case 0x13: calc->z80.clock += calc->hwregs[LCD_PORT_DELAY]; set_lcd_wait_timer(calc); tilem_lcd_t6a04_write(calc, value); break; case 0x14: if (calc->hwregs[PROTECTSTATE] == 7) { if (value & 1) tilem_message(calc, "Flash unlocked"); else tilem_message(calc, "Flash locked"); calc->flash.unlock = value&1; } else { tilem_warning(calc, "Writing to protected port 14"); } break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: r = (port & 0xff) - 0x18; calc->md5assist.regs[r] >>= 8; calc->md5assist.regs[r] |= (value << 24); break; case 0x1E: calc->md5assist.shift = value & 0x1f; break; case 0x1F: calc->md5assist.mode = value & 3; break; case 0x20: calc->hwregs[PORT20] = value; if (value & 3) { tilem_z80_set_speed(calc, 15000); } else { tilem_z80_set_speed(calc, 6000); } setup_clockdelays(calc); break; case 0x21: if (calc->flash.unlock) { calc->hwregs[PORT21] = value; t = (value >> 4) & 3; calc->hwregs[NO_EXEC_RAM_MASK] = (0x8000 << t) - 0x400; calc->flash.overridegroup = value & 3; } else { tilem_warning(calc, "Writing to protected port 21"); } break; case 0x22: if (calc->flash.unlock) { calc->hwregs[PORT22] = value; } else { tilem_warning(calc, "Writing to protected port 22"); } break; case 0x23: if (calc->flash.unlock) { calc->hwregs[PORT23] = value; } else { tilem_warning(calc, "Writing to protected port 23"); } break; case 0x25: if (calc->flash.unlock) { calc->hwregs[PORT25] = value; calc->hwregs[NO_EXEC_RAM_LOWER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 25"); } break; case 0x26: if (calc->flash.unlock) { calc->hwregs[PORT26] = value; calc->hwregs[NO_EXEC_RAM_UPPER] = value * 0x400; } else { tilem_warning(calc, "Writing to protected port 26"); } break; case 0x27: calc->hwregs[PORT27] = value; break; case 0x28: calc->hwregs[PORT28] = value; break; case 0x29: calc->hwregs[PORT29] = value; setup_clockdelays(calc); break; case 0x2A: calc->hwregs[PORT2A] = value; setup_clockdelays(calc); break; case 0x2B: calc->hwregs[PORT2B] = value; setup_clockdelays(calc); break; case 0x2C: calc->hwregs[PORT2C] = value; setup_clockdelays(calc); break; case 0x2D: calc->hwregs[PORT2D] = value; break; case 0x2E: calc->hwregs[PORT2E] = value; setup_clockdelays(calc); break; case 0x2F: calc->hwregs[PORT2F] = value; break; case 0x30: tilem_user_timer_set_frequency(calc, 0, value); break; case 0x31: tilem_user_timer_set_mode(calc, 0, value); break; case 0x32: tilem_user_timer_start(calc, 0, value); break; case 0x33: tilem_user_timer_set_frequency(calc, 1, value); break; case 0x34: tilem_user_timer_set_mode(calc, 1, value); break; case 0x35: tilem_user_timer_start(calc, 1, value); break; case 0x36: tilem_user_timer_set_frequency(calc, 2, value); break; case 0x37: tilem_user_timer_set_mode(calc, 2, value); break; case 0x38: tilem_user_timer_start(calc, 2, value); break; case 0x40: time(&curtime); if ((calc->hwregs[CLOCK_MODE] & 1) != (value & 1)) { if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; else calc->hwregs[CLOCK_DIFF] += curtime; } if (!(calc->hwregs[CLOCK_MODE] & 2) && (value & 2)) { calc->hwregs[CLOCK_DIFF] = calc->hwregs[CLOCK_INPUT]; if (value & 1) calc->hwregs[CLOCK_DIFF] -= curtime; } calc->hwregs[CLOCK_MODE] = value & 3; break; case 0x41: calc->hwregs[CLOCK_INPUT] &= 0xffffff00; calc->hwregs[CLOCK_INPUT] |= value; break; case 0x42: calc->hwregs[CLOCK_INPUT] &= 0xffff00ff; calc->hwregs[CLOCK_INPUT] |= (value << 8); break; case 0x43: calc->hwregs[CLOCK_INPUT] &= 0xff00ffff; calc->hwregs[CLOCK_INPUT] |= (value << 16); break; case 0x44: calc->hwregs[CLOCK_INPUT] &= 0x00ffffff; calc->hwregs[CLOCK_INPUT] |= (value << 24); break; } return; } void xz_z80_ptimer(TilemCalc* calc, int id) { switch (id) { case TIMER_INT1: if (calc->hwregs[PORT3] & 0x02) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1; break; case TIMER_INT2A: case TIMER_INT2B: if (calc->hwregs[PORT3] & 0x04) calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2; break; case TIMER_LCD_WAIT: calc->hwregs[LCD_WAIT] = 0; break; } } tilem-2.0/emu/xz/xz_memory.c000066400000000000000000000115121220200411600160750ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xz.h" void xz_z80_wrmem(TilemCalc* calc, dword A, byte v) { unsigned long pa; byte page; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) { calc->z80.clock += calc->hwregs[FLASH_WRITE_DELAY]; tilem_flash_write_byte(calc, pa, v); } else if (pa < 0x220000) { calc->z80.clock += calc->hwregs[RAM_WRITE_DELAY]; *(calc->mem+pa) = v; } } static inline byte readbyte(TilemCalc* calc, dword pa) { static const byte protectbytes[6] = {0x00,0x00,0xed,0x56,0xf3,0xd3}; int state = calc->hwregs[PROTECTSTATE]; byte value; if (pa < 0x200000 && (calc->flash.state || calc->flash.busy)) value = tilem_flash_read_byte(calc, pa); else value = *(calc->mem + pa); if (pa < 0x1B0000 || pa >= 0x200000 || (pa >= 0x1C0000 && pa < 0x1F0000)) calc->hwregs[PROTECTSTATE] = 0; else if (state == 6) calc->hwregs[PROTECTSTATE] = 7; else if (state < 6 && value == protectbytes[state]) calc->hwregs[PROTECTSTATE] = state + 1; else calc->hwregs[PROTECTSTATE] = 0; return (value); } byte xz_z80_rdmem(TilemCalc* calc, dword A) { byte page; unsigned long pa; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) calc->z80.clock += calc->hwregs[FLASH_READ_DELAY]; else calc->z80.clock += calc->hwregs[RAM_READ_DELAY]; value = readbyte(calc, pa); return (value); } byte xz_z80_rdmem_m1(TilemCalc* calc, dword A) { byte page; unsigned long pa, m; byte value; page = calc->mempagemap[A>>14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } if (TILEM_UNLIKELY(page == 0x7E && !calc->flash.unlock)) { tilem_warning(calc, "Reading from read-protected sector"); return (0xff); } pa = (A & 0x3FFF) + 0x4000L*page; if (pa < 0x200000) { calc->z80.clock += calc->hwregs[FLASH_EXEC_DELAY]; if (TILEM_UNLIKELY(page >= calc->hwregs[PORT22] && page <= calc->hwregs[PORT23])) { tilem_warning(calc, "Executing in restricted Flash area"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } } else { calc->z80.clock += calc->hwregs[RAM_EXEC_DELAY]; m = pa & calc->hwregs[NO_EXEC_RAM_MASK]; if (TILEM_UNLIKELY(m < calc->hwregs[NO_EXEC_RAM_LOWER] || m > calc->hwregs[NO_EXEC_RAM_UPPER])) { tilem_warning(calc, "Executing in restricted RAM area"); tilem_z80_exception(calc, TILEM_EXC_RAM_EXEC); } } value = readbyte(calc, pa); if (TILEM_UNLIKELY(value == 0xff && A == 0x0038)) { tilem_warning(calc, "No OS installed"); tilem_z80_exception(calc, TILEM_EXC_FLASH_EXEC); } return (value); } dword xz_mem_ltop(TilemCalc* calc, dword A) { byte page = calc->mempagemap[A >> 14]; if (A & 0x8000) { if (A > (0xFFFF - 64 * calc->hwregs[PORT27])) page = 0x80; else if (A < (0x8000 + 64 * calc->hwregs[PORT28])) page = 0x81; } return ((page << 14) | (A & 0x3fff)); } dword xz_mem_ptol(TilemCalc* calc, dword A) { byte page = A >> 14; if (!page) return (A & 0x3fff); if (page == calc->mempagemap[1]) return (0x4000 | (A & 0x3fff)); if ((A & 0x3fff) < 64 * calc->hwregs[PORT28]) { if (page == 0x81) return (0x8000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[2]) return (0x8000 | (A & 0x3fff)); } if ((A & 0x3fff) >= (0x4000 - 64 * calc->hwregs[PORT27])) { if (page == 0x80) return (0xC000 | (A & 0x3fff)); } else { if (page == calc->mempagemap[3]) return (0xC000 | (A & 0x3fff)); } return (0xffffffff); } tilem-2.0/emu/xz/xz_subcore.c000066400000000000000000000050711220200411600162320ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2001 Solignac Julien * Copyright (C) 2004-2012 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "xz.h" static const TilemFlashSector flashsectors[] = { {0x000000, 0x10000, 0}, {0x010000, 0x10000, 0}, {0x020000, 0x10000, 0}, {0x030000, 0x10000, 0}, {0x040000, 0x10000, 0}, {0x050000, 0x10000, 0}, {0x060000, 0x10000, 0}, {0x070000, 0x10000, 0}, {0x080000, 0x10000, 0}, {0x090000, 0x10000, 0}, {0x0A0000, 0x10000, 0}, {0x0B0000, 0x10000, 0}, {0x0C0000, 0x10000, 0}, {0x0D0000, 0x10000, 0}, {0x0E0000, 0x10000, 0}, {0x0F0000, 0x10000, 0}, {0x100000, 0x10000, 0}, {0x110000, 0x10000, 0}, {0x120000, 0x10000, 0}, {0x130000, 0x10000, 0}, {0x140000, 0x10000, 0}, {0x150000, 0x10000, 0}, {0x160000, 0x10000, 0}, {0x170000, 0x10000, 0}, {0x180000, 0x10000, 0}, {0x190000, 0x10000, 0}, {0x1A0000, 0x10000, 0}, {0x1B0000, 0x10000, 2}, {0x1C0000, 0x10000, 0}, {0x1D0000, 0x10000, 0}, {0x1E0000, 0x10000, 0}, {0x1F0000, 0x08000, 0}, {0x1F8000, 0x02000, 0}, {0x1FA000, 0x02000, 0}, {0x1FC000, 0x04000, 2}}; #define NUM_FLASH_SECTORS (sizeof(flashsectors) / sizeof(TilemFlashSector)) static const char* hwregnames[NUM_HW_REGS] = HW_REG_NAMES; static const char* hwtimernames[NUM_HW_TIMERS] = HW_TIMER_NAMES; extern const char* xp_keynames[]; TilemHardware hardware_ti84pse = { 'z', "ti84pse", "TI-84 Plus Silver Edition", (TILEM_CALC_HAS_LINK | TILEM_CALC_HAS_LINK_ASSIST | TILEM_CALC_HAS_T6A04 | TILEM_CALC_HAS_FLASH | TILEM_CALC_HAS_MD5_ASSIST), 96, 64, 128 * 0x4000, 8 * 0x4000, 16 * 64, 0x80, NUM_FLASH_SECTORS, flashsectors, 3, NUM_HW_REGS, hwregnames, NUM_HW_TIMERS, hwtimernames, xp_keynames, xz_reset, xz_stateloaded, xz_z80_in, xz_z80_out, xz_z80_wrmem, xz_z80_rdmem, xz_z80_rdmem_m1, NULL, xz_z80_ptimer, tilem_lcd_t6a04_get_data, xz_mem_ltop, xz_mem_ptol }; tilem-2.0/emu/z80.c000066400000000000000000000566221220200411600140370ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "tilem.h" #include "z80.h" /* Timer manipulation */ /* static void dumptimers(TilemZ80* z80) { int tmr; int t; printf("*** RT:"); for (tmr = z80->timer_rt; tmr; tmr = z80->timers[tmr].next) { t = z80->timers[tmr].count - z80->clock; printf(" %d:%d", tmr, t); } printf("\n*** CPU:"); for (tmr = z80->timer_cpu; tmr; tmr = z80->timers[tmr].next) { t = z80->timers[tmr].count - z80->clock; printf(" %d:%d", tmr, t); } printf("\n*** Free:"); for (tmr = z80->timer_free; tmr; tmr = z80->timers[tmr].next) { printf(" %d", tmr); } printf("\n"); } */ static inline void timer_free(TilemZ80* z80, int tmr) { z80->timers[tmr].callback = NULL; z80->timers[tmr].callbackdata = NULL; z80->timers[tmr].next = z80->timer_free; z80->timers[tmr].prev = 0; z80->timer_free = tmr; } static inline int timer_alloc(TilemZ80* z80) { int tmr, i; if (z80->timer_free) { tmr = z80->timer_free; z80->timer_free = z80->timers[tmr].next; z80->timers[tmr].next = 0; return tmr; } i = z80->ntimers; z80->ntimers = i * 2 + 1; z80->timers = tilem_renew(TilemZ80Timer, z80->timers, z80->ntimers); while (i < z80->ntimers) { timer_free(z80, i); i++; } tmr = z80->timer_free; z80->timer_free = z80->timers[tmr].next; z80->timers[tmr].next = 0; return tmr; } static inline int timer_earlier(TilemZ80* z80, int tmr1, int tmr2) { dword count1, count2; count1 = z80->timers[tmr1].count + 10000 - z80->clock; count2 = z80->timers[tmr2].count + 10000 - z80->clock; return (count1 < count2); } static inline void timer_insert(TilemZ80* z80, int* list, int tmr) { int prev, next; if (!*list || timer_earlier(z80, tmr, *list)) { z80->timers[tmr].prev = 0; z80->timers[tmr].next = *list; z80->timers[*list].prev = tmr; *list = tmr; return; } prev = *list; next = z80->timers[prev].next; while (next && timer_earlier(z80, next, tmr)) { prev = next; next = z80->timers[prev].next; } z80->timers[prev].next = tmr; z80->timers[next].prev = tmr; z80->timers[tmr].prev = prev; z80->timers[tmr].next = next; } static inline void timer_set(TilemZ80* z80, int tmr, dword count, dword period, int rt, dword extra) { dword clocks; qword kclocks; if (!count) { /* leave timer disabled */ z80->timers[tmr].prev = 0; z80->timers[tmr].next = 0; } else if (rt) { kclocks = z80->clockspeed; kclocks *= count; clocks = (kclocks + 500) / 1000 - extra; z80->timers[tmr].count = z80->clock + clocks; z80->timers[tmr].period = period; timer_insert(z80, &z80->timer_rt, tmr); } else { clocks = count - extra; z80->timers[tmr].count = z80->clock + clocks; z80->timers[tmr].period = period; timer_insert(z80, &z80->timer_cpu, tmr); } } static inline void timer_unset(TilemZ80* z80, int tmr) { int prev, next; if (tmr == z80->timer_cpu) z80->timer_cpu = z80->timers[tmr].next; if (tmr == z80->timer_rt) z80->timer_rt = z80->timers[tmr].next; prev = z80->timers[tmr].prev; next = z80->timers[tmr].next; z80->timers[prev].next = next; z80->timers[next].prev = prev; z80->timers[tmr].prev = 0; z80->timers[tmr].next = 0; } /* Breakpoint manipulation */ static inline void bp_free(TilemZ80* z80, int bp) { z80->breakpoints[bp].type = 0; z80->breakpoints[bp].testfunc = NULL; z80->breakpoints[bp].testdata = NULL; z80->breakpoints[bp].next = z80->breakpoint_free; z80->breakpoints[bp].prev = 0; z80->breakpoint_free = bp; } static inline int bp_alloc(TilemZ80* z80) { int bp, i; if (z80->breakpoint_free) { bp = z80->breakpoint_free; z80->breakpoint_free = z80->breakpoints[bp].next; return bp; } i = z80->nbreakpoints; z80->nbreakpoints = i * 2 + 2; z80->breakpoints = tilem_renew(TilemZ80Breakpoint, z80->breakpoints, z80->nbreakpoints); while (i < z80->nbreakpoints) { bp_free(z80, i); i++; } bp = z80->breakpoint_free; z80->breakpoint_free = z80->breakpoints[bp].next; return bp; } static int* bp_head(TilemCalc *calc, int type) { if (type & TILEM_BREAK_DISABLED) return &calc->z80.breakpoint_disabled; switch (type & TILEM_BREAK_TYPE_MASK) { case TILEM_BREAK_MEM_READ: return (type & TILEM_BREAK_PHYSICAL ? &calc->z80.breakpoint_mpr : &calc->z80.breakpoint_mr); case TILEM_BREAK_MEM_EXEC: return (type & TILEM_BREAK_PHYSICAL ? &calc->z80.breakpoint_mpx : &calc->z80.breakpoint_mx); case TILEM_BREAK_MEM_WRITE: return (type & TILEM_BREAK_PHYSICAL ? &calc->z80.breakpoint_mpw : &calc->z80.breakpoint_mw); case TILEM_BREAK_PORT_READ: return &calc->z80.breakpoint_pr; case TILEM_BREAK_PORT_WRITE: return &calc->z80.breakpoint_pw; case TILEM_BREAK_EXECUTE: return &calc->z80.breakpoint_op; default: tilem_internal(calc, "invalid bp type"); return 0; } } static int bp_add(TilemCalc *calc, int bp, int type) { int *head = bp_head(calc, type); if (!head) { bp_free(&calc->z80, bp); return 0; } calc->z80.breakpoints[bp].next = *head; calc->z80.breakpoints[*head].prev = *head ? bp : 0; *head = bp; return bp; } static void bp_rem(TilemCalc *calc, int bp, int type) { int prev, next; int *head = bp_head(calc, type); prev = calc->z80.breakpoints[bp].prev; next = calc->z80.breakpoints[bp].next; if (bp == *head) *head = next; calc->z80.breakpoints[prev].next = prev ? next : 0; calc->z80.breakpoints[next].prev = next ? prev : 0; } static void invoke_ptimer(TilemCalc* calc, void* data) { (*calc->hw.z80_ptimer)(calc, TILEM_PTR_TO_DWORD(data)); } /* Z80 API */ void tilem_z80_reset(TilemCalc* calc) { int i; AF = BC = DE = HL = AF2 = BC2 = DE2 = HL2 = 0xffff; IX = IY = IR = SP = WZ = WZ2 = 0xffff; PC = 0; Rh = 0x80; IFF1 = IFF2 = IM = 0; calc->z80.interrupts = 0; calc->z80.halted = 0; /* Set up hardware timers */ if (!calc->z80.ntimers) { calc->z80.ntimers = (calc->hw.nhwtimers + TILEM_NUM_SYS_TIMERS + 1); tilem_free(calc->z80.timers); calc->z80.timers = tilem_new(TilemZ80Timer, calc->z80.ntimers); for (i = 1; i < calc->z80.ntimers; i++) { calc->z80.timers[i].next = 0; calc->z80.timers[i].prev = 0; calc->z80.timers[i].count = 0; calc->z80.timers[i].period = 0; calc->z80.timers[i].callback = &invoke_ptimer; calc->z80.timers[i].callbackdata = TILEM_DWORD_TO_PTR(i); } calc->z80.timers[TILEM_TIMER_LCD_DELAY].callback = &tilem_lcd_delay_timer; calc->z80.timers[TILEM_TIMER_FLASH_DELAY].callback = tilem_flash_delay_timer; calc->z80.timers[TILEM_TIMER_LINK_ASSIST].callback = tilem_linkport_assist_timer; for (i = 0; i < TILEM_MAX_USER_TIMERS; i++) { calc->z80.timers[TILEM_TIMER_USER1 + i].callback = tilem_user_timer_expired; calc->z80.timers[TILEM_TIMER_USER1 + i].callbackdata = TILEM_DWORD_TO_PTR(i); } } } void tilem_z80_stop(TilemCalc* calc, dword reason) { if (!(reason & calc->z80.stop_mask)) { calc->z80.stop_reason |= reason; calc->z80.stopping = 1; } } void tilem_z80_exception(TilemCalc* calc, unsigned type) { calc->z80.exception |= type; } void tilem_z80_set_speed(TilemCalc* calc, int speed) { int tmr; qword t; int oldspeed = calc->z80.clockspeed; if (oldspeed == speed) return; for (tmr = calc->z80.timer_rt; tmr; tmr = calc->z80.timers[tmr].next) { if ((calc->z80.clock - calc->z80.timers[tmr].count) < 10000) continue; t = calc->z80.timers[tmr].count - calc->z80.clock; t = (t * speed + oldspeed / 2) / oldspeed; calc->z80.timers[tmr].count = calc->z80.clock + t; } calc->z80.clockspeed = speed; } int tilem_z80_add_timer(TilemCalc* calc, dword count, dword period, int rt, TilemZ80TimerFunc func, void* data) { int id; id = timer_alloc(&calc->z80); calc->z80.timers[id].callback = func; calc->z80.timers[id].callbackdata = data; timer_set(&calc->z80, id, count, period, rt, 0); return id; } void tilem_z80_set_timer(TilemCalc* calc, int id, dword count, dword period, int rt) { if (id < 1 || id > calc->z80.ntimers || !calc->z80.timers[id].callback) { tilem_internal(calc, "setting invalid timer %d", id); return; } timer_unset(&calc->z80, id); timer_set(&calc->z80, id, count, period, rt, 0); } void tilem_z80_set_timer_period(TilemCalc* calc, int id, dword period) { if (id < 1 || id > calc->z80.ntimers || !calc->z80.timers[id].callback) { tilem_internal(calc, "setting invalid timer %d", id); return; } calc->z80.timers[id].period = period; } void tilem_z80_remove_timer(TilemCalc* calc, int id) { if (id <= calc->hw.nhwtimers + TILEM_NUM_SYS_TIMERS || id > calc->z80.ntimers || !calc->z80.timers[id].callback) { tilem_internal(calc, "removing invalid timer %d", id); return; } timer_unset(&calc->z80, id); timer_free(&calc->z80, id); } int tilem_z80_timer_running(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.ntimers || !calc->z80.timers[id].callback) { tilem_internal(calc, "querying invalid timer %d", id); return 0; } if (id == calc->z80.timer_rt || id == calc->z80.timer_cpu) return 1; if (calc->z80.timers[id].prev) return 1; return 0; } int tilem_z80_get_timer_clocks(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.ntimers || !calc->z80.timers[id].callback) { tilem_internal(calc, "querying invalid timer %d", id); return 0; } return (calc->z80.timers[id].count - calc->z80.clock); } int tilem_z80_get_timer_microseconds(TilemCalc* calc, int id) { int n = tilem_z80_get_timer_clocks(calc, id); if (n < 0) { n = ((((qword) -n * 1000) + (calc->z80.clockspeed / 2)) / calc->z80.clockspeed); return -n; } else { n = ((((qword) n * 1000) + (calc->z80.clockspeed / 2)) / calc->z80.clockspeed); return n; } } int tilem_z80_add_breakpoint(TilemCalc* calc, int type, dword start, dword end, dword mask, TilemZ80BreakpointFunc func, void* data) { int bp; bp = bp_alloc(&calc->z80); calc->z80.breakpoints[bp].type = type; calc->z80.breakpoints[bp].start = start; calc->z80.breakpoints[bp].end = end; calc->z80.breakpoints[bp].mask = mask; calc->z80.breakpoints[bp].testfunc = func; calc->z80.breakpoints[bp].testdata = data; calc->z80.breakpoints[bp].prev = 0; return bp_add(calc, bp, type); } void tilem_z80_remove_breakpoint(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to remove invalid breakpoint %d", id); return; } bp_rem(calc, id, calc->z80.breakpoints[id].type); bp_free(&calc->z80, id); } void tilem_z80_enable_breakpoint(TilemCalc* calc, int id) { int type = tilem_z80_get_breakpoint_type(calc, id); tilem_z80_set_breakpoint_type(calc, id, type & ~TILEM_BREAK_DISABLED); } void tilem_z80_disable_breakpoint(TilemCalc* calc, int id) { int type = tilem_z80_get_breakpoint_type(calc, id); tilem_z80_set_breakpoint_type(calc, id, type | TILEM_BREAK_DISABLED); } int tilem_z80_breakpoint_enabled(TilemCalc* calc, int id) { int type = tilem_z80_get_breakpoint_type(calc, id); return !(type & TILEM_BREAK_DISABLED); } int tilem_z80_get_breakpoint_type(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return -1; } return calc->z80.breakpoints[id].type; } dword tilem_z80_get_breakpoint_address_start(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return -1; } return calc->z80.breakpoints[id].start; } dword tilem_z80_get_breakpoint_address_end(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return -1; } return calc->z80.breakpoints[id].end; } dword tilem_z80_get_breakpoint_address_mask(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return -1; } return calc->z80.breakpoints[id].mask; } TilemZ80BreakpointFunc tilem_z80_get_breakpoint_callback(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return 0; } return calc->z80.breakpoints[id].testfunc; } void* tilem_z80_get_breakpoint_data(TilemCalc* calc, int id) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to access invalid breakpoint %d", id); return 0; } return calc->z80.breakpoints[id].testdata; } void tilem_z80_set_breakpoint_type(TilemCalc* calc, int id, int type) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } if (type == calc->z80.breakpoints[id].type) return; bp_rem(calc, id, calc->z80.breakpoints[id].type); calc->z80.breakpoints[id].type = type; bp_add(calc, id, type); } void tilem_z80_set_breakpoint_address_start(TilemCalc* calc, int id, dword start) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } calc->z80.breakpoints[id].start = start; } void tilem_z80_set_breakpoint_address_end(TilemCalc* calc, int id, dword end) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } calc->z80.breakpoints[id].end = end; } void tilem_z80_set_breakpoint_address_mask(TilemCalc* calc, int id, dword mask) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } calc->z80.breakpoints[id].mask = mask; } void tilem_z80_set_breakpoint_callback(TilemCalc* calc, int id, TilemZ80BreakpointFunc func) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } calc->z80.breakpoints[id].testfunc = func; } void tilem_z80_set_breakpoint_data(TilemCalc* calc, int id, void* data) { if (id < 1 || id > calc->z80.nbreakpoints || !calc->z80.breakpoints[id].type) { tilem_internal(calc, "attempt to modify invalid breakpoint %d", id); return; } calc->z80.breakpoints[id].testdata = data; } static inline void check_timers(TilemCalc* calc) { int tmr; dword t; TilemZ80TimerFunc callback; void* callbackdata; while (calc->z80.timer_cpu) { tmr = calc->z80.timer_cpu; t = calc->z80.clock - calc->z80.timers[tmr].count; if (t >= 10000) break; callback = calc->z80.timers[tmr].callback; callbackdata = calc->z80.timers[tmr].callbackdata; timer_unset(&calc->z80, tmr); timer_set(&calc->z80, tmr, calc->z80.timers[tmr].period, calc->z80.timers[tmr].period, 0, t); (*callback)(calc, callbackdata); } while (calc->z80.timer_rt) { tmr = calc->z80.timer_rt; t = calc->z80.clock - calc->z80.timers[tmr].count; if (t >= 10000) break; callback = calc->z80.timers[tmr].callback; callbackdata = calc->z80.timers[tmr].callbackdata; timer_unset(&calc->z80, tmr); timer_set(&calc->z80, tmr, calc->z80.timers[tmr].period, calc->z80.timers[tmr].period, 1, t); (*callback)(calc, callbackdata); } } static inline void check_breakpoints(TilemCalc* calc, int list, dword addr) { dword masked; int bp; TilemZ80BreakpointFunc testfunc; void* testdata; for (bp = list; bp; bp = calc->z80.breakpoints[bp].next) { masked = addr & calc->z80.breakpoints[bp].mask; if (masked < calc->z80.breakpoints[bp].start || masked > calc->z80.breakpoints[bp].end) continue; testfunc = calc->z80.breakpoints[bp].testfunc; testdata = calc->z80.breakpoints[bp].testdata; if (testfunc && !(*testfunc)(calc, addr, testdata)) continue; calc->z80.stop_breakpoint = bp; tilem_z80_stop(calc, TILEM_STOP_BREAKPOINT); } } static inline void check_mem_breakpoints(TilemCalc* calc, int list_l, int list_p, dword addr) { check_breakpoints(calc, list_l, addr); if (list_p) { addr = (*calc->hw.mem_ltop)(calc, addr); check_breakpoints(calc, list_p, addr); } } static inline byte z80_readb_m1(TilemCalc* calc, dword addr) { byte b; addr &= 0xffff; b = (*calc->hw.z80_rdmem_m1)(calc, addr); check_mem_breakpoints(calc, calc->z80.breakpoint_mx, calc->z80.breakpoint_mpx, addr); Rl++; return b; } static inline byte z80_readb(TilemCalc* calc, dword addr) { byte b; addr &= 0xffff; b = (*calc->hw.z80_rdmem)(calc, addr); check_mem_breakpoints(calc, calc->z80.breakpoint_mr, calc->z80.breakpoint_mpr, addr); return b; } static inline dword z80_readw(TilemCalc* calc, dword addr) { dword v; addr &= 0xffff; v = (*calc->hw.z80_rdmem)(calc, addr); check_mem_breakpoints(calc, calc->z80.breakpoint_mr, calc->z80.breakpoint_mpr, addr); addr = (addr + 1) & 0xffff; v |= (*calc->hw.z80_rdmem)(calc, addr) << 8; check_mem_breakpoints(calc, calc->z80.breakpoint_mr, calc->z80.breakpoint_mpr, addr); return v; } static inline byte z80_input(TilemCalc* calc, dword addr) { byte b; addr &= 0xffff; check_timers(calc); b = (*calc->hw.z80_in)(calc, addr); check_breakpoints(calc, calc->z80.breakpoint_pr, addr); return b; } static inline void z80_writeb(TilemCalc* calc, dword addr, byte value) { addr &= 0xffff; (*calc->hw.z80_wrmem)(calc, addr, value); check_mem_breakpoints(calc, calc->z80.breakpoint_mw, calc->z80.breakpoint_mpw, addr); calc->z80.lastwrite = calc->z80.clock; } static inline void z80_writew(TilemCalc* calc, dword addr, word value) { addr &= 0xffff; (*calc->hw.z80_wrmem)(calc, addr, value); check_mem_breakpoints(calc, calc->z80.breakpoint_mw, calc->z80.breakpoint_mpw, addr); addr = (addr + 1) & 0xffff; value >>= 8; (*calc->hw.z80_wrmem)(calc, addr, value); check_mem_breakpoints(calc, calc->z80.breakpoint_mw, calc->z80.breakpoint_mpw, addr); calc->z80.lastwrite = calc->z80.clock; } static inline void z80_output(TilemCalc* calc, dword addr, byte value) { addr &= 0xffff; check_timers(calc); (*calc->hw.z80_out)(calc, addr, value); check_breakpoints(calc, calc->z80.breakpoint_pw, addr); } #define readb_m1(aaa) z80_readb_m1(calc, aaa) #define readb(aaa) z80_readb(calc, aaa) #define readw(aaa) z80_readw(calc, aaa) #define input(aaa) z80_input(calc, aaa) #define writeb(aaa, vvv) z80_writeb(calc, aaa, vvv) #define writew(aaa, vvv) z80_writew(calc, aaa, vvv) #define output(aaa, vvv) z80_output(calc, aaa, vvv) #define delay(nnn) calc->z80.clock += (nnn) #include "z80cmds.h" static dword z80_execute_opcode(TilemCalc* calc, byte op) { byte tmp1; word tmp2; int offs; #ifdef DISABLE_Z80_WZ_REGISTER TilemZ80Reg temp_wz, temp_wz2; #endif opcode_main: #include "z80main.h" return op; opcode_cb: #include "z80cb.h" return op | 0xcb00; opcode_ed: #include "z80ed.h" return op | 0xed00; #define PREFIX_DD opcode_dd: #include "z80ddfd.h" return op | 0xdd00; opcode_ddcb: #include "z80cb.h" return op | 0xddcb0000; #undef PREFIX_DD #define PREFIX_FD opcode_fd: #include "z80ddfd.h" return op | 0xfd00; opcode_fdcb: #include "z80cb.h" return op | 0xfdcb0000; #undef PREFIX_FD } static void z80_execute(TilemCalc* calc) { TilemZ80* z80 = &calc->z80; byte busbyte; dword op; dword t1, t2; z80->stopping = 0; z80->stop_reason = 0; z80->stop_breakpoint = 0; if (!z80->timer_cpu && !z80->timer_rt) { tilem_internal(calc, "No timers set"); return; } while (!z80->stopping) { z80->exception = 0; op = (*calc->hw.z80_rdmem_m1)(calc, PC); PC++; Rl++; op = z80_execute_opcode(calc, op); check_breakpoints(calc, z80->breakpoint_op, op); check_timers(calc); if (z80->interrupts && IFF1 && op != 0xfb && op != 0xddfb && op != 0xfdfb) { IFF1 = IFF2 = 0; Rl++; z80->halted = 0; /* Depending on the calculator, this value varies somewhat randomly from one interrupt to the next (making IM 2 rather difficult to use, and IM 0 essentially worthless.) Most likely, there is nothing connected to the data bus at interrupt time. I seem to remember somebody (sigma, perhaps?) experimenting with this on the TI-83+ and finding it usually 3F, 7F, BF, or FF. Or maybe I'm completely wrong. In any case it is unwise for programs to depend on this value! */ busbyte = rand() & 0xff; switch (IM) { case 0: delay(2); z80_execute_opcode(calc, busbyte); break; case 1: push(PC); PC = 0x0038; delay(13); break; case 2: /* FIXME: does accepting an IM 2 interrupt affect WZ? It seems very likely. */ push(PC); PC = readw((IR & 0xff00) | busbyte); delay(19); } check_mem_breakpoints(calc, z80->breakpoint_mx, z80->breakpoint_mpx, PC); check_timers(calc); } else if (op != 0x76) { check_mem_breakpoints(calc, z80->breakpoint_mx, z80->breakpoint_mpx, PC); } else { z80->halted = 1; PC--; if (z80->stopping) break; /* CPU halted: fast-forward to next timer event */ if (z80->timer_cpu && z80->timer_rt) { t1 = (z80->timers[z80->timer_cpu].count - z80->clock); t2 = (z80->timers[z80->timer_rt].count - z80->clock); if (t1 > t2) t1 = t2; } else if (z80->timer_cpu) { t1 = (z80->timers[z80->timer_cpu].count - z80->clock); } else if (z80->timer_rt) { t1 = (z80->timers[z80->timer_rt].count - z80->clock); } else { tilem_internal(calc, "No timers set"); return; } z80->clock += t1 & ~3; Rl += t1 / 4; check_timers(calc); } if (TILEM_UNLIKELY(z80->exception)) { if (z80->emuflags & TILEM_Z80_BREAK_EXCEPTIONS) tilem_z80_stop(calc, TILEM_STOP_EXCEPTION); if (!(z80->emuflags & TILEM_Z80_IGNORE_EXCEPTIONS)) tilem_calc_reset(calc); } } } static void tmr_stop(TilemCalc* calc, void* data TILEM_ATTR_UNUSED) { tilem_z80_stop(calc, TILEM_STOP_TIMEOUT); } dword tilem_z80_run(TilemCalc* calc, int clocks, int* remaining) { int tmr = tilem_z80_add_timer(calc, clocks, 0, 0, &tmr_stop, 0); z80_execute(calc); if (remaining) *remaining = tilem_z80_get_timer_clocks(calc, tmr); tilem_z80_remove_timer(calc, tmr); return calc->z80.stop_reason; } dword tilem_z80_run_time(TilemCalc* calc, int microseconds, int* remaining) { int tmr = tilem_z80_add_timer(calc, microseconds, 0, 1, &tmr_stop, 0); z80_execute(calc); if (remaining) *remaining = tilem_z80_get_timer_microseconds(calc, tmr); tilem_z80_remove_timer(calc, tmr); return calc->z80.stop_reason; } tilem-2.0/emu/z80.h000066400000000000000000000053651220200411600140420ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifndef _TILEM_Z80_H #define _TILEM_Z80_H /* Internal Z80 data structures */ struct _TilemZ80Timer { int next, prev; dword count; dword period; TilemZ80TimerFunc callback; void* callbackdata; }; struct _TilemZ80Breakpoint { int next, prev; int type; dword start; dword end; dword mask; TilemZ80BreakpointFunc testfunc; void* testdata; }; /* Useful definitions */ #define AF (calc->z80.r.af.d) #define BC (calc->z80.r.bc.d) #define DE (calc->z80.r.de.d) #define HL (calc->z80.r.hl.d) #define AF2 (calc->z80.r.af2.d) #define BC2 (calc->z80.r.bc2.d) #define DE2 (calc->z80.r.de2.d) #define HL2 (calc->z80.r.hl2.d) #define IX (calc->z80.r.ix.d) #define IY (calc->z80.r.iy.d) #define SP (calc->z80.r.sp.d) #define PC (calc->z80.r.pc.d) #define IR (calc->z80.r.ir.d) #define A (calc->z80.r.af.b.h) #define F (calc->z80.r.af.b.l) #define B (calc->z80.r.bc.b.h) #define C (calc->z80.r.bc.b.l) #define D (calc->z80.r.de.b.h) #define E (calc->z80.r.de.b.l) #define H (calc->z80.r.hl.b.h) #define L (calc->z80.r.hl.b.l) #define IXh (calc->z80.r.ix.b.h) #define IXl (calc->z80.r.ix.b.l) #define IYh (calc->z80.r.iy.b.h) #define IYl (calc->z80.r.iy.b.l) #define I (calc->z80.r.ir.b.h) #define Rh (calc->z80.r.r7) #define Rl (calc->z80.r.ir.b.l) #define R ((Rl & 0x7f) | Rh) #ifdef DISABLE_Z80_WZ_REGISTER # define WZ temp_wz.d # define WZ2 temp_wz2.d # define W temp_wz.b.h # define Z temp_wz.b.l #else # define WZ (calc->z80.r.wz.d) # define WZ2 (calc->z80.r.wz2.d) # define W (calc->z80.r.wz.b.h) # define Z (calc->z80.r.wz.b.l) #endif #define IFF1 (calc->z80.r.iff1) #define IFF2 (calc->z80.r.iff2) #define IM (calc->z80.r.im) #define FLAG_S 0x80 #define FLAG_Z 0x40 #define FLAG_Y 0x20 #define FLAG_H 0x10 #define FLAG_X 0x08 #define FLAG_P 0x04 #define FLAG_V FLAG_P #define FLAG_N 0x02 #define FLAG_C 0x01 #define BCw (calc->z80.r.bc.w.l) #define DEw (calc->z80.r.de.w.l) #define HLw (calc->z80.r.hl.w.l) #define SPw (calc->z80.r.sp.w.l) #define IXw (calc->z80.r.ix.w.l) #define IYw (calc->z80.r.iy.w.l) #endif tilem-2.0/emu/z80cb.h000066400000000000000000000301521220200411600143370ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #if defined(PREFIX_DD) || defined(PREFIX_FD) # define CBINST(fnc, reg) do { \ UNDOCUMENTED(16); \ tmp1 = readb(WZ); \ fnc(tmp1); \ writeb(WZ, tmp1); \ (reg) = tmp1; \ delay(19); \ } while (0) # define CBINST_HL(fnc) do { \ tmp1 = readb(WZ); \ fnc(tmp1); \ writeb(WZ, tmp1); \ delay(19); \ } while (0) # define CBINST_UNDOC(fnc, reg) CBINST(fnc, reg) # define CBINST_UNDOC_HL(fnc) do { \ UNDOCUMENTED(12); \ CBINST_HL(fnc); \ } while (0) # define CB_BIT(b, reg) do { \ UNDOCUMENTED(12); \ CB_BIT_HL(b); \ } while (0) # define CB_BIT_HL(b) do { \ tmp1 = readb(WZ) & (1 << b); \ F = ((tmp1 & FLAG_S) /* S */ \ | (W & FLAG_XY) /* X/Y */ \ | (tmp1 ? 0 : FLAG_ZP) /* Z/P */ \ | (FLAG_H) /* H */ \ | (F & FLAG_C)); \ delay(16); \ } while (0) # define CB_RES(b, reg) do { \ UNDOCUMENTED(16); \ tmp1 = readb(WZ) & ~(1 << b); \ writeb(WZ, tmp1); \ (reg) = tmp1; \ delay(19); \ } while (0) # define CB_RES_HL(b) do { \ tmp1 = readb(WZ) & ~(1 << b); \ writeb(WZ, tmp1); \ delay(19); \ } while (0) # define CB_SET(b, reg) do { \ UNDOCUMENTED(16); \ tmp1 = readb(WZ) | (1 << b); \ writeb(WZ, tmp1); \ (reg) = tmp1; \ delay(19); \ } while (0) # define CB_SET_HL(b) do { \ tmp1 = readb(WZ) | (1 << b); \ writeb(WZ, tmp1); \ delay(19); \ } while (0) #else /* ! PREFIX_DD, ! PREFIX_FD */ # define CBINST(fnc, reg) do { \ fnc(reg); \ delay(8); \ } while (0) # define CBINST_HL(fnc) do { \ tmp1 = readb(HL); \ fnc(tmp1); \ writeb(HL, tmp1); \ delay(15); \ } while (0) # define CBINST_UNDOC(fnc, reg) do { \ UNDOCUMENTED(8); \ CBINST(fnc, reg); \ } while (0) # define CBINST_UNDOC_HL(fnc) do { \ UNDOCUMENTED(8); \ CBINST_HL(fnc); \ } while (0) # define CB_BIT(b, reg) do { \ tmp1 = (reg) & (1 << b); \ F = ((tmp1 & FLAG_SXY) /* S/X/Y */ \ | (tmp1 ? 0 : FLAG_ZP) /* Z/P */ \ | (FLAG_H) /* H */ \ | (F & FLAG_C)); \ delay(8); \ } while (0) # define CB_BIT_HL(b) do { \ tmp1 = readb(HL) & (1 << b); \ F = ((tmp1 & FLAG_S) /* S */ \ | (W & FLAG_XY) /* X/Y */ \ | (tmp1 ? 0 : FLAG_ZP) /* Z/P */ \ | (FLAG_H) /* H */ \ | (F & FLAG_C)); \ delay(12); \ } while (0) # define CB_RES(b, reg) do { \ (reg) &= ~(1 << b); \ delay(8); \ } while (0) # define CB_RES_HL(b) do { \ writeb(HL, readb(HL) & ~(1 << b)); \ delay(15); \ } while (0) # define CB_SET(b, reg) do { \ (reg) |= (1 << b); \ delay(8); \ } while (0) # define CB_SET_HL(b) do { \ writeb(HL, readb(HL) | (1 << b)); \ delay(15); \ } while (0) #endif switch (op) { case 0x00: CBINST(rlc, B); break; case 0x01: CBINST(rlc, C); break; case 0x02: CBINST(rlc, D); break; case 0x03: CBINST(rlc, E); break; case 0x04: CBINST(rlc, H); break; case 0x05: CBINST(rlc, L); break; case 0x06: CBINST_HL(rlc); break; case 0x07: CBINST(rlc, A); break; case 0x08: CBINST(rrc, B); break; case 0x09: CBINST(rrc, C); break; case 0x0A: CBINST(rrc, D); break; case 0x0B: CBINST(rrc, E); break; case 0x0C: CBINST(rrc, H); break; case 0x0D: CBINST(rrc, L); break; case 0x0E: CBINST_HL(rrc); break; case 0x0F: CBINST(rrc, A); break; case 0x10: CBINST(rl, B); break; case 0x11: CBINST(rl, C); break; case 0x12: CBINST(rl, D); break; case 0x13: CBINST(rl, E); break; case 0x14: CBINST(rl, H); break; case 0x15: CBINST(rl, L); break; case 0x16: CBINST_HL(rl); break; case 0x17: CBINST(rl, A); break; case 0x18: CBINST(rr, B); break; case 0x19: CBINST(rr, C); break; case 0x1A: CBINST(rr, D); break; case 0x1B: CBINST(rr, E); break; case 0x1C: CBINST(rr, H); break; case 0x1D: CBINST(rr, L); break; case 0x1E: CBINST_HL(rr); break; case 0x1F: CBINST(rr, A); break; case 0x20: CBINST(sla, B); break; case 0x21: CBINST(sla, C); break; case 0x22: CBINST(sla, D); break; case 0x23: CBINST(sla, E); break; case 0x24: CBINST(sla, H); break; case 0x25: CBINST(sla, L); break; case 0x26: CBINST_HL(sla); break; case 0x27: CBINST(sla, A); break; case 0x28: CBINST(sra, B); break; case 0x29: CBINST(sra, C); break; case 0x2A: CBINST(sra, D); break; case 0x2B: CBINST(sra, E); break; case 0x2C: CBINST(sra, H); break; case 0x2D: CBINST(sra, L); break; case 0x2E: CBINST_HL(sra); break; case 0x2F: CBINST(sra, A); break; case 0x30: CBINST_UNDOC(slia, B); break; case 0x31: CBINST_UNDOC(slia, C); break; case 0x32: CBINST_UNDOC(slia, D); break; case 0x33: CBINST_UNDOC(slia, E); break; case 0x34: CBINST_UNDOC(slia, H); break; case 0x35: CBINST_UNDOC(slia, L); break; case 0x36: CBINST_UNDOC_HL(slia); break; case 0x37: CBINST_UNDOC(slia, A); break; case 0x38: CBINST(srl, B); break; case 0x39: CBINST(srl, C); break; case 0x3A: CBINST(srl, D); break; case 0x3B: CBINST(srl, E); break; case 0x3C: CBINST(srl, H); break; case 0x3D: CBINST(srl, L); break; case 0x3E: CBINST_HL(srl); break; case 0x3F: CBINST(srl, A); break; case 0x40: CB_BIT(0, B); break; case 0x41: CB_BIT(0, C); break; case 0x42: CB_BIT(0, D); break; case 0x43: CB_BIT(0, E); break; case 0x44: CB_BIT(0, H); break; case 0x45: CB_BIT(0, L); break; case 0x46: CB_BIT_HL(0); break; case 0x47: CB_BIT(0, A); break; case 0x48: CB_BIT(1, B); break; case 0x49: CB_BIT(1, C); break; case 0x4A: CB_BIT(1, D); break; case 0x4B: CB_BIT(1, E); break; case 0x4C: CB_BIT(1, H); break; case 0x4D: CB_BIT(1, L); break; case 0x4E: CB_BIT_HL(1); break; case 0x4F: CB_BIT(1, A); break; case 0x50: CB_BIT(2, B); break; case 0x51: CB_BIT(2, C); break; case 0x52: CB_BIT(2, D); break; case 0x53: CB_BIT(2, E); break; case 0x54: CB_BIT(2, H); break; case 0x55: CB_BIT(2, L); break; case 0x56: CB_BIT_HL(2); break; case 0x57: CB_BIT(2, A); break; case 0x58: CB_BIT(3, B); break; case 0x59: CB_BIT(3, C); break; case 0x5A: CB_BIT(3, D); break; case 0x5B: CB_BIT(3, E); break; case 0x5C: CB_BIT(3, H); break; case 0x5D: CB_BIT(3, L); break; case 0x5E: CB_BIT_HL(3); break; case 0x5F: CB_BIT(3, A); break; case 0x60: CB_BIT(4, B); break; case 0x61: CB_BIT(4, C); break; case 0x62: CB_BIT(4, D); break; case 0x63: CB_BIT(4, E); break; case 0x64: CB_BIT(4, H); break; case 0x65: CB_BIT(4, L); break; case 0x66: CB_BIT_HL(4); break; case 0x67: CB_BIT(4, A); break; case 0x68: CB_BIT(5, B); break; case 0x69: CB_BIT(5, C); break; case 0x6A: CB_BIT(5, D); break; case 0x6B: CB_BIT(5, E); break; case 0x6C: CB_BIT(5, H); break; case 0x6D: CB_BIT(5, L); break; case 0x6E: CB_BIT_HL(5); break; case 0x6F: CB_BIT(5, A); break; case 0x70: CB_BIT(6, B); break; case 0x71: CB_BIT(6, C); break; case 0x72: CB_BIT(6, D); break; case 0x73: CB_BIT(6, E); break; case 0x74: CB_BIT(6, H); break; case 0x75: CB_BIT(6, L); break; case 0x76: CB_BIT_HL(6); break; case 0x77: CB_BIT(6, A); break; case 0x78: CB_BIT(7, B); break; case 0x79: CB_BIT(7, C); break; case 0x7A: CB_BIT(7, D); break; case 0x7B: CB_BIT(7, E); break; case 0x7C: CB_BIT(7, H); break; case 0x7D: CB_BIT(7, L); break; case 0x7E: CB_BIT_HL(7); break; case 0x7F: CB_BIT(7, A); break; case 0x80: CB_RES(0, B); break; case 0x81: CB_RES(0, C); break; case 0x82: CB_RES(0, D); break; case 0x83: CB_RES(0, E); break; case 0x84: CB_RES(0, H); break; case 0x85: CB_RES(0, L); break; case 0x86: CB_RES_HL(0); break; case 0x87: CB_RES(0, A); break; case 0x88: CB_RES(1, B); break; case 0x89: CB_RES(1, C); break; case 0x8A: CB_RES(1, D); break; case 0x8B: CB_RES(1, E); break; case 0x8C: CB_RES(1, H); break; case 0x8D: CB_RES(1, L); break; case 0x8E: CB_RES_HL(1); break; case 0x8F: CB_RES(1, A); break; case 0x90: CB_RES(2, B); break; case 0x91: CB_RES(2, C); break; case 0x92: CB_RES(2, D); break; case 0x93: CB_RES(2, E); break; case 0x94: CB_RES(2, H); break; case 0x95: CB_RES(2, L); break; case 0x96: CB_RES_HL(2); break; case 0x97: CB_RES(2, A); break; case 0x98: CB_RES(3, B); break; case 0x99: CB_RES(3, C); break; case 0x9A: CB_RES(3, D); break; case 0x9B: CB_RES(3, E); break; case 0x9C: CB_RES(3, H); break; case 0x9D: CB_RES(3, L); break; case 0x9E: CB_RES_HL(3); break; case 0x9F: CB_RES(3, A); break; case 0xA0: CB_RES(4, B); break; case 0xA1: CB_RES(4, C); break; case 0xA2: CB_RES(4, D); break; case 0xA3: CB_RES(4, E); break; case 0xA4: CB_RES(4, H); break; case 0xA5: CB_RES(4, L); break; case 0xA6: CB_RES_HL(4); break; case 0xA7: CB_RES(4, A); break; case 0xA8: CB_RES(5, B); break; case 0xA9: CB_RES(5, C); break; case 0xAA: CB_RES(5, D); break; case 0xAB: CB_RES(5, E); break; case 0xAC: CB_RES(5, H); break; case 0xAD: CB_RES(5, L); break; case 0xAE: CB_RES_HL(5); break; case 0xAF: CB_RES(5, A); break; case 0xB0: CB_RES(6, B); break; case 0xB1: CB_RES(6, C); break; case 0xB2: CB_RES(6, D); break; case 0xB3: CB_RES(6, E); break; case 0xB4: CB_RES(6, H); break; case 0xB5: CB_RES(6, L); break; case 0xB6: CB_RES_HL(6); break; case 0xB7: CB_RES(6, A); break; case 0xB8: CB_RES(7, B); break; case 0xB9: CB_RES(7, C); break; case 0xBA: CB_RES(7, D); break; case 0xBB: CB_RES(7, E); break; case 0xBC: CB_RES(7, H); break; case 0xBD: CB_RES(7, L); break; case 0xBE: CB_RES_HL(7); break; case 0xBF: CB_RES(7, A); break; case 0xC0: CB_SET(0, B); break; case 0xC1: CB_SET(0, C); break; case 0xC2: CB_SET(0, D); break; case 0xC3: CB_SET(0, E); break; case 0xC4: CB_SET(0, H); break; case 0xC5: CB_SET(0, L); break; case 0xC6: CB_SET_HL(0); break; case 0xC7: CB_SET(0, A); break; case 0xC8: CB_SET(1, B); break; case 0xC9: CB_SET(1, C); break; case 0xCA: CB_SET(1, D); break; case 0xCB: CB_SET(1, E); break; case 0xCC: CB_SET(1, H); break; case 0xCD: CB_SET(1, L); break; case 0xCE: CB_SET_HL(1); break; case 0xCF: CB_SET(1, A); break; case 0xD0: CB_SET(2, B); break; case 0xD1: CB_SET(2, C); break; case 0xD2: CB_SET(2, D); break; case 0xD3: CB_SET(2, E); break; case 0xD4: CB_SET(2, H); break; case 0xD5: CB_SET(2, L); break; case 0xD6: CB_SET_HL(2); break; case 0xD7: CB_SET(2, A); break; case 0xD8: CB_SET(3, B); break; case 0xD9: CB_SET(3, C); break; case 0xDA: CB_SET(3, D); break; case 0xDB: CB_SET(3, E); break; case 0xDC: CB_SET(3, H); break; case 0xDD: CB_SET(3, L); break; case 0xDE: CB_SET_HL(3); break; case 0xDF: CB_SET(3, A); break; case 0xE0: CB_SET(4, B); break; case 0xE1: CB_SET(4, C); break; case 0xE2: CB_SET(4, D); break; case 0xE3: CB_SET(4, E); break; case 0xE4: CB_SET(4, H); break; case 0xE5: CB_SET(4, L); break; case 0xE6: CB_SET_HL(4); break; case 0xE7: CB_SET(4, A); break; case 0xE8: CB_SET(5, B); break; case 0xE9: CB_SET(5, C); break; case 0xEA: CB_SET(5, D); break; case 0xEB: CB_SET(5, E); break; case 0xEC: CB_SET(5, H); break; case 0xED: CB_SET(5, L); break; case 0xEE: CB_SET_HL(5); break; case 0xEF: CB_SET(5, A); break; case 0xF0: CB_SET(6, B); break; case 0xF1: CB_SET(6, C); break; case 0xF2: CB_SET(6, D); break; case 0xF3: CB_SET(6, E); break; case 0xF4: CB_SET(6, H); break; case 0xF5: CB_SET(6, L); break; case 0xF6: CB_SET_HL(6); break; case 0xF7: CB_SET(6, A); break; case 0xF8: CB_SET(7, B); break; case 0xF9: CB_SET(7, C); break; case 0xFA: CB_SET(7, D); break; case 0xFB: CB_SET(7, E); break; case 0xFC: CB_SET(7, H); break; case 0xFD: CB_SET(7, L); break; case 0xFE: CB_SET_HL(7); break; case 0xFF: CB_SET(7, A); break; } #undef CBINST #undef CBINST_HL #undef CBINST_UNDOC #undef CBINST_UNDOC_HL #undef CB_BIT #undef CB_BIT_HL #undef CB_RES #undef CB_RES_HL #undef CB_SET #undef CB_SET_HL tilem-2.0/emu/z80cmds.h000066400000000000000000001034221220200411600147020ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009-2011 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ /* Flag magic: S (the Sign flag) is set when the result is negative (i.e., copied from the MS bit.) Z (the Zero flag) is set when the result is zero. Y (undocumented flag) is usually copied from the result. H (the Half-carry flag) is set when a carry occurs from LS to MS nibble. Since bit 4 of the result is equal to (bit 4 of first arg) xor (bit 4 of second arg) xor H, we can infer that H equals (bit 4 of first arg) xor (bit 4 of second arg) xor (bit 4 of result). X (undocumented flag) is copied from the same place as is Y. P (parity flag) is set -- by logic operations -- when the result has even parity; i.e., it's the xor of all the bits of the result and 1. V (overflow flag, which is another name for the parity flag) is set -- by arithmetic operations -- when the result overflows. This can happen when a positive plus a positive is negative, or a negative plus a negative is positive, or a positive minus a negative is negative, or a negative minus a positive is positive. (In 8 bits, a positive plus a negative is at least 0 + -128 = -128 and at most 127 + -1 + 1 = 127. A positive minus a positive is at least 0 - 127 - 1 = -128 and at most 127 - 0 = 127. A negative minus a negative is at least -128 - -1 - 1 = -128 and at most -1 - -128 = 127. Thus these cases can never overflow.) When adding, then, overflow occurs if the args are equal in the MS bit and the result differs in the MS bit. When subtracting, overflow occurs if the args differ in the MS bit and the result differs from the first arg in the MS bit. N (subtract flag) is set or cleared depending on the operation. C (carry flag) is the leftover bit after an addition or subtraction. */ #define FLAG_XY (FLAG_X | FLAG_Y) #define FLAG_XYC (FLAG_X | FLAG_Y | FLAG_C) #define FLAG_SXY (FLAG_S | FLAG_X | FLAG_Y) #define FLAG_SXYC (FLAG_S | FLAG_X | FLAG_Y | FLAG_C) #define FLAG_ZP (FLAG_Z | FLAG_P) #define FLAG_SZPC (FLAG_S | FLAG_Z | FLAG_P | FLAG_C) #define lsb(xxx) ((xxx) & 0xff) #define UNDOCUMENTED(clks) \ if (calc->z80.emuflags & TILEM_Z80_BREAK_UNDOCUMENTED) \ tilem_z80_stop(calc, TILEM_STOP_UNDOCUMENTED_INST); \ if (calc->z80.emuflags & TILEM_Z80_SKIP_UNDOCUMENTED) { \ delay(clks); \ break; \ } \ if (calc->z80.emuflags & TILEM_Z80_RESET_UNDOCUMENTED) { \ tilem_warning(calc, "Invalid opcode %x", op); \ tilem_z80_exception(calc, TILEM_EXC_INSTRUCTION); \ break; \ } #define add8(dst, src) do { \ word arg1 = (dst); \ word arg2 = (src); \ word res = arg1 + arg2; \ byte resb = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (resb ? 0 : FLAG_Z) /* Z */ \ | ((arg1 ^ arg2 ^ res) & FLAG_H) /* H */ \ | (((arg1 ^ ~arg2) & (arg1 ^ res) & 0x80) >> 5) \ | (res >> 8)); /* C */ \ (dst) = resb; \ } while (0) #define adc8(dst, src) do { \ word arg1 = (dst); \ word arg2 = (src); \ word res = arg1 + arg2 + (F & 1); \ byte resb = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (resb ? 0 : FLAG_Z) /* Z */ \ | ((arg1 ^ arg2 ^ res) & FLAG_H) /* H */ \ | (((arg1 ^ ~arg2) & (arg1 ^ res) & 0x80) >> 5) \ | (res >> 8)); /* C */ \ (dst) = resb; \ } while (0) #define sub8(dst, src) do { \ word arg1 = (dst); \ word arg2 = (src); \ word res = arg1 - arg2; \ byte resb = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (resb ? 0 : FLAG_Z) /* Z */ \ | ((arg1 ^ arg2 ^ res) & FLAG_H) /* H */ \ | (((arg1 ^ arg2) & (arg1 ^ res) & 0x80) >> 5) \ | (FLAG_N) /* N */ \ | ((res >> 8) & 1)); /* C */ \ (dst) = resb; \ } while (0) #define sbc8(dst, src) do { \ word arg1 = (dst); \ word arg2 = (src); \ word res = arg1 - arg2 - (F & 1); \ byte resb = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (resb ? 0 : FLAG_Z) /* Z */ \ | ((arg1 ^ arg2 ^ res) & FLAG_H) /* H */ \ | (((arg1 ^ arg2) & (arg1 ^ res) & 0x80) >> 5) \ | (FLAG_N) /* N */ \ | ((res >> 8) & 1)); /* C */ \ (dst) = resb; \ } while (0) #define and(dst, src) do { \ byte arg1 = (dst); \ byte arg2 = (src); \ byte res = (arg1 & arg2); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | (FLAG_H) /* H */ \ | parity_table[res]); /* P */ \ (dst) = res; \ } while (0) #define xor(dst, src) do { \ byte arg1 = (dst); \ byte arg2 = (src); \ byte res = (arg1 ^ arg2); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res]); /* P */ \ (dst) = res; \ } while (0) #define or(dst, src) do { \ byte arg1 = (dst); \ byte arg2 = (src); \ byte res = (arg1 | arg2); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res]); /* P */ \ (dst) = res; \ } while (0) #define cp(dst, src) do { \ word arg1 = (dst); \ word arg2 = (src); \ word res = arg1 - arg2; \ byte resb = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (resb ? 0 : FLAG_Z) /* Z */ \ | ((arg1 ^ arg2 ^ res) & FLAG_H) /* H */ \ | (((arg1 ^ arg2) & (arg1 ^ res) & 0x80) >> 5) \ | (FLAG_N) /* N */ \ | ((res >> 8) & 1)); /* C */ \ } while (0) #define add16(dst, src) do { \ dword arg1 = (dst); \ dword arg2 = (src); \ dword res = arg1 + arg2; \ F = ((F & (FLAG_S | FLAG_Z | FLAG_P)) \ | ((res >> 8) & FLAG_XY) /* X/Y */ \ | (((arg1 ^ arg2 ^ res) >> 8) & FLAG_H) /* H */ \ | (res >> 16)); /* C */ \ (dst) = res; \ } while (0) #define adc16(dst, src) do { \ dword arg1 = (dst); \ dword arg2 = (src); \ dword res = arg1 + arg2 + (F & 1); \ word resw = res; \ F = (((res >> 8) & FLAG_SXY) /* S/X/Y */\ | (resw ? 0 : FLAG_Z) /* Z */ \ | (((arg1 ^ arg2 ^ res) >> 8) & FLAG_H) /* H */ \ | (((arg1 ^ ~arg2) & (arg1 ^ res) & 0x8000) >> 11) \ | (res >> 16)); /* C */ \ (dst) = resw; \ } while (0) #define sbc16(dst, src) do { \ dword arg1 = (dst); \ dword arg2 = (src); \ dword res = arg1 - arg2 - (F & 1); \ word resw = res; \ F = (((res >> 8) & FLAG_SXY) /* S/X/Y */\ | (resw ? 0 : FLAG_Z) /* Z */ \ | (((arg1 ^ arg2 ^ res) >> 8) & FLAG_H) /* H */ \ | (((arg1 ^ arg2) & (arg1 ^ res) & 0x8000) >> 11) \ | (FLAG_N) /* N */ \ | ((res >> 16) & 1)); /* C */ \ (dst) = resw; \ } while (0) #define inc(reg) do { \ byte arg = (reg); \ byte res = arg + 1; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | ((arg ^ res) & FLAG_H) /* H */ \ | (res == 0x80 ? FLAG_V : 0) /* V */ \ | (F & FLAG_C)); \ (reg) = res; \ } while (0) #define dec(reg) do { \ byte arg = (reg); \ byte res = arg - 1; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | ((arg ^ res) & FLAG_H) /* H */ \ | (res == 0x7f ? FLAG_V : 0) /* V */ \ | (FLAG_N) /* N */ \ | (F & FLAG_C)); \ (reg) = res; \ } while (0) #define cpl(reg) do { \ byte arg = (reg); \ byte res = ~arg; \ F = ((res & FLAG_XY) /* X/Y */ \ | FLAG_H | FLAG_N /* H/N */ \ | (F & FLAG_SZPC)); \ (reg) = res; \ } while (0) #define neg(reg) do { \ byte arg = (reg); \ byte res = -arg; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | ((arg ^ res) & FLAG_H) /* H */ \ | (arg == 0x80 ? FLAG_V : 0) /* V */ \ | (FLAG_N) /* N */ \ | (!!arg)); /* C */ \ (reg) = res; \ } while (0) #define daa do { \ word idx = (((F & 0x10) << 6) | ((F & 0x03) << 8) | A); \ AF = daa_table[idx]; \ } while (0) #define rlca do { \ byte arg = A; \ byte res = ((arg << 1) | (arg >> 7)); \ F = ((F & (FLAG_S | FLAG_Z | FLAG_P)) \ | (res & FLAG_XYC)); /* X/Y/C */ \ A = res; \ } while (0) #define rrca do { \ byte arg = A; \ byte res = ((arg >> 1) | (arg << 7)); \ F = ((F & (FLAG_S | FLAG_Z | FLAG_P)) \ | (res & FLAG_XY) /* X/Y */ \ | (arg & FLAG_C)); /* C */ \ A = res; \ } while (0) #define rla do { \ byte arg = A; \ byte res = ((arg << 1) | (F & 1)); \ F = ((F & (FLAG_S | FLAG_Z | FLAG_P)) \ | (res & FLAG_XY) /* X/Y */ \ | (arg >> 7)); /* C */ \ A = res; \ } while (0) #define rra do { \ byte arg = A; \ byte res = ((arg >> 1) | (F << 7)); \ F = ((F & (FLAG_S | FLAG_Z | FLAG_P)) \ | (res & FLAG_XY) /* X/Y */ \ | (arg & FLAG_C)); /* C */ \ A = res; \ } while (0) #define rlc(reg) do { \ byte arg = (reg); \ byte res = ((arg << 1) | (arg >> 7)); \ F = ((res & FLAG_SXYC) /* S/X/Y/C */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res]); /* P */ \ (reg) = res; \ } while (0) #define rrc(reg) do { \ byte arg = (reg); \ byte res = ((arg >> 1) | (arg << 7)); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg & FLAG_C)); /* C */ \ (reg) = res; \ } while (0) #define rl(reg) do { \ byte arg = (reg); \ byte res = ((arg << 1) | (F & 1)); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg >> 7)); /* C */ \ (reg) = res; \ } while (0) #define rr(reg) do { \ byte arg = (reg); \ byte res = ((arg >> 1) | (F << 7)); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg & FLAG_C)); /* C */ \ (reg) = res; \ } while (0) #define sla(reg) do { \ byte arg = (reg); \ byte res = (arg << 1); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg >> 7)); /* C */ \ (reg) = res; \ } while (0) #define sra(reg) do { \ byte arg = (reg); \ byte res = ((signed char) arg >> 1); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg & FLAG_C)); /* C */ \ (reg) = res; \ } while (0) #define slia(reg) do { \ byte arg = (reg); \ byte res = ((arg << 1) | 1); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg >> 7)); /* C */ \ (reg) = res; \ } while (0) #define srl(reg) do { \ byte arg = (reg); \ byte res = (arg >> 1); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (arg & FLAG_C)); /* C */ \ (reg) = res; \ } while (0) #define rld do { \ byte arg1 = readb(HL); \ byte arg2 = A; \ byte res = ((arg2 & 0xf0) | (arg1 >> 4)); \ WZ = HL + 1; \ writeb(HL, (arg1 << 4) | (arg2 & 0xf)); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (F & FLAG_C)); \ A = res; \ } while (0) #define rrd do { \ byte arg1 = readb(HL); \ byte arg2 = A; \ byte res = ((arg2 & 0xf0) | (arg1 & 0x0f)); \ WZ = HL + 1; \ writeb(HL, (arg1 >> 4) | (arg2 << 4)); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (F & FLAG_C)); \ A = res; \ } while (0) #define push(reg) do { \ SP -= 2; \ writew(SP, (reg)); \ } while (0) #define pop(reg) do { \ (reg) = readw(SP); \ SP += 2; \ } while (0) #define ex(aaa, bbb) do { \ tmp2 = (aaa); \ (aaa) = (bbb); \ (bbb) = tmp2; \ } while (0) #define in(reg) do { \ byte res = input(WZ); \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | parity_table[res] /* P */ \ | (F & FLAG_C)); \ (reg) = res; \ } while (0) #define ld_a_ir(reg) do { \ byte res = (reg); \ A = res; \ F = ((res & FLAG_SXY) /* S/X/Y */ \ | (res ? 0 : FLAG_Z) /* Z */ \ | (IFF2 ? FLAG_P : 0) /* P */ \ | (F & FLAG_C)); \ } while (0) #define ldi do { \ byte res = readb(HL++); \ writeb(DE++, res); \ BC--; \ F = ((F & (FLAG_S | FLAG_Z | FLAG_C)) \ | ((res << 4) & FLAG_Y) /* Y */ \ | (res & FLAG_X) /* X */ \ | (BCw ? FLAG_P : 0)); /* P */ \ } while (0) #define ldd do { \ byte res = readb(HL--); \ writeb(DE--, res); \ BC--; \ F = ((F & (FLAG_S | FLAG_Z | FLAG_C)) \ | ((res << 4) & FLAG_Y) /* Y */ \ | (res & FLAG_X) /* X */ \ | (BCw ? FLAG_P : 0)); /* P */ \ } while (0) /* FIXME: CPI and CPD obviously use WZ, but I haven't yet figured out precisely how. */ #define cpi do { \ word arg1 = A; \ word arg2 = readb(HL++); \ word res = arg1 - arg2; \ byte hc = ((arg1 ^ arg2 ^ res) & 0x10); \ byte res2 = res - (hc >> 4); \ BC--; \ F = ((res & FLAG_S) /* S */ \ | (lsb(res) ? 0 : FLAG_Z) /* Z */ \ | ((res2 << 4) & FLAG_Y) /* Y */ \ | hc /* H */ \ | (res2 & FLAG_X) /* X */ \ | (BCw ? FLAG_P : 0) /* P */ \ | FLAG_N /* N */ \ | (F & FLAG_C)); \ } while (0) #define cpd do { \ word arg1 = A; \ word arg2 = readb(HL--); \ word res = arg1 - arg2; \ byte hc = ((arg1 ^ arg2 ^ res) & 0x10); \ byte res2 = res - (hc >> 4); \ BC--; \ F = ((res & FLAG_S) /* S */ \ | (lsb(res) ? 0 : FLAG_Z) /* Z */ \ | ((res2 << 4) & FLAG_Y) /* Y */ \ | hc /* H */ \ | (res2 & FLAG_X) /* X */ \ | (BCw ? FLAG_P : 0) /* P */ \ | FLAG_N /* N */ \ | (F & FLAG_C)); \ } while (0) #define ini do { \ byte value, count; \ word k; \ value = input(BC); \ writeb(HL++, value); \ WZ = BC + 1; \ k = Z + value; \ count = --B; \ F = ((count & FLAG_SXY) /* S/X/Y */ \ | (count ? 0 : FLAG_Z) /* Z */ \ | ((k >> 8) ? 0x11 : 0) /* H/C */ \ | parity_table[(k & 7) ^ count] /* P */ \ | ((value >> 6) & FLAG_N)); /* N */ \ } while (0) #define ind do { \ byte value, count; \ word k; \ value = input(BC); \ writeb(HL--, value); \ WZ = BC - 1; \ k = Z + value; \ count = --B; \ F = ((count & FLAG_SXY) /* S/X/Y */ \ | (count ? 0 : FLAG_Z) /* Z */ \ | ((k >> 8) ? 0x11 : 0) /* H/C */ \ | parity_table[(k & 7) ^ count] /* P */ \ | ((value >> 6) & FLAG_N)); /* N */ \ } while (0) #define outi do { \ byte value, count; \ word k; \ value = readb(HL++); \ count = --B; \ output(BC, value); \ k = L + value; \ WZ = BC + 1; \ F = ((count & FLAG_SXY) /* S/X/Y */ \ | (count ? 0 : FLAG_Z) /* Z */ \ | ((k >> 8) ? 0x11 : 0) /* H/C */ \ | parity_table[(k & 7) ^ count] /* P */ \ | ((value >> 6) & FLAG_N)); /* N */ \ } while (0) #define outd do { \ byte value, count; \ word k; \ value = readb(HL--); \ count = --B; \ output(BC, value); \ k = L + value; \ WZ = BC - 1; \ F = ((count & FLAG_SXY) /* S/X/Y */ \ | (count ? 0 : FLAG_Z) /* Z */ \ | ((k >> 8) ? 0x11 : 0) /* H/C */ \ | parity_table[(k & 7) ^ count] /* P */ \ | ((value >> 6) & FLAG_N)); /* N */ \ } while (0) /* Table giving parity flag values. (Also known as the Thue-Morse sequence.) */ static const byte parity_table[256] = { 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, 4,0,0,4,0,4,4,0, 4,0,0,4,0,4,4,0, 0,4,4,0,4,0,0,4, }; /* Table giving AF values following DAA */ static const word daa_table[2048] = { 0x0044, 0x0100, 0x0200, 0x0304, 0x0400, 0x0504, 0x0604, 0x0700, 0x0808, 0x090c, 0x1010, 0x1114, 0x1214, 0x1310, 0x1414, 0x1510, 0x1000, 0x1104, 0x1204, 0x1300, 0x1404, 0x1500, 0x1600, 0x1704, 0x180c, 0x1908, 0x2030, 0x2134, 0x2234, 0x2330, 0x2434, 0x2530, 0x2020, 0x2124, 0x2224, 0x2320, 0x2424, 0x2520, 0x2620, 0x2724, 0x282c, 0x2928, 0x3034, 0x3130, 0x3230, 0x3334, 0x3430, 0x3534, 0x3024, 0x3120, 0x3220, 0x3324, 0x3420, 0x3524, 0x3624, 0x3720, 0x3828, 0x392c, 0x4010, 0x4114, 0x4214, 0x4310, 0x4414, 0x4510, 0x4000, 0x4104, 0x4204, 0x4300, 0x4404, 0x4500, 0x4600, 0x4704, 0x480c, 0x4908, 0x5014, 0x5110, 0x5210, 0x5314, 0x5410, 0x5514, 0x5004, 0x5100, 0x5200, 0x5304, 0x5400, 0x5504, 0x5604, 0x5700, 0x5808, 0x590c, 0x6034, 0x6130, 0x6230, 0x6334, 0x6430, 0x6534, 0x6024, 0x6120, 0x6220, 0x6324, 0x6420, 0x6524, 0x6624, 0x6720, 0x6828, 0x692c, 0x7030, 0x7134, 0x7234, 0x7330, 0x7434, 0x7530, 0x7020, 0x7124, 0x7224, 0x7320, 0x7424, 0x7520, 0x7620, 0x7724, 0x782c, 0x7928, 0x8090, 0x8194, 0x8294, 0x8390, 0x8494, 0x8590, 0x8080, 0x8184, 0x8284, 0x8380, 0x8484, 0x8580, 0x8680, 0x8784, 0x888c, 0x8988, 0x9094, 0x9190, 0x9290, 0x9394, 0x9490, 0x9594, 0x9084, 0x9180, 0x9280, 0x9384, 0x9480, 0x9584, 0x9684, 0x9780, 0x9888, 0x998c, 0x0055, 0x0111, 0x0211, 0x0315, 0x0411, 0x0515, 0x0045, 0x0101, 0x0201, 0x0305, 0x0401, 0x0505, 0x0605, 0x0701, 0x0809, 0x090d, 0x1011, 0x1115, 0x1215, 0x1311, 0x1415, 0x1511, 0x1001, 0x1105, 0x1205, 0x1301, 0x1405, 0x1501, 0x1601, 0x1705, 0x180d, 0x1909, 0x2031, 0x2135, 0x2235, 0x2331, 0x2435, 0x2531, 0x2021, 0x2125, 0x2225, 0x2321, 0x2425, 0x2521, 0x2621, 0x2725, 0x282d, 0x2929, 0x3035, 0x3131, 0x3231, 0x3335, 0x3431, 0x3535, 0x3025, 0x3121, 0x3221, 0x3325, 0x3421, 0x3525, 0x3625, 0x3721, 0x3829, 0x392d, 0x4011, 0x4115, 0x4215, 0x4311, 0x4415, 0x4511, 0x4001, 0x4105, 0x4205, 0x4301, 0x4405, 0x4501, 0x4601, 0x4705, 0x480d, 0x4909, 0x5015, 0x5111, 0x5211, 0x5315, 0x5411, 0x5515, 0x5005, 0x5101, 0x5201, 0x5305, 0x5401, 0x5505, 0x5605, 0x5701, 0x5809, 0x590d, 0x6035, 0x6131, 0x6231, 0x6335, 0x6431, 0x6535, 0x6025, 0x6121, 0x6221, 0x6325, 0x6421, 0x6525, 0x6625, 0x6721, 0x6829, 0x692d, 0x7031, 0x7135, 0x7235, 0x7331, 0x7435, 0x7531, 0x7021, 0x7125, 0x7225, 0x7321, 0x7425, 0x7521, 0x7621, 0x7725, 0x782d, 0x7929, 0x8091, 0x8195, 0x8295, 0x8391, 0x8495, 0x8591, 0x8081, 0x8185, 0x8285, 0x8381, 0x8485, 0x8581, 0x8681, 0x8785, 0x888d, 0x8989, 0x9095, 0x9191, 0x9291, 0x9395, 0x9491, 0x9595, 0x9085, 0x9181, 0x9281, 0x9385, 0x9481, 0x9585, 0x9685, 0x9781, 0x9889, 0x998d, 0xa0b5, 0xa1b1, 0xa2b1, 0xa3b5, 0xa4b1, 0xa5b5, 0xa0a5, 0xa1a1, 0xa2a1, 0xa3a5, 0xa4a1, 0xa5a5, 0xa6a5, 0xa7a1, 0xa8a9, 0xa9ad, 0xb0b1, 0xb1b5, 0xb2b5, 0xb3b1, 0xb4b5, 0xb5b1, 0xb0a1, 0xb1a5, 0xb2a5, 0xb3a1, 0xb4a5, 0xb5a1, 0xb6a1, 0xb7a5, 0xb8ad, 0xb9a9, 0xc095, 0xc191, 0xc291, 0xc395, 0xc491, 0xc595, 0xc085, 0xc181, 0xc281, 0xc385, 0xc481, 0xc585, 0xc685, 0xc781, 0xc889, 0xc98d, 0xd091, 0xd195, 0xd295, 0xd391, 0xd495, 0xd591, 0xd081, 0xd185, 0xd285, 0xd381, 0xd485, 0xd581, 0xd681, 0xd785, 0xd88d, 0xd989, 0xe0b1, 0xe1b5, 0xe2b5, 0xe3b1, 0xe4b5, 0xe5b1, 0xe0a1, 0xe1a5, 0xe2a5, 0xe3a1, 0xe4a5, 0xe5a1, 0xe6a1, 0xe7a5, 0xe8ad, 0xe9a9, 0xf0b5, 0xf1b1, 0xf2b1, 0xf3b5, 0xf4b1, 0xf5b5, 0xf0a5, 0xf1a1, 0xf2a1, 0xf3a5, 0xf4a1, 0xf5a5, 0xf6a5, 0xf7a1, 0xf8a9, 0xf9ad, 0x0055, 0x0111, 0x0211, 0x0315, 0x0411, 0x0515, 0x0045, 0x0101, 0x0201, 0x0305, 0x0401, 0x0505, 0x0605, 0x0701, 0x0809, 0x090d, 0x1011, 0x1115, 0x1215, 0x1311, 0x1415, 0x1511, 0x1001, 0x1105, 0x1205, 0x1301, 0x1405, 0x1501, 0x1601, 0x1705, 0x180d, 0x1909, 0x2031, 0x2135, 0x2235, 0x2331, 0x2435, 0x2531, 0x2021, 0x2125, 0x2225, 0x2321, 0x2425, 0x2521, 0x2621, 0x2725, 0x282d, 0x2929, 0x3035, 0x3131, 0x3231, 0x3335, 0x3431, 0x3535, 0x3025, 0x3121, 0x3221, 0x3325, 0x3421, 0x3525, 0x3625, 0x3721, 0x3829, 0x392d, 0x4011, 0x4115, 0x4215, 0x4311, 0x4415, 0x4511, 0x4001, 0x4105, 0x4205, 0x4301, 0x4405, 0x4501, 0x4601, 0x4705, 0x480d, 0x4909, 0x5015, 0x5111, 0x5211, 0x5315, 0x5411, 0x5515, 0x5005, 0x5101, 0x5201, 0x5305, 0x5401, 0x5505, 0x5605, 0x5701, 0x5809, 0x590d, 0x6035, 0x6131, 0x6231, 0x6335, 0x6431, 0x6535, 0x0046, 0x0102, 0x0202, 0x0306, 0x0402, 0x0506, 0x0606, 0x0702, 0x080a, 0x090e, 0x0402, 0x0506, 0x0606, 0x0702, 0x080a, 0x090e, 0x1002, 0x1106, 0x1206, 0x1302, 0x1406, 0x1502, 0x1602, 0x1706, 0x180e, 0x190a, 0x1406, 0x1502, 0x1602, 0x1706, 0x180e, 0x190a, 0x2022, 0x2126, 0x2226, 0x2322, 0x2426, 0x2522, 0x2622, 0x2726, 0x282e, 0x292a, 0x2426, 0x2522, 0x2622, 0x2726, 0x282e, 0x292a, 0x3026, 0x3122, 0x3222, 0x3326, 0x3422, 0x3526, 0x3626, 0x3722, 0x382a, 0x392e, 0x3422, 0x3526, 0x3626, 0x3722, 0x382a, 0x392e, 0x4002, 0x4106, 0x4206, 0x4302, 0x4406, 0x4502, 0x4602, 0x4706, 0x480e, 0x490a, 0x4406, 0x4502, 0x4602, 0x4706, 0x480e, 0x490a, 0x5006, 0x5102, 0x5202, 0x5306, 0x5402, 0x5506, 0x5606, 0x5702, 0x580a, 0x590e, 0x5402, 0x5506, 0x5606, 0x5702, 0x580a, 0x590e, 0x6026, 0x6122, 0x6222, 0x6326, 0x6422, 0x6526, 0x6626, 0x6722, 0x682a, 0x692e, 0x6422, 0x6526, 0x6626, 0x6722, 0x682a, 0x692e, 0x7022, 0x7126, 0x7226, 0x7322, 0x7426, 0x7522, 0x7622, 0x7726, 0x782e, 0x792a, 0x7426, 0x7522, 0x7622, 0x7726, 0x782e, 0x792a, 0x8082, 0x8186, 0x8286, 0x8382, 0x8486, 0x8582, 0x8682, 0x8786, 0x888e, 0x898a, 0x8486, 0x8582, 0x8682, 0x8786, 0x888e, 0x898a, 0x9086, 0x9182, 0x9282, 0x9386, 0x9482, 0x9586, 0x9686, 0x9782, 0x988a, 0x998e, 0x3423, 0x3527, 0x3627, 0x3723, 0x382b, 0x392f, 0x4003, 0x4107, 0x4207, 0x4303, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x5007, 0x5103, 0x5203, 0x5307, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x6027, 0x6123, 0x6223, 0x6327, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x7023, 0x7127, 0x7227, 0x7323, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x8083, 0x8187, 0x8287, 0x8383, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x9087, 0x9183, 0x9283, 0x9387, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f, 0xa0a7, 0xa1a3, 0xa2a3, 0xa3a7, 0xa4a3, 0xa5a7, 0xa6a7, 0xa7a3, 0xa8ab, 0xa9af, 0xa4a3, 0xa5a7, 0xa6a7, 0xa7a3, 0xa8ab, 0xa9af, 0xb0a3, 0xb1a7, 0xb2a7, 0xb3a3, 0xb4a7, 0xb5a3, 0xb6a3, 0xb7a7, 0xb8af, 0xb9ab, 0xb4a7, 0xb5a3, 0xb6a3, 0xb7a7, 0xb8af, 0xb9ab, 0xc087, 0xc183, 0xc283, 0xc387, 0xc483, 0xc587, 0xc687, 0xc783, 0xc88b, 0xc98f, 0xc483, 0xc587, 0xc687, 0xc783, 0xc88b, 0xc98f, 0xd083, 0xd187, 0xd287, 0xd383, 0xd487, 0xd583, 0xd683, 0xd787, 0xd88f, 0xd98b, 0xd487, 0xd583, 0xd683, 0xd787, 0xd88f, 0xd98b, 0xe0a3, 0xe1a7, 0xe2a7, 0xe3a3, 0xe4a7, 0xe5a3, 0xe6a3, 0xe7a7, 0xe8af, 0xe9ab, 0xe4a7, 0xe5a3, 0xe6a3, 0xe7a7, 0xe8af, 0xe9ab, 0xf0a7, 0xf1a3, 0xf2a3, 0xf3a7, 0xf4a3, 0xf5a7, 0xf6a7, 0xf7a3, 0xf8ab, 0xf9af, 0xf4a3, 0xf5a7, 0xf6a7, 0xf7a3, 0xf8ab, 0xf9af, 0x0047, 0x0103, 0x0203, 0x0307, 0x0403, 0x0507, 0x0607, 0x0703, 0x080b, 0x090f, 0x0403, 0x0507, 0x0607, 0x0703, 0x080b, 0x090f, 0x1003, 0x1107, 0x1207, 0x1303, 0x1407, 0x1503, 0x1603, 0x1707, 0x180f, 0x190b, 0x1407, 0x1503, 0x1603, 0x1707, 0x180f, 0x190b, 0x2023, 0x2127, 0x2227, 0x2323, 0x2427, 0x2523, 0x2623, 0x2727, 0x282f, 0x292b, 0x2427, 0x2523, 0x2623, 0x2727, 0x282f, 0x292b, 0x3027, 0x3123, 0x3223, 0x3327, 0x3423, 0x3527, 0x3627, 0x3723, 0x382b, 0x392f, 0x3423, 0x3527, 0x3627, 0x3723, 0x382b, 0x392f, 0x4003, 0x4107, 0x4207, 0x4303, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x5007, 0x5103, 0x5203, 0x5307, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x6027, 0x6123, 0x6223, 0x6327, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x7023, 0x7127, 0x7227, 0x7323, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x8083, 0x8187, 0x8287, 0x8383, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x9087, 0x9183, 0x9283, 0x9387, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f, 0x0604, 0x0700, 0x0808, 0x090c, 0x0a0c, 0x0b08, 0x0c0c, 0x0d08, 0x0e08, 0x0f0c, 0x1010, 0x1114, 0x1214, 0x1310, 0x1414, 0x1510, 0x1600, 0x1704, 0x180c, 0x1908, 0x1a08, 0x1b0c, 0x1c08, 0x1d0c, 0x1e0c, 0x1f08, 0x2030, 0x2134, 0x2234, 0x2330, 0x2434, 0x2530, 0x2620, 0x2724, 0x282c, 0x2928, 0x2a28, 0x2b2c, 0x2c28, 0x2d2c, 0x2e2c, 0x2f28, 0x3034, 0x3130, 0x3230, 0x3334, 0x3430, 0x3534, 0x3624, 0x3720, 0x3828, 0x392c, 0x3a2c, 0x3b28, 0x3c2c, 0x3d28, 0x3e28, 0x3f2c, 0x4010, 0x4114, 0x4214, 0x4310, 0x4414, 0x4510, 0x4600, 0x4704, 0x480c, 0x4908, 0x4a08, 0x4b0c, 0x4c08, 0x4d0c, 0x4e0c, 0x4f08, 0x5014, 0x5110, 0x5210, 0x5314, 0x5410, 0x5514, 0x5604, 0x5700, 0x5808, 0x590c, 0x5a0c, 0x5b08, 0x5c0c, 0x5d08, 0x5e08, 0x5f0c, 0x6034, 0x6130, 0x6230, 0x6334, 0x6430, 0x6534, 0x6624, 0x6720, 0x6828, 0x692c, 0x6a2c, 0x6b28, 0x6c2c, 0x6d28, 0x6e28, 0x6f2c, 0x7030, 0x7134, 0x7234, 0x7330, 0x7434, 0x7530, 0x7620, 0x7724, 0x782c, 0x7928, 0x7a28, 0x7b2c, 0x7c28, 0x7d2c, 0x7e2c, 0x7f28, 0x8090, 0x8194, 0x8294, 0x8390, 0x8494, 0x8590, 0x8680, 0x8784, 0x888c, 0x8988, 0x8a88, 0x8b8c, 0x8c88, 0x8d8c, 0x8e8c, 0x8f88, 0x9094, 0x9190, 0x9290, 0x9394, 0x9490, 0x9594, 0x9684, 0x9780, 0x9888, 0x998c, 0x9a8c, 0x9b88, 0x9c8c, 0x9d88, 0x9e88, 0x9f8c, 0x0055, 0x0111, 0x0211, 0x0315, 0x0411, 0x0515, 0x0605, 0x0701, 0x0809, 0x090d, 0x0a0d, 0x0b09, 0x0c0d, 0x0d09, 0x0e09, 0x0f0d, 0x1011, 0x1115, 0x1215, 0x1311, 0x1415, 0x1511, 0x1601, 0x1705, 0x180d, 0x1909, 0x1a09, 0x1b0d, 0x1c09, 0x1d0d, 0x1e0d, 0x1f09, 0x2031, 0x2135, 0x2235, 0x2331, 0x2435, 0x2531, 0x2621, 0x2725, 0x282d, 0x2929, 0x2a29, 0x2b2d, 0x2c29, 0x2d2d, 0x2e2d, 0x2f29, 0x3035, 0x3131, 0x3231, 0x3335, 0x3431, 0x3535, 0x3625, 0x3721, 0x3829, 0x392d, 0x3a2d, 0x3b29, 0x3c2d, 0x3d29, 0x3e29, 0x3f2d, 0x4011, 0x4115, 0x4215, 0x4311, 0x4415, 0x4511, 0x4601, 0x4705, 0x480d, 0x4909, 0x4a09, 0x4b0d, 0x4c09, 0x4d0d, 0x4e0d, 0x4f09, 0x5015, 0x5111, 0x5211, 0x5315, 0x5411, 0x5515, 0x5605, 0x5701, 0x5809, 0x590d, 0x5a0d, 0x5b09, 0x5c0d, 0x5d09, 0x5e09, 0x5f0d, 0x6035, 0x6131, 0x6231, 0x6335, 0x6431, 0x6535, 0x6625, 0x6721, 0x6829, 0x692d, 0x6a2d, 0x6b29, 0x6c2d, 0x6d29, 0x6e29, 0x6f2d, 0x7031, 0x7135, 0x7235, 0x7331, 0x7435, 0x7531, 0x7621, 0x7725, 0x782d, 0x7929, 0x7a29, 0x7b2d, 0x7c29, 0x7d2d, 0x7e2d, 0x7f29, 0x8091, 0x8195, 0x8295, 0x8391, 0x8495, 0x8591, 0x8681, 0x8785, 0x888d, 0x8989, 0x8a89, 0x8b8d, 0x8c89, 0x8d8d, 0x8e8d, 0x8f89, 0x9095, 0x9191, 0x9291, 0x9395, 0x9491, 0x9595, 0x9685, 0x9781, 0x9889, 0x998d, 0x9a8d, 0x9b89, 0x9c8d, 0x9d89, 0x9e89, 0x9f8d, 0xa0b5, 0xa1b1, 0xa2b1, 0xa3b5, 0xa4b1, 0xa5b5, 0xa6a5, 0xa7a1, 0xa8a9, 0xa9ad, 0xaaad, 0xaba9, 0xacad, 0xada9, 0xaea9, 0xafad, 0xb0b1, 0xb1b5, 0xb2b5, 0xb3b1, 0xb4b5, 0xb5b1, 0xb6a1, 0xb7a5, 0xb8ad, 0xb9a9, 0xbaa9, 0xbbad, 0xbca9, 0xbdad, 0xbead, 0xbfa9, 0xc095, 0xc191, 0xc291, 0xc395, 0xc491, 0xc595, 0xc685, 0xc781, 0xc889, 0xc98d, 0xca8d, 0xcb89, 0xcc8d, 0xcd89, 0xce89, 0xcf8d, 0xd091, 0xd195, 0xd295, 0xd391, 0xd495, 0xd591, 0xd681, 0xd785, 0xd88d, 0xd989, 0xda89, 0xdb8d, 0xdc89, 0xdd8d, 0xde8d, 0xdf89, 0xe0b1, 0xe1b5, 0xe2b5, 0xe3b1, 0xe4b5, 0xe5b1, 0xe6a1, 0xe7a5, 0xe8ad, 0xe9a9, 0xeaa9, 0xebad, 0xeca9, 0xedad, 0xeead, 0xefa9, 0xf0b5, 0xf1b1, 0xf2b1, 0xf3b5, 0xf4b1, 0xf5b5, 0xf6a5, 0xf7a1, 0xf8a9, 0xf9ad, 0xfaad, 0xfba9, 0xfcad, 0xfda9, 0xfea9, 0xffad, 0x0055, 0x0111, 0x0211, 0x0315, 0x0411, 0x0515, 0x0605, 0x0701, 0x0809, 0x090d, 0x0a0d, 0x0b09, 0x0c0d, 0x0d09, 0x0e09, 0x0f0d, 0x1011, 0x1115, 0x1215, 0x1311, 0x1415, 0x1511, 0x1601, 0x1705, 0x180d, 0x1909, 0x1a09, 0x1b0d, 0x1c09, 0x1d0d, 0x1e0d, 0x1f09, 0x2031, 0x2135, 0x2235, 0x2331, 0x2435, 0x2531, 0x2621, 0x2725, 0x282d, 0x2929, 0x2a29, 0x2b2d, 0x2c29, 0x2d2d, 0x2e2d, 0x2f29, 0x3035, 0x3131, 0x3231, 0x3335, 0x3431, 0x3535, 0x3625, 0x3721, 0x3829, 0x392d, 0x3a2d, 0x3b29, 0x3c2d, 0x3d29, 0x3e29, 0x3f2d, 0x4011, 0x4115, 0x4215, 0x4311, 0x4415, 0x4511, 0x4601, 0x4705, 0x480d, 0x4909, 0x4a09, 0x4b0d, 0x4c09, 0x4d0d, 0x4e0d, 0x4f09, 0x5015, 0x5111, 0x5211, 0x5315, 0x5411, 0x5515, 0x5605, 0x5701, 0x5809, 0x590d, 0x5a0d, 0x5b09, 0x5c0d, 0x5d09, 0x5e09, 0x5f0d, 0x6035, 0x6131, 0x6231, 0x6335, 0x6431, 0x6535, 0xfabe, 0xfbba, 0xfcbe, 0xfdba, 0xfeba, 0xffbe, 0x0046, 0x0102, 0x0202, 0x0306, 0x0402, 0x0506, 0x0606, 0x0702, 0x080a, 0x090e, 0x0a1e, 0x0b1a, 0x0c1e, 0x0d1a, 0x0e1a, 0x0f1e, 0x1002, 0x1106, 0x1206, 0x1302, 0x1406, 0x1502, 0x1602, 0x1706, 0x180e, 0x190a, 0x1a1a, 0x1b1e, 0x1c1a, 0x1d1e, 0x1e1e, 0x1f1a, 0x2022, 0x2126, 0x2226, 0x2322, 0x2426, 0x2522, 0x2622, 0x2726, 0x282e, 0x292a, 0x2a3a, 0x2b3e, 0x2c3a, 0x2d3e, 0x2e3e, 0x2f3a, 0x3026, 0x3122, 0x3222, 0x3326, 0x3422, 0x3526, 0x3626, 0x3722, 0x382a, 0x392e, 0x3a3e, 0x3b3a, 0x3c3e, 0x3d3a, 0x3e3a, 0x3f3e, 0x4002, 0x4106, 0x4206, 0x4302, 0x4406, 0x4502, 0x4602, 0x4706, 0x480e, 0x490a, 0x4a1a, 0x4b1e, 0x4c1a, 0x4d1e, 0x4e1e, 0x4f1a, 0x5006, 0x5102, 0x5202, 0x5306, 0x5402, 0x5506, 0x5606, 0x5702, 0x580a, 0x590e, 0x5a1e, 0x5b1a, 0x5c1e, 0x5d1a, 0x5e1a, 0x5f1e, 0x6026, 0x6122, 0x6222, 0x6326, 0x6422, 0x6526, 0x6626, 0x6722, 0x682a, 0x692e, 0x6a3e, 0x6b3a, 0x6c3e, 0x6d3a, 0x6e3a, 0x6f3e, 0x7022, 0x7126, 0x7226, 0x7322, 0x7426, 0x7522, 0x7622, 0x7726, 0x782e, 0x792a, 0x7a3a, 0x7b3e, 0x7c3a, 0x7d3e, 0x7e3e, 0x7f3a, 0x8082, 0x8186, 0x8286, 0x8382, 0x8486, 0x8582, 0x8682, 0x8786, 0x888e, 0x898a, 0x8a9a, 0x8b9e, 0x8c9a, 0x8d9e, 0x8e9e, 0x8f9a, 0x9086, 0x9182, 0x9282, 0x9386, 0x3423, 0x3527, 0x3627, 0x3723, 0x382b, 0x392f, 0x3a3f, 0x3b3b, 0x3c3f, 0x3d3b, 0x3e3b, 0x3f3f, 0x4003, 0x4107, 0x4207, 0x4303, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x4a1b, 0x4b1f, 0x4c1b, 0x4d1f, 0x4e1f, 0x4f1b, 0x5007, 0x5103, 0x5203, 0x5307, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x5a1f, 0x5b1b, 0x5c1f, 0x5d1b, 0x5e1b, 0x5f1f, 0x6027, 0x6123, 0x6223, 0x6327, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x6a3f, 0x6b3b, 0x6c3f, 0x6d3b, 0x6e3b, 0x6f3f, 0x7023, 0x7127, 0x7227, 0x7323, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x7a3b, 0x7b3f, 0x7c3b, 0x7d3f, 0x7e3f, 0x7f3b, 0x8083, 0x8187, 0x8287, 0x8383, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x8a9b, 0x8b9f, 0x8c9b, 0x8d9f, 0x8e9f, 0x8f9b, 0x9087, 0x9183, 0x9283, 0x9387, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f, 0x9a9f, 0x9b9b, 0x9c9f, 0x9d9b, 0x9e9b, 0x9f9f, 0xa0a7, 0xa1a3, 0xa2a3, 0xa3a7, 0xa4a3, 0xa5a7, 0xa6a7, 0xa7a3, 0xa8ab, 0xa9af, 0xaabf, 0xabbb, 0xacbf, 0xadbb, 0xaebb, 0xafbf, 0xb0a3, 0xb1a7, 0xb2a7, 0xb3a3, 0xb4a7, 0xb5a3, 0xb6a3, 0xb7a7, 0xb8af, 0xb9ab, 0xbabb, 0xbbbf, 0xbcbb, 0xbdbf, 0xbebf, 0xbfbb, 0xc087, 0xc183, 0xc283, 0xc387, 0xc483, 0xc587, 0xc687, 0xc783, 0xc88b, 0xc98f, 0xca9f, 0xcb9b, 0xcc9f, 0xcd9b, 0xce9b, 0xcf9f, 0xd083, 0xd187, 0xd287, 0xd383, 0xd487, 0xd583, 0xd683, 0xd787, 0xd88f, 0xd98b, 0xda9b, 0xdb9f, 0xdc9b, 0xdd9f, 0xde9f, 0xdf9b, 0xe0a3, 0xe1a7, 0xe2a7, 0xe3a3, 0xe4a7, 0xe5a3, 0xe6a3, 0xe7a7, 0xe8af, 0xe9ab, 0xeabb, 0xebbf, 0xecbb, 0xedbf, 0xeebf, 0xefbb, 0xf0a7, 0xf1a3, 0xf2a3, 0xf3a7, 0xf4a3, 0xf5a7, 0xf6a7, 0xf7a3, 0xf8ab, 0xf9af, 0xfabf, 0xfbbb, 0xfcbf, 0xfdbb, 0xfebb, 0xffbf, 0x0047, 0x0103, 0x0203, 0x0307, 0x0403, 0x0507, 0x0607, 0x0703, 0x080b, 0x090f, 0x0a1f, 0x0b1b, 0x0c1f, 0x0d1b, 0x0e1b, 0x0f1f, 0x1003, 0x1107, 0x1207, 0x1303, 0x1407, 0x1503, 0x1603, 0x1707, 0x180f, 0x190b, 0x1a1b, 0x1b1f, 0x1c1b, 0x1d1f, 0x1e1f, 0x1f1b, 0x2023, 0x2127, 0x2227, 0x2323, 0x2427, 0x2523, 0x2623, 0x2727, 0x282f, 0x292b, 0x2a3b, 0x2b3f, 0x2c3b, 0x2d3f, 0x2e3f, 0x2f3b, 0x3027, 0x3123, 0x3223, 0x3327, 0x3423, 0x3527, 0x3627, 0x3723, 0x382b, 0x392f, 0x3a3f, 0x3b3b, 0x3c3f, 0x3d3b, 0x3e3b, 0x3f3f, 0x4003, 0x4107, 0x4207, 0x4303, 0x4407, 0x4503, 0x4603, 0x4707, 0x480f, 0x490b, 0x4a1b, 0x4b1f, 0x4c1b, 0x4d1f, 0x4e1f, 0x4f1b, 0x5007, 0x5103, 0x5203, 0x5307, 0x5403, 0x5507, 0x5607, 0x5703, 0x580b, 0x590f, 0x5a1f, 0x5b1b, 0x5c1f, 0x5d1b, 0x5e1b, 0x5f1f, 0x6027, 0x6123, 0x6223, 0x6327, 0x6423, 0x6527, 0x6627, 0x6723, 0x682b, 0x692f, 0x6a3f, 0x6b3b, 0x6c3f, 0x6d3b, 0x6e3b, 0x6f3f, 0x7023, 0x7127, 0x7227, 0x7323, 0x7427, 0x7523, 0x7623, 0x7727, 0x782f, 0x792b, 0x7a3b, 0x7b3f, 0x7c3b, 0x7d3f, 0x7e3f, 0x7f3b, 0x8083, 0x8187, 0x8287, 0x8383, 0x8487, 0x8583, 0x8683, 0x8787, 0x888f, 0x898b, 0x8a9b, 0x8b9f, 0x8c9b, 0x8d9f, 0x8e9f, 0x8f9b, 0x9087, 0x9183, 0x9283, 0x9387, 0x9483, 0x9587, 0x9687, 0x9783, 0x988b, 0x998f }; tilem-2.0/emu/z80ddfd.h000066400000000000000000000175151220200411600146640ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef PREFIX_DD # define RegH IXh # define RegL IXl # define RegHL IX #else # define RegH IYh # define RegL IYl # define RegHL IY #endif switch (op) { case 0x09: /* ADD IX, BC */ WZ = RegHL + 1; add16(RegHL, BC); delay(11); break; case 0x19: /* ADD IX, DE */ WZ = RegHL + 1; add16(RegHL, DE); delay(11); break; case 0x21: /* LD IX, nn */ RegHL = readw(PC); PC += 2; delay(10); break; case 0x22: /* LD (nn), IX */ WZ = readw(PC); PC += 2; writeb(WZ, RegL); WZ++; writeb(WZ, RegH); delay(16); break; case 0x23: /* INC IX */ RegHL++; delay(6); break; case 0x24: /* INC IXH */ UNDOCUMENTED(4); inc(RegH); delay(4); break; case 0x25: /* DEC IXH */ UNDOCUMENTED(4); dec(RegH); delay(4); break; case 0x26: /* LD IXH, n */ UNDOCUMENTED(4); RegH = readb(PC++); delay(7); break; case 0x29: /* ADD IX, IX */ WZ = RegHL + 1; add16(RegHL, RegHL); delay(11); break; case 0x2A: /* LD IX, (nn) */ WZ = readw(PC); PC += 2; RegL = readb(WZ); WZ++; RegH = readb(WZ); delay(16); break; case 0x2B: /* DEC IX */ RegHL--; delay(6); break; case 0x2C: /* INC IXL */ UNDOCUMENTED(4); inc(RegL); delay(4); break; case 0x2D: /* DEC IXL */ UNDOCUMENTED(4); dec(RegL); delay(4); break; case 0x2E: /* LD IXL,n */ UNDOCUMENTED(4); RegL = readb(PC++); delay(7); break; case 0x34: /* INC (IX + n) */ offs = (int) (signed char) readb(PC++); WZ = RegHL + offs; tmp1 = readb(WZ); inc(tmp1); writeb(WZ, tmp1); delay(19); break; case 0x35: /* DEC (IX + n) */ offs = (int) (signed char) readb(PC++); WZ = RegHL + offs; tmp1 = readb(WZ); dec(tmp1); writeb(WZ, tmp1); delay(19); break; case 0x36: /* LD (IX + n), n */ offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, readb(PC++)); delay(15); /* Yes, really! */ break; case 0x39: /* ADD IX, SP */ WZ = RegHL + 1; add16(RegHL, SP); delay(11); break; case 0x44: UNDOCUMENTED(4); B = RegH; delay(4); break; case 0x45: UNDOCUMENTED(4); B = RegL; delay(4); break; case 0x46: offs = (int) (signed char) readb(PC++); B = readb(RegHL + offs); delay(15); break; case 0x4C: UNDOCUMENTED(4); C = RegH; delay(4); break; case 0x4D: UNDOCUMENTED(4); C = RegL; delay(4); break; case 0x4E: offs = (int) (signed char) readb(PC++); C = readb(RegHL + offs); delay(15); break; case 0x54: UNDOCUMENTED(4); D = RegH; delay(4); break; case 0x55: UNDOCUMENTED(4); D = RegL; delay(4); break; case 0x56: offs = (int) (signed char) readb(PC++); D = readb(RegHL + offs); delay(15); break; case 0x5C: UNDOCUMENTED(4); E = RegH; delay(4); break; case 0x5D: UNDOCUMENTED(4); E = RegL; delay(4); break; case 0x5E: offs = (int) (signed char) readb(PC++); E = readb(RegHL + offs); delay(15); break; case 0x60: UNDOCUMENTED(4); RegH = B; delay(4); break; case 0x61: UNDOCUMENTED(4); RegH = C; delay(4); break; case 0x62: UNDOCUMENTED(4); RegH = D; delay(4); break; case 0x63: UNDOCUMENTED(4); RegH = E; delay(4); break; case 0x64: UNDOCUMENTED(4); RegH = RegH; delay(4); break; case 0x65: UNDOCUMENTED(4); RegH = RegL; delay(4); break; case 0x66: offs = (int) (signed char) readb(PC++); H = readb(RegHL + offs); delay(15); break; case 0x67: UNDOCUMENTED(4); RegH = A; delay(4); break; case 0x68: UNDOCUMENTED(4); RegL = B; delay(4); break; case 0x69: UNDOCUMENTED(4); RegL = C; delay(4); break; case 0x6A: UNDOCUMENTED(4); RegL = D; delay(4); break; case 0x6B: UNDOCUMENTED(4); RegL = E; delay(4); break; case 0x6C: UNDOCUMENTED(4); RegL = RegH; delay(4); break; case 0x6D: UNDOCUMENTED(4); RegL = RegL; delay(4); break; case 0x6E: offs = (int) (signed char) readb(PC++); L = readb(RegHL + offs); delay(15); break; case 0x6F: UNDOCUMENTED(4); RegL = A; delay(4); break; case 0x70: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, B); delay(15); break; case 0x71: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, C); delay(15); break; case 0x72: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, D); delay(15); break; case 0x73: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, E); delay(15); break; case 0x74: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, H); delay(15); break; case 0x75: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, L); delay(15); break; case 0x77: offs = (int) (signed char) readb(PC++); writeb(RegHL + offs, A); delay(15); break; case 0x7C: UNDOCUMENTED(4); A = RegH; delay(4); break; case 0x7D: UNDOCUMENTED(4); A = RegL; delay(4); break; case 0x7E: offs = (int) (signed char) readb(PC++); A = readb(RegHL + offs); delay(15); break; case 0x84: UNDOCUMENTED(4); add8(A, RegH); delay(4); break; case 0x85: UNDOCUMENTED(4); add8(A, RegL); delay(4); break; case 0x86: offs = (int) (signed char) readb(PC++); add8(A, readb(RegHL + offs)); delay(7); break; case 0x8C: UNDOCUMENTED(4); adc8(A, RegH); delay(4); break; case 0x8D: UNDOCUMENTED(4); adc8(A, RegL); delay(4); break; case 0x8E: offs = (int) (signed char) readb(PC++); adc8(A, readb(RegHL + offs)); delay(15); break; case 0x94: UNDOCUMENTED(4); sub8(A, RegH); delay(4); break; case 0x95: UNDOCUMENTED(4); sub8(A, RegL); delay(4); break; case 0x96: offs = (int) (signed char) readb(PC++); sub8(A, readb(RegHL + offs)); delay(15); break; case 0x9C: UNDOCUMENTED(4); sbc8(A, RegH); delay(4); break; case 0x9D: UNDOCUMENTED(4); sbc8(A, RegL); delay(4); break; case 0x9E: offs = (int) (signed char) readb(PC++); sbc8(A, readb(RegHL + offs)); delay(15); break; case 0xA4: UNDOCUMENTED(4); and(A, RegH); delay(4); break; case 0xA5: UNDOCUMENTED(4); and(A, RegL); delay(4); break; case 0xA6: offs = (int) (signed char) readb(PC++); and(A, readb(RegHL + offs)); delay(15); break; case 0xAC: UNDOCUMENTED(4); xor(A, RegH); delay(4); break; case 0xAD: UNDOCUMENTED(4); xor(A, RegL); delay(4); break; case 0xAE: offs = (int) (signed char) readb(PC++); xor(A, readb(RegHL + offs)); delay(15); break; case 0xB4: UNDOCUMENTED(4); or(A, RegH); delay(4); break; case 0xB5: UNDOCUMENTED(4); or(A, RegL); delay(4); break; case 0xB6: offs = (int) (signed char) readb(PC++); or(A, readb(RegHL + offs)); delay(15); break; case 0xBC: UNDOCUMENTED(4); cp(A, RegH); delay(4); break; case 0xBD: UNDOCUMENTED(4); cp(A, RegL); delay(4); break; case 0xBE: offs = (int) (signed char) readb(PC++); cp(A, readb(RegHL + offs)); delay(15); break; case 0xCB: offs = (int) (signed char) readb(PC++); WZ = RegHL + offs; op = readb(PC++); #ifdef PREFIX_DD goto opcode_ddcb; #else goto opcode_fdcb; #endif case 0xE1: /* POP IX */ pop(RegHL); delay(10); break; case 0xE3: /* EX (SP), IX */ WZ = readw(SP); writew(SP, RegHL); RegHL = WZ; delay(19); break; case 0xE5: /* PUSH IX */ push(RegHL); delay(11); break; case 0xE9: /* JP IX */ PC = RegHL; delay(4); break; case 0xF9: /* LD SP, IX */ SP = RegHL; delay(4); break; default: goto opcode_main; } #undef RegH #undef RegL #undef RegHL tilem-2.0/emu/z80ed.h000066400000000000000000000160611220200411600143460ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ switch (op) { case 0x40: /* IN B, (C) */ WZ = BC; delay(12); in(B); break; case 0x41: /* OUT (C), B */ delay(12); output(BC, B); break; case 0x42: /* SBC HL, BC */ WZ = HL + 1; sbc16(HLw, BCw); delay(15); break; case 0x43: /* LD (nn), BC */ WZ = readw(PC); PC += 2; writew(WZ++, BC); delay(20); break; case 0x44: /* NEG */ neg(A); delay(8); break; case 0x45: /* RETN */ IFF1 = IFF2; pop(PC); delay(14); break; case 0x46: /* IM 0 */ IM = 0; delay(8); break; case 0x47: /* LD I,A */ I = A; delay(9); break; case 0x48: /* IN C, (C) */ WZ = BC; delay(12); in(C); break; case 0x49: /* OUT (C), C */ delay(12); output(BC, C); break; case 0x4A: /* ADC HL, BC */ WZ = HL + 1; adc16(HLw, BCw); delay(15); break; case 0x4B: /* LD BC, (nn) */ WZ = readw(PC); PC += 2; BC = readw(WZ++); delay(20); break; case 0x4C: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x4D: /* RETI */ IFF1 = IFF2; pop(PC); delay(14); break; case 0x4E: /* IM 0 */ UNDOCUMENTED(8); IM = 0; delay(8); break; case 0x4F: /* LD R,A */ Rl = A; Rh = A & 0x80; delay(9); break; case 0x50: /* IN D, (C) */ WZ = BC; delay(12); in(D); break; case 0x51: /* OUT (C), D */ delay(12); output(BC, D); break; case 0x52: /* SBC HL, DE */ WZ = HL + 1; sbc16(HLw, DEw); delay(15); break; case 0x53: /* LD (nn), DE */ WZ = readw(PC); PC += 2; writew(WZ++, DE); delay(20); break; case 0x54: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x55: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x56: /* IM 1 */ IM = 1; delay(8); break; case 0x57: /* LD A,I */ ld_a_ir(I); delay(9); break; case 0x58: /* IN E, (C) */ WZ = BC; delay(12); in(E); break; case 0x59: /* OUT (C), E */ delay(12); output(BC, E); break; case 0x5A: /* ADC HL, DE */ WZ = HL + 1; adc16(HLw, DEw); delay(15); break; case 0x5B: /* LD DE, (nn) */ WZ = readw(PC); PC += 2; DE = readw(WZ++); delay(20); break; case 0x5C: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x5D: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x5E: /* IM 2 */ IM = 2; delay(8); break; case 0x5F: /* LD A,R */ ld_a_ir(R); delay(9); break; case 0x60: /* IN H, (C) */ WZ = BC; delay(12); in(H); break; case 0x61: /* OUT (C), H */ delay(12); output(BC, H); break; case 0x62: /* SBC HL, HL */ WZ = HL + 1; sbc16(HLw, HLw); delay(15); break; case 0x63: /* LD (nn), HL */ WZ = readw(PC); PC += 2; writew(WZ++, HL); delay(20); break; case 0x64: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x65: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x66: /* IM 0 */ UNDOCUMENTED(8); IM = 0; delay(8); break; case 0x67: /* RRD */ rrd; delay(18); break; case 0x68: /* IN L, (C) */ WZ = BC; delay(12); in(L); break; case 0x69: /* OUT (C), L */ delay(12); output(BC, L); break; case 0x6A: /* ADC HL, HL */ WZ = HL + 1; adc16(HLw, HLw); delay(15); break; case 0x6B: /* LD HL, (nn) */ WZ = readw(PC); PC += 2; HL = readw(WZ++); delay(20); break; case 0x6C: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x6D: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x6E: /* IM 0 */ UNDOCUMENTED(8); IM = 0; delay(8); break; case 0x6F: /* RLD */ rld; delay(18); break; case 0x70: /* IN (C) */ UNDOCUMENTED(8); WZ = BC; delay(12); in(tmp1); break; case 0x71: /* OUT (C), 0 */ UNDOCUMENTED(8); delay(12); output(BC, 0); break; case 0x72: /* SBC HL, SP */ WZ = HL + 1; sbc16(HLw, SPw); delay(15); break; case 0x73: /* LD (nn), SP */ WZ = readw(PC); PC += 2; writew(WZ++, SP); delay(20); break; case 0x74: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x75: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x76: /* IM 1 */ UNDOCUMENTED(8); IM = 1; delay(8); break; case 0x78: /* IN A, (C) */ WZ = BC; delay(12); in(A); break; case 0x79: /* OUT (C), A */ delay(12); output(BC, A); break; case 0x7A: /* ADC HL, SP */ WZ = HL + 1; adc16(HLw, SPw); delay(15); break; case 0x7B: /* LD SP, (nn) */ WZ = readw(PC); PC += 2; SP = readw(WZ); WZ++; delay(20); break; case 0x7C: /* NEG */ UNDOCUMENTED(8); neg(A); delay(8); break; case 0x7D: /* RETN */ UNDOCUMENTED(8); IFF1 = IFF2; pop(PC); delay(14); break; case 0x7E: /* IM 2 */ UNDOCUMENTED(8); IM = 2; delay(8); break; case 0xA0: /* LDI */ ldi; delay(16); break; case 0xA1: /* CPI */ cpi; delay(16); break; case 0xA2: /* INI */ delay(13); ini; delay(3); break; case 0xA3: /* OUTI */ delay(16); outi; break; case 0xA8: /* LDD */ ldd; delay(16); break; case 0xA9: /* CPD */ cpd; delay(16); break; case 0xAA: /* IND */ delay(13); ind; delay(3); break; case 0xAB: /* OUTD */ delay(16); outd; break; case 0xB0: /* LDIR */ ldi; if (BCw) { PC -= 2; delay(21); } else delay(16); break; case 0xB1: /* CPIR */ cpi; if (BCw && !(F & FLAG_Z)) { PC -= 2; delay(21); } else delay(16); break; case 0xB2: /* INIR */ delay(13); ini; if (B) { PC -= 2; delay(8); } else delay(3); break; case 0xB3: /* OTIR */ delay(16); outi; if (B) { PC -= 2; delay(5); } break; case 0xB8: /* LDDR */ ldd; if (BCw) { PC -= 2; delay(21); } else delay(16); break; case 0xB9: /* CPDR */ cpd; if (BCw && !(F & FLAG_Z)) { PC -= 2; delay(21); } else delay(16); break; case 0xBA: /* INDR */ delay(13); ind; if (B) { PC -= 2; delay(8); } else delay(3); break; case 0xBB: /* OTDR */ delay(16); outd; if (B) { PC -= 2; delay(5); } break; default: delay(8); if (calc->hw.z80_instr) (*calc->hw.z80_instr)(calc, 0xed00 | op); else if (calc->z80.emuflags & TILEM_Z80_BREAK_INVALID) tilem_z80_stop(calc, TILEM_STOP_INVALID_INST); break; } tilem-2.0/emu/z80main.h000066400000000000000000000410611220200411600147000ustar00rootroot00000000000000/* * libtilemcore - Graphing calculator emulation library * * Copyright (C) 2009 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ switch (op) { case 0x00: /* NOP */ delay(4); break; case 0x01: /* LD BC, nn */ BC = readw(PC); PC += 2; delay(10); break; case 0x02: /* LD (BC), A */ W = A; writeb(BC, A); delay(7); break; case 0x03: /* INC BC */ BC++; delay(6); break; case 0x04: /* INC B */ inc(B); delay(4); break; case 0x05: /* DEC B */ dec(B); delay(4); break; case 0x06: /* LD B, n */ B = readb(PC++); delay(7); break; case 0x07: /* RLCA */ rlca; delay(4); break; case 0x08: /* EX AF, AF' */ ex(AF, AF2); delay(4); break; case 0x09: /* ADD HL, BC */ WZ = HL + 1; add16(HLw, BCw); delay(11); break; case 0x0A: /* LD A, (BC) */ WZ = BC; A = readb(WZ++); delay(7); break; case 0x0B: /* DEC BC */ BC--; delay(6); break; case 0x0C: /* INC C */ inc(C); delay(4); break; case 0x0D: /* DEC C */ dec(C); delay(4); break; case 0x0E: /* LD C, n */ C = readb(PC++); delay(7); break; case 0x0F: /* RRCA */ rrca; delay(4); break; case 0x10: /* DJNZ $+n */ offs = (int) (signed char) readb(PC++); B--; if (B) { WZ = PC + offs; PC = WZ; delay(13); } else delay(8); break; case 0x11: /* LD DE, nn */ DE = readw(PC); PC += 2; delay(10); break; case 0x12: /* LD (DE), A */ W = A; writeb(DE, A); delay(7); break; case 0x13: /* INC DE */ DE++; delay(6); break; case 0x14: /* INC D */ inc(D); delay(4); break; case 0x15: /* DEC D */ dec(D); delay(4); break; case 0x16: /* LD D, n */ D = readb(PC++); delay(7); break; case 0x17: /* RLA */ rla; delay(4); break; case 0x18: /* JR $+n */ offs = (int) (signed char) readb(PC++); WZ = PC + offs; PC = WZ; delay(12); break; case 0x19: /* ADD HL, DE */ WZ = HL + 1; add16(HLw, DEw); delay(11); break; case 0x1A: /* LD A, (DE) */ WZ = DE; A = readb(WZ++); delay(7); break; case 0x1B: /* DEC DE */ DE--; delay(6); break; case 0x1C: /* INC E */ inc(E); delay(4); break; case 0x1D: /* DEC E */ dec(E); delay(4); break; case 0x1E: /* LD E, n */ E = readb(PC++); delay(7); break; case 0x1F: /* RRA */ rra; delay(4); break; case 0x20: /* JR NZ, $+n */ offs = (int) (signed char) readb(PC++); if (!(F & FLAG_Z)) { WZ = PC + offs; PC = WZ; delay(12); } else delay(7); break; case 0x21: /* LD HL, nn */ HL = readw(PC); PC += 2; delay(10); break; case 0x22: /* LD (nn), HL */ WZ = readw(PC); PC += 2; writew(WZ++, HL); delay(16); break; case 0x23: /* INC HL */ HL++; delay(6); break; case 0x24: /* INC H */ inc(H); delay(4); break; case 0x25: /* DEC H */ dec(H); delay(4); break; case 0x26: /* LD H, n */ H = readb(PC++); delay(7); break; case 0x27: /* DAA */ daa; delay(4); break; case 0x28: /* JR Z, $+n */ offs = (int) (signed char) readb(PC++); if (F & FLAG_Z) { WZ = PC + offs; PC = WZ; delay(12); } else delay(7); break; case 0x29: /* ADD HL, HL */ WZ = HL + 1; add16(HLw, HLw); delay(11); break; case 0x2A: /* LD HL, (nn) */ WZ = readw(PC); PC += 2; HL = readw(WZ++); delay(16); break; case 0x2B: /* DEC HL */ HL--; delay(6); break; case 0x2C: /* INC L */ inc(L); delay(4); break; case 0x2D: /* DEC L */ dec(L); delay(4); break; case 0x2E: /* LD L,n */ L = readb(PC++); delay(7); break; case 0x2F: /* CPL */ cpl(A); delay(4); break; case 0x30: /* JR NC, $+n */ offs = (int) (signed char) readb(PC++); if (!(F & FLAG_C)) { WZ = PC + offs; PC = WZ; delay(12); } else delay(7); break; case 0x31: /* LD SP, nn */ SP = readw(PC); PC += 2; delay(10); break; case 0x32: /* LD (nn), A */ tmp2 = readw(PC); PC += 2; writeb(tmp2, A); W = A; /* is this really correct?! */ delay(13); break; case 0x33: /* INC SP */ SP++; delay(6); break; case 0x34: /* INC (HL) */ tmp1 = readb(HL); inc(tmp1); writeb(HL, tmp1); delay(11); break; case 0x35: /* DEC (HL) */ tmp1 = readb(HL); dec(tmp1); writeb(HL, tmp1); delay(11); break; case 0x36: /* LD (HL), n */ tmp1 = readb(PC++); writeb(HL, tmp1); delay(10); break; case 0x37: /* SCF */ F |= FLAG_C; delay(4); break; case 0x38: /* JR C, $+n */ offs = (int) (signed char) readb(PC++); if (F & FLAG_C) { WZ = PC + offs; PC = WZ; delay(12); } else delay(7); break; case 0x39: /* ADD HL, SP */ WZ = HL + 1; add16(HLw, SPw); delay(11); break; case 0x3A: /* LD A, (nn) */ WZ = readw(PC); PC += 2; A = readb(WZ++); delay(13); break; case 0x3B: /* DEC SP */ SP--; delay(6); break; case 0x3C: /* INC A */ inc(A); delay(4); break; case 0x3D: /* DEC A */ dec(A); delay(4); break; case 0x3E: /* LD A, n */ A = readb(PC++); delay(7); break; case 0x3F: /* CCF */ F ^= FLAG_C; delay(4); break; case 0x40: B = B; delay(4); break; case 0x41: B = C; delay(4); break; case 0x42: B = D; delay(4); break; case 0x43: B = E; delay(4); break; case 0x44: B = H; delay(4); break; case 0x45: B = L; delay(4); break; case 0x46: B = readb(HL); delay(7); break; case 0x47: B = A; delay(4); break; case 0x48: C = B; delay(4); break; case 0x49: C = C; delay(4); break; case 0x4A: C = D; delay(4); break; case 0x4B: C = E; delay(4); break; case 0x4C: C = H; delay(4); break; case 0x4D: C = L; delay(4); break; case 0x4E: C = readb(HL); delay(7); break; case 0x4F: C = A; delay(4); break; case 0x50: D = B; delay(4); break; case 0x51: D = C; delay(4); break; case 0x52: D = D; delay(4); break; case 0x53: D = E; delay(4); break; case 0x54: D = H; delay(4); break; case 0x55: D = L; delay(4); break; case 0x56: D = readb(HL); delay(7); break; case 0x57: D = A; delay(4); break; case 0x58: E = B; delay(4); break; case 0x59: E = C; delay(4); break; case 0x5A: E = D; delay(4); break; case 0x5B: E = E; delay(4); break; case 0x5C: E = H; delay(4); break; case 0x5D: E = L; delay(4); break; case 0x5E: E = readb(HL); delay(7); break; case 0x5F: E = A; delay(4); break; case 0x60: H = B; delay(4); break; case 0x61: H = C; delay(4); break; case 0x62: H = D; delay(4); break; case 0x63: H = E; delay(4); break; case 0x64: H = H; delay(4); break; case 0x65: H = L; delay(4); break; case 0x66: H = readb(HL); delay(7); break; case 0x67: H = A; delay(4); break; case 0x68: L = B; delay(4); break; case 0x69: L = C; delay(4); break; case 0x6A: L = D; delay(4); break; case 0x6B: L = E; delay(4); break; case 0x6C: L = H; delay(4); break; case 0x6D: L = L; delay(4); break; case 0x6E: L = readb(HL); delay(7); break; case 0x6F: L = A; delay(4); break; case 0x70: writeb(HL, B); delay(7); break; case 0x71: writeb(HL, C); delay(7); break; case 0x72: writeb(HL, D); delay(7); break; case 0x73: writeb(HL, E); delay(7); break; case 0x74: writeb(HL, H); delay(7); break; case 0x75: writeb(HL, L); delay(7); break; case 0x76: delay(4); break; case 0x77: writeb(HL, A); delay(7); break; case 0x78: A = B; delay(4); break; case 0x79: A = C; delay(4); break; case 0x7A: A = D; delay(4); break; case 0x7B: A = E; delay(4); break; case 0x7C: A = H; delay(4); break; case 0x7D: A = L; delay(4); break; case 0x7E: A = readb(HL); delay(7); break; case 0x7F: A = A; delay(4); break; case 0x80: add8(A, B); delay(4); break; case 0x81: add8(A, C); delay(4); break; case 0x82: add8(A, D); delay(4); break; case 0x83: add8(A, E); delay(4); break; case 0x84: add8(A, H); delay(4); break; case 0x85: add8(A, L); delay(4); break; case 0x86: add8(A, readb(HL)); delay(7); break; case 0x87: add8(A, A); delay(4); break; case 0x88: adc8(A, B); delay(4); break; case 0x89: adc8(A, C); delay(4); break; case 0x8A: adc8(A, D); delay(4); break; case 0x8B: adc8(A, E); delay(4); break; case 0x8C: adc8(A, H); delay(4); break; case 0x8D: adc8(A, L); delay(4); break; case 0x8E: adc8(A, readb(HL)); delay(7); break; case 0x8F: adc8(A, A); delay(4); break; case 0x90: sub8(A, B); delay(4); break; case 0x91: sub8(A, C); delay(4); break; case 0x92: sub8(A, D); delay(4); break; case 0x93: sub8(A, E); delay(4); break; case 0x94: sub8(A, H); delay(4); break; case 0x95: sub8(A, L); delay(4); break; case 0x96: sub8(A, readb(HL)); delay(7); break; case 0x97: sub8(A, A); delay(4); break; case 0x98: sbc8(A, B); delay(4); break; case 0x99: sbc8(A, C); delay(4); break; case 0x9A: sbc8(A, D); delay(4); break; case 0x9B: sbc8(A, E); delay(4); break; case 0x9C: sbc8(A, H); delay(4); break; case 0x9D: sbc8(A, L); delay(4); break; case 0x9E: sbc8(A, readb(HL)); delay(7); break; case 0x9F: sbc8(A, A); delay(4); break; case 0xA0: and(A, B); delay(4); break; case 0xA1: and(A, C); delay(4); break; case 0xA2: and(A, D); delay(4); break; case 0xA3: and(A, E); delay(4); break; case 0xA4: and(A, H); delay(4); break; case 0xA5: and(A, L); delay(4); break; case 0xA6: and(A, readb(HL)); delay(7); break; case 0xA7: and(A, A); delay(4); break; case 0xA8: xor(A, B); delay(4); break; case 0xA9: xor(A, C); delay(4); break; case 0xAA: xor(A, D); delay(4); break; case 0xAB: xor(A, E); delay(4); break; case 0xAC: xor(A, H); delay(4); break; case 0xAD: xor(A, L); delay(4); break; case 0xAE: xor(A, readb(HL)); delay(7); break; case 0xAF: xor(A, A); delay(4); break; case 0xB0: or(A, B); delay(4); break; case 0xB1: or(A, C); delay(4); break; case 0xB2: or(A, D); delay(4); break; case 0xB3: or(A, E); delay(4); break; case 0xB4: or(A, H); delay(4); break; case 0xB5: or(A, L); delay(4); break; case 0xB6: or(A, readb(HL)); delay(7); break; case 0xB7: or(A, A); delay(4); break; case 0xB8: cp(A, B); delay(4); break; case 0xB9: cp(A, C); delay(4); break; case 0xBA: cp(A, D); delay(4); break; case 0xBB: cp(A, E); delay(4); break; case 0xBC: cp(A, H); delay(4); break; case 0xBD: cp(A, L); delay(4); break; case 0xBE: cp(A, readb(HL)); delay(7); break; case 0xBF: cp(A, A); delay(4); break; case 0xC0: /* RET NZ */ if (!(F & FLAG_Z)) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xC1: /* POP BC */ pop(BC); delay(10); break; case 0xC2: /* JP NZ, nn */ WZ = readw(PC); if (!(F & FLAG_Z)) PC = WZ; else PC += 2; delay(10); break; case 0xC3: /* JP nn */ WZ = readw(PC); PC = WZ; delay(10); break; case 0xC4: /* CALL NZ, nn */ WZ = readw(PC); PC += 2; if (!(F & FLAG_Z)) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xC5: /* PUSH BC */ push(BC); delay(11); break; case 0xC6: /* ADD A, n */ add8(A, readb(PC++)); delay(7); break; case 0xC7: /* RST 00h */ /* FIXME: I have not tested whether RST affects WZ */ push(PC); PC = 0x0000; delay(11); break; case 0xC8: /* RET Z */ if (F & FLAG_Z) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xC9: /* RET */ pop(WZ); PC = WZ; delay(10); break; case 0xCA: /* JP Z, nn */ WZ = readw(PC); if (F & FLAG_Z) PC = WZ; else PC += 2; delay(10); break; case 0xCB: op = readb_m1(PC++); goto opcode_cb; case 0xCC: /* CALL Z, nn */ WZ = readw(PC); PC += 2; if (F & FLAG_Z) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xCD: /* CALL nn */ WZ = readw(PC); PC += 2; push(PC); PC = WZ; delay(17); break; case 0xCE: /* ADC A, n */ adc8(A, readb(PC++)); delay(7); break; case 0xCF: /* RST 08h */ push(PC); PC = 0x0008; delay(11); break; case 0xD0: /* RET NC */ if (!(F & FLAG_C)) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xD1: /* POP DE */ pop(DE); delay(10); break; case 0xD2: /* JP NC, nn */ WZ = readw(PC); if (!(F & FLAG_C)) PC = WZ; else PC += 2; delay(10); break; case 0xD3: /* OUT (n), A */ W = A; Z = readb(PC++); delay(11); output(WZ, A); break; case 0xD4: /* CALL NC, nn */ WZ = readw(PC); PC += 2; if (!(F & FLAG_C)) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xD5: /* PUSH DE */ push(DE); delay(11); break; case 0xD6: /* SUB n */ sub8(A, readb(PC++)); delay(7); break; case 0xD7: /* RST 10h */ push(PC); PC = 0x0010; delay(11); break; case 0xD8: /* RET C */ if (F & FLAG_C) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xD9: /* EXX */ ex(BC, BC2); ex(DE, DE2); ex(HL, HL2); ex(WZ, WZ2); delay(4); break; case 0xDA: /* JP C, nn */ WZ = readw(PC); if (F & FLAG_C) PC = WZ; else PC += 2; delay(10); break; case 0xDB: /* IN A, (n) */ W = A; Z = readb(PC++); delay(11); A = input(WZ); break; case 0xDC: /* CALL C, nn */ WZ = readw(PC); PC += 2; if (F & FLAG_C) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xDD: op = readb_m1(PC++); delay(4); goto opcode_dd; case 0xDE: /* SBC A, n */ sbc8(A, readb(PC++)); delay(7); break; case 0xDF: /* RST 18h */ push(PC); PC = 0x0018; delay(11); break; case 0xE0: /* RET PO */ if (!(F & FLAG_P)) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xE1: /* POP HL */ pop(HL); delay(10); break; case 0xE2: /* JP PO, nn */ WZ = readw(PC); if (!(F & FLAG_P)) PC = WZ; else PC += 2; delay(10); break; case 0xE3: /* EX (SP), HL */ WZ = readw(SP); writew(SP, HL); HL = WZ; delay(19); break; case 0xE4: /* CALL PO, nn */ WZ = readw(PC); PC += 2; if (!(F & FLAG_P)) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xE5: /* PUSH HL */ push(HL); delay(11); break; case 0xE6: /* AND n */ and(A, readb(PC++)); delay(7); break; case 0xE7: /* RST 20h */ push(PC); PC = 0x0020; delay(11); break; case 0xE8: /* RET PE */ if (F & FLAG_P) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xE9: /* JP HL */ PC = HL; delay(4); break; case 0xEA: /* JP PE, nn */ WZ = readw(PC); if (F & FLAG_P) PC = WZ; else PC += 2; delay(10); break; case 0xEB: /* EX DE,HL */ ex(DE, HL); delay(4); break; case 0xEC: /* CALL PE, nn */ WZ = readw(PC); PC += 2; if (F & FLAG_P) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xED: op = readb_m1(PC++); goto opcode_ed; case 0xEE: /* XOR n */ xor(A, readb(PC++)); delay(7); break; case 0xEF: /* RST 28h */ push(PC); PC = 0x0028; delay(11); break; case 0xF0: /* RET P */ if (!(F & FLAG_S)) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xF1: /* POP AF */ pop(AF); delay(10); break; case 0xF2: /* JP P, nn */ WZ = readw(PC); if (!(F & FLAG_S)) PC = WZ; else PC += 2; delay(10); break; case 0xF3: /* DI */ IFF1 = IFF2 = 0; delay(4); break; case 0xF4: /* CALL P, nn */ WZ = readw(PC); PC += 2; if (!(F & FLAG_S)) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xF5: /* PUSH AF */ push(AF); delay(11); break; case 0xF6: /* OR n */ or(A, readb(PC++)); delay(7); break; case 0xF7: /* RST 30h */ push(PC); PC = 0x0030; delay(11); break; case 0xF8: /* RET M */ if (F & FLAG_S) { pop(WZ); PC = WZ; delay(11); } else delay(5); break; case 0xF9: /* LD SP, HL */ SP = HL; delay(4); break; case 0xFA: /* JP M, nn */ WZ = readw(PC); if (F & FLAG_S) PC = WZ; else PC += 2; delay(10); break; case 0xFB: /* EI */ IFF1 = IFF2 = 1; delay(4); break; case 0xFC: /* CALL M, nn */ WZ = readw(PC); PC += 2; if (F & FLAG_S) { push(PC); PC = WZ; delay(17); } else delay(10); break; case 0xFD: op = readb_m1(PC++); delay(4); goto opcode_fd; case 0xFE: /* CP n */ cp(A, readb(PC++)); delay(7); break; case 0xFF: /* RST 38h */ push(PC); PC = 0x0038; delay(11); break; } tilem-2.0/gui/000077500000000000000000000000001220200411600132355ustar00rootroot00000000000000tilem-2.0/gui/Makefile.in000066400000000000000000000145661220200411600153160ustar00rootroot00000000000000prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = @bindir@ datadir = @datadir@ pkgdatadir = @datadir@/tilem2 mandir = @mandir@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ GUI_LDFLAGS = @GUI_LDFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ SHELL = @SHELL@ WINDRES = @WINDRES@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_LIBS = @GTK_LIBS@ TICALCS_CFLAGS = @TICALCS_CFLAGS@ TICALCS_LIBS = @TICALCS_LIBS@ TILEMCORE_CFLAGS = -I$(top_srcdir)/emu TILEMCORE_LIBS = -L$(top_builddir)/emu -ltilemcore TILEMDB_CFLAGS = -I$(top_srcdir)/db TILEMDB_LIBS = -L$(top_builddir)/db -ltilemdb DEF_SHARE_DIR = -DSHARE_DIR=\"$(pkgdatadir)\" \ -DUNINSTALLED_SHARE_DIR=\"$(top_srcdir)/data\" gui_extra_objects = @gui_extra_objects@ objects = tilem2.o \ address.o \ animatedgif.o \ animation.o \ breakpoints.o \ config.o \ charmap.o \ debugger.o \ disasmview.o \ emulator.o \ emucore.o \ emuwin.o \ event.o \ filedlg.o \ files.o \ fixedtreeview.o \ gifencod.o \ icons.o \ keybindings.o \ keypaddlg.o \ link.o \ macro.o \ memmodel.o \ memview.o \ memory.o \ pbar.o \ preferences.o \ sendfile.o \ screenshot.o \ skinops.o \ ti81prg.o \ menu.o \ rcvmenu.o \ tool.o \ $(gui_extra_objects) libs = $(TILEMDB_LIBS) $(TILEMCORE_LIBS) $(GTK_LIBS) $(TICALCS_LIBS) $(LIBS) compile = $(CC) -I$(top_builddir) -I$(srcdir) $(CFLAGS) $(CPPFLAGS) $(DEFS) \ $(TILEMCORE_CFLAGS) $(TILEMDB_CFLAGS) \ $(GTK_CFLAGS) $(TICALCS_CFLAGS) link = $(CC) $(CFLAGS) $(LDFLAGS) $(GUI_LDFLAGS) common_headers = ../config.h ../emu/tilem.h ../db/tilemdb.h \ gui.h emulator.h debugger.h emuwin.h skinops.h animation.h \ gtk-compat.h msgbox.h fixedtreeview.h all: tilem2@EXEEXT@ #Main emulator GUI tilem2@EXEEXT@: $(objects) ../emu/libtilemcore.a $(link) -o tilem2@EXEEXT@ $(objects) $(libs) tilem2.o: tilem2.c icons.h files.h $(common_headers) $(compile) -c $(srcdir)/tilem2.c # Debugger debugger.o: debugger.c disasmview.h $(common_headers) $(compile) -c $(srcdir)/debugger.c # Disassembly view disasmview.o: disasmview.c disasmview.h $(common_headers) $(compile) -c $(srcdir)/disasmview.c # Memory view memview.o: memview.c memmodel.h $(common_headers) $(compile) -c $(srcdir)/memview.c # Tree model interface for calc memory memmodel.o: memmodel.c memmodel.h $(common_headers) $(compile) -c $(srcdir)/memmodel.c # Breakpoint dialog breakpoints.o: breakpoints.c $(common_headers) $(compile) -c $(srcdir)/breakpoints.c # Utility functions for debugging address.o: address.c $(common_headers) $(compile) -c $(srcdir)/address.c # Keypad dialog keypaddlg.o: keypaddlg.c $(common_headers) $(compile) -c $(srcdir)/keypaddlg.c # Memory management and messages memory.o: memory.c ../emu/tilem.h $(compile) -c $(srcdir)/memory.c # Emulator management emulator.o: emulator.c emucore.h $(common_headers) $(compile) -c $(srcdir)/emulator.c # Emulator main loop emucore.o: emucore.c emucore.h $(common_headers) $(compile) -c $(srcdir)/emucore.c # Emulator GUI (main window) emuwin.o: emuwin.c $(common_headers) $(compile) -c $(srcdir)/emuwin.c # Handle events event.o: event.c $(common_headers) $(compile) -c $(srcdir)/event.c # Preferences dialog preferences.o: preferences.c $(common_headers) $(compile) -c $(srcdir)/preferences.c # Open skin (skn format file) originally created by Julien Blache and Romain Lievins skinops.o: skinops.c skinops.h $(compile) -c $(srcdir)/skinops.c # Popups and other stuff tool.o: tool.c $(common_headers) $(compile) -c $(srcdir)/tool.c # Manage config.ini config.o: config.c files.h $(common_headers) $(compile) -c $(srcdir)/config.c # Handle internal link link.o: link.c emucore.h ti81prg.h $(common_headers) $(compile) -c $(srcdir)/link.c # Handle macro macro.o: macro.c $(common_headers) $(compile) -c $(srcdir)/macro.c # Create and modify animated gif gifencod.o: gifencod.c gifencod.h $(compile) -c $(srcdir)/gifencod.c # Handle screenshot anim (animated gif) animatedgif.o: animatedgif.c $(common_headers) $(compile) -c $(srcdir)/animatedgif.c # Screenshot widget screenshot.o: screenshot.c $(common_headers) $(compile) -c $(srcdir)/screenshot.c # Progress bar widget pbar.o: pbar.c $(common_headers) $(compile) -c $(srcdir)/pbar.c # Screenshot/animation recording animation.o: animation.c $(common_headers) $(compile) -c $(srcdir)/animation.c # Shared/configuration files files.o: files.c files.h $(compile) $(DEF_SHARE_DIR) -c $(srcdir)/files.c # Custom icons icons.o: icons.c icons.h $(compile) $(DEF_SHARE_DIR) -c $(srcdir)/icons.c # Keybindings keybindings.o: keybindings.c files.h $(common_headers) $(compile) -c $(srcdir)/keybindings.c # Menu menu.o: menu.c $(common_headers) $(compile) -c $(srcdir)/menu.c # Link receive dialog rcvmenu.o: rcvmenu.c $(common_headers) $(compile) -c $(srcdir)/rcvmenu.c # Link send dialog sendfile.o: sendfile.c emucore.h $(common_headers) $(compile) -c $(srcdir)/sendfile.c # File open/save dialogs filedlg.o: filedlg.c filedlg.h $(compile) -c $(srcdir)/filedlg.c # Fixed-width tree view fixedtreeview.o: fixedtreeview.c fixedtreeview.h $(compile) -c $(srcdir)/fixedtreeview.c # TI-81 program file functions ti81prg.o: ti81prg.c ti81prg.h ../emu/tilem.h $(compile) -c $(srcdir)/ti81prg.c # Character conversion charmap.o: charmap.c charmap.h ../emu/tilem.h $(compile) -c $(srcdir)/charmap.c # Windows resource file tilem2rc.o: tilem2.rc major=`echo "@PACKAGE_VERSION@" | sed 's/\..*//'` ; \ minor=`echo "@PACKAGE_VERSION@" | sed 's/.*\.//;s/[^0-9].*//'` ; \ svnver=`svnversion "$(top_srcdir)" 2>/dev/null | sed 's/[^0-9].*//'` ; \ [ -n "$$svnver" ] || svnver=0 ; \ $(WINDRES) -DBUILD_VERSION=$$major,$$minor,0,$$svnver tilem2.rc tilem2rc.o tilem2.rc: tilem2.rc.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status gui/tilem2.rc install: tilem2@EXEEXT@ $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) $(INSTALL_PROGRAM) -m 755 tilem2@EXEEXT@ $(DESTDIR)$(bindir) uninstall: rm -f $(DESTDIR)$(bindir)/tilem2@EXEEXT@ clean: rm -f *.o rm -f tilem2@EXEEXT@ Makefile: Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && $(SHELL) ./config.status --recheck .PRECIOUS: Makefile $(top_builddir)/config.status .PHONY: all clean install uninstall tilem-2.0/gui/address.c000066400000000000000000000143321220200411600150310ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" char * tilem_format_addr(TilemDebugger *dbg, dword addr, gboolean physical) { dword page, addr_l; g_return_val_if_fail(dbg != NULL, NULL); g_return_val_if_fail(dbg->emu != NULL, NULL); g_return_val_if_fail(dbg->emu->calc != NULL, NULL); if (!physical) return g_strdup_printf("%04X", addr); if (addr >= dbg->emu->calc->hw.romsize) page = (((addr - dbg->emu->calc->hw.romsize) >> 14) + dbg->emu->calc->hw.rampagemask); else page = addr >> 14; addr_l = (*dbg->emu->calc->hw.mem_ptol)(dbg->emu->calc, addr); if (addr_l == 0xffffffff) addr_l = (addr & 0x3fff) | 0x4000; return g_strdup_printf("%02X:%04X", page, addr_l); } static gboolean parse_hex(const char *string, dword *value) { const char *n; char *e; dword a; if (string[0] == '$') n = string + 1; else if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) n = string + 2; else n = string; a = strtol(n, &e, 16); if (value) *value = a; if (e == n) return FALSE; if (*e == 'h' || *e == 'H') e++; return (*e == 0); } gboolean tilem_parse_paged_addr(TilemDebugger *dbg, const char *pagestr, const char *offsstr, dword *value) { dword page, offs; g_return_val_if_fail(dbg != NULL, FALSE); g_return_val_if_fail(dbg->emu != NULL, FALSE); g_return_val_if_fail(dbg->emu->calc != NULL, FALSE); if (!parse_hex(pagestr, &page)) return FALSE; if (!tilem_parse_addr(dbg, offsstr, &offs, NULL)) return FALSE; offs &= 0x3fff; if (page & dbg->emu->calc->hw.rampagemask) { page &= ~dbg->emu->calc->hw.rampagemask; offs += (offs << 14); if (offs > dbg->emu->calc->hw.ramsize) return FALSE; offs += dbg->emu->calc->hw.romsize; } else { offs += (page << 14); if (offs > dbg->emu->calc->hw.romsize) return FALSE; } if (value) *value = offs; return TRUE; } gboolean tilem_parse_addr(TilemDebugger *dbg, const char *string, dword *value, gboolean *physical) { const char *offstr; char *pagestr; g_return_val_if_fail(dbg != NULL, FALSE); g_return_val_if_fail(dbg->emu != NULL, FALSE); g_return_val_if_fail(dbg->emu->calc != NULL, FALSE); if (parse_hex(string, value)) { if (physical) *physical = FALSE; return TRUE; } if (physical && (offstr = strchr(string, ':'))) { pagestr = g_strndup(string, offstr - string); offstr++; if (tilem_parse_paged_addr(dbg, pagestr, offstr, value)) { *physical = TRUE; return TRUE; } } if (dbg->dasm && tilem_disasm_get_label(dbg->dasm, string, value)) { if (physical) *physical = FALSE; return TRUE; } return FALSE; } struct addrdlg { GtkWidget *dlg; TilemDebugger *dbg; gboolean physical; }; static void edited(GtkEntry *entry, gpointer data) { struct addrdlg *adlg = data; const char *text; gboolean valid, phys; text = gtk_entry_get_text(entry); valid = tilem_parse_addr(adlg->dbg, text, NULL, adlg->physical ? &phys : NULL); gtk_dialog_set_response_sensitive(GTK_DIALOG(adlg->dlg), GTK_RESPONSE_OK, valid); } gboolean tilem_prompt_address(TilemDebugger *dbg, GtkWindow *parent, const char *title, const char *prompt, dword *value, gboolean physical, gboolean usedefault) { GtkWidget *dlg, *hbox, *vbox, *lbl, *ent; struct addrdlg adlg; const char *text; gboolean phys; char *s; g_return_val_if_fail(dbg != NULL, FALSE); g_return_val_if_fail(dbg->emu != NULL, FALSE); g_return_val_if_fail(dbg->emu->calc != NULL, FALSE); dlg = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); hbox = gtk_hbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); lbl = gtk_label_new(prompt); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); ent = gtk_entry_new(); gtk_entry_set_activates_default(GTK_ENTRY(ent), TRUE); gtk_box_pack_start(GTK_BOX(hbox), ent, TRUE, TRUE, 0); if (usedefault) { s = tilem_format_addr(dbg, *value, physical); gtk_entry_set_text(GTK_ENTRY(ent), s); g_free(s); } adlg.dlg = dlg; adlg.dbg = dbg; adlg.physical = physical; g_signal_connect(ent, "changed", G_CALLBACK(edited), &adlg); edited(GTK_ENTRY(ent), &adlg); gtk_widget_show_all(hbox); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); if (gtk_dialog_run(GTK_DIALOG(dlg)) != GTK_RESPONSE_OK) { gtk_widget_destroy(dlg); return FALSE; } text = gtk_entry_get_text(GTK_ENTRY(ent)); if (!tilem_parse_addr(dbg, text, value, physical ? &phys : NULL)) { gtk_widget_destroy(dlg); return FALSE; } if (physical && !phys) { tilem_calc_emulator_lock(dbg->emu); *value &= 0xffff; *value = (*dbg->emu->calc->hw.mem_ltop)(dbg->emu->calc, *value); tilem_calc_emulator_unlock(dbg->emu); } gtk_widget_destroy(dlg); return TRUE; } tilem-2.0/gui/animatedgif.c000066400000000000000000000201271220200411600156530ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "gui.h" static void write_global_header(FILE* fp, int width, int height, byte* palette, int palette_size); static void write_global_footer(FILE* fp); static void write_extension_block(FILE* fout, word delay); static void write_image_block_start(FILE *fp, int width, int height); static void write_image_block_end(FILE *fp); static void write_comment(FILE* fp); static void write_application_extension(FILE * fp) ; static void write_global_header(FILE* fp, int width, int height, byte* palette, int palette_size) { /* Magic number for Gif file format */ char global_header_magic_number[] = {'G', 'I', 'F', '8', '9', 'a'}; /* Size of canvas width on 2 bytes, heigth on 2 bytes */ char global_header_canvas[] = {96, 0, 64, 0 }; global_header_canvas[0] = width; global_header_canvas[1] = (width >> 8) ; global_header_canvas[2] = height; global_header_canvas[3] = (height >> 8); /* Flag */ /* The 11th byte is a set of flags : bit 0: Global Color Table Flag (GCTF) bit 1..3: Color Resolution bit 4: Sort Flag to Global Color Table bit 5..7: Size of Global Color Table: 2^(1+n) It means "use the GCT wich is given after (from the size bit 5..7) and a resolution bit 1..3 The Background color is an index in the Global Color Table */ /* FIXME : if we change the palette size, we need to change this flag too and I don't do this currently */ char global_header_flag[] = { 0xf7 }; /* The index in global color table */ char global_header_background_index[] = {0x00}; /* Aspect pixel ratio (unknown) */ char global_header_aspect_pixel_ratio[] = {0x00}; fwrite(global_header_magic_number, 6, 1, fp); fwrite(global_header_canvas, 4, 1, fp); fwrite(global_header_flag, 1, 1, fp); fwrite(global_header_background_index, 1, 1, fp); fwrite(global_header_aspect_pixel_ratio, 1, 1, fp); //byte* palette = tilem_color_palette_new_packed(255, 255, 255, 0, 0, 0, 2.2); fwrite(palette, palette_size * 3, 1, fp); } static void write_global_footer(FILE* fp) { /* This value means end of gif file */ char footer_trailer[1] = { 0x3b}; fwrite(footer_trailer, 1, 1,fp); } static void write_extension_block(FILE* fp, word delay) { /* Extension block introduced by 0x21 ('!'), size before extension_block_terminator, flag byte, delay (10/100) 2 bytes */ char extension_block_header[2] = {0x21, 0xf9}; /* Size before extension_block_terminator */ char extension_block_size[1] = { 0x04} ; /* Flag (unknown) */ char extension_block_flag[1] = { 0x00} ; /* Delay (x/100 sec) on 2 bytes*/ char extension_block_delay[2] = {10, 0} ; extension_block_delay[0] = delay; /* The index designed by this variable become transparent even if palette gives a black(or something else) color. */ char extension_block_transparent_index[1] = {0xff}; /* End of extension block */ char extension_block_terminator[1] = {0x00}; fwrite(extension_block_header, 2, 1, fp); fwrite(extension_block_size, 1, 1, fp); fwrite(extension_block_flag, 1, 1, fp); fwrite(extension_block_delay, 2, 1, fp); fwrite(extension_block_transparent_index, 1, 1, fp); fwrite(extension_block_terminator, 1, 1, fp); } static void write_image_block_start(FILE *fp, int width, int height) { /* Header */ char image_block_header[] = { 0x2c}; /* Left corner x (2 bytes), left corner y (2 bytes), width (2 bytes), height (2 bytes) */ char image_block_canvas[] = { 0, 0, 0, 0, 96, 0, 64, 0}; image_block_canvas[4] = width; image_block_canvas[5] = (width >> 8) ; image_block_canvas[6] = height; image_block_canvas[7] = (height >> 8); /* Flag */ char image_block_flag[] = { 0x00 }; fwrite(image_block_header, 1, 1, fp); fwrite(image_block_canvas, 8, 1, fp); fwrite(image_block_flag, 1, 1, fp); } static void write_image_block_end(FILE *fp) { /* Give an end to the image block */ char image_block_end[1] = {0x00}; fwrite(image_block_end, 1, 1,fp); } static void write_comment(FILE* fp) { char comment[] = {0x21, 0xfe, 8, 'T', 'i', 'l', 'E', 'm', '2', 0, 0, 0}; fwrite(comment, 12, 1, fp); } static void write_application_extension(FILE * fp) { /* Magic number to start the block */ char application_extension_magic_number[] = { 0x21, 0xff, 0x0b }; /* Application name */ char application_extension_application_name[] = { 'N', 'E', 'T', 'S', 'C', 'A', 'P', 'E', '2', '.', '0' }; /* magic number */ char application_extension_data_follow[] = { 0x03, 0x01 }; /* 0 to 65535 loop */ char application_extension_number_of_loop[] = { 0xff, 0xff}; /* the end of the block */ char application_extension_terminator[] = { 0x00 }; //char gif_infos[31] = { //0x21, 0xff, 0x0b, 'N', 'E', 'T', 'S', 'C', 'A', 'P', 'E', '2', '.', '0', 3, 1, 0xff, 0xff, 0x00 }; //fwrite(gif_infos, 19, 1, fp); fwrite(application_extension_magic_number, 3, 1, fp); fwrite(application_extension_application_name, 11, 1, fp); fwrite(application_extension_data_follow, 2, 1, fp); fwrite(application_extension_number_of_loop, 2, 1, fp); fwrite(application_extension_terminator, 1, 1, fp); } /* Apparently, most current web browsers are seriously and deliberately broken in their handling of animated GIFs. Internet Explorer does not allow any frame to be shorter than 60 ms, and Gecko does not allow any frame shorter than 20 ms. Furthermore, rather than simply imposing a lower limit, or skipping frames, these browsers take any frame they deem "too short" and extend it to a full 100 ms out of sheer spite. If we want animations to look correct in all web browsers (which is, after all, the main reason for using GIF animations in the first place), we have to limit ourselves to 60-ms frames or longer. */ #define MIN_FRAME_DELAY 6 void tilem_animation_write_gif(TilemAnimation *anim, byte* palette, int palette_size, FILE *fp) { GdkPixbufAnimation *ganim; int width, height, delay, n; gdouble time_stretch, t; byte *image; TilemAnimFrame *frm, *next; gboolean is_static; g_return_if_fail(TILEM_IS_ANIMATION(anim)); g_return_if_fail(fp != NULL); ganim = GDK_PIXBUF_ANIMATION(anim); width = gdk_pixbuf_animation_get_width(ganim); height = gdk_pixbuf_animation_get_height(ganim); is_static = gdk_pixbuf_animation_is_static_image(ganim); time_stretch = 1.0 / tilem_animation_get_speed(anim); frm = tilem_animation_next_frame(anim, NULL); g_return_if_fail(frm != NULL); write_global_header(fp, width, height, palette, palette_size); if (!is_static) write_application_extension(fp); write_comment(fp); t = MIN_FRAME_DELAY * 5.0; /* FIXME: combine multiple frames by averaging rather than simply taking the last one */ while (frm) { next = tilem_animation_next_frame(anim, frm); if (!is_static) { delay = tilem_anim_frame_get_duration(frm); t += delay * time_stretch; n = t / 10.0; if (n < MIN_FRAME_DELAY && next != NULL) { frm = next; continue; } t -= n * 10.0; if (n > 0xffff) n = 0xffff; else if (n < MIN_FRAME_DELAY) n = MIN_FRAME_DELAY; write_extension_block(fp, n); } tilem_animation_get_indexed_image(anim, frm, &image, &width, &height); write_image_block_start(fp, width, height); GifEncode(fp, image, 8, width * height); write_image_block_end(fp); g_free(image); frm = next; } write_global_footer(fp); } tilem-2.0/gui/animation.c000066400000000000000000000374111220200411600153660ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #define GDK_PIXBUF_ENABLE_BACKEND #include #include #include #include #include #include #include #include "gui.h" #define GAMMA 2.2 struct _TilemAnimFrame { struct _TilemAnimFrame *next; unsigned duration : 24; unsigned contrast : 8; byte data[1]; }; struct _TilemAnimation { GdkPixbufAnimation parent; int num_frames; TilemAnimFrame *start; TilemAnimFrame *end; dword last_stamp; TilemLCDBuffer *temp_buffer; GdkPixbuf *static_pixbuf; int base_contrast; int display_width; int display_height; int frame_rowstride; int frame_size; int image_width; int image_height; dword *palette; gdouble speed; gdouble time_stretch; gboolean out_of_memory; }; struct _TilemAnimationClass { GdkPixbufAnimationClass parent_class; }; #define TILEM_TYPE_ANIM_ITER (tilem_anim_iter_get_type()) #define TILEM_ANIM_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TILEM_TYPE_ANIM_ITER, TilemAnimIter)) #define TILEM_ANIM_ITER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TILEM_TYPE_ANIM_ITER, TilemAnimIterClass)) #define TILEM_IS_ANIM_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TILEM_TYPE_ANIM_ITER)) #define TILEM_IS_ANIM_ITER_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), TILEM_TYPE_ANIM_ITER)) #define TILEM_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TILEM_TYPE_ANIM_ITER, TilemAnimIterClass)) typedef struct _TilemAnimIter { GdkPixbufAnimationIter parent; GTimeVal current_time; int time_elapsed; TilemAnimation *anim; TilemAnimFrame *frame; GdkPixbuf *pixbuf; } TilemAnimIter; typedef struct _TilemAnimIterClass { GdkPixbufAnimationIterClass parent_class; } TilemAnimIterClass; G_DEFINE_TYPE(TilemAnimation, tilem_animation, GDK_TYPE_PIXBUF_ANIMATION); G_DEFINE_TYPE(TilemAnimIter, tilem_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER); static TilemAnimFrame * alloc_frame(int bufsize) { TilemAnimFrame *frm; frm = g_try_malloc(sizeof(TilemAnimFrame) + bufsize - 1); if (!frm) return NULL; frm->next = NULL; return frm; } static void free_frame(TilemAnimFrame *frm) { g_free(frm); } static int adjust_contrast(TilemAnimation *anim, int contrast) { TilemAnimFrame *frm; if (!contrast) return 0; if (!anim->base_contrast) { for (frm = anim->start; frm; frm = frm->next) { if (frm->contrast != 0) { anim->base_contrast = frm->contrast; break; } } } contrast = (contrast - anim->base_contrast + 32); return CLAMP(contrast, 0, 63); } static void set_lcdbuf_from_frame(TilemAnimation *anim, TilemLCDBuffer *buf, const TilemAnimFrame *frm) { buf->width = anim->display_width; buf->height = anim->display_height; buf->rowstride = anim->frame_rowstride; buf->contrast = adjust_contrast(anim, frm->contrast); buf->data = (byte *) frm->data; } static GdkPixbuf * frame_to_pixbuf(TilemAnimation *anim, const TilemAnimFrame *frm) { GdkPixbuf *pb; pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, anim->image_width, anim->image_height); set_lcdbuf_from_frame(anim, anim->temp_buffer, frm); tilem_draw_lcd_image_rgb(anim->temp_buffer, gdk_pixbuf_get_pixels(pb), anim->image_width, anim->image_height, gdk_pixbuf_get_rowstride(pb), 3, anim->palette, TILEM_SCALE_SMOOTH); anim->temp_buffer->data = NULL; return pb; } static gboolean tilem_animation_is_static_image(GdkPixbufAnimation *ganim) { TilemAnimation *anim = TILEM_ANIMATION(ganim); g_return_val_if_fail(TILEM_IS_ANIMATION(ganim), FALSE); if (anim->start == anim->end) return TRUE; else return FALSE; } static GdkPixbuf * tilem_animation_get_static_image(GdkPixbufAnimation *ganim) { TilemAnimation *anim = TILEM_ANIMATION(ganim); g_return_val_if_fail(TILEM_IS_ANIMATION(anim), NULL); g_return_val_if_fail(anim->start != NULL, NULL); if (!anim->static_pixbuf) anim->static_pixbuf = frame_to_pixbuf(anim, anim->start); return anim->static_pixbuf; } static void tilem_animation_get_size(GdkPixbufAnimation *ganim, int *width, int *height) { TilemAnimation *anim = TILEM_ANIMATION(ganim); g_return_if_fail(TILEM_IS_ANIMATION(anim)); if (width) *width = anim->image_width; if (height) *height = anim->image_height; } static GdkPixbufAnimationIter * tilem_animation_get_iter(GdkPixbufAnimation *ganim, const GTimeVal *start_time) { TilemAnimation *anim = TILEM_ANIMATION(ganim); TilemAnimIter *iter; g_return_val_if_fail(TILEM_IS_ANIMATION(anim), NULL); iter = g_object_new(TILEM_TYPE_ANIM_ITER, NULL); iter->anim = anim; iter->frame = anim->start; iter->current_time = *start_time; g_object_ref(anim); return GDK_PIXBUF_ANIMATION_ITER(iter); } static void tilem_animation_init(G_GNUC_UNUSED TilemAnimation *anim) { } static void tilem_animation_finalize(GObject *obj) { TilemAnimation *anim = TILEM_ANIMATION(obj); TilemAnimFrame *frm; g_return_if_fail(TILEM_IS_ANIMATION(anim)); while (anim->start) { frm = anim->start; anim->start = frm->next; free_frame(frm); } anim->start = anim->end = NULL; if (anim->temp_buffer) tilem_lcd_buffer_free(anim->temp_buffer); anim->temp_buffer = NULL; if (anim->palette) tilem_free(anim->palette); anim->palette = NULL; if (anim->static_pixbuf) g_object_unref(anim->static_pixbuf); anim->static_pixbuf = NULL; if (G_OBJECT_CLASS(tilem_animation_parent_class)->finalize) (*G_OBJECT_CLASS(tilem_animation_parent_class)->finalize)(obj); } static void tilem_animation_class_init(TilemAnimationClass *klass) { GdkPixbufAnimationClass *aclass = GDK_PIXBUF_ANIMATION_CLASS(klass); GObjectClass *oclass = G_OBJECT_CLASS(klass); aclass->is_static_image = tilem_animation_is_static_image; aclass->get_static_image = tilem_animation_get_static_image; aclass->get_size = tilem_animation_get_size; aclass->get_iter = tilem_animation_get_iter; oclass->finalize = tilem_animation_finalize; } static int tilem_anim_iter_get_delay_time(GdkPixbufAnimationIter *giter) { TilemAnimIter *iter = TILEM_ANIM_ITER(giter); g_return_val_if_fail(TILEM_IS_ANIM_ITER(iter), 0); g_return_val_if_fail(iter->anim != NULL, 0); g_return_val_if_fail(iter->frame != NULL, 0); if (iter->anim->start == iter->anim->end) return -1; else return ((iter->frame->duration - iter->time_elapsed) * iter->anim->time_stretch); } static GdkPixbuf * tilem_anim_iter_get_pixbuf(GdkPixbufAnimationIter *giter) { TilemAnimIter *iter = TILEM_ANIM_ITER(giter); g_return_val_if_fail(TILEM_IS_ANIM_ITER(iter), NULL); g_return_val_if_fail(iter->anim != NULL, NULL); g_return_val_if_fail(iter->frame != NULL, NULL); if (!iter->pixbuf) iter->pixbuf = frame_to_pixbuf(iter->anim, iter->frame); return iter->pixbuf; } static gboolean tilem_anim_iter_on_currently_loading_frame(G_GNUC_UNUSED GdkPixbufAnimationIter *giter) { return FALSE; } static gboolean tilem_anim_iter_advance(GdkPixbufAnimationIter *giter, const GTimeVal *current_time) { TilemAnimIter *iter = TILEM_ANIM_ITER(giter); int ms; g_return_val_if_fail(TILEM_IS_ANIM_ITER(iter), FALSE); g_return_val_if_fail(iter->anim != NULL, FALSE); g_return_val_if_fail(iter->frame != NULL, FALSE); ms = ((current_time->tv_usec - iter->current_time.tv_usec) / 1000 + (current_time->tv_sec - iter->current_time.tv_sec) * 1000); g_time_val_add(&iter->current_time, ms * 1000); ms *= iter->anim->speed; ms += iter->time_elapsed; if (ms < iter->frame->duration) { iter->time_elapsed = ms; return FALSE; } if (iter->pixbuf) g_object_unref(iter->pixbuf); iter->pixbuf = NULL; while (ms >= iter->frame->duration) { ms -= iter->frame->duration; if (iter->frame->next) iter->frame = iter->frame->next; else iter->frame = iter->anim->start; } iter->time_elapsed = ms; return TRUE; } static void tilem_anim_iter_init(G_GNUC_UNUSED TilemAnimIter *iter) { } static void tilem_anim_iter_finalize(GObject *obj) { TilemAnimIter *iter = TILEM_ANIM_ITER(obj); g_return_if_fail(TILEM_IS_ANIM_ITER(obj)); if (iter->anim) g_object_unref(iter->anim); iter->anim = NULL; if (iter->pixbuf) g_object_unref(iter->pixbuf); iter->pixbuf = NULL; if (G_OBJECT_CLASS(tilem_anim_iter_parent_class)->finalize) (*G_OBJECT_CLASS(tilem_anim_iter_parent_class)->finalize)(obj); } static void tilem_anim_iter_class_init(TilemAnimIterClass *klass) { GdkPixbufAnimationIterClass *iclass = GDK_PIXBUF_ANIMATION_ITER_CLASS(klass); GObjectClass *oclass = G_OBJECT_CLASS(klass); iclass->get_delay_time = tilem_anim_iter_get_delay_time; iclass->get_pixbuf = tilem_anim_iter_get_pixbuf; iclass->on_currently_loading_frame = tilem_anim_iter_on_currently_loading_frame; iclass->advance = tilem_anim_iter_advance; oclass->finalize = tilem_anim_iter_finalize; } TilemAnimation * tilem_animation_new(int display_width, int display_height) { TilemAnimation *anim; TilemAnimFrame *dummy_frame; g_return_val_if_fail(display_width > 0, NULL); g_return_val_if_fail(display_height > 0, NULL); anim = g_object_new(TILEM_TYPE_ANIMATION, NULL); anim->display_width = display_width; anim->display_height = display_height; anim->frame_rowstride = (display_width + 7) & ~7; anim->frame_size = anim->frame_rowstride * display_height; anim->image_width = display_width; anim->image_height = display_height; anim->speed = 1.0; anim->time_stretch = 1.0; anim->temp_buffer = tilem_lcd_buffer_new(); anim->palette = tilem_color_palette_new(255, 255, 255, 0, 0, 0, GAMMA); dummy_frame = alloc_frame(anim->frame_size); dummy_frame->duration = 0; dummy_frame->contrast = 0; anim->start = anim->end = dummy_frame; return anim; } gboolean tilem_animation_append_frame(TilemAnimation *anim, const TilemLCDBuffer *buf, int duration) { TilemAnimFrame *frm; g_return_val_if_fail(TILEM_IS_ANIMATION(anim), FALSE); g_return_val_if_fail(anim->end != NULL, FALSE); g_return_val_if_fail(buf != NULL, FALSE); g_return_val_if_fail(buf->data != NULL, FALSE); g_return_val_if_fail(buf->height == anim->display_height, FALSE); g_return_val_if_fail(buf->rowstride == anim->frame_rowstride, FALSE); if (anim->out_of_memory) return FALSE; if (anim->end->contrast == buf->contrast && (anim->last_stamp == buf->stamp || !memcmp(anim->end->data, buf->data, anim->frame_size))) { anim->end->duration += duration; } else { if (anim->end->duration == 0) { frm = anim->end; } else { frm = alloc_frame(anim->frame_size); if (!frm) { anim->out_of_memory = TRUE; return FALSE; } anim->end->next = frm; anim->end = frm; } frm->contrast = buf->contrast; frm->duration = duration; memcpy(frm->data, buf->data, anim->frame_size); } anim->last_stamp = buf->stamp; return TRUE; } void tilem_animation_set_size(TilemAnimation *anim, int width, int height) { g_return_if_fail(TILEM_IS_ANIMATION(anim)); anim->image_width = width; anim->image_height = height; } void tilem_animation_set_colors(TilemAnimation *anim, const GdkColor *foreground, const GdkColor *background) { g_return_if_fail(TILEM_IS_ANIMATION(anim)); g_return_if_fail(foreground != NULL); g_return_if_fail(background != NULL); if (anim->palette) tilem_free(anim->palette); anim->palette = tilem_color_palette_new(background->red >> 8, background->green >> 8, background->blue >> 8, foreground->red >> 8, foreground->green >> 8, foreground->blue >> 8, GAMMA); } void tilem_animation_set_speed(TilemAnimation *anim, gdouble factor) { g_return_if_fail(TILEM_IS_ANIMATION(anim)); g_return_if_fail(factor > 0.0); anim->speed = factor; anim->time_stretch = 1.0 / factor; } gdouble tilem_animation_get_speed(TilemAnimation *anim) { g_return_val_if_fail(TILEM_IS_ANIMATION(anim), 1.0); return anim->speed; } TilemAnimFrame *tilem_animation_next_frame(TilemAnimation *anim, TilemAnimFrame *frm) { g_return_val_if_fail(TILEM_IS_ANIMATION(anim), NULL); if (frm) return frm->next; else return anim->start; } int tilem_anim_frame_get_duration(TilemAnimFrame *frm) { g_return_val_if_fail(frm != NULL, 0); return frm->duration; } void tilem_animation_get_indexed_image(TilemAnimation *anim, TilemAnimFrame *frm, byte **buffer, int *width, int *height) { g_return_if_fail(TILEM_IS_ANIMATION(anim)); g_return_if_fail(frm != NULL); g_return_if_fail(buffer != NULL); g_return_if_fail(width != NULL); g_return_if_fail(height != NULL); *width = anim->image_width; *height = anim->image_height; *buffer = g_new(byte, anim->image_width * anim->image_height); set_lcdbuf_from_frame(anim, anim->temp_buffer, frm); tilem_draw_lcd_image_indexed(anim->temp_buffer, *buffer, anim->image_width, anim->image_height, anim->image_width, TILEM_SCALE_SMOOTH); anim->temp_buffer->data = NULL; } gboolean tilem_animation_save(TilemAnimation *anim, const char *fname, const char *type, char **option_keys, char **option_values, GError **err) { FILE *fp; char *dname; int errnum; GdkPixbuf *pb; gboolean status; byte palette[768]; int i; g_return_val_if_fail(TILEM_IS_ANIMATION(anim), FALSE); g_return_val_if_fail(fname != NULL, FALSE); g_return_val_if_fail(type != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); if (strcmp(type, "gif") != 0) { pb = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION(anim)); status = gdk_pixbuf_savev(pb, fname, type, option_keys, option_values, err); return status; } fp = g_fopen(fname, "wb"); if (!fp) { errnum = errno; dname = g_filename_display_name(fname); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Failed to open '%s' for writing: %s", dname, g_strerror(errnum)); g_free(dname); return FALSE; } for (i = 0; i < 256; i++) { palette[3 * i] = anim->palette[i] >> 16; palette[3 * i + 1] = anim->palette[i] >> 8; palette[3 * i + 2] = anim->palette[i]; } tilem_animation_write_gif(anim, palette, 256, fp); if (fclose(fp)) { errnum = errno; dname = g_filename_display_name(fname); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Error while closing '%s': %s", dname, g_strerror(errnum)); g_free(dname); return FALSE; } return TRUE; } tilem-2.0/gui/animation.h000066400000000000000000000073611220200411600153740ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #include G_BEGIN_DECLS #define TILEM_TYPE_ANIMATION (tilem_animation_get_type()) #define TILEM_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TILEM_TYPE_ANIMATION, TilemAnimation)) #define TILEM_ANIMATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TILEM_TYPE_ANIMATION, TilemAnimationClass)) #define TILEM_IS_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TILEM_TYPE_ANIMATION)) #define TILEM_IS_ANIMATION_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), TILEM_TYPE_ANIMATION)) #define TILEM_ANIMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TILEM_TYPE_ANIMATION, TilemAnimationClass)) typedef struct _TilemAnimation TilemAnimation; typedef struct _TilemAnimationClass TilemAnimationClass; typedef struct _TilemAnimFrame TilemAnimFrame; GType tilem_animation_get_type(void) G_GNUC_CONST; /* Create a new TilemAnimation for the given display dimensions. */ TilemAnimation * tilem_animation_new(int display_width, int display_height); /* Add a frame to the animation. BUF holds the LCD contents, DURATION is the length of time this frame should be displayed (in milliseconds.) */ gboolean tilem_animation_append_frame(TilemAnimation *anim, const TilemLCDBuffer *buf, int duration); /* Set output image size. */ void tilem_animation_set_size(TilemAnimation *anim, int width, int height); /* Set output image colors. */ void tilem_animation_set_colors(TilemAnimation *anim, const GdkColor *foreground, const GdkColor *background); /* Set animation speed factor */ void tilem_animation_set_speed(TilemAnimation *anim, gdouble factor); /* Get animation speed factor */ gdouble tilem_animation_get_speed(TilemAnimation *anim); /* Retrieve the next frame of the animation. If FRM is NULL, retrieve the first frame. If FRM is non-null, it must be a frame belonging to this animation. */ TilemAnimFrame *tilem_animation_next_frame(TilemAnimation *anim, TilemAnimFrame *frm); /* Get the duration of this frame (milliseconds by the original clock.) */ int tilem_anim_frame_get_duration(TilemAnimFrame *frm); /* Convert frame to an indexed-color image buffer. FRM must be a frame belonging to this animation. The returned buffer must be freed with g_free(). */ void tilem_animation_get_indexed_image(TilemAnimation *anim, TilemAnimFrame *frm, byte **buffer, int *width, int *height); /* Save animation to a file. TYPE is an ASCII string describing the type. Options are specified by OPTION_KEYS and OPTION_VALUES (see gdk_pixbuf_savev().) */ gboolean tilem_animation_save(TilemAnimation *anim, const char *fname, const char *type, char **option_keys, char **option_values, GError **err); G_END_DECLS tilem-2.0/gui/breakpoints.c000066400000000000000000000744341220200411600157360ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "gui.h" #include "disasmview.h" #include "fixedtreeview.h" /**************** Add/edit breakpoint dialog ****************/ struct hex_entry { GtkWidget *addr_label; GtkWidget *addr_entry; GtkWidget *page_label; GtkWidget *page_entry; }; struct breakpoint_dlg { TilemDebugger *dbg; GtkWidget *dlg; GtkWidget *box; GtkWidget *type_combo; GtkWidget *access_cb[3]; GtkWidget *single_rb; GtkWidget *range_rb; GtkWidget *access_label; GtkWidget *address_label; struct hex_entry start; struct hex_entry end; }; static const struct { char abbrev; const char *desc; const char *value_label; int use_pages; guint access_mask; } type_info[] = { { 'M', "Memory address (logical)", "Address", 0, 7 }, { 'M', "Memory address (absolute)", "Address", 1, 7 }, { 'P', "I/O port", "Port Number", 0, 6 }, { 'I', "Z80 instruction", "Opcode", 0, 0 } }; /* Determine currently selected address type */ static guint get_bp_type(struct breakpoint_dlg *bpdlg) { int i = gtk_combo_box_get_active(GTK_COMBO_BOX(bpdlg->type_combo)); return (i < 0 ? 0 : i); } /* Format address as a string */ static void hex_entry_set_value(struct hex_entry *he, TilemDebugger *dbg, int type, dword value) { const TilemCalc *calc; char buf[20]; unsigned int page; g_return_if_fail(dbg->emu != NULL); g_return_if_fail(dbg->emu->calc != NULL); calc = dbg->emu->calc; switch (type) { case TILEM_DB_BREAK_LOGICAL: g_snprintf(buf, sizeof(buf), "%04X", value); break; case TILEM_DB_BREAK_PHYSICAL: if (value >= calc->hw.romsize) { value -= calc->hw.romsize; page = (value >> 14) + calc->hw.rampagemask; } else { page = (value >> 14); } g_snprintf(buf, sizeof(buf), "%02X", page); gtk_entry_set_text(GTK_ENTRY(he->page_entry), buf); g_snprintf(buf, sizeof(buf), "%04X", value & 0x3fff); break; case TILEM_DB_BREAK_PORT: g_snprintf(buf, sizeof(buf), "%02X", value); break; case TILEM_DB_BREAK_OPCODE: if (value < 0x100) g_snprintf(buf, sizeof(buf), "%02X", value); else if (value < 0x10000) g_snprintf(buf, sizeof(buf), "%04X", value); else if (value < 0x1000000) g_snprintf(buf, sizeof(buf), "%06X", value); else g_snprintf(buf, sizeof(buf), "%08X", value); break; default: g_return_if_reached(); } gtk_entry_set_text(GTK_ENTRY(he->addr_entry), buf); } /* Parse contents of entry */ static gboolean parse_num(TilemDebugger *dbg, const char *s, dword *a) { const char *n; char *e; g_return_val_if_fail(s != NULL, FALSE); if (s[0] == '$') n = s + 1; else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) n = s + 2; else n = s; *a = strtol(n, &e, 16); if (e != n) { if (*e == 'h' || *e == 'H') e++; if (*e == 0) return TRUE; } if (dbg->dasm && tilem_disasm_get_label(dbg->dasm, s, a)) return TRUE; return FALSE; } /* Parse user input from hex entry */ static gboolean hex_entry_parse_value(struct hex_entry *he, TilemDebugger *dbg, int type, dword *value) { const TilemCalc *calc = dbg->emu->calc; dword page; const char *s; g_return_val_if_fail(calc != NULL, 0); s = gtk_entry_get_text(GTK_ENTRY(he->addr_entry)); if (!parse_num(dbg, s, value)) return FALSE; if (type != TILEM_DB_BREAK_PHYSICAL) return TRUE; s = gtk_entry_get_text(GTK_ENTRY(he->page_entry)); if (!parse_num(dbg, s, &page)) return FALSE; *value &= 0x3fff; if (page >= calc->hw.rampagemask) { *value += ((page - calc->hw.rampagemask) << 14); *value %= calc->hw.ramsize; *value += calc->hw.romsize; } else { *value += (page << 14); *value %= calc->hw.romsize; } return TRUE; } /* Parse input fields and check if they make sense */ static gboolean parse_input(struct breakpoint_dlg *bpdlg, TilemDebugBreakpoint *bp) { int i; dword addr0, addr1; bp->mask = bp->start = bp->end = 0xffffffff; bp->type = get_bp_type(bpdlg); bp->mode = 0; for (i = 0; i < 3; i++) if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bpdlg->access_cb[i]))) bp->mode += (1 << i); bp->mode &= type_info[bp->type].access_mask; if (bp->type == TILEM_DB_BREAK_OPCODE) bp->mode = TILEM_DB_BREAK_EXEC; else if (bp->mode == 0) return FALSE; if (!hex_entry_parse_value(&bpdlg->start, bpdlg->dbg, bp->type, &addr0)) return FALSE; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bpdlg->range_rb))) { if (!hex_entry_parse_value(&bpdlg->end, bpdlg->dbg, bp->type, &addr1)) return FALSE; } else { addr1 = addr0; } if (bp->type == TILEM_DB_BREAK_LOGICAL) bp->mask = 0xffff; else if (bp->type == TILEM_DB_BREAK_PORT) bp->mask = 0xff; else bp->mask = 0xffffffff; bp->start = addr0 & bp->mask; bp->end = addr1 & bp->mask; if (bp->end < bp->start) return FALSE; return TRUE; } /* Check if input fields are valid, and enable/disable OK response as appropriate */ static void validate(struct breakpoint_dlg *bpdlg) { TilemDebugBreakpoint tmpbp; if (parse_input(bpdlg, &tmpbp)) gtk_dialog_set_response_sensitive(GTK_DIALOG(bpdlg->dlg), GTK_RESPONSE_OK, TRUE); else gtk_dialog_set_response_sensitive(GTK_DIALOG(bpdlg->dlg), GTK_RESPONSE_OK, FALSE); } /* Enable/disable check buttons for access mode */ static void set_access_mask(struct breakpoint_dlg *bpdlg, guint mask) { int i; if (mask) gtk_widget_show(bpdlg->access_label); else gtk_widget_hide(bpdlg->access_label); for (i = 0; i < 3; i++) { if (mask & (1 << i)) gtk_widget_show(bpdlg->access_cb[i]); else gtk_widget_hide(bpdlg->access_cb[i]); } } /* Combo box changed */ static void addr_type_changed(G_GNUC_UNUSED GtkComboBox *combo, gpointer data) { struct breakpoint_dlg *bpdlg = data; int type = get_bp_type(bpdlg); gboolean range = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bpdlg->range_rb)); char *s; s = g_strdup_printf("%s", type_info[type].value_label); gtk_label_set_markup(GTK_LABEL(bpdlg->address_label), s); g_free(s); set_access_mask(bpdlg, type_info[type].access_mask); if (type_info[type].use_pages) { gtk_widget_show(bpdlg->start.page_label); gtk_widget_show(bpdlg->start.page_entry); } else { gtk_widget_hide(bpdlg->start.page_label); gtk_widget_hide(bpdlg->start.page_entry); } if (range) { gtk_label_set_text_with_mnemonic(GTK_LABEL(bpdlg->start.addr_label), "_Start:"); gtk_widget_show(bpdlg->end.addr_label); gtk_widget_show(bpdlg->end.addr_entry); } else { gtk_label_set_text_with_mnemonic(GTK_LABEL(bpdlg->start.addr_label), "_Value:"); gtk_widget_hide(bpdlg->end.addr_label); gtk_widget_hide(bpdlg->end.addr_entry); } if (type_info[type].use_pages && range) { gtk_widget_show(bpdlg->end.page_label); gtk_widget_show(bpdlg->end.page_entry); } else { gtk_widget_hide(bpdlg->end.page_label); gtk_widget_hide(bpdlg->end.page_entry); } validate(bpdlg); } /* Access mode changed */ static void access_changed(G_GNUC_UNUSED GtkToggleButton *tb, gpointer data) { struct breakpoint_dlg *bpdlg = data; validate(bpdlg); } /* Single/range mode changed */ static void range_mode_changed(G_GNUC_UNUSED GtkToggleButton *tb, gpointer data) { struct breakpoint_dlg *bpdlg = data; addr_type_changed(NULL, bpdlg); } /* Text of entry changed */ static void entry_edited(G_GNUC_UNUSED GtkEntry *entry, gpointer data) { struct breakpoint_dlg *bpdlg = data; validate(bpdlg); } /* Key presssed in entry */ static gboolean entry_key_event(G_GNUC_UNUSED GtkWidget *entry, GdkEventKey *ev, gpointer data) { struct breakpoint_dlg *bpdlg = data; TilemDebugBreakpoint tmpbp; if (ev->state & GDK_MODIFIER_MASK) return FALSE; if (ev->keyval != GDK_Return && ev->keyval != GDK_KP_Enter && ev->keyval != GDK_ISO_Enter) return FALSE; if (parse_input(bpdlg, &tmpbp)) gtk_dialog_response(GTK_DIALOG(bpdlg->dlg), GTK_RESPONSE_OK); else gtk_widget_child_focus(bpdlg->box, GTK_DIR_TAB_FORWARD); return TRUE; } static void init_hex_entry(struct breakpoint_dlg *bpdlg, struct hex_entry *he, const char *label, GtkTable *tbl, int ypos) { GtkWidget *align, *lbl; he->addr_label = lbl = gtk_label_new_with_mnemonic(label); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); align = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 6); gtk_container_add(GTK_CONTAINER(align), lbl); gtk_table_attach(tbl, align, 0, 1, ypos, ypos + 1, GTK_FILL, GTK_FILL, 0, 0); he->addr_entry = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), he->addr_entry); gtk_table_attach(tbl, he->addr_entry, 1, 2, ypos, ypos + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); g_signal_connect(he->addr_entry, "changed", G_CALLBACK(entry_edited), bpdlg); g_signal_connect(he->addr_entry, "key-press-event", G_CALLBACK(entry_key_event), bpdlg); he->page_label = lbl = gtk_label_new("Page:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(tbl, lbl, 2, 3, ypos, ypos + 1, GTK_FILL, GTK_FILL, 6, 0); he->page_entry = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(he->page_entry), 5); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), he->page_entry); gtk_table_attach(tbl, he->page_entry, 3, 4, ypos, ypos + 1, GTK_FILL, GTK_FILL, 0, 0); g_signal_connect(he->page_entry, "changed", G_CALLBACK(entry_edited), bpdlg); g_signal_connect(he->page_entry, "key-press-event", G_CALLBACK(entry_key_event), bpdlg); } static gboolean edit_breakpoint(TilemDebugger *dbg, GtkWindow *parent_window, const char *title, TilemDebugBreakpoint *bp, gboolean edit_existing) { GtkWidget *dlg, *vbox, *frame, *tbl, *hbox, *lbl, *combo, *cb, *rb; struct breakpoint_dlg bpdlg; gsize i; g_return_val_if_fail(bp != NULL, FALSE); g_return_val_if_fail(dbg != NULL, FALSE); g_return_val_if_fail(dbg->emu != NULL, FALSE); g_return_val_if_fail(dbg->emu->calc != NULL, FALSE); bpdlg.dbg = dbg; dlg = gtk_dialog_new_with_buttons(title, parent_window, GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); bpdlg.dlg = dlg; bpdlg.box = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(bpdlg.box), 6); tbl = gtk_table_new(2, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tbl), 6); gtk_table_set_col_spacings(GTK_TABLE(tbl), 6); /* Breakpoint type */ lbl = gtk_label_new_with_mnemonic("Breakpoint _type:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); combo = gtk_combo_box_new_text(); for (i = 0; i < G_N_ELEMENTS(type_info); i++) gtk_combo_box_append_text(GTK_COMBO_BOX(combo), type_info[i].desc); bpdlg.type_combo = combo; gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), combo); gtk_table_attach(GTK_TABLE(tbl), combo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_combo_box_set_active(GTK_COMBO_BOX(combo), bp->type); /* Access mode */ bpdlg.access_label = lbl = gtk_label_new("Break when:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); hbox = gtk_hbox_new(FALSE, 6); cb = gtk_check_button_new_with_mnemonic("_Reading"); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); bpdlg.access_cb[2] = cb; cb = gtk_check_button_new_with_mnemonic("_Writing"); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); bpdlg.access_cb[1] = cb; cb = gtk_check_button_new_with_mnemonic("E_xecuting"); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); bpdlg.access_cb[0] = cb; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bpdlg.access_cb[0]), bp->mode & 1); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bpdlg.access_cb[1]), bp->mode & 2); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bpdlg.access_cb[2]), bp->mode & 4); gtk_table_attach(GTK_TABLE(tbl), hbox, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); frame = new_frame("Breakpoint Condition", tbl); gtk_box_pack_start(GTK_BOX(bpdlg.box), frame, FALSE, FALSE, 0); /* Addresses */ tbl = gtk_table_new(3, 4, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tbl), 6); hbox = gtk_hbox_new(FALSE, 6); rb = gtk_radio_button_new_with_mnemonic(NULL, "Si_ngle"); gtk_box_pack_start(GTK_BOX(hbox), rb, FALSE, FALSE, 0); bpdlg.single_rb = rb; rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(rb), "R_ange"); gtk_box_pack_start(GTK_BOX(hbox), rb, FALSE, FALSE, 0); bpdlg.range_rb = rb; if (edit_existing && bp->end != bp->start) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); gtk_table_attach(GTK_TABLE(tbl), hbox, 0, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); init_hex_entry(&bpdlg, &bpdlg.start, "S_tart:", GTK_TABLE(tbl), 1); init_hex_entry(&bpdlg, &bpdlg.end, "_End:", GTK_TABLE(tbl), 2); frame = new_frame("Address", tbl); bpdlg.address_label = gtk_frame_get_label_widget(GTK_FRAME(frame)); gtk_box_pack_start(GTK_BOX(bpdlg.box), frame, FALSE, FALSE, 0); gtk_widget_show_all(bpdlg.box); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox), bpdlg.box, FALSE, FALSE, 0); if (edit_existing) { hex_entry_set_value(&bpdlg.start, dbg, bp->type, bp->start); hex_entry_set_value(&bpdlg.end, dbg, bp->type, bp->end); } g_signal_connect(combo, "changed", G_CALLBACK(addr_type_changed), &bpdlg); g_signal_connect(bpdlg.access_cb[0], "toggled", G_CALLBACK(access_changed), &bpdlg); g_signal_connect(bpdlg.access_cb[1], "toggled", G_CALLBACK(access_changed), &bpdlg); g_signal_connect(bpdlg.access_cb[2], "toggled", G_CALLBACK(access_changed), &bpdlg); g_signal_connect(bpdlg.single_rb, "toggled", G_CALLBACK(range_mode_changed), &bpdlg); addr_type_changed(NULL, &bpdlg); gtk_widget_grab_focus(bpdlg.start.addr_entry); do { if (gtk_dialog_run(GTK_DIALOG(dlg)) != GTK_RESPONSE_OK) { gtk_widget_destroy(dlg); return FALSE; } } while (!parse_input(&bpdlg, bp)); gtk_widget_destroy(dlg); return TRUE; } /**************** Breakpoint list dialog ****************/ enum { COL_BP, COL_START, COL_END, COL_TYPE_STR, COL_START_STR, COL_END_STR, COL_ENABLED, N_COLUMNS }; struct bplist_dlg { TilemDebugger *dbg; GtkWidget *dlg; GtkListStore *store; GtkWidget *treeview; GtkWidget *remove_btn; GtkWidget *edit_btn; GtkWidget *clear_btn; }; /* Convert address into a displayable string */ static void format_address(TilemDebugger *dbg, char *buf, int bufsize, int type, dword value) { const TilemCalc *calc; unsigned int page; g_return_if_fail(dbg->emu != NULL); g_return_if_fail(dbg->emu->calc != NULL); calc = dbg->emu->calc; switch (type) { case TILEM_DB_BREAK_LOGICAL: g_snprintf(buf, bufsize, "%04X", value); break; case TILEM_DB_BREAK_PHYSICAL: if (value >= calc->hw.romsize) { value -= calc->hw.romsize; page = (value >> 14) + calc->hw.rampagemask; } else { page = (value >> 14); } g_snprintf(buf, bufsize, "%02X:%04X", page, value & 0x3fff); break; case TILEM_DB_BREAK_PORT: g_snprintf(buf, bufsize, "%02X", value); break; case TILEM_DB_BREAK_OPCODE: if (value < 0x100) g_snprintf(buf, bufsize, "%02X", value); else if (value < 0x10000) g_snprintf(buf, bufsize, "%04X", value); else if (value < 0x1000000) g_snprintf(buf, bufsize, "%06X", value); else g_snprintf(buf, bufsize, "%08X", value); break; default: g_return_if_reached(); } } /* Store breakpoint properties in tree model */ static void set_iter_from_bp(struct bplist_dlg *bpldlg, GtkTreeIter *iter, const TilemDebugBreakpoint *bp) { char tbuf[5], sbuf[10], ebuf[10]; int i, j; g_return_if_fail(bp != NULL); tbuf[0] = type_info[bp->type].abbrev; j = 1; for (i = 0; i < 3; i++) if (bp->mode & (4 >> i)) tbuf[j++] = "RWX"[i]; tbuf[j] = 0; format_address(bpldlg->dbg, sbuf, sizeof(sbuf), bp->type, bp->start); format_address(bpldlg->dbg, ebuf, sizeof(ebuf), bp->type, bp->end); gtk_list_store_set(bpldlg->store, iter, COL_BP, bp, COL_START, bp->start, COL_END, bp->end, COL_TYPE_STR, tbuf, COL_START_STR, sbuf, COL_END_STR, ebuf, COL_ENABLED, !bp->disabled, -1); } /* Get breakpoint pointer for the given tree model row */ static TilemDebugBreakpoint *get_iter_bp(struct bplist_dlg *bpldlg, GtkTreeIter *iter) { gpointer ptr; gtk_tree_model_get(GTK_TREE_MODEL(bpldlg->store), iter, COL_BP, &ptr, -1); return (TilemDebugBreakpoint *) ptr; } /* Set buttons sensitive or insensitive depending on whether any BPs are selected */ static void update_buttons(struct bplist_dlg *bpldlg) { GtkTreeSelection *sel; gboolean any_sel; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(bpldlg->treeview)); any_sel = gtk_tree_selection_get_selected(sel, NULL, NULL); gtk_widget_set_sensitive(bpldlg->remove_btn, any_sel); gtk_widget_set_sensitive(bpldlg->edit_btn, any_sel); gtk_widget_set_sensitive(bpldlg->clear_btn, bpldlg->dbg->breakpoints != NULL); } /* "Add breakpoint" button clicked */ static void add_clicked(G_GNUC_UNUSED GtkButton *btn, gpointer data) { struct bplist_dlg *bpldlg = data; TilemDebugBreakpoint tmpbp, *newbp; TilemDebugger *dbg = bpldlg->dbg; GtkTreeIter iter; memset(&tmpbp, 0, sizeof(tmpbp)); tmpbp.type = dbg->last_bp_type; tmpbp.mode = dbg->last_bp_mode; if (!edit_breakpoint(dbg, GTK_WINDOW(bpldlg->dlg), "Add Breakpoint", &tmpbp, FALSE)) return; dbg->last_bp_type = tmpbp.type; dbg->last_bp_mode = tmpbp.mode; newbp = tilem_debugger_add_breakpoint(dbg, &tmpbp); gtk_list_store_append(bpldlg->store, &iter); set_iter_from_bp(bpldlg, &iter, newbp); update_buttons(bpldlg); } /* "Remove breakpoint" button clicked */ static void remove_clicked(G_GNUC_UNUSED GtkButton *btn, gpointer data) { struct bplist_dlg *bpldlg = data; GtkTreeSelection *sel; GtkTreeIter iter; TilemDebugBreakpoint *bp; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(bpldlg->treeview)); if (!gtk_tree_selection_get_selected(sel, NULL, &iter)) return; bp = get_iter_bp(bpldlg, &iter); g_return_if_fail(bp != NULL); gtk_list_store_remove(bpldlg->store, &iter); tilem_debugger_remove_breakpoint(bpldlg->dbg, bp); update_buttons(bpldlg); } /* Edit an existing breakpoint */ static void edit_row(struct bplist_dlg *bpldlg, GtkTreeIter *iter) { TilemDebugBreakpoint *bp, tmpbp; bp = get_iter_bp(bpldlg, iter); g_return_if_fail(bp != NULL); tmpbp = *bp; if (!edit_breakpoint(bpldlg->dbg, GTK_WINDOW(bpldlg->dlg), "Edit Breakpoint", &tmpbp, TRUE)) return; tmpbp.disabled = 0; tilem_debugger_change_breakpoint(bpldlg->dbg, bp, &tmpbp); set_iter_from_bp(bpldlg, iter, bp); update_buttons(bpldlg); } /* "Edit breakpoint" button clicked */ static void edit_clicked(G_GNUC_UNUSED GtkButton *btn, gpointer data) { struct bplist_dlg *bpldlg = data; GtkTreeSelection *sel; GtkTreeIter iter; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(bpldlg->treeview)); if (!gtk_tree_selection_get_selected(sel, NULL, &iter)) return; edit_row(bpldlg, &iter); } /* "Clear breakpoints" button clicked */ static void clear_clicked(G_GNUC_UNUSED GtkButton *btn, gpointer data) { struct bplist_dlg *bpldlg = data; GtkWidget *dlg; TilemDebugBreakpoint *bp; dlg = gtk_message_dialog_new(GTK_WINDOW(bpldlg->dlg), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "Clear all breakpoints?"); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG(dlg), "All existing breakpoints will be deleted and" " cannot be restored."); gtk_dialog_add_buttons(GTK_DIALOG(dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CLEAR, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { while (bpldlg->dbg->breakpoints) { bp = bpldlg->dbg->breakpoints->data; tilem_debugger_remove_breakpoint(bpldlg->dbg, bp); } gtk_list_store_clear(bpldlg->store); update_buttons(bpldlg); } gtk_widget_destroy(dlg); } /* Row activated (double-clicked, usually) */ static void row_activated(G_GNUC_UNUSED GtkTreeView *treeview, GtkTreePath *path, G_GNUC_UNUSED GtkTreeViewColumn *col, gpointer data) { struct bplist_dlg *bpldlg = data; GtkTreeIter iter; if (gtk_tree_model_get_iter(GTK_TREE_MODEL(bpldlg->store), &iter, path)) edit_row(bpldlg, &iter); } /* Toggle button clicked for a breakpoint */ static void enabled_toggled(G_GNUC_UNUSED GtkCellRendererToggle *cell, gchar *pathstr, gpointer data) { struct bplist_dlg *bpldlg = data; GtkTreePath *path; GtkTreeIter iter; TilemDebugBreakpoint *bp, tmpbp; path = gtk_tree_path_new_from_string(pathstr); if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(bpldlg->store), &iter, path)) { gtk_tree_path_free(path); return; } gtk_tree_path_free(path); bp = get_iter_bp(bpldlg, &iter); g_return_if_fail(bp != NULL); tmpbp = *bp; tmpbp.disabled = !tmpbp.disabled; tilem_debugger_change_breakpoint(bpldlg->dbg, bp, &tmpbp); set_iter_from_bp(bpldlg, &iter, bp); } /* Selection changed */ static void selection_changed(G_GNUC_UNUSED GtkTreeSelection *sel, gpointer data) { struct bplist_dlg *bpldlg = data; update_buttons(bpldlg); } /* Show a dialog letting the user add, remove, and edit breakpoints */ void tilem_debugger_edit_breakpoints(TilemDebugger *dbg) { struct bplist_dlg bpldlg; GtkWidget *dlg, *hbox, *treeview, *sw, *bbox, *btn, *vbox, *vbox2, *invalid_cb, *undoc_cb; GtkListStore *store; GtkTreeViewColumn *col; GtkCellRenderer *cell; GtkTreeIter iter; GSList *l; GtkTreeSelection *sel; unsigned int flags; g_return_if_fail(dbg != NULL); g_return_if_fail(dbg->emu != NULL); g_return_if_fail(dbg->emu->calc != NULL); bpldlg.dbg = dbg; dlg = gtk_dialog_new_with_buttons("Breakpoints", GTK_WINDOW(dbg->window), GTK_DIALOG_MODAL, GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_default_size(GTK_WINDOW(dlg), -1, 300); store = gtk_list_store_new(N_COLUMNS, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); bpldlg.dlg = dlg; bpldlg.store = store; vbox = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(vbox), 6); hbox = gtk_hbox_new(FALSE, 6); for (l = dbg->breakpoints; l; l = l->next) { gtk_list_store_append(store, &iter); set_iter_from_bp(&bpldlg, &iter, l->data); } treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE); bpldlg.treeview = treeview; fixed_tree_view_init(treeview, 0, COL_TYPE_STR, "MRWX ", COL_START_STR, "DD:DDDD ", COL_END_STR, "DD:DDDD ", COL_ENABLED, TRUE, -1); g_signal_connect(treeview, "row-activated", G_CALLBACK(row_activated), &bpldlg); /* Enabled/type column */ col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Type"); gtk_tree_view_column_set_sort_column_id(col, COL_TYPE_STR); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); cell = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(col, cell, FALSE); gtk_tree_view_column_set_attributes(col, cell, "active", COL_ENABLED, NULL); g_signal_connect(cell, "toggled", G_CALLBACK(enabled_toggled), &bpldlg); cell = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(col, cell, TRUE); gtk_tree_view_column_set_attributes(col, cell, "text", COL_TYPE_STR, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col); /* Start column */ cell = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes ("Start", cell, "text", COL_START_STR, NULL); gtk_tree_view_column_set_sort_column_id(col, COL_START); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col); /* End column */ cell = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes ("End", cell, "text", COL_END_STR, NULL); gtk_tree_view_column_set_sort_column_id(col, COL_END); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col); sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_box_pack_start(GTK_BOX(hbox), sw, TRUE, TRUE, 0); /* Buttons */ bbox = gtk_vbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START); gtk_box_set_spacing(GTK_BOX(bbox), 6); btn = gtk_button_new_from_stock(GTK_STOCK_ADD); g_signal_connect(btn, "clicked", G_CALLBACK(add_clicked), &bpldlg); gtk_container_add(GTK_CONTAINER(bbox), btn); btn = gtk_button_new_from_stock(GTK_STOCK_REMOVE); g_signal_connect(btn, "clicked", G_CALLBACK(remove_clicked), &bpldlg); gtk_container_add(GTK_CONTAINER(bbox), btn); bpldlg.remove_btn = btn; btn = gtk_button_new_from_stock(GTK_STOCK_EDIT); g_signal_connect(btn, "clicked", G_CALLBACK(edit_clicked), &bpldlg); gtk_container_add(GTK_CONTAINER(bbox), btn); bpldlg.edit_btn = btn; btn = gtk_button_new_from_stock(GTK_STOCK_CLEAR); g_signal_connect(btn, "clicked", G_CALLBACK(clear_clicked), &bpldlg); gtk_container_add(GTK_CONTAINER(bbox), btn); bpldlg.clear_btn = btn; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); g_signal_connect(sel, "changed", G_CALLBACK(selection_changed), &bpldlg); update_buttons(&bpldlg); gtk_box_pack_start(GTK_BOX(hbox), bbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); invalid_cb = gtk_check_button_new_with_mnemonic ("Break on _invalid instructions"); undoc_cb = gtk_check_button_new_with_mnemonic ("Break on _undocumented instructions"); tilem_calc_emulator_lock(dbg->emu); flags = dbg->emu->calc->z80.emuflags; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(invalid_cb), (flags & TILEM_Z80_BREAK_INVALID)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(undoc_cb), (flags & TILEM_Z80_BREAK_UNDOCUMENTED)); tilem_calc_emulator_unlock(dbg->emu); gtk_box_pack_start(GTK_BOX(vbox), invalid_cb, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), undoc_cb, FALSE, FALSE, 0); gtk_widget_show_all(vbox); gtk_widget_grab_focus(treeview); vbox2 = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0); gtk_dialog_run(GTK_DIALOG(dlg)); tilem_calc_emulator_lock(dbg->emu); flags = dbg->emu->calc->z80.emuflags; flags &= ~(TILEM_Z80_BREAK_INVALID | TILEM_Z80_BREAK_UNDOCUMENTED); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(invalid_cb))) flags |= TILEM_Z80_BREAK_INVALID; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(undoc_cb))) flags |= TILEM_Z80_BREAK_UNDOCUMENTED; dbg->emu->calc->z80.emuflags = flags; tilem_calc_emulator_unlock(dbg->emu); gtk_widget_destroy(dlg); } tilem-2.0/gui/charmap.c000066400000000000000000000103031220200411600150110ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "charmap.h" #define UNDEF 0xfffd static const unsigned long ti81chars[256] = { 0, ' ', 0x2192, 0x2191, 0x2193, 0x25B6, '<', 0x2264, '=', 0x2260, '>', 0x2265, 0x3D20DE, 0x207C, '+', '-', '*', '/', '^', 0x221A, '(', ')', '[', ']', '{', '}', '?', '!', ':', ',', 0x2026, 0x207B00B9, 0x207B, 0xB7, 0x2070, 0xB9, 0xB2, 0xB3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 'E', 0x2081, 0x2082, 0x2083, 0x2084, 0x23E8, 0x209C, '"', 0x207B, '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'E', 0x2B3, 0xB0, 0x3B8, 'R', 'T', 0x2E3, 0x2B8, 0x780305, 0x790305, 0x3A3, 0x3C3, 0x3C0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x3B8, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 0xD7, 0x2588, 0x219120DE, 0x4120DE, '_', 0x21910332, 0x410332, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF }; static const unsigned long * getmap(int model) { switch (model) { case TILEM_CALC_TI73: return ti73_charset; case TILEM_CALC_TI81: return ti81chars; case TILEM_CALC_TI82: return ti82_charset; case TILEM_CALC_TI76: case TILEM_CALC_TI83: return ti83_charset; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return ti83p_charset; case TILEM_CALC_TI85: return ti85_charset; case TILEM_CALC_TI86: return ti86_charset; default: return ti83p_charset; } } /* Convert a byte value from the calculator large-font character set into a printable UTF-8 string. */ char *ti_to_unicode(int model, unsigned int value) { const unsigned long *map = getmap(model); unsigned long v; char buf[12]; int n; v = map[value]; if (v == 0) v = 0x2400; /* SYMBOL FOR NULL */ else if (v == '\n') v = 0x240A; /* SYMBOL FOR LINE FEED */ else if (v == ' ') v = 0x2423; /* OPEN BOX */ /* in the ticonv character tables, non-BMP characters are represented by a surrogate pair */ if ((v & 0xfc00fc00) == 0xd800dc00) { v = (((v & 0x3ff0000) >> 6) | (v & 0x3ff)) + 0x10000; n = g_unichar_to_utf8(v, buf); } else if (v & 0xffff0000) { n = g_unichar_to_utf8(v >> 16, buf); n += g_unichar_to_utf8(v & 0xffff, buf + n); } else { n = g_unichar_to_utf8(v, buf); } return g_strndup(buf, n); } tilem-2.0/gui/charmap.h000066400000000000000000000015431220200411600150240ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* Convert a byte value from the calculator large-font character set into a printable UTF-8 string. */ char *ti_to_unicode(int model, unsigned int value); tilem-2.0/gui/config.c000066400000000000000000000172451220200411600146570ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "msgbox.h" #ifndef CONFIG_FILE #define CONFIG_FILE "config.ini" #endif #define MAX_RECENT_FILES 10 /* Store a filename in a GKeyFile. Any control characters or non-UTF-8 filenames are stored in octal. Note that g_key_file_set/get_string() can't be used because they only allow UTF-8 */ static void key_file_set_filename(GKeyFile *gkf, const char *group, const char *key, const char *value) { char *escaped; const char *p; char *q; gunichar uc; int b; q = escaped = g_new(char, strlen(value) * 4 + 1); while (*value != 0) { uc = g_utf8_get_char_validated(value, -1); if (uc < 0x20 || uc == 0x7F || !g_unichar_validate(uc)) { b = (unsigned char) *value; q[0] = '\\'; q[1] = '0' + (b >> 6); q[2] = '0' + ((b >> 3) & 7); q[3] = '0' + (b & 7); q += 4; value++; } else if (uc == '\\') { q[0] = q[1] = '\\'; q += 2; value++; } else { p = g_utf8_next_char(value); while (value != p) *q++ = *value++; } } *q = 0; g_key_file_set_value(gkf, group, key, escaped); g_free(escaped); } /* Retrieve a filename from a GKeyFile. */ static char *key_file_get_filename(GKeyFile *gkf, const char *group, const char *key, GError **error) { char *value, *unescaped; value = g_key_file_get_value(gkf, group, key, error); if (!value) return NULL; unescaped = g_strcompress(value); g_free(value); return unescaped; } /* Load and parse the configuration file. */ static GKeyFile *load_config(gboolean writable) { static gboolean warned; GKeyFile *gkf; GKeyFileFlags flags; char *cfname, *dname; GError *err = NULL; gkf = g_key_file_new(); cfname = get_shared_file_path(CONFIG_FILE, NULL); if (!cfname) return gkf; if (writable) flags = (G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS); else flags = 0; if (!g_key_file_load_from_file(gkf, cfname, flags, &err)) { /* don't bother the user more than once */ if (!warned) { dname = g_filename_display_name(cfname); messagebox02(NULL, GTK_MESSAGE_ERROR, "Unable to read settings", "An error occurred while reading %s: %s", dname, err->message); g_free(dname); warned = TRUE; } g_error_free(err); } g_free(cfname); return gkf; } /* Save the configuration file. */ static void save_config(GKeyFile *gkf) { static gboolean warned; char *cfname, *dname; char *data; gsize length; GError *err = NULL; data = g_key_file_to_data(gkf, &length, NULL); cfname = get_config_file_path(CONFIG_FILE, NULL); if (!g_file_set_contents(cfname, data, length, &err)) { /* don't bother the user more than once */ if (!warned) { dname = g_filename_display_name(cfname); messagebox02(NULL, GTK_MESSAGE_ERROR, "Unable to save settings", "An error occurred while writing %s: %s", dname, err->message); g_free(dname); warned = TRUE; } g_error_free(err); } g_free(cfname); g_free(data); } /* Retrieve settings from the configuration file. */ void tilem_config_get(const char *group, const char *option, ...) { va_list ap; GKeyFile *gkf; const char *type, *defvalue; GError *err = NULL; char *key, *p; char **strp; int *intp; double *dblp; GdkColor *colorp; g_return_if_fail(group != NULL); g_return_if_fail(option != NULL); gkf = load_config(FALSE); va_start(ap, option); while (option != NULL) { type = strrchr(option, '/'); if (type == NULL || type[1] == 0 || (type[2] != 0 && type[2] != '=')) { g_critical("invalid argument\n"); break; } if (type[2] == '=') defvalue = &type[3]; else defvalue = NULL; key = g_strndup(option, type - option); if (type[1] == 'f') { strp = va_arg(ap, char **); *strp = key_file_get_filename(gkf, group, key, &err); if (err && defvalue) *strp = g_strdup(defvalue); } else if (type[1] == 's') { strp = va_arg(ap, char **); *strp = g_key_file_get_string(gkf, group, key, &err); if (err && defvalue) *strp = g_strdup(defvalue); } else if (type[1] == 'i') { intp = va_arg(ap, int *); *intp = g_key_file_get_integer(gkf, group, key, &err); if (err && defvalue) *intp = g_ascii_strtoll(defvalue, NULL, 10); } else if (type[1] == 'r') { dblp = va_arg(ap, double *); *dblp = g_key_file_get_double(gkf, group, key, &err); if (err && defvalue) *dblp = g_ascii_strtod(defvalue, NULL); } else if (type[1] == 'b') { intp = va_arg(ap, int *); *intp = g_key_file_get_boolean(gkf, group, key, &err); if (err && defvalue) *intp = g_ascii_strtoll(defvalue, NULL, 10); } else if (type[1] == 'c') { colorp = va_arg(ap, GdkColor *); p = g_key_file_get_string(gkf, group, key, &err); if (p == NULL || !gdk_color_parse(p, colorp)) { if (defvalue) { gdk_color_parse(defvalue, colorp); } else { colorp->red = 0; colorp->green = 0; colorp->blue = 0; } } g_free(p); } else { g_critical("invalid argument\n"); g_free(key); break; } g_clear_error(&err); g_free(key); option = va_arg(ap, const char *); } va_end(ap); g_key_file_free(gkf); } /* Save settings to the configuration file. */ void tilem_config_set(const char *group, const char *option, ...) { va_list ap; GKeyFile *gkf; const char *type; char *key; const char *strv; int intv; double dblv; const GdkColor *colorv; char *p; g_return_if_fail(group != NULL); g_return_if_fail(option != NULL); gkf = load_config(TRUE); va_start(ap, option); while (option != NULL) { type = strrchr(option, '/'); if (type == NULL || type[1] == 0 || type[2] != 0) { g_critical("invalid argument\n"); break; } key = g_strndup(option, type - option); if (type[1] == 'f') { strv = va_arg(ap, const char *); key_file_set_filename(gkf, group, key, strv); } else if (type[1] == 's') { strv = va_arg(ap, const char *); g_key_file_set_string(gkf, group, key, strv); } else if (type[1] == 'i') { intv = va_arg(ap, int); g_key_file_set_integer(gkf, group, key, intv); } else if (type[1] == 'r') { dblv = va_arg(ap, double); g_key_file_set_double(gkf, group, key, dblv); } else if (type[1] == 'b') { intv = va_arg(ap, int); g_key_file_set_boolean(gkf, group, key, !!intv); } else if (type[1] == 'c') { colorv = va_arg(ap, const GdkColor *); p = g_strdup_printf("#%02x%02x%02x", colorv->red >> 8, colorv->green >> 8, colorv->blue >> 8); g_key_file_set_string(gkf, group, key, p); g_free(p); } else { g_critical("invalid argument\n"); g_free(key); break; } g_free(key); option = va_arg(ap, const char *); } va_end(ap); save_config(gkf); g_key_file_free(gkf); } tilem-2.0/gui/debugger.c000066400000000000000000001153761220200411600152020ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "gui.h" #include "disasmview.h" #include "files.h" #include "msgbox.h" #include "fixedtreeview.h" #include "memmodel.h" /* Stack list */ enum { COL_OFFSET_STK = 0, COL_VALUE_STK, NUM_COLS_STK }; /* Indices in reg_entries */ enum { R_AF, R_BC, R_DE, R_HL, R_IX, R_SP, R_AF2, R_BC2, R_DE2, R_HL2, R_IY, R_PC, R_IM, R_I, NUM_REGS }; /* Labels for the entries */ static const char * const reg_labels[] = { "A_F:", "B_C:", "D_E:", "H_L:", "I_X:", "SP:", "AF':", "BC':", "DE':", "HL':", "I_Y:", "PC:", "IM:", "I:" }; /* Labels for the flag buttons */ static const char flag_labels[][2] = { "C", "N", "P", "X", "H", "Y", "Z", "S" }; /* Read a word */ static dword read_mem_word(TilemCalc *calc, dword addr) { dword phys, v; phys = (*calc->hw.mem_ltop)(calc, addr & 0xffff); v = calc->mem[phys]; phys = (*calc->hw.mem_ltop)(calc, (addr + 1) & 0xffff); v += calc->mem[phys] << 8; return v; } /* Determine model name for the purpose of looking up default system symbols */ static const char *get_sys_name(const TilemCalc *calc) { g_return_val_if_fail(calc != NULL, NULL); switch (calc->hw.model_id) { case TILEM_CALC_TI83: case TILEM_CALC_TI76: return "ti83"; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return "ti83p"; default: return calc->hw.name; } } /* Load default system symbols */ static void load_default_symbols(TilemDebugger *dbg) { char *base, *path, *dname; const char *errstr; FILE *symfile; base = g_strdup_printf("%s.sym", get_sys_name(dbg->emu->calc)); path = get_shared_file_path("symbols", base, NULL); g_free(base); if (!path) return; symfile = g_fopen(path, "rb"); if (!symfile) { errstr = g_strerror(errno); dname = g_filename_display_name(path); messagebox02(NULL, GTK_MESSAGE_ERROR, "Unable to read symbols", "An error occurred while reading %s: %s", dname, errstr); g_free(dname); g_free(path); return; } tilem_disasm_read_symbol_file(dbg->dasm, symfile); fclose(symfile); g_free(path); } /* Cancel temporary breakpoint */ static void cancel_step_bp(TilemDebugger *dbg) { if (!dbg->step_bp) return; g_return_if_fail(dbg->emu->calc != NULL); tilem_calc_emulator_lock(dbg->emu); tilem_z80_remove_breakpoint(dbg->emu->calc, dbg->step_bp); tilem_calc_emulator_unlock(dbg->emu); dbg->step_bp = 0; } /* Actions */ /* Run (but leave debugger window open) */ static void action_run(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; cancel_step_bp(dbg); tilem_calc_emulator_run(dbg->emu); tilem_debugger_refresh(dbg, TRUE); } /* Pause */ static void action_pause(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; tilem_debugger_show(dbg); cancel_step_bp(dbg); } /* Stepping */ static int bptest_step(TilemCalc *calc, dword op, G_GNUC_UNUSED void *data) { /* Single step condition: if calculator is halted, wait until an interrupt occurs; otherwise, stop after any instruction. */ if (op != 0x76 && (op & ~0x2000) != 0xdd76) /* not a HALT instruction */ return 1; else if (calc->z80.interrupts != 0 && calc->z80.r.iff1) return 1; else return 0; } static int bptest_step_over(TilemCalc *calc, dword op, void *data) { TilemDebugger *dbg = data; dword destaddr; /* Step-over condition: behavior depends on what instruction is executed. For most instructions, stop when we reach the "next line" as determined by disassembly. This means skipping over CALLs, RSTs, HALTs, and macros. For jump and return instructions, stop at the current PC, whatever that is. In both cases, wait until we actually reach the target PC, rather than halting immediately; the effect of this is that if an interrupt has occurred, we also "step over" the ISR. */ if ((op & ~0x20ff) == 0xdd00) op &= 0xff; if (op == 0xc3 /* JP */ || op == 0xc9 /* RET */ || op == 0xe9 /* JP HL/IX/IY */ || (op & ~0x38) == 0 /* JR, DJNZ, NOP, or EX AF,AF' */ || (op & ~0x38) == 0xc2 /* conditional JP */ || (op & ~0x38) == 0xc0 /* conditional RET */ || (op & ~0x38) == 0xed45) /* RETI/RETN */ destaddr = calc->z80.r.pc.d; else destaddr = dbg->step_next_addr; destaddr &= 0xffff; /* Delete this breakpoint, and replace it with a simple exec breakpoint at the target address. */ tilem_z80_remove_breakpoint(calc, dbg->step_bp); dbg->step_bp = tilem_z80_add_breakpoint(calc, TILEM_BREAK_MEM_EXEC, destaddr, destaddr, 0xffff, NULL, NULL); return 0; } static int bptest_finish(TilemCalc *calc, dword op, void *data) { dword exitsp = TILEM_PTR_TO_DWORD(data); byte f; /* Finish condition: wait until stack pointer is greater than a certain value, and we execute a return instruction. JP HL/IX/IY are also considered return instructions. */ if (calc->z80.r.sp.w.l <= exitsp) return 0; if ((op & ~0x20ff) == 0xdd00) op &= 0xff; f = calc->z80.r.af.b.l; switch (op) { case 0xc9: /* RET */ case 0xe9: /* JP HL/IX/IY */ case 0xed45: /* RETN */ case 0xed4d: /* RETI */ case 0xed55: case 0xed5d: case 0xed65: case 0xed6d: case 0xed75: case 0xed7d: return 1; /* conditionals: check if condition was true */ case 0xc0: return !(f & 0x40); case 0xc8: return (f & 0x40); case 0xd0: return !(f & 0x01); case 0xd8: return (f & 0x01); case 0xe0: return !(f & 0x04); case 0xe8: return (f & 0x04); case 0xf0: return !(f & 0x80); case 0xf8: return (f & 0x80); default: return 0; } } static gboolean post_resume_refresh(gpointer data) { TilemDebugger *dbg = data; tilem_debugger_refresh(dbg, FALSE); return FALSE; } static void run_with_step_condition(TilemDebugger *dbg, TilemZ80BreakpointFunc func, void *data) { tilem_calc_emulator_lock(dbg->emu); dbg->step_bp = tilem_z80_add_breakpoint(dbg->emu->calc, TILEM_BREAK_EXECUTE, 0, 0, 0, func, data); tilem_calc_emulator_unlock(dbg->emu); tilem_calc_emulator_run(dbg->emu); /* Don't refresh right away, to avoid flickering */ g_timeout_add(10, &post_resume_refresh, dbg); } /* Execute one instruction */ static void action_step(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; if (!dbg->emu->paused) return; g_return_if_fail(dbg->emu->calc != NULL); cancel_step_bp(dbg); run_with_step_condition(dbg, &bptest_step, NULL); } /* Skip over an instruction */ static void action_step_over(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; if (!dbg->emu->paused) return; g_return_if_fail(dbg->emu->calc != NULL); cancel_step_bp(dbg); tilem_calc_emulator_lock(dbg->emu); tilem_disasm_disassemble(dbg->dasm, dbg->emu->calc, 0, dbg->emu->calc->z80.r.pc.w.l, &dbg->step_next_addr, NULL, 0); tilem_calc_emulator_unlock(dbg->emu); run_with_step_condition(dbg, &bptest_step_over, dbg); } /* Run until current subroutine finishes */ static void action_finish(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; dword sp; if (!dbg->emu->paused) return; g_return_if_fail(dbg->emu->calc != NULL); cancel_step_bp(dbg); tilem_calc_emulator_lock(dbg->emu); sp = dbg->emu->calc->z80.r.sp.w.l; tilem_calc_emulator_unlock(dbg->emu); run_with_step_condition(dbg, &bptest_finish, TILEM_DWORD_TO_PTR(sp)); } /* Toggle breakpoint at selected line */ static void action_toggle_breakpoint(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; GtkWidget *focus; focus = gtk_window_get_focus(GTK_WINDOW(dbg->window)); if (TILEM_IS_DISASM_VIEW(focus)) tilem_disasm_view_toggle_breakpoint(TILEM_DISASM_VIEW(focus)); } /* Edit breakpoints */ static void action_edit_breakpoints(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; tilem_debugger_edit_breakpoints(dbg); } /* Close debugger window */ static void action_close(G_GNUC_UNUSED GtkAction *a, gpointer data) { TilemDebugger *dbg = data; tilem_debugger_hide(dbg); } static void keypad_dlg_response(G_GNUC_UNUSED GtkDialog *dlg, G_GNUC_UNUSED int response, gpointer data) { gtk_toggle_action_set_active(data, FALSE); } /* Show/hide keypad dialog */ static void action_view_keypad(GtkToggleAction *action, gpointer data) { TilemDebugger *dbg = data; if (!dbg->keypad_dialog) { dbg->keypad_dialog = tilem_keypad_dialog_new(dbg); g_signal_connect(dbg->keypad_dialog->window, "response", G_CALLBACK(keypad_dlg_response), action); } if (gtk_toggle_action_get_active(action)) gtk_window_present(GTK_WINDOW(dbg->keypad_dialog->window)); else gtk_widget_hide(dbg->keypad_dialog->window); } /* Set memory addressing mode */ static void action_mem_mode(GtkRadioAction *action, G_GNUC_UNUSED GtkRadioAction *current, gpointer data) { TilemDebugger *dbg = data; dbg->mem_logical = gtk_radio_action_get_current_value(action); tilem_disasm_view_set_logical(TILEM_DISASM_VIEW(dbg->disasm_view), dbg->mem_logical); tilem_debugger_mem_view_configure(dbg->mem_view, dbg->emu, dbg->mem_rowsize, dbg->mem_start, dbg->mem_logical); tilem_config_set("debugger", "mem_logical/b", dbg->mem_logical, NULL); } /* Prompt for an address to view */ static void action_go_to_address(G_GNUC_UNUSED GtkAction *action, gpointer data) { TilemDebugger *dbg = data; TilemDisasmView *dv = TILEM_DISASM_VIEW(dbg->disasm_view); dword addr; gboolean addr_set, logical; addr_set = tilem_disasm_view_get_cursor(dv, &addr, &logical); if (!tilem_prompt_address(dbg, GTK_WINDOW(dbg->window), "Go to Address", "Address:", &addr, !logical, addr_set)) return; tilem_disasm_view_go_to_address(dv, addr, logical); gtk_widget_grab_focus(dbg->disasm_view); } /* Jump to address at given stack index */ static void go_to_stack_pos(TilemDebugger *dbg, int pos) { dword addr; GtkTreePath *path; GtkTreeSelection *sel; dbg->stack_index = pos; tilem_calc_emulator_lock(dbg->emu); if (pos < 0) addr = dbg->emu->calc->z80.r.pc.d; else addr = read_mem_word(dbg->emu->calc, dbg->emu->calc->z80.r.sp.d + 2 * pos); tilem_calc_emulator_unlock(dbg->emu); tilem_disasm_view_go_to_address(TILEM_DISASM_VIEW(dbg->disasm_view), addr, TRUE); gtk_widget_grab_focus(dbg->disasm_view); if (pos >= 0) { path = gtk_tree_path_new_from_indices(pos, -1); gtk_tree_view_set_cursor(GTK_TREE_VIEW(dbg->stack_view), path, NULL, FALSE); gtk_tree_path_free(path); } else { sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dbg->stack_view)); gtk_tree_selection_unselect_all(sel); } gtk_action_set_sensitive(dbg->prev_stack_action, (pos >= 0)); } /* Jump to current PC */ static void action_go_to_pc(G_GNUC_UNUSED GtkAction *action, gpointer data) { TilemDebugger *dbg = data; go_to_stack_pos(dbg, -1); } /* Jump to previous stack entry */ static void action_prev_stack_entry(G_GNUC_UNUSED GtkAction *action, gpointer data) { TilemDebugger *dbg = data; if (dbg->stack_index >= 0) go_to_stack_pos(dbg, dbg->stack_index - 1); } /* Jump to next stack entry */ static void action_next_stack_entry(G_GNUC_UNUSED GtkAction *action, gpointer data) { TilemDebugger *dbg = data; go_to_stack_pos(dbg, dbg->stack_index + 1); } static const GtkActionEntry run_action_ents[] = {{ "pause", GTK_STOCK_MEDIA_PAUSE, "_Pause", "Escape", "Pause emulation", G_CALLBACK(action_pause) }}; static const GtkActionEntry paused_action_ents[] = {{ "run", GTK_STOCK_MEDIA_PLAY, "_Run", "F5", "Resume emulation", G_CALLBACK(action_run) }, { "step", "tilem-db-step", "_Step", "F7", "Execute one instruction", G_CALLBACK(action_step) }, { "step-over", "tilem-db-step-over", "Step _Over", "F8", "Run to the next line (skipping over subroutines)", G_CALLBACK(action_step_over) }, { "finish", "tilem-db-finish", "_Finish Subroutine", "F9", "Run to end of the current subroutine", G_CALLBACK(action_finish) }, { "toggle-breakpoint", NULL, "Toggle Breakpoint", "F2", "Enable or disable breakpoint at the selected address", G_CALLBACK(action_toggle_breakpoint) }, { "edit-breakpoints", NULL, "_Breakpoints", "B", "Add, remove, or modify breakpoints", G_CALLBACK(action_edit_breakpoints) }, { "go-to-address", GTK_STOCK_JUMP_TO, "_Address...", "L", "Jump to an address", G_CALLBACK(action_go_to_address) }, { "go-to-pc", NULL, "Current P_C", "Home", "Jump to the current program counter", G_CALLBACK(action_go_to_pc) }, { "prev-stack-entry", GTK_STOCK_GO_UP, "_Previous Stack Entry", "Page_Up", "Jump to the previous address in the stack", G_CALLBACK(action_prev_stack_entry) }, { "next-stack-entry", GTK_STOCK_GO_DOWN, "_Next Stack Entry", "Page_Down", "Jump to the next address in the stack", G_CALLBACK(action_next_stack_entry) }}; static const GtkRadioActionEntry mem_mode_ents[] = {{ "view-logical", 0, "_Logical Addresses", 0, "Show contents of the current Z80 address space", 1 }, { "view-absolute", 0, "_Absolute Addresses", 0, "Show all memory contents", 0 }}; static const GtkActionEntry misc_action_ents[] = {{ "debug-menu", 0, "_Debug", 0, 0, 0 }, { "view-menu", 0, "_View", 0, 0, 0 }, { "go-menu", 0, "_Go", 0, 0, 0 }, { "close", GTK_STOCK_CLOSE, 0, 0, "Close the debugger", G_CALLBACK(action_close) }}; static const GtkToggleActionEntry misc_toggle_ents[] = {{ "view-keypad", 0, "_Keypad", 0, "Show the calculator keypad state", G_CALLBACK(action_view_keypad), FALSE }}; /* Callbacks */ /* Register edited */ static void reg_edited(GtkEntry *ent, gpointer data) { TilemDebugger *dbg = data; TilemCalc *calc; const char *text; char *end; dword value; int i; if (dbg->refreshing) return; calc = dbg->emu->calc; g_return_if_fail(calc != NULL); text = gtk_entry_get_text(ent); value = strtol(text, &end, 16); for (i = 0; i < NUM_REGS; i++) if (ent == (GtkEntry*) dbg->reg_entries[i]) break; tilem_calc_emulator_lock(dbg->emu); switch (i) { case R_AF: calc->z80.r.af.d = value; break; case R_BC: calc->z80.r.bc.d = value; break; case R_DE: calc->z80.r.de.d = value; break; case R_HL: calc->z80.r.hl.d = value; break; case R_AF2: calc->z80.r.af2.d = value; break; case R_BC2: calc->z80.r.bc2.d = value; break; case R_DE2: calc->z80.r.de2.d = value; break; case R_HL2: calc->z80.r.hl2.d = value; break; case R_SP: calc->z80.r.sp.d = value; break; case R_PC: calc->z80.r.pc.d = value; break; case R_IX: calc->z80.r.ix.d = value; break; case R_IY: calc->z80.r.iy.d = value; break; case R_I: calc->z80.r.ir.b.h = value; break; } tilem_calc_emulator_unlock(dbg->emu); /* Set the value of the register immediately, but don't refresh the display: refreshing the registers themselves while user is trying to edit them would just be obnoxious, and refreshing stack and disassembly would be at least distracting. Instead, we'll refresh only when focus changes. */ dbg->delayed_refresh = TRUE; } /* Flag button toggled */ static void flag_edited(GtkToggleButton *btn, gpointer data) { TilemDebugger *dbg = data; TilemCalc *calc; int i; if (dbg->refreshing) return; calc = dbg->emu->calc; g_return_if_fail(calc != NULL); for (i = 0; i < 8; i++) if (btn == (GtkToggleButton*) dbg->flag_buttons[i]) break; tilem_calc_emulator_lock(dbg->emu); if (gtk_toggle_button_get_active(btn)) calc->z80.r.af.d |= (1 << i); else calc->z80.r.af.d &= ~(1 << i); tilem_calc_emulator_unlock(dbg->emu); /* refresh AF */ tilem_debugger_refresh(dbg, FALSE); } /* IM edited */ static void im_edited(GtkEntry *ent, gpointer data) { TilemDebugger *dbg = data; TilemCalc *calc; const char *text; char *end; int value; if (dbg->refreshing) return; calc = dbg->emu->calc; g_return_if_fail(calc != NULL); text = gtk_entry_get_text(ent); value = strtol(text, &end, 0); tilem_calc_emulator_lock(dbg->emu); if (value >= 0 && value <= 2) calc->z80.r.im = value; tilem_calc_emulator_unlock(dbg->emu); /* no need to refresh */ } /* IFF button toggled */ static void iff_edited(GtkToggleButton *btn, gpointer data) { TilemDebugger *dbg = data; TilemCalc *calc; if (dbg->refreshing) return; calc = dbg->emu->calc; g_return_if_fail(calc != NULL); tilem_calc_emulator_lock(dbg->emu); if (gtk_toggle_button_get_active(btn)) calc->z80.r.iff1 = calc->z80.r.iff2 = 1; else calc->z80.r.iff1 = calc->z80.r.iff2 = 0; tilem_calc_emulator_unlock(dbg->emu); /* no need to refresh */ } /* Main window's focus widget changed */ static void focus_changed(G_GNUC_UNUSED GtkWindow *win, G_GNUC_UNUSED GtkWidget *widget, gpointer data) { TilemDebugger *dbg = data; /* delayed refresh - see reg_edited() above */ if (dbg->delayed_refresh) tilem_debugger_refresh(dbg, FALSE); } /* Main window received a "delete" message */ static gboolean delete_win(G_GNUC_UNUSED GtkWidget *w, G_GNUC_UNUSED GdkEvent *ev, gpointer data) { TilemDebugger *dbg = data; tilem_debugger_hide(dbg); return TRUE; } /* Create table of widgets for editing registers */ static GtkWidget *create_registers(TilemDebugger *dbg) { GtkWidget *vbox, *tbl, *lbl, *hbox, *ent, *btn; int i; vbox = gtk_vbox_new(FALSE, 6); tbl = gtk_table_new(6, 4, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tbl), 6); gtk_table_set_col_spacings(GTK_TABLE(tbl), 6); gtk_table_set_col_spacing(GTK_TABLE(tbl), 1, 12); for (i = 0; i < 12; i++) { lbl = gtk_label_new_with_mnemonic(reg_labels[i]); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 2 * (i / 6), 2 * (i / 6) + 1, (i % 6), (i % 6) + 1, GTK_FILL, GTK_FILL, 0, 0); dbg->reg_entries[i] = ent = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(ent), 5); g_signal_connect(ent, "changed", G_CALLBACK(reg_edited), dbg); gtk_table_attach(GTK_TABLE(tbl), ent, 2 * (i / 6) + 1, 2 * (i / 6) + 2, (i % 6), (i % 6) + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ent); } gtk_box_pack_start(GTK_BOX(vbox), tbl, FALSE, FALSE, 0); hbox = gtk_hbox_new(TRUE, 0); for (i = 7; i >= 0; i--) { btn = gtk_toggle_button_new_with_label(flag_labels[i]); dbg->flag_buttons[i] = btn; g_signal_connect(btn, "toggled", G_CALLBACK(flag_edited), dbg); gtk_box_pack_start(GTK_BOX(hbox), btn, TRUE, TRUE, 0); } gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 6); for (i = 12; i < 14; i++) { lbl = gtk_label_new(reg_labels[i]); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); dbg->reg_entries[i] = ent = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), ent, TRUE, TRUE, 0); } g_signal_connect(dbg->reg_entries[R_I], "changed", G_CALLBACK(reg_edited), dbg); g_signal_connect(dbg->reg_entries[R_IM], "changed", G_CALLBACK(im_edited), dbg); gtk_entry_set_width_chars(GTK_ENTRY(dbg->reg_entries[R_IM]), 2); gtk_entry_set_width_chars(GTK_ENTRY(dbg->reg_entries[R_I]), 3); dbg->iff_checkbox = btn = gtk_check_button_new_with_label("EI"); g_signal_connect(btn, "toggled", G_CALLBACK(iff_edited), dbg); gtk_box_pack_start(GTK_BOX(hbox), btn, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); return vbox; } /* Create the GtkTreeView to show the stack */ static GtkWidget *create_stack_view() { GtkCellRenderer *renderer; GtkWidget *treeview; GtkTreeViewColumn *column; /* Create the stack list tree view and set title invisible */ treeview = gtk_tree_view_new(); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_VALUE_STK); /* Create the columns */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("ADDR", renderer, "text", COL_OFFSET_STK, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("VAL", renderer, "text", COL_VALUE_STK, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); return treeview; } /* Create a new scrolled window with sensible default settings. */ static GtkWidget *new_scrolled_window(GtkWidget *contents) { GtkWidget *sw; sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(sw), contents); return sw; } static const char uidesc[] = "" "

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "" "" " " " " " " " " " " " " "" ""; /* Create a new TilemDebugger. */ TilemDebugger *tilem_debugger_new(TilemCalcEmulator *emu) { TilemDebugger *dbg; GtkWidget *hbox, *vbox, *vbox2, *vpaned, *sw, *menubar, *toolbar; GtkUIManager *uimgr; GtkAccelGroup *accelgrp; GError *err = NULL; int defwidth, defheight; g_return_val_if_fail(emu != NULL, NULL); dbg = g_slice_new0(TilemDebugger); dbg->emu = emu; dbg->dasm = tilem_disasm_new(); dbg->last_bp_type = TILEM_DB_BREAK_LOGICAL; dbg->last_bp_mode = TILEM_DB_BREAK_EXEC; dbg->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(dbg->window), "TilEm Debugger"); gtk_window_set_role(GTK_WINDOW(dbg->window), "Debugger"); tilem_config_get("debugger", "width/i", &defwidth, "height/i", &defheight, "mem_width/i", &dbg->mem_rowsize, "mem_start/i", &dbg->mem_start, "mem_logical/b=1", &dbg->mem_logical, NULL); if (dbg->mem_rowsize <= 0) dbg->mem_rowsize = 8; if (dbg->mem_start < 0 || dbg->mem_start >= dbg->mem_rowsize) dbg->mem_start = 0; if (defwidth <= 0 || defheight <= 0) { defwidth = 600; defheight = 400; } gtk_window_set_default_size(GTK_WINDOW(dbg->window), defwidth, defheight); g_signal_connect(dbg->window, "set-focus", G_CALLBACK(focus_changed), dbg); g_signal_connect(dbg->window, "delete-event", G_CALLBACK(delete_win), dbg); vbox2 = gtk_vbox_new(FALSE, 0); /* Actions and menu bar */ uimgr = gtk_ui_manager_new(); dbg->run_actions = gtk_action_group_new("Debug"); gtk_action_group_add_actions(dbg->run_actions, run_action_ents, G_N_ELEMENTS(run_action_ents), dbg); gtk_ui_manager_insert_action_group(uimgr, dbg->run_actions, 0); dbg->paused_actions = gtk_action_group_new("Debug"); gtk_action_group_add_actions(dbg->paused_actions, paused_action_ents, G_N_ELEMENTS(paused_action_ents), dbg); gtk_action_group_add_radio_actions(dbg->paused_actions, mem_mode_ents, G_N_ELEMENTS(mem_mode_ents), dbg->mem_logical, G_CALLBACK(action_mem_mode), dbg); gtk_ui_manager_insert_action_group(uimgr, dbg->paused_actions, 0); dbg->misc_actions = gtk_action_group_new("Debug"); gtk_action_group_add_actions(dbg->misc_actions, misc_action_ents, G_N_ELEMENTS(misc_action_ents), dbg); gtk_action_group_add_toggle_actions(dbg->misc_actions, misc_toggle_ents, G_N_ELEMENTS(misc_toggle_ents), dbg); gtk_ui_manager_insert_action_group(uimgr, dbg->misc_actions, 0); dbg->prev_stack_action = gtk_action_group_get_action(dbg->paused_actions, "prev-stack-entry"); accelgrp = gtk_ui_manager_get_accel_group(uimgr); gtk_window_add_accel_group(GTK_WINDOW(dbg->window), accelgrp); if (!gtk_ui_manager_add_ui_from_string(uimgr, uidesc, -1, &err)) g_error("Failed to create menus: %s", err->message); menubar = gtk_ui_manager_get_widget(uimgr, "/menu-bar"); gtk_box_pack_start(GTK_BOX(vbox2), menubar, FALSE, FALSE, 0); toolbar = gtk_ui_manager_get_widget(uimgr, "/toolbar"); gtk_box_pack_start(GTK_BOX(vbox2), toolbar, FALSE, FALSE, 0); g_object_unref(uimgr); hbox = gtk_hbox_new(FALSE, 6); vpaned = gtk_vpaned_new(); /* Disassembly view */ dbg->disasm_view = tilem_disasm_view_new(dbg); tilem_disasm_view_set_logical(TILEM_DISASM_VIEW(dbg->disasm_view), dbg->mem_logical); sw = new_scrolled_window(dbg->disasm_view); gtk_paned_pack1(GTK_PANED(vpaned), sw, TRUE, TRUE); /* Memory view */ dbg->mem_view = tilem_debugger_mem_view_new(dbg); sw = new_scrolled_window(dbg->mem_view); gtk_paned_pack2(GTK_PANED(vpaned), sw, TRUE, TRUE); gtk_box_pack_start(GTK_BOX(hbox), vpaned, TRUE, TRUE, 0); vbox = gtk_vbox_new(FALSE, 6); /* Registers */ dbg->regbox = create_registers(dbg); gtk_box_pack_start(GTK_BOX(vbox), dbg->regbox, FALSE, FALSE, 0); /* Stack view */ dbg->stack_view = create_stack_view(); sw = new_scrolled_window(dbg->stack_view); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0); gtk_widget_show_all(vbox2); gtk_container_add(GTK_CONTAINER(dbg->window), vbox2); tilem_debugger_calc_changed(dbg); return dbg; } /* Save the dimension for the debugger */ static void save_debugger_dimension(TilemDebugger *dbg) { gint width, height; if (!dbg->window) return; gtk_window_get_size(GTK_WINDOW(dbg->window), &width, &height); if (width <= 0 || height <= 0) return; tilem_config_set("debugger", "width/i", width, "height/i", height, NULL); } static void free_all_breakpoints(TilemDebugger *dbg) { GSList *l; TilemDebugBreakpoint *bp; for (l = dbg->breakpoints; l; l = l->next) { bp = l->data; g_slice_free(TilemDebugBreakpoint, bp); } g_slist_free(dbg->breakpoints); dbg->breakpoints = NULL; } /* Free a TilemDebugger. */ void tilem_debugger_free(TilemDebugger *dbg) { g_return_if_fail(dbg != NULL); save_debugger_dimension(dbg); if (dbg->emu && dbg->emu->dbg == dbg) dbg->emu->dbg = NULL; if (dbg->window) { gtk_widget_destroy(dbg->window); } if (dbg->dasm) tilem_disasm_free(dbg->dasm); if (dbg->run_actions) g_object_unref(dbg->run_actions); if (dbg->paused_actions) g_object_unref(dbg->paused_actions); if (dbg->misc_actions) g_object_unref(dbg->misc_actions); free_all_breakpoints(dbg); g_slice_free(TilemDebugger, dbg); } static void entry_printf(GtkWidget *ent, const char *s, ...) { char buf[20]; va_list ap; va_start(ap, s); g_vsnprintf(buf, sizeof(buf), s, ap); va_end(ap); gtk_entry_set_text(GTK_ENTRY(ent), buf); } static void refresh_regs(TilemDebugger *dbg) { TilemCalc *calc = dbg->emu->calc; int i; GtkToggleButton *btn; entry_printf(dbg->reg_entries[R_AF], "%04X", calc->z80.r.af.w.l); entry_printf(dbg->reg_entries[R_BC], "%04X", calc->z80.r.bc.w.l); entry_printf(dbg->reg_entries[R_DE], "%04X", calc->z80.r.de.w.l); entry_printf(dbg->reg_entries[R_HL], "%04X", calc->z80.r.hl.w.l); entry_printf(dbg->reg_entries[R_AF2], "%04X", calc->z80.r.af2.w.l); entry_printf(dbg->reg_entries[R_BC2], "%04X", calc->z80.r.bc2.w.l); entry_printf(dbg->reg_entries[R_DE2], "%04X", calc->z80.r.de2.w.l); entry_printf(dbg->reg_entries[R_HL2], "%04X", calc->z80.r.hl2.w.l); entry_printf(dbg->reg_entries[R_SP], "%04X", calc->z80.r.sp.w.l); entry_printf(dbg->reg_entries[R_PC], "%04X", calc->z80.r.pc.w.l); entry_printf(dbg->reg_entries[R_IX], "%04X", calc->z80.r.ix.w.l); entry_printf(dbg->reg_entries[R_IY], "%04X", calc->z80.r.iy.w.l); entry_printf(dbg->reg_entries[R_I], "%02X", calc->z80.r.ir.b.h); entry_printf(dbg->reg_entries[R_IM], "%d", calc->z80.r.im); for (i = 0; i < 8; i++) { btn = GTK_TOGGLE_BUTTON(dbg->flag_buttons[i]); gtk_toggle_button_set_active(btn, calc->z80.r.af.d & (1 << i)); } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dbg->iff_checkbox), calc->z80.r.iff1); } /* Create GtkListStore and attach it */ static GtkTreeModel* fill_stk_list(TilemDebugger *dbg) { GtkListStore *store; GtkTreeIter iter; char stack_offset[10]; char stack_value[10]; dword i, v; int n = 0; store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); i = dbg->emu->calc->z80.r.sp.w.l; while (i < 0x10000 && n < 512) { g_snprintf(stack_offset, sizeof(stack_offset), "%04X:", i); v = read_mem_word(dbg->emu->calc, i); g_snprintf(stack_value, sizeof(stack_value), "%04X", v); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, COL_OFFSET_STK, stack_offset, COL_VALUE_STK, stack_value, -1); i += 0x0002; n++; } return GTK_TREE_MODEL (store); } static void refresh_stack(TilemDebugger *dbg) { GtkTreeModel *model = fill_stk_list(dbg); gtk_tree_view_set_model(GTK_TREE_VIEW(dbg->stack_view), model); g_object_unref(model); fixed_tree_view_init(dbg->stack_view, 0, COL_OFFSET_STK, "DDDD: ", COL_VALUE_STK, "DDDD ", -1); } static void unselect_all(GtkTreeView *tv) { GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); gtk_tree_selection_unselect_all(sel); } static void refresh_all(TilemDebugger *dbg, gboolean updatemem) { TilemCalc *calc; gboolean paused; gboolean updatedasm = FALSE; GtkTreeModel *model; dbg->refreshing = TRUE; dbg->delayed_refresh = FALSE; tilem_calc_emulator_lock(dbg->emu); calc = dbg->emu->calc; paused = dbg->emu->paused; if (calc) { refresh_regs(dbg); if (dbg->lastwrite != calc->z80.lastwrite) updatemem = TRUE; if (updatemem || dbg->lastsp != calc->z80.r.sp.d) refresh_stack(dbg); if (paused && dbg->lastpc != calc->z80.r.pc.d) updatedasm = TRUE; dbg->lastwrite = calc->z80.lastwrite; dbg->lastsp = calc->z80.r.sp.d; dbg->lastpc = calc->z80.r.pc.d; } tilem_calc_emulator_unlock(dbg->emu); model = gtk_tree_view_get_model(GTK_TREE_VIEW(dbg->mem_view)); tilem_mem_model_clear_cache(TILEM_MEM_MODEL(model)); gtk_widget_queue_draw(dbg->mem_view); if (paused != dbg->paused) { dbg->paused = paused; gtk_widget_set_sensitive(dbg->regbox, paused); gtk_widget_set_sensitive(dbg->disasm_view, paused); gtk_widget_set_sensitive(dbg->mem_view, paused); gtk_widget_set_sensitive(dbg->stack_view, paused); gtk_action_group_set_sensitive(dbg->run_actions, !paused); gtk_action_group_set_sensitive(dbg->paused_actions, paused); updatedasm = TRUE; /* need to redraw icons */ } if (updatemem || updatedasm) tilem_disasm_view_refresh(TILEM_DISASM_VIEW(dbg->disasm_view)); if (!paused) { unselect_all(GTK_TREE_VIEW(dbg->disasm_view)); unselect_all(GTK_TREE_VIEW(dbg->mem_view)); unselect_all(GTK_TREE_VIEW(dbg->stack_view)); } if (dbg->keypad_dialog) tilem_keypad_dialog_refresh(dbg->keypad_dialog); dbg->refreshing = FALSE; } /* Show debugger, and pause emulator if not already paused. */ void tilem_debugger_show(TilemDebugger *dbg) { g_return_if_fail(dbg != NULL); g_return_if_fail(dbg->emu->calc != NULL); tilem_calc_emulator_pause(dbg->emu); cancel_step_bp(dbg); refresh_all(dbg, TRUE); go_to_stack_pos(dbg, -1); gtk_window_present(GTK_WINDOW(dbg->window)); } /* Hide debugger, and resume emulation if not already running. */ void tilem_debugger_hide(TilemDebugger *dbg) { g_return_if_fail(dbg != NULL); gtk_widget_hide(dbg->window); tilem_calc_emulator_run(dbg->emu); save_debugger_dimension(dbg); } /* New calculator loaded. */ void tilem_debugger_calc_changed(TilemDebugger *dbg) { TilemCalc *calc; g_return_if_fail(dbg != NULL); tilem_disasm_free(dbg->dasm); dbg->dasm = tilem_disasm_new(); dbg->step_bp = 0; free_all_breakpoints(dbg); calc = dbg->emu->calc; if (!calc) return; load_default_symbols(dbg); tilem_debugger_mem_view_configure(dbg->mem_view, dbg->emu, dbg->mem_rowsize, dbg->mem_start, dbg->mem_logical); tilem_debugger_refresh(dbg, TRUE); if (dbg->keypad_dialog) tilem_keypad_dialog_calc_changed(dbg->keypad_dialog); } /* Update display. */ void tilem_debugger_refresh(TilemDebugger *dbg, gboolean updatemem) { g_return_if_fail(dbg != NULL); if (!gtk_widget_get_visible(dbg->window)) return; refresh_all(dbg, updatemem); } /* Breakpoint manipulation */ /* Convert debugger type/mode into a core breakpoint type (core breakpoints have only a single access type, for efficiency, so a single TilemDebugBreakpoint may correspond to up to 3 core breakpoints) */ static int get_core_bp_type(int type, int mode) { switch (type) { case TILEM_DB_BREAK_LOGICAL: switch (mode) { case TILEM_DB_BREAK_READ: return TILEM_BREAK_MEM_READ; case TILEM_DB_BREAK_WRITE: return TILEM_BREAK_MEM_WRITE; case TILEM_DB_BREAK_EXEC: return TILEM_BREAK_MEM_EXEC; } break; case TILEM_DB_BREAK_PHYSICAL: switch (mode) { case TILEM_DB_BREAK_READ: return TILEM_BREAK_MEM_READ | TILEM_BREAK_PHYSICAL; case TILEM_DB_BREAK_WRITE: return TILEM_BREAK_MEM_WRITE | TILEM_BREAK_PHYSICAL; case TILEM_DB_BREAK_EXEC: return TILEM_BREAK_MEM_EXEC | TILEM_BREAK_PHYSICAL; } break; case TILEM_DB_BREAK_PORT: switch (mode) { case TILEM_DB_BREAK_READ: return TILEM_BREAK_PORT_READ; case TILEM_DB_BREAK_WRITE: return TILEM_BREAK_PORT_WRITE; } break; case TILEM_DB_BREAK_OPCODE: return TILEM_BREAK_EXECUTE; } g_return_val_if_reached(0); } /* Install core breakpoint(s) */ static void set_bp(TilemDebugger *dbg, TilemDebugBreakpoint *bp) { int i, t, n; tilem_calc_emulator_lock(dbg->emu); for (i = 0; i < 3; i++) { if (!bp->disabled && (bp->mode & (1 << i))) { t = get_core_bp_type(bp->type, (1 << i)); n = tilem_z80_add_breakpoint(dbg->emu->calc, t, bp->start, bp->end, bp->mask, NULL, NULL); bp->id[i] = n; } else { bp->id[i] = 0; } } tilem_calc_emulator_unlock(dbg->emu); } /* Remove core breakpoint(s) */ static void unset_bp(TilemDebugger *dbg, TilemDebugBreakpoint *bp) { int i; tilem_calc_emulator_lock(dbg->emu); for (i = 0; i < 3; i++) { if (bp->id[i]) tilem_z80_remove_breakpoint(dbg->emu->calc, bp->id[i]); bp->id[i] = 0; } tilem_calc_emulator_unlock(dbg->emu); } static gboolean is_mem_exec_bp(const TilemDebugBreakpoint *bp) { return ((bp->type == TILEM_DB_BREAK_LOGICAL || bp->type == TILEM_DB_BREAK_PHYSICAL) && (bp->mode & TILEM_DB_BREAK_EXEC)); } /* Add a new debugger breakpoint */ TilemDebugBreakpoint * tilem_debugger_add_breakpoint(TilemDebugger *dbg, const TilemDebugBreakpoint *bp) { TilemDebugBreakpoint *bp2; g_return_val_if_fail(dbg != NULL, NULL); g_return_val_if_fail(bp != NULL, NULL); g_return_val_if_fail(bp->mode != 0, NULL); bp2 = g_slice_new(TilemDebugBreakpoint); *bp2 = *bp; dbg->breakpoints = g_slist_append(dbg->breakpoints, bp2); set_bp(dbg, bp2); if (is_mem_exec_bp(bp) && dbg->disasm_view) tilem_disasm_view_refresh(TILEM_DISASM_VIEW(dbg->disasm_view)); return bp2; } /* Remove a debugger breakpoint */ void tilem_debugger_remove_breakpoint(TilemDebugger *dbg, TilemDebugBreakpoint *bp) { gboolean isexec; g_return_if_fail(dbg != NULL); g_return_if_fail(bp != NULL); g_return_if_fail(g_slist_index(dbg->breakpoints, bp) != -1); isexec = is_mem_exec_bp(bp); unset_bp(dbg, bp); dbg->breakpoints = g_slist_remove(dbg->breakpoints, bp); g_slice_free(TilemDebugBreakpoint, bp); if (isexec && dbg->disasm_view) tilem_disasm_view_refresh(TILEM_DISASM_VIEW(dbg->disasm_view)); } /* Modify a debugger breakpoint */ void tilem_debugger_change_breakpoint(TilemDebugger *dbg, TilemDebugBreakpoint *bp, const TilemDebugBreakpoint *newbp) { gboolean isexec; g_return_if_fail(dbg != NULL); g_return_if_fail(bp != NULL); g_return_if_fail(newbp != NULL); g_return_if_fail(g_slist_index(dbg->breakpoints, bp) != -1); isexec = (is_mem_exec_bp(bp) || is_mem_exec_bp(newbp)); unset_bp(dbg, bp); *bp = *newbp; set_bp(dbg, bp); if (isexec && dbg->disasm_view) tilem_disasm_view_refresh(TILEM_DISASM_VIEW(dbg->disasm_view)); } tilem-2.0/gui/debugger.h000066400000000000000000000106741220200411600152020ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ typedef struct _TilemDebugBreakpoint { enum { TILEM_DB_BREAK_LOGICAL, TILEM_DB_BREAK_PHYSICAL, TILEM_DB_BREAK_PORT, TILEM_DB_BREAK_OPCODE } type; enum { TILEM_DB_BREAK_READ = 4, TILEM_DB_BREAK_WRITE = 2, TILEM_DB_BREAK_EXEC = 1 } mode; dword start; dword end; dword mask; int disabled; int id[3]; } TilemDebugBreakpoint; typedef struct _TilemDebugger { struct _TilemCalcEmulator *emu; struct _TilemDisasm *dasm; /* Debugger widgets */ GtkWidget *window; /* Main debugger window */ GtkWidget *disasm_view; /* Disassembly view */ GtkWidget *mem_view; /* Memory view */ GtkWidget *stack_view; /* Stack view */ GtkWidget *regbox; /* Box containing registers */ GtkWidget *reg_entries[14]; /* Entries for registers */ GtkWidget *iff_checkbox; /* Checkbox for IFF */ GtkWidget *flag_buttons[8]; /* Buttons for flags */ /* Action groups */ GtkActionGroup *run_actions; GtkActionGroup *paused_actions; GtkActionGroup *misc_actions; /* Memory settings */ int mem_rowsize; int mem_start; gboolean mem_logical; /* Stack navigation */ GtkAction *prev_stack_action; int stack_index; /* Breakpoints */ GSList *breakpoints; int last_bp_type; int last_bp_mode; /* Temporary breakpoint info */ int step_bp; /* Breakpoint ID */ dword step_next_addr; /* Target address */ dword lastwrite; dword lastsp; dword lastpc; gboolean paused; gboolean refreshing; gboolean delayed_refresh; /* Other windows */ struct _TilemKeypadDialog *keypad_dialog; } TilemDebugger; /* Create a new TilemDebugger. */ TilemDebugger *tilem_debugger_new(TilemCalcEmulator *emu); /* Free a TilemDebugger. */ void tilem_debugger_free(TilemDebugger *dbg); /* Show debugger, and pause emulator if not already paused. */ void tilem_debugger_show(TilemDebugger *dbg); /* Hide debugger, and resume emulation if not already running. */ void tilem_debugger_hide(TilemDebugger *dbg); /* New calculator loaded. */ void tilem_debugger_calc_changed(TilemDebugger *dbg); /* Update display. */ void tilem_debugger_refresh(TilemDebugger *dbg, gboolean updatemem); /* Add a new breakpoint. */ TilemDebugBreakpoint * tilem_debugger_add_breakpoint(TilemDebugger *dbg, const TilemDebugBreakpoint *bp); /* Remove an existing breakpoint. */ void tilem_debugger_remove_breakpoint(TilemDebugger *dbg, TilemDebugBreakpoint *bp); /* Modify an existing breakpoint. */ void tilem_debugger_change_breakpoint(TilemDebugger *dbg, TilemDebugBreakpoint *bp, const TilemDebugBreakpoint *newbp); /* Show a dialog letting the user add, remove, and edit breakpoints. */ void tilem_debugger_edit_breakpoints(TilemDebugger *dbg); /* Memory view */ /* Create the memory view */ GtkWidget *tilem_debugger_mem_view_new(TilemDebugger *dbg); /* Set memory view settings */ void tilem_debugger_mem_view_configure(GtkWidget *mem_view, TilemCalcEmulator *emu, int rowsize, int start, gboolean logical); /* Keypad dialog */ typedef struct _TilemKeypadDialog { TilemDebugger *dbg; gboolean refreshing; GtkWidget *window; GtkWidget *output[7]; GtkWidget *keys[7][8]; GtkWidget *input[8]; } TilemKeypadDialog; /* Create a new TilemKeypadDialog. */ TilemKeypadDialog *tilem_keypad_dialog_new(TilemDebugger *dbg); /* Free a TilemKeypadDialog. */ void tilem_keypad_dialog_free(TilemKeypadDialog *kpdlg); /* New calculator loaded. */ void tilem_keypad_dialog_calc_changed(TilemKeypadDialog *kpdlg); /* Refresh key states. */ void tilem_keypad_dialog_refresh(TilemKeypadDialog *kpdlg); tilem-2.0/gui/disasmview.c000066400000000000000000000723551220200411600155700ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "gui.h" #include "disasmview.h" G_DEFINE_TYPE(TilemDisasmView, tilem_disasm_view, GTK_TYPE_TREE_VIEW); /* This is a HORRIBLE kludge. Don't ever do anything like this. ;) We want a widget that has the look and feel of a GtkTreeView. But our "data model" isn't consistent with a GtkTreeModel, since it changes depending on where we are. This widget keeps track of how high each row will be once rendered, and uses that to construct a GtkListStore with the appropriate number of rows to fill the window. We also override the move-cursor signal so that we can handle the boundaries. */ /* Model columns */ enum { COL_POSITION, COL_ADDRESS, COL_MNEMONIC, COL_ARGUMENTS, COL_SHOW_MNEMONIC, COL_ICON, NUM_COLUMNS }; static GtkTreeViewClass *parent_class; /* We define two "positions" for each actual address; the second is used if there's a label to be displayed at that address. */ #define POS_TO_ADDR(x) ((x) >> 1) #define ADDR_TO_POS(x) ((x) << 1) /* Disassembly */ /* Convert physical to logical address; if address is not currently mapped, use the bank-A address */ static dword default_ptol(TilemCalc *calc, dword addr) { dword addr_l; g_return_val_if_fail(calc != NULL, 0); addr_l = (*calc->hw.mem_ptol)(calc, addr); if (addr_l == 0xffffffff) addr_l = (addr & 0x3fff) | 0x4000; return addr_l; } /* Check for a label at the given address (physical or logical depending on the mode of the DisasmView) */ static const char *get_label(TilemDisasmView *dv, TilemCalc *calc, dword addr) { g_return_val_if_fail(calc != NULL, NULL); g_return_val_if_fail(dv->dbg->dasm != NULL, NULL); if (!dv->use_logical) addr = default_ptol(calc, addr); return tilem_disasm_get_label_at_address(dv->dbg->dasm, addr); } /* Disassemble a line */ static void disassemble(TilemDisasmView *dv, TilemCalc *calc, dword pos, dword *nextpos, char **mnemonic, char **args) { dword addr = POS_TO_ADDR(pos); const char *lbl; char buf[500], *p; g_return_if_fail(calc != NULL); g_return_if_fail(dv->dbg->dasm != NULL); if (!(pos & 1) && (lbl = get_label(dv, calc, addr))) { if (mnemonic) { *mnemonic = NULL; *args = g_strdup_printf("%s:", lbl); } if (nextpos) *nextpos = pos + 1; } else if (mnemonic) { tilem_disasm_disassemble(dv->dbg->dasm, calc, !dv->use_logical, addr, &addr, buf, sizeof(buf)); p = strchr(buf, '\t'); if (p) { *mnemonic = g_strndup(buf, p - buf); *args = g_strdup(p + 1); } else { *mnemonic = g_strdup(buf); *args = NULL; } if (nextpos) *nextpos = ADDR_TO_POS(addr); } else { tilem_disasm_disassemble(dv->dbg->dasm, calc, !dv->use_logical, addr, &addr, NULL, 0); if (nextpos) *nextpos = ADDR_TO_POS(addr); } } /* Get "next" position */ static dword get_next_pos(TilemDisasmView *dv, TilemCalc *calc, dword pos) { disassemble(dv, calc, pos, &pos, NULL, NULL); return pos; } /* Get "previous" position */ static dword get_prev_pos(TilemDisasmView *dv, TilemCalc *calc, dword pos) { dword addr = POS_TO_ADDR(pos); g_return_val_if_fail(calc != NULL, 0); if (pos & 1) { return pos - 1; } else { if (addr > 0) addr--; else if (dv->use_logical) addr = 0xffff; else addr = (calc->hw.romsize + calc->hw.ramsize - 1); if (get_label(dv, calc, addr)) return ADDR_TO_POS(addr) + 1; else return ADDR_TO_POS(addr); } } /* Convert physical to logical position */ static dword pos_ptol(TilemCalc *calc, dword pos) { dword addr; g_return_val_if_fail(calc != NULL, 0); if (pos == (dword) -1) return pos; addr = default_ptol(calc, POS_TO_ADDR(pos)); return ADDR_TO_POS(addr) + (pos & 1); } /* Convert logical to physical position */ static dword pos_ltop(TilemCalc *calc, dword pos) { dword addr; g_return_val_if_fail(calc != NULL, 0); if (pos == (dword) -1) return pos; addr = (*calc->hw.mem_ltop)(calc, POS_TO_ADDR(pos)); return ADDR_TO_POS(addr) + (pos & 1); } /* Icons */ static GdkPixbuf *get_icon(TilemDisasmView *dv, gboolean ispc, gboolean isbp) { const char *name; if (ispc && isbp) name = "tilem-disasm-break-pc"; else if (isbp) name = "tilem-disasm-break"; else if (ispc) name = "tilem-disasm-pc"; else return NULL; return gtk_widget_render_icon(GTK_WIDGET(dv), name, GTK_ICON_SIZE_MENU, NULL); } /* List model management */ /* Create a new list store for disassembly */ static GtkTreeModel * new_dasm_model() { GtkListStore *store; g_assert(NUM_COLUMNS == 6); store = gtk_list_store_new(6, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF); return GTK_TREE_MODEL(store); } /* Append dummy data to the model; used for sizing */ static void append_dummy_line(TilemDisasmView *dv, GtkTreeModel *model, GtkTreeIter *iter) { GtkTreeIter iter1; GdkPixbuf *icon; gtk_list_store_append(GTK_LIST_STORE(model), &iter1); icon = get_icon(dv, TRUE, FALSE); gtk_list_store_set(GTK_LIST_STORE(model), &iter1, COL_ICON, icon, COL_ADDRESS, "DD:DDDD", COL_MNEMONIC, "ROM_CALL", COL_ARGUMENTS, "_fnord", COL_SHOW_MNEMONIC, TRUE, -1); if (icon) g_object_unref(icon); if (iter) *iter = iter1; } /* Check if given logical address is a breakpoint (according to current mapping) */ static TilemDebugBreakpoint *find_bp_logical(TilemDebugger *dbg, TilemCalc *calc, dword addr) { GSList *l; TilemDebugBreakpoint *bp; dword pa = (*calc->hw.mem_ltop)(calc, addr); for (l = dbg->breakpoints; l; l = l->next) { bp = l->data; if (!(bp->mode & TILEM_DB_BREAK_EXEC)) continue; if (bp->type == TILEM_DB_BREAK_LOGICAL && bp->start <= addr && bp->end >= addr && !bp->disabled) return bp; if (bp->type == TILEM_DB_BREAK_PHYSICAL && bp->start <= pa && bp->end >= pa && !bp->disabled) return bp; } return NULL; } /* Check if given physical address is a breakpoint (according to current mapping) */ static TilemDebugBreakpoint *find_bp_physical(TilemDebugger *dbg, TilemCalc *calc, dword addr) { GSList *l; TilemDebugBreakpoint *bp; dword la, pa; int i, mapped[4]; /* NOTE: this assumes that bits 0-13 are unaffected by the mapping! This is true for all current models, but might need to be changed in the future */ for (i = 0; i < 4; i++) { la = (i << 14) + (addr & 0x3fff); pa = (*calc->hw.mem_ltop)(calc, la); mapped[i] = (addr == pa); } for (l = dbg->breakpoints; l; l = l->next) { bp = l->data; if (!(bp->mode & TILEM_DB_BREAK_EXEC)) continue; if (bp->type == TILEM_DB_BREAK_PHYSICAL && bp->start <= addr && bp->end >= addr && !bp->disabled) return bp; if (bp->type == TILEM_DB_BREAK_LOGICAL && !bp->disabled) { for (i = 0; i < 4; i++) { la = (i << 14) + (addr & 0x3fff); if (bp->start <= la && bp->end >= la && mapped[i]) return bp; } } } return NULL; } /* Check if line has a breakpoint set */ static TilemDebugBreakpoint *find_line_bp(TilemDisasmView *dv, dword pos) { TilemDebugBreakpoint *bp; dword addr = POS_TO_ADDR(pos); TilemCalc *calc; tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; if (dv->use_logical) bp = find_bp_logical(dv->dbg, calc, addr); else bp = find_bp_physical(dv->dbg, calc, addr); tilem_calc_emulator_unlock(dv->dbg->emu); return bp; } /* Enable breakpoint on the given line */ static void enable_line_bp(TilemDisasmView *dv, dword pos) { TilemDebugBreakpoint *bp, tmpbp; if ((bp = find_line_bp(dv, pos))) return; tmpbp.type = (dv->use_logical ? TILEM_DB_BREAK_LOGICAL : TILEM_DB_BREAK_PHYSICAL); tmpbp.mode = TILEM_DB_BREAK_EXEC; tmpbp.start = POS_TO_ADDR(pos); tmpbp.end = POS_TO_ADDR(pos); tmpbp.mask = (dv->use_logical ? 0xffff : 0xffffffff); tmpbp.disabled = 0; tilem_debugger_add_breakpoint(dv->dbg, &tmpbp); } /* Disable breakpoint on the given line */ static void disable_line_bp(TilemDisasmView *dv, dword pos) { TilemDebugBreakpoint *bp, tmpbp; if (!(bp = find_line_bp(dv, pos))) return; if (bp->mode != TILEM_DB_BREAK_EXEC || bp->start != bp->end) { /* special breakpoint; do not delete it, just disable it */ tmpbp = *bp; tmpbp.disabled = 1; tilem_debugger_change_breakpoint(dv->dbg, bp, &tmpbp); } else { /* regular breakpoint */ tilem_debugger_remove_breakpoint(dv->dbg, bp); } } /* Append a line to the dasm model */ static void append_dasm_line(TilemDisasmView *dv, TilemCalc *calc, GtkTreeModel *model, GtkTreeIter *iter, dword pos, dword *nextpos) { GtkTreeIter iter1; char *astr, *mnem, *args; dword addr, pc; gboolean ispc; TilemDebugBreakpoint *bp; GdkPixbuf *icon; g_return_if_fail(calc != NULL); gtk_list_store_append(GTK_LIST_STORE(model), &iter1); addr = POS_TO_ADDR(pos); astr = tilem_format_addr(dv->dbg, addr, !dv->use_logical); disassemble(dv, calc, pos, nextpos, &mnem, &args); if (!mnem) bp = NULL; else if (dv->use_logical) bp = find_bp_logical(dv->dbg, calc, addr); else bp = find_bp_physical(dv->dbg, calc, addr); if (!mnem || !dv->dbg->emu->paused) { ispc = FALSE; } else { pc = calc->z80.r.pc.w.l; if (!dv->use_logical) pc = (*calc->hw.mem_ltop)(calc, pc); ispc = (addr == pc); } icon = get_icon(dv, ispc, (bp != NULL)); gtk_list_store_set(GTK_LIST_STORE(model), &iter1, COL_POSITION, (int) pos, COL_ADDRESS, astr, COL_MNEMONIC, mnem, COL_SHOW_MNEMONIC, (mnem ? TRUE : FALSE), COL_ARGUMENTS, args, COL_ICON, icon, -1); if (icon) g_object_unref(icon); g_free(astr); g_free(mnem); g_free(args); if (iter) *iter = iter1; } /* Refresh the view by creating and populating a new model */ static void refresh_disassembly(TilemDisasmView *dv, dword pos, int nlines, dword selectpos) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *selectpath = NULL; TilemCalc *calc; dword nextpos; int i; model = new_dasm_model(); dv->startpos = pos; tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; if (!calc) nlines = 0; for (i = 0; i < nlines; i++) { append_dasm_line(dv, calc, model, &iter, pos, &nextpos); if (pos == selectpos) selectpath = gtk_tree_model_get_path(model, &iter); pos = nextpos; } tilem_calc_emulator_unlock(dv->dbg->emu); dv->endpos = pos; dv->nlines = nlines; gtk_tree_view_set_model(GTK_TREE_VIEW(dv), model); g_object_unref(model); if (selectpath) { gtk_tree_view_set_cursor(GTK_TREE_VIEW(dv), selectpath, NULL, FALSE); gtk_tree_path_free(selectpath); } } /* Determine the (absolute) position and (display-relative) line number of the cursor, if any */ static gboolean get_cursor_line(TilemDisasmView *dv, dword *pos, int *linenum) { GtkTreePath *path; GtkTreeModel *model; GtkTreeIter iter; gint *i, p; gtk_tree_view_get_cursor(GTK_TREE_VIEW(dv), &path, NULL); if (!path) { if (pos) *pos = (dword) -1; if (linenum) *linenum = -1; return FALSE; } if (pos) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(dv)); if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get(model, &iter, COL_POSITION, &p, -1); *pos = p; } else { *pos = (dword) -1; } } if (linenum) { i = gtk_tree_path_get_indices(path); *linenum = i[0]; } gtk_tree_path_free(path); return TRUE; } /* Size allocation */ /* Get the desired height for the tree view (based on size of the data we've inserted into the model) */ static int get_parent_request_height(GtkWidget *w) { GtkRequisition req; (*GTK_WIDGET_CLASS(parent_class)->size_request)(w, &req); return req.height; } /* Widget is assigned a size and position */ static void tilem_disasm_view_size_allocate(GtkWidget *w, GtkAllocation *alloc) { TilemDisasmView *dv; GtkTreeModel *model; dword curpos; int n, height1, height2; g_return_if_fail(TILEM_IS_DISASM_VIEW(w)); dv = TILEM_DISASM_VIEW(w); (*GTK_WIDGET_CLASS(parent_class)->size_allocate)(w, alloc); if (alloc->height < 1) return; get_cursor_line(dv, &curpos, NULL); /* Calculate line height */ if (!dv->line_height) { model = new_dasm_model(); append_dummy_line(dv, model, NULL); gtk_tree_view_set_model(GTK_TREE_VIEW(dv), model); height1 = get_parent_request_height(w); append_dummy_line(dv, model, NULL); height2 = get_parent_request_height(w); dv->line_height = height2 - height1; dv->base_height = height1 - dv->line_height; g_object_unref(model); dv->nlines = 0; if (dv->line_height <= 0) { dv->line_height = 0; return; } } n = (alloc->height - dv->base_height) / dv->line_height; if (n < 1) n = 1; if (n != dv->nlines) refresh_disassembly(dv, dv->startpos, n, curpos); } /* Get widget's desired size */ static void tilem_disasm_view_size_request(GtkWidget *w, GtkRequisition *req) { (*GTK_WIDGET_CLASS(parent_class)->size_request)(w, req); req->height = 100; /* ignore requested height */ } /* Widget style set */ static void tilem_disasm_view_style_set(GtkWidget *w, GtkStyle *oldstyle) { TilemDisasmView *dv; GtkTreeModel *model; GtkTreeIter iter; GList *cols, *cp; GtkTreeViewColumn *col; int width; g_return_if_fail(TILEM_IS_DISASM_VIEW(w)); dv = TILEM_DISASM_VIEW(w); (*GTK_WIDGET_CLASS(parent_class)->style_set)(w, oldstyle); /* line height must be recalculated */ dv->line_height = 0; /* set column widths based on a dummy model */ model = new_dasm_model(); append_dummy_line(dv, model, &iter); cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(dv)); for (cp = cols; cp; cp = cp->next) { col = cp->data; gtk_tree_view_column_cell_set_cell_data(col, model, &iter, FALSE, FALSE); gtk_tree_view_column_cell_get_size(col, NULL, NULL, NULL, &width, NULL); gtk_tree_view_column_set_fixed_width(col, width + 2); } g_list_free(cols); g_object_unref(model); } /* Cursor movement commands */ /* Move up by COUNT lines */ static gboolean move_up_lines(TilemDisasmView *dv, int count) { TilemCalc *calc; dword pos; int linenum; if (!get_cursor_line(dv, NULL, &linenum)) linenum = 0; if (linenum >= count) return FALSE; tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; pos = dv->startpos; count -= linenum; while (count > 0) { pos = get_prev_pos(dv, calc, pos); count--; } tilem_calc_emulator_unlock(dv->dbg->emu); refresh_disassembly(dv, pos, dv->nlines, pos); return TRUE; } /* Move down by COUNT lines */ static gboolean move_down_lines(TilemDisasmView *dv, int count) { TilemCalc *calc; dword startpos, selpos; int linenum; if (!get_cursor_line(dv, NULL, &linenum)) linenum = -1; if (linenum + count < dv->nlines) return FALSE; tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; startpos = get_next_pos(dv, calc, dv->startpos); selpos = dv->endpos; count -= dv->nlines - linenum; while (count > 0) { startpos = get_next_pos(dv, calc, startpos); selpos = get_next_pos(dv, calc, selpos); count--; } tilem_calc_emulator_unlock(dv->dbg->emu); refresh_disassembly(dv, startpos, dv->nlines, selpos); return TRUE; } /* Move down by COUNT bytes */ static void move_bytes(TilemDisasmView *dv, int count) { dword pos, addr; const TilemCalc *calc = dv->dbg->emu->calc; g_return_if_fail(calc != NULL); if (!get_cursor_line(dv, &pos, NULL)) pos = dv->startpos; addr = POS_TO_ADDR(pos); if (dv->use_logical) addr = (addr + count) & 0xffff; else { addr += calc->hw.romsize + calc->hw.ramsize + count; addr %= calc->hw.romsize + calc->hw.ramsize; } pos = ADDR_TO_POS(addr); refresh_disassembly(dv, pos, dv->nlines, pos - 1); } /* Move the cursor (action signal) */ static gboolean tilem_disasm_view_move_cursor(GtkTreeView *tv, GtkMovementStep step, gint count) { TilemDisasmView *dv; g_return_val_if_fail(TILEM_IS_DISASM_VIEW(tv), FALSE); dv = TILEM_DISASM_VIEW(tv); if (!dv->dbg->emu->calc) return FALSE; switch (step) { case GTK_MOVEMENT_DISPLAY_LINES: if (count < 0) { if (move_up_lines(dv, -count)) return TRUE; } else { if (move_down_lines(dv, count)) return TRUE; } break; case GTK_MOVEMENT_PARAGRAPHS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_PAGES: /* FIXME: might be better to move by actual "pages" of code */ move_bytes(dv, count * 0x100); return TRUE; case GTK_MOVEMENT_BUFFER_ENDS: move_bytes(dv, count * 0x4000); return TRUE; case GTK_MOVEMENT_LOGICAL_POSITIONS: case GTK_MOVEMENT_VISUAL_POSITIONS: case GTK_MOVEMENT_WORDS: case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_HORIZONTAL_PAGES: default: break; } return (*GTK_TREE_VIEW_CLASS(parent_class)->move_cursor)(tv, step, count); } /* Popup menu */ static void toggle_bp(G_GNUC_UNUSED GtkCheckMenuItem *item, gpointer data) { TilemDisasmView *dv = data; tilem_disasm_view_toggle_breakpoint(dv); } void tilem_disasm_view_toggle_breakpoint(TilemDisasmView *dv) { dword curpos; g_return_if_fail(TILEM_IS_DISASM_VIEW(dv)); get_cursor_line(dv, &curpos, NULL); if (curpos == (dword) -1) return; if (find_line_bp(dv, curpos)) disable_line_bp(dv, curpos); else enable_line_bp(dv, curpos); } static void prompt_go_to(G_GNUC_UNUSED GtkMenuItem *item, gpointer data) { TilemDisasmView *dv = data; GtkWidget *window; dword curpos, addr; window = gtk_widget_get_toplevel(GTK_WIDGET(dv)); get_cursor_line(dv, &curpos, NULL); addr = POS_TO_ADDR(curpos); if (tilem_prompt_address(dv->dbg, GTK_WINDOW(window), "Go to Address", "Address:", &addr, !dv->use_logical, (curpos != (dword) -1))) tilem_disasm_view_go_to_address(dv, addr, dv->use_logical); } static void go_to_pc(G_GNUC_UNUSED GtkMenuItem *item, gpointer data) { TilemDisasmView *dv = data; TilemCalc *calc; dword pc; g_return_if_fail(dv->dbg != NULL); g_return_if_fail(dv->dbg->emu != NULL); g_return_if_fail(dv->dbg->emu->calc != NULL); tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; pc = calc->z80.r.pc.w.l; tilem_calc_emulator_unlock(dv->dbg->emu); tilem_disasm_view_go_to_address(dv, pc, TRUE); } /* Determine where to pop up menu (if not activated by a mouse event) */ static void place_menu(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) { TilemDisasmView *dv = data; GtkTreePath *path; GdkRectangle rect; GdkWindow *win; GdkScreen *screen; int n; win = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(dv)); gdk_window_get_origin(win, x, y); gtk_tree_view_get_cursor(GTK_TREE_VIEW(dv), &path, NULL); if (path) { gtk_tree_view_get_cell_area(GTK_TREE_VIEW(dv), path, NULL, &rect); gtk_tree_path_free(path); *y += rect.y + rect.height; } screen = gdk_drawable_get_screen(win); n = gdk_screen_get_monitor_at_point(screen, *x, *y); gtk_menu_set_monitor(menu, n); *push_in = FALSE; } /* Create and show the popup menu */ static void show_popup_menu(TilemDisasmView *dv, GdkEventButton *event) { GtkWidget *menu, *item; dword curpos; if (dv->popup_menu) gtk_widget_destroy(dv->popup_menu); dv->popup_menu = menu = gtk_menu_new(); /* Enable/disable breakpoint */ item = gtk_check_menu_item_new_with_mnemonic("_Breakpoint Here"); get_cursor_line(dv, &curpos, NULL); if (curpos == (dword) -1) gtk_widget_set_sensitive(item, FALSE); else if (find_line_bp(dv, curpos)) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); g_signal_connect(item, "toggled", G_CALLBACK(toggle_bp), dv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); /* Jump to address */ item = gtk_menu_item_new_with_mnemonic("_Go to Address..."); g_signal_connect(item, "activate", G_CALLBACK(prompt_go_to), dv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); item = gtk_menu_item_new_with_mnemonic("Go to P_C"); g_signal_connect(item, "activate", G_CALLBACK(go_to_pc), dv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); if (event) gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); else gtk_menu_popup(GTK_MENU(menu), NULL, NULL, &place_menu, dv, 0, gtk_get_current_event_time()); } /* Button pressed */ static gboolean tilem_disasm_view_button_press(GtkWidget *w, GdkEventButton *event) { g_return_val_if_fail(TILEM_IS_DISASM_VIEW(w), FALSE); (*GTK_WIDGET_CLASS(parent_class)->button_press_event)(w, event); if (event->button == 3) show_popup_menu(TILEM_DISASM_VIEW(w), event); return TRUE; } /* Key pressed to activate context menu */ static gboolean tilem_disasm_view_popup_menu(GtkWidget *w) { g_return_val_if_fail(TILEM_IS_DISASM_VIEW(w), FALSE); show_popup_menu(TILEM_DISASM_VIEW(w), NULL); return TRUE; } /* Row activated (double-clicked) */ static void tilem_disasm_view_row_activated(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col) { TilemDisasmView *dv = TILEM_DISASM_VIEW(tv); GtkTreeModel *model; GtkTreeIter iter; gint pos; model = gtk_tree_view_get_model(tv); if (!gtk_tree_model_get_iter(model, &iter, path)) return; gtk_tree_model_get(model, &iter, COL_POSITION, &pos, -1); if (col == dv->icon_column) { if (find_line_bp(dv, pos)) disable_line_bp(dv, pos); else enable_line_bp(dv, pos); } } /* Unrealize widget */ static void tilem_disasm_view_unrealize(GtkWidget *w) { TilemDisasmView *dv = TILEM_DISASM_VIEW(w); if (dv->popup_menu) gtk_widget_destroy(dv->popup_menu); dv->popup_menu = NULL; (*GTK_WIDGET_CLASS(parent_class)->unrealize)(w); } /* Initialize a new TilemDisasmView */ static void tilem_disasm_view_init(TilemDisasmView *dv) { GtkTreeView *tv = GTK_TREE_VIEW(dv); GtkCellRenderer *cell; GtkTreeViewColumn *col; dv->use_logical = TRUE; gtk_tree_view_set_enable_search(tv, FALSE); gtk_tree_view_set_fixed_height_mode(tv, TRUE); gtk_tree_view_set_headers_visible(tv, FALSE); cell = gtk_cell_renderer_pixbuf_new(); col = gtk_tree_view_column_new_with_attributes(NULL, cell, "pixbuf", COL_ICON, NULL); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(tv, col); dv->icon_column = col; cell = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes("Addr", cell, "text", COL_ADDRESS, NULL); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_append_column(tv, col); col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Disassembly"); cell = gtk_cell_renderer_text_new(); g_object_set(cell, "xpad", 10, NULL); gtk_tree_view_column_pack_start(col, cell, FALSE); gtk_tree_view_column_set_attributes(col, cell, "text", COL_MNEMONIC, "visible", COL_SHOW_MNEMONIC, NULL); cell = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(col, cell, TRUE); gtk_tree_view_column_set_attributes(col, cell, "text", COL_ARGUMENTS, NULL); gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_expand(col, TRUE); gtk_tree_view_append_column(tv, col); } static const char default_style[] = "style \"tilem-disasm-default\" { font_name = \"Monospace\" } " "widget \"*.TilemDisasmView\" style:application \"tilem-disasm-default\""; /* Initialize the TilemDisasmView class */ static void tilem_disasm_view_class_init(TilemDisasmViewClass *klass) { GtkTreeViewClass *tv_class = GTK_TREE_VIEW_CLASS(klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); gtk_rc_parse_string(default_style); parent_class = g_type_class_peek_parent(klass); widget_class->style_set = &tilem_disasm_view_style_set; widget_class->size_request = &tilem_disasm_view_size_request; widget_class->size_allocate = &tilem_disasm_view_size_allocate; widget_class->button_press_event = &tilem_disasm_view_button_press; widget_class->popup_menu = &tilem_disasm_view_popup_menu; widget_class->unrealize = &tilem_disasm_view_unrealize; tv_class->move_cursor = &tilem_disasm_view_move_cursor; tv_class->row_activated = &tilem_disasm_view_row_activated; } GtkWidget * tilem_disasm_view_new(TilemDebugger *dbg) { TilemDisasmView *dv; g_return_val_if_fail(dbg != NULL, NULL); dv = g_object_new(TILEM_TYPE_DISASM_VIEW, NULL); dv->dbg = dbg; return GTK_WIDGET(dv); } /* Select memory addressing mode. */ void tilem_disasm_view_set_logical(TilemDisasmView *dv, gboolean logical) { dword start, curpos; TilemCalc *calc; g_return_if_fail(TILEM_IS_DISASM_VIEW(dv)); g_return_if_fail(dv->dbg->emu->calc != NULL); get_cursor_line(dv, &curpos, NULL); if (logical && !dv->use_logical) { tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; curpos = pos_ptol(calc, curpos); start = pos_ptol(calc, dv->startpos); tilem_calc_emulator_unlock(dv->dbg->emu); dv->use_logical = TRUE; refresh_disassembly(dv, start, dv->nlines, curpos); } else if (!logical && dv->use_logical) { tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; curpos = pos_ltop(calc, curpos); start = pos_ltop(calc, dv->startpos); tilem_calc_emulator_unlock(dv->dbg->emu); dv->use_logical = FALSE; refresh_disassembly(dv, start, dv->nlines, curpos); } } /* Refresh contents of view. */ void tilem_disasm_view_refresh(TilemDisasmView *dv) { dword curpos; g_return_if_fail(TILEM_IS_DISASM_VIEW(dv)); get_cursor_line(dv, &curpos, NULL); refresh_disassembly(dv, dv->startpos, dv->nlines, curpos); } /* Find tree path for the given position */ static GtkTreePath *find_path_for_position(GtkTreeModel *model, int pos) { gint p; GtkTreeIter iter; if (!gtk_tree_model_get_iter_first(model, &iter)) return NULL; do { gtk_tree_model_get(model, &iter, COL_POSITION, &p, -1); if (p == pos) { return gtk_tree_model_get_path(model, &iter); } } while (gtk_tree_model_iter_next(model, &iter)); return NULL; } /* Highlight the specified address. */ void tilem_disasm_view_go_to_address(TilemDisasmView *dv, dword addr, gboolean logical) { dword pos; GtkTreeModel *model; GtkTreePath *path; TilemCalc *calc; g_return_if_fail(TILEM_IS_DISASM_VIEW(dv)); tilem_calc_emulator_lock(dv->dbg->emu); calc = dv->dbg->emu->calc; if (logical) { addr &= 0xffff; if (dv->use_logical) pos = ADDR_TO_POS(addr); else pos = pos_ltop(calc, ADDR_TO_POS(addr)); } else { if (dv->use_logical) { addr = (*calc->hw.mem_ptol)(calc, addr); if (addr == (dword) -1) { tilem_calc_emulator_unlock(dv->dbg->emu); return; } } pos = ADDR_TO_POS(addr); } tilem_calc_emulator_unlock(dv->dbg->emu); if (pos >= dv->startpos && pos < dv->endpos) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(dv)); path = find_path_for_position(model, pos); if (path) { gtk_tree_view_set_cursor(GTK_TREE_VIEW(dv), path, NULL, FALSE); gtk_tree_path_free(path); return; } } refresh_disassembly(dv, pos, dv->nlines, pos); } /* Get currently selected address. */ gboolean tilem_disasm_view_get_cursor(TilemDisasmView *dv, dword *addr, gboolean *is_logical) { dword pos; g_return_val_if_fail(TILEM_IS_DISASM_VIEW(dv), FALSE); if (is_logical) *is_logical = dv->use_logical; if (!get_cursor_line(dv, &pos, NULL)) return FALSE; if (addr) *addr = POS_TO_ADDR(pos); return TRUE; } tilem-2.0/gui/disasmview.h000066400000000000000000000052011220200411600155570ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ G_BEGIN_DECLS #define TILEM_TYPE_DISASM_VIEW (tilem_disasm_view_get_type()) #define TILEM_DISASM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TILEM_TYPE_DISASM_VIEW, TilemDisasmView)) #define TILEM_DISASM_VIEW_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TILEM_TYPE_DISASM_VIEW, TilemDisasmViewClass)) #define TILEM_IS_DISASM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TILEM_TYPE_DISASM_VIEW)) #define TILEM_IS_DISASM_VIEW_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), TILEM_TYPE_DISASM_VIEW)) #define TILEM_DISASM_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TILEM_TYPE_DISASM_VIEW, TilemDisasmViewClass)) typedef struct _TilemDisasmView { GtkTreeView parent; TilemDebugger *dbg; gboolean use_logical; int base_height; /* base height of tree view */ int line_height; /* height of each row */ dword startpos; /* position at start of window */ dword endpos; /* position at end of window */ int nlines; /* number of lines visible */ GtkTreeViewColumn *icon_column; GtkWidget *popup_menu; } TilemDisasmView; typedef struct _TilemDisasmViewClass { GtkTreeViewClass parent_class; } TilemDisasmViewClass; GType tilem_disasm_view_get_type(void) G_GNUC_CONST; /* Create a new TilemDisasmView. */ GtkWidget * tilem_disasm_view_new(TilemDebugger *dbg); /* Select memory addressing mode. */ void tilem_disasm_view_set_logical(TilemDisasmView *dv, gboolean logical); /* Refresh contents of view. */ void tilem_disasm_view_refresh(TilemDisasmView *dv); /* Highlight the specified address. */ void tilem_disasm_view_go_to_address(TilemDisasmView *dv, dword addr, gboolean logical); /* Get currently selected address. */ gboolean tilem_disasm_view_get_cursor(TilemDisasmView *dv, dword *addr, gboolean *is_logical); /* Toggle breakpoint at selected address. */ void tilem_disasm_view_toggle_breakpoint(TilemDisasmView *dv); G_END_DECLS tilem-2.0/gui/emucore.c000066400000000000000000000250571220200411600150510ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" #include "emucore.h" #define MICROSEC_PER_TICK 10000 typedef struct { TilemCalcEmulator *emu; TilemTaskMainFunc mainf; TilemTaskFinishedFunc finishedf; gpointer userdata; gboolean cancelled; } Task; /* Add a task to the queue. */ void tilem_calc_emulator_begin(TilemCalcEmulator *emu, TilemTaskMainFunc mainf, TilemTaskFinishedFunc finishedf, gpointer data) { Task *task; g_return_if_fail(emu != NULL); g_return_if_fail(mainf != NULL); task = g_slice_new0(Task); task->emu = emu; task->mainf = mainf; task->finishedf = finishedf; task->userdata = data; tilem_calc_emulator_lock(emu); g_queue_push_tail(emu->task_queue, task); tilem_calc_emulator_unlock(emu); } /* Cancel all pending tasks. If a task is currently running, this will wait for it to finish. */ void tilem_calc_emulator_cancel_tasks(TilemCalcEmulator *emu) { GQueue *oldqueue; Task *task; tilem_calc_emulator_lock(emu); emu->task_abort = TRUE; emu->link_update->cancel = TRUE; oldqueue = emu->task_queue; emu->task_queue = g_queue_new(); tilem_calc_emulator_unlock(emu); while ((task = g_queue_pop_head(oldqueue))) { if (task->finishedf) (*task->finishedf)(emu, task->userdata, TRUE); g_slice_free(Task, task); } g_queue_free(oldqueue); g_mutex_lock(emu->calc_mutex); while (emu->task_busy) g_cond_wait(emu->task_finished_cond, emu->calc_mutex); emu->task_abort = FALSE; emu->link_update->cancel = FALSE; g_cond_broadcast(emu->calc_wakeup_cond); g_mutex_unlock(emu->calc_mutex); } /* Check if calculator is powered off */ static gboolean calc_asleep(TilemCalcEmulator *emu) { return (emu->calc->z80.halted && !emu->calc->z80.interrupts && !emu->calc->poweronhalt && !emu->key_queue_timer); } static gboolean refresh_lcd(gpointer data) { TilemCalcEmulator* emu = data; if (emu->ewin) tilem_emulator_window_refresh_lcd(emu->ewin); return FALSE; } /* Update screen for display while paused */ static void update_screen_mono(TilemCalcEmulator *emu) { g_mutex_lock(emu->lcd_mutex); tilem_lcd_get_frame(emu->calc, emu->lcd_buffer); if (!emu->lcd_update_pending) { emu->lcd_update_pending = TRUE; g_idle_add_full(G_PRIORITY_DEFAULT, &refresh_lcd, emu, NULL); } g_mutex_unlock(emu->lcd_mutex); } /* idle callback to update progress bar */ static gboolean pbar_update(gpointer data) { TilemCalcEmulator *emu = data; progress_bar_update(emu); return FALSE; } static void update_progress(TilemCalcEmulator *emu, gboolean force) { if (force || emu->progress_changed) g_idle_add(&pbar_update, emu); emu->progress_changed = FALSE; } static gboolean show_debugger(gpointer data) { TilemCalcEmulator* emu = data; if (emu->dbg) tilem_debugger_show(emu->dbg); return FALSE; } #define BREAK_MASK (TILEM_STOP_BREAKPOINT \ | TILEM_STOP_INVALID_INST \ | TILEM_STOP_UNDOCUMENTED_INST) /* Run one iteration of the emulator. */ dword tilem_em_run(TilemCalcEmulator *emu, int linkmode, dword events, dword ff_events, gboolean keep_awake, int timeout, int *elapsed) { dword all_events, ev_auto, ev_user; int rem; gulong tcur, delaytime; if (emu->exiting || emu->task_abort) { if (elapsed) *elapsed = 0; return 0; } else if (emu->paused) { update_screen_mono(emu); update_progress(emu, TRUE); g_cond_wait(emu->calc_wakeup_cond, emu->calc_mutex); update_progress(emu, TRUE); g_timer_elapsed(emu->timer, &emu->timevalue); if (elapsed) *elapsed = 0; return 0; } else if (!keep_awake && calc_asleep(emu)) { update_progress(emu, FALSE); update_screen_mono(emu); g_cond_wait(emu->calc_wakeup_cond, emu->calc_mutex); g_timer_elapsed(emu->timer, &emu->timevalue); if (elapsed) *elapsed = timeout; return 0; } update_progress(emu, FALSE); all_events = events | BREAK_MASK; emu->calc->linkport.linkemu = linkmode; emu->calc->z80.stop_mask = ~all_events; tilem_z80_run_time(emu->calc, timeout, &rem); ev_user = emu->calc->z80.stop_reason & events; ev_auto = emu->calc->z80.stop_reason & ~events; if (elapsed) *elapsed = timeout - rem; if (ev_auto & BREAK_MASK) { emu->paused = TRUE; g_idle_add(&show_debugger, emu); } if (emu->limit_speed && !(ff_events & ev_user) && ff_events != TILEM_EM_ALWAYS_FF) { emu->timevalue += timeout - rem; g_timer_elapsed(emu->timer, &tcur); /* emu->timevalue is the "ideal" time when the operation should be completed. If emu->timevalue is greater than tcur, we're running faster than real time. Try to sleep for (emu->timevalue - tcur) microseconds. If emu->timevalue is less than tcur, we're running slower than real time. If the difference is small, just keep going and hope we'll catch up later. If the difference is substantial (more than 1/10 second in either direction), re-synchronize. */ delaytime = emu->timevalue - tcur; if (delaytime <= (gulong) 100000 + timeout) { tilem_em_unlock(emu); g_usleep(delaytime); tilem_em_lock(emu); } else { tilem_em_check_yield(emu); if (delaytime < (gulong) -100000) emu->timevalue = tcur; } } else { tilem_em_check_yield(emu); } return ev_user; } static gboolean taskfinished(gpointer data) { Task *task = data; if (task->finishedf) (*task->finishedf)(task->emu, task->userdata, task->cancelled); g_slice_free(Task, task); return FALSE; } static void run_task(TilemCalcEmulator *emu, Task *task) { gboolean status; emu->task_busy = TRUE; status = (*task->mainf)(emu, task->userdata); g_idle_add(&taskfinished, task); if (!status) { while ((task = g_queue_pop_head(emu->task_queue))) { task->cancelled = TRUE; g_idle_add(&taskfinished, task); } } emu->task_busy = FALSE; } /* Main loop */ gpointer tilem_em_main(gpointer data) { TilemCalcEmulator *emu = data; Task *task; tilem_em_lock(emu); g_timer_start(emu->timer); g_timer_elapsed(emu->timer, &emu->timevalue); while (!emu->exiting) { task = g_queue_pop_head(emu->task_queue); if (task) { run_task(emu, task); } else if (emu->task_abort) { g_cond_broadcast(emu->task_finished_cond); g_cond_wait(emu->calc_wakeup_cond, emu->calc_mutex); } else { tilem_em_run(emu, 0, 0, 0, FALSE, MICROSEC_PER_TICK, NULL); } } tilem_em_unlock(emu); return NULL; } /* Run the calculator for a short time. */ void tilem_em_delay(TilemCalcEmulator *emu, int timeout, gboolean ff) { int t; G_GNUC_UNUSED dword events; while (!emu->task_abort && timeout > 0) { t = MIN(MICROSEC_PER_TICK, timeout); events = tilem_em_run(emu, 0, 0, (ff ? TILEM_EM_ALWAYS_FF : 0), TRUE, t, &t); timeout -= t; } } #define LINK_EVENTS (TILEM_STOP_LINK_READ_BYTE \ | TILEM_STOP_LINK_WRITE_BYTE \ | TILEM_STOP_LINK_ERROR) static int run_until_ready(TilemCalcEmulator *emu, int timeout, gboolean ff) { int t; dword events; emu->calc->linkport.linkemu = TILEM_LINK_EMULATOR_GRAY; while (!emu->task_abort && timeout > 0) { if (tilem_linkport_graylink_ready(emu->calc)) return 0; t = MIN(MICROSEC_PER_TICK, timeout); events = tilem_em_run(emu, TILEM_LINK_EMULATOR_GRAY, LINK_EVENTS, (ff ? LINK_EVENTS : 0), TRUE, t, &t); timeout -= t; if (events & TILEM_STOP_LINK_ERROR) break; } return -1; } /* Send a byte to the calculator. */ int tilem_em_send_byte(TilemCalcEmulator *emu, unsigned value, int timeout, gboolean ff) { if (run_until_ready(emu, timeout, ff)) return -1; if (tilem_linkport_graylink_send_byte(emu->calc, value)) return -1; if (run_until_ready(emu, timeout, ff)) return -1; return 0; } /* Receive a byte from the calculator. */ int tilem_em_get_byte(TilemCalcEmulator *emu, int timeout, gboolean ff) { int t, v; dword events; while (!emu->task_abort && timeout > 0) { v = tilem_linkport_graylink_get_byte(emu->calc); if (v >= 0) return v; t = MIN(MICROSEC_PER_TICK, timeout); events = tilem_em_run(emu, TILEM_LINK_EMULATOR_GRAY, LINK_EVENTS, (ff ? LINK_EVENTS : 0), FALSE, t, &t); timeout -= t; if (events & TILEM_STOP_LINK_ERROR) break; } return -1; } /* Wake up calculator if currently turned off. */ void tilem_em_wake_up(TilemCalcEmulator *emu, gboolean ff) { tilem_em_delay(emu, 1000000, ff); if (!calc_asleep(emu)) return; tilem_keypad_press_key(emu->calc, TILEM_KEY_ON); tilem_em_delay(emu, 500000, ff); tilem_keypad_release_key(emu->calc, TILEM_KEY_ON); tilem_em_delay(emu, 500000, ff); } /* Set progress window title. Set TITLE to NULL to disable progress window. */ void tilem_em_set_progress_title(TilemCalcEmulator *emu, const char *title) { g_mutex_lock(emu->pbar_mutex); g_free(emu->pbar_title); g_free(emu->pbar_status); emu->pbar_title = title ? g_strdup(title) : NULL; emu->pbar_status = NULL; emu->pbar_progress = 0.0; if (!emu->pbar_update_pending) emu->progress_changed = TRUE; emu->pbar_update_pending = TRUE; g_mutex_unlock(emu->pbar_mutex); } /* Set current progress information. FRAC is the estimated fraction of the task completed; STATUS is a text description of the current operation. */ void tilem_em_set_progress(TilemCalcEmulator *emu, gdouble frac, const char *status) { g_mutex_lock(emu->pbar_mutex); if (!emu->pbar_status || !status || strcmp(status, emu->pbar_status)) { g_free(emu->pbar_status); emu->pbar_status = status ? g_strdup(status) : NULL; } emu->pbar_progress = frac; if (!emu->pbar_update_pending) emu->progress_changed = TRUE; emu->pbar_update_pending = TRUE; g_mutex_unlock(emu->pbar_mutex); } tilem-2.0/gui/emucore.h000066400000000000000000000067641220200411600150620ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* IMPORTANT: The following functions may ONLY be used within tilem_em_main() or a task function, and must be called while holding the emulator lock. */ #define TILEM_EM_ALWAYS_FF 0xffffffff /* Run one iteration of the emulator. LINKMODE is the link port emulation mode. EVENTS is a mask of events we are interested in; emulation will stop early if any of these events occur, or possibly for other reasons (e.g., a breakpoint being hit.) FF_EVENTS is a mask of events we want to fast-forward through (i.e., not apply speed limiting even if enabled.) If FF_EVENTS is set to the constant ALWAYS_FF, speed limiting is completely disabled. If KEEP_AWAKE is FALSE and the calculator CPU is turned off, this function may block until another thread wakes it up; in that case, no timer events will be triggered, and the elapsed time cannot be measured in any meaningful way. If KEEP_AWAKE is TRUE, the emulator continues running even when the CPU is turned off. TIMEOUT is the length of time (microseconds) to run the emulator. If ELAPSED is non-null, *ELAPSED will be set to the actual number of microseconds elapsed. The return value is a mask indicating which of the requested events occurred. */ dword tilem_em_run(TilemCalcEmulator *emu, int linkmode, dword events, dword ff_events, gboolean keep_awake, int timeout, int *elapsed); /* Main loop */ gpointer tilem_em_main(gpointer data); /* Run the calculator for a short time. */ void tilem_em_delay(TilemCalcEmulator *emu, int timeout, gboolean ff); /* Send a byte to the calculator. */ int tilem_em_send_byte(TilemCalcEmulator *emu, unsigned value, int timeout, gboolean ff); /* Receive a byte from the calculator. */ int tilem_em_get_byte(TilemCalcEmulator *emu, int timeout, gboolean ff); /* Wake up calculator if currently turned off. */ void tilem_em_wake_up(TilemCalcEmulator *emu, gboolean ff); /* Set progress window title. Set TITLE to NULL to disable progress window. */ void tilem_em_set_progress_title(TilemCalcEmulator *emu, const char *title); /* Set current progress information. FRAC is the estimated fraction of the task completed; STATUS is a text description of the current operation. */ void tilem_em_set_progress(TilemCalcEmulator *emu, gdouble frac, const char *status); /* Lock emulator. */ #define tilem_em_lock(emu) \ g_mutex_lock(emu->calc_mutex) /* Unlock temporarily if another thread is waiting. */ #define tilem_em_check_yield(emu) \ do { \ if (g_atomic_int_get(&emu->calc_lock_waiting)) \ g_cond_wait(emu->calc_wakeup_cond, emu->calc_mutex); \ } while (0) /* Unlock emulator. */ #define tilem_em_unlock(emu) \ do { \ tilem_em_check_yield(emu); \ g_mutex_unlock(emu->calc_mutex); \ } while (0) tilem-2.0/gui/emulator.c000066400000000000000000000532161220200411600152400ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" #include "emucore.h" #include "msgbox.h" #include "filedlg.h" #define MILLISEC_PER_FRAME 30 #define MICROSEC_PER_FRAME (MILLISEC_PER_FRAME * 1000) #define GRAY_WINDOW_SIZE 4 #define GRAY_SAMPLE_INT 200 /* Lock emulator. Notify the core loop that we wish to do so - note that if the core is running at full speed, it keeps the mutex locked almost all the time, so we need to explicitly ask it to yield. (This may not be necessary with all mutex implementations, but definitely is necessary with some.) */ void tilem_calc_emulator_lock(TilemCalcEmulator *emu) { g_atomic_int_inc(&emu->calc_lock_waiting); g_mutex_lock(emu->calc_mutex); } /* Unlock emulator and (if no other threads are waiting to lock it) wake up the core thread. This also serves to resume emulation if the calculator has been powered off. */ void tilem_calc_emulator_unlock(TilemCalcEmulator *emu) { if (g_atomic_int_dec_and_test(&emu->calc_lock_waiting)) g_cond_signal(emu->calc_wakeup_cond); g_mutex_unlock(emu->calc_mutex); } static gboolean refresh_lcd(gpointer data) { TilemCalcEmulator* emu = data; if (emu->ewin) tilem_emulator_window_refresh_lcd(emu->ewin); return FALSE; } static void tmr_screen_update(TilemCalc *calc, void *data) { TilemCalcEmulator *emu = data; g_mutex_lock(emu->lcd_mutex); if (emu->glcd) tilem_gray_lcd_get_frame(emu->glcd, emu->lcd_buffer); else tilem_lcd_get_frame(calc, emu->lcd_buffer); if (emu->anim) { if (emu->anim_grayscale) { tilem_animation_append_frame(emu->anim, emu->lcd_buffer, MILLISEC_PER_FRAME); } else { tilem_lcd_get_frame(calc, emu->tmp_lcd_buffer); tilem_animation_append_frame(emu->anim, emu->tmp_lcd_buffer, MILLISEC_PER_FRAME); } } if (!emu->lcd_update_pending) { emu->lcd_update_pending = TRUE; g_idle_add_full(G_PRIORITY_DEFAULT, &refresh_lcd, emu, NULL); } g_mutex_unlock(emu->lcd_mutex); } static void cancel_animation(TilemCalcEmulator *emu) { if (emu->anim) g_object_unref(emu->anim); emu->anim = NULL; } static GtkWidget *get_toplevel(TilemCalcEmulator *emu) { if (emu->ewin) return emu->ewin->window; else return NULL; } static void link_update_nop() { } TilemCalcEmulator *tilem_calc_emulator_new() { TilemCalcEmulator *emu = g_new0(TilemCalcEmulator, 1); CalcUpdate *update; emu->calc_mutex = g_mutex_new(); emu->calc_wakeup_cond = g_cond_new(); emu->lcd_mutex = g_mutex_new(); tilem_config_get("emulation", "grayscale/b=1", &emu->grayscale, "limit_speed/b=1", &emu->limit_speed, NULL); emu->task_queue = g_queue_new(); emu->task_finished_cond = g_cond_new(); emu->timer = g_timer_new(); emu->pbar_mutex = g_mutex_new(); update = g_new0(CalcUpdate, 1); update->start = &link_update_nop; update->stop = &link_update_nop; update->refresh = &link_update_nop; update->pbar = &link_update_nop; update->label = &link_update_nop; emu->link_update = update; return emu; } void tilem_calc_emulator_free(TilemCalcEmulator *emu) { g_return_if_fail(emu != NULL); tilem_calc_emulator_cancel_tasks(emu); tilem_calc_emulator_lock(emu); cancel_animation(emu); emu->exiting = TRUE; tilem_calc_emulator_unlock(emu); if (emu->z80_thread) g_thread_join(emu->z80_thread); g_free(emu->key_queue); g_free(emu->rom_file_name); g_free(emu->state_file_name); g_mutex_free(emu->calc_mutex); g_mutex_free(emu->lcd_mutex); g_cond_free(emu->calc_wakeup_cond); g_cond_free(emu->task_finished_cond); g_queue_free(emu->task_queue); g_timer_destroy(emu->timer); g_mutex_free(emu->pbar_mutex); g_free(emu->link_update); if (emu->lcd_buffer) tilem_lcd_buffer_free(emu->lcd_buffer); if (emu->tmp_lcd_buffer) tilem_lcd_buffer_free(emu->tmp_lcd_buffer); if (emu->glcd) tilem_gray_lcd_free(emu->glcd); if (emu->calc) tilem_calc_free(emu->calc); g_free(emu); } static char *get_sav_name(const char *romname) { char *dname, *bname, *sname, *suff; dname = g_path_get_dirname(romname); bname = g_path_get_basename(romname); if ((suff = strrchr(bname, '.'))) *suff = 0; sname = g_strconcat(dname, G_DIR_SEPARATOR_S, bname, ".sav", NULL); g_free(dname); g_free(bname); return sname; } gboolean tilem_calc_emulator_load_state(TilemCalcEmulator *emu, const char *romfname, const char *statefname, int model, GError **err) { const char *modelname; FILE *romfile, *savfile; char *rname = NULL, *sname = NULL; TilemCalc *calc; char *dname; int errnum; g_return_val_if_fail(emu != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); tilem_calc_emulator_cancel_tasks(emu); if (romfname) rname = g_strdup(romfname); if (!sname && statefname) sname = g_strdup(statefname); /* Choose ROM file */ if (!rname && model) { modelname = model_to_name(model); g_return_val_if_fail(modelname != NULL, FALSE); if (sname) g_free(sname); tilem_config_get(modelname, "rom_file/f", &rname, "state_file/f", &sname, NULL); } if (!rname) { g_set_error(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_NO_ROM, "No ROM file specified"); g_free(rname); g_free(sname); return FALSE; } /* Open ROM file */ romfile = g_fopen(rname, "rb"); if (!romfile) { errnum = errno; dname = g_filename_display_basename(rname); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for reading: %s", dname, g_strerror(errnum)); g_free(dname); g_free(rname); g_free(sname); return FALSE; } /* Open state file */ if (!sname) sname = get_sav_name(rname); savfile = g_fopen(sname, "rb"); if (!savfile && errno != ENOENT) { errnum = errno; dname = g_filename_display_basename(sname); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for reading: %s", dname, g_strerror(errnum)); g_free(dname); g_free(rname); g_free(sname); fclose(romfile); return FALSE; } /* Determine model from state file, if possible */ if (!model && savfile) model = tilem_get_sav_type(savfile); /* Otherwise, guess from ROM file; ask user if ambiguous */ if (!model) { model = tilem_guess_rom_type(romfile); if (model) { model = choose_rom_popup(get_toplevel(emu), rname, model); } else { dname = g_filename_display_basename(rname); g_set_error(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_INVALID_ROM, "The file %s is not a recognized" " calculator ROM file.", dname); g_free(dname); } } if (!model) { fclose(romfile); if (savfile) fclose(savfile); g_free(rname); g_free(sname); return FALSE; } /* Create new calc, and load state */ calc = tilem_calc_new(model); if (tilem_calc_load_state(calc, romfile, savfile)) { g_set_error(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_INVALID_STATE, "The specified ROM or state file is invalid."); fclose(romfile); if (savfile) fclose(savfile); g_free(rname); g_free(sname); return FALSE; } if (!savfile) { /* save model as default for the future */ savfile = g_fopen(sname, "wb"); if (savfile) fprintf(savfile, "MODEL = %s\n", calc->hw.name); } fclose(romfile); if (savfile) fclose(savfile); /* Switch to new calc */ tilem_calc_emulator_lock(emu); cancel_animation(emu); if (emu->glcd) tilem_gray_lcd_free(emu->glcd); if (emu->calc) tilem_calc_free(emu->calc); emu->calc = calc; emu->lcd_buffer = tilem_lcd_buffer_new(); emu->tmp_lcd_buffer = tilem_lcd_buffer_new(); if (emu->grayscale) emu->glcd = tilem_gray_lcd_new(calc, GRAY_WINDOW_SIZE, GRAY_SAMPLE_INT); else emu->glcd = NULL; tilem_z80_add_timer(calc, MICROSEC_PER_FRAME, MICROSEC_PER_FRAME, 1, &tmr_screen_update, emu); tilem_calc_emulator_unlock(emu); if (emu->rom_file_name) g_free(emu->rom_file_name); emu->rom_file_name = rname; if (emu->state_file_name) g_free(emu->state_file_name); emu->state_file_name = sname; tilem_keybindings_init(emu, calc->hw.name); if (emu->ewin) tilem_emulator_window_calc_changed(emu->ewin); if (emu->dbg) tilem_debugger_calc_changed(emu->dbg); if (emu->rcvdlg) tilem_receive_dialog_free(emu->rcvdlg); emu->rcvdlg = NULL; return TRUE; } gboolean tilem_calc_emulator_revert_state(TilemCalcEmulator *emu, GError **err) { FILE *romfile, *savfile; char *dname; int errnum = 0; gboolean status = TRUE; g_return_val_if_fail(emu != NULL, FALSE); g_return_val_if_fail(emu->calc != NULL, FALSE); g_return_val_if_fail(emu->rom_file_name != NULL, FALSE); g_return_val_if_fail(emu->state_file_name != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); /* Open ROM file */ if (emu->calc->hw.flags & TILEM_CALC_HAS_FLASH) { romfile = g_fopen(emu->rom_file_name, "rb"); if (!romfile) { errnum = errno; dname = g_filename_display_basename(emu->rom_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for reading: %s", dname, g_strerror(errnum)); g_free(dname); return FALSE; } } else { romfile = NULL; } /* Open state file */ savfile = g_fopen(emu->state_file_name, "rb"); if (!savfile) { errnum = errno; dname = g_filename_display_basename(emu->state_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for reading: %s", dname, g_strerror(errnum)); g_free(dname); if (romfile) fclose(romfile); return FALSE; } /* Read state */ tilem_calc_emulator_lock(emu); if (tilem_calc_load_state(emu->calc, romfile, savfile)) { g_set_error(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_INVALID_STATE, "The specified ROM or state file is invalid."); status = FALSE; } tilem_calc_emulator_unlock(emu); if (emu->dbg) tilem_debugger_refresh(emu->dbg, TRUE); if (romfile) fclose(romfile); fclose(savfile); return status; } gboolean tilem_calc_emulator_save_state(TilemCalcEmulator *emu, GError **err) { FILE *romfile, *savfile; char *dname; int errnum = 0; g_return_val_if_fail(emu != NULL, FALSE); g_return_val_if_fail(emu->calc != NULL, FALSE); g_return_val_if_fail(emu->rom_file_name != NULL, FALSE); g_return_val_if_fail(emu->state_file_name != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); /* Open ROM file */ if (emu->calc->hw.flags & TILEM_CALC_HAS_FLASH) { romfile = g_fopen(emu->rom_file_name, "r+b"); if (!romfile) { errnum = errno; dname = g_filename_display_basename(emu->rom_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for writing: %s", dname, g_strerror(errnum)); g_free(dname); return FALSE; } } else { romfile = NULL; } /* Open state file */ savfile = g_fopen(emu->state_file_name, "wb"); if (!savfile) { errnum = errno; dname = g_filename_display_basename(emu->state_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for writing: %s", dname, g_strerror(errnum)); g_free(dname); if (romfile) fclose(romfile); return FALSE; } /* Write state */ tilem_calc_emulator_lock(emu); if (romfile && tilem_calc_save_state(emu->calc, romfile, NULL)) errnum = errno; if (romfile && fclose(romfile)) errnum = errno; if (errnum) { dname = g_filename_display_basename(emu->rom_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Error writing %s: %s", dname, g_strerror(errnum)); g_free(dname); fclose(savfile); tilem_calc_emulator_unlock(emu); return FALSE; } if (tilem_calc_save_state(emu->calc, NULL, savfile)) errnum = errno; if (fclose(savfile)) errnum = errno; tilem_calc_emulator_unlock(emu); if (errnum) { dname = g_filename_display_basename(emu->state_file_name); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Error writing %s: %s", dname, g_strerror(errnum)); g_free(dname); return FALSE; } return TRUE; } void tilem_calc_emulator_reset(TilemCalcEmulator *emu) { g_return_if_fail(emu != NULL); g_return_if_fail(emu->calc != NULL); tilem_calc_emulator_lock(emu); tilem_calc_reset(emu->calc); tilem_calc_emulator_unlock(emu); if (emu->dbg) tilem_debugger_refresh(emu->dbg, TRUE); } void tilem_calc_emulator_pause(TilemCalcEmulator *emu) { g_return_if_fail(emu != NULL); tilem_calc_emulator_lock(emu); emu->paused = TRUE; tilem_calc_emulator_unlock(emu); } void tilem_calc_emulator_run(TilemCalcEmulator *emu) { g_return_if_fail(emu != NULL); g_return_if_fail(emu->calc != NULL); tilem_calc_emulator_lock(emu); emu->paused = FALSE; tilem_calc_emulator_unlock(emu); if (!emu->z80_thread) emu->z80_thread = g_thread_create(&tilem_em_main, emu, TRUE, NULL); } void tilem_calc_emulator_set_limit_speed(TilemCalcEmulator *emu, gboolean limit) { emu->limit_speed = limit; } void tilem_calc_emulator_set_grayscale(TilemCalcEmulator *emu, gboolean grayscale) { emu->grayscale = grayscale; if (grayscale && emu->calc && !emu->glcd) { tilem_calc_emulator_lock(emu); emu->glcd = tilem_gray_lcd_new(emu->calc, GRAY_WINDOW_SIZE, GRAY_SAMPLE_INT); tilem_calc_emulator_unlock(emu); } else if (!grayscale && emu->glcd) { tilem_calc_emulator_lock(emu); tilem_gray_lcd_free(emu->glcd); emu->glcd = NULL; tilem_calc_emulator_unlock(emu); } } /* If currently recording a macro, record a keypress */ static void record_key(TilemCalcEmulator* emu, int code) { char* codechar; int type = 0; if (emu->isMacroRecording) { codechar = g_strdup_printf("%04d", code); tilem_macro_add_action(emu->macro, type, codechar); g_free(codechar); } } void tilem_calc_emulator_press_key(TilemCalcEmulator *emu, int key) { g_return_if_fail(emu != NULL); if (key == 0) return; tilem_calc_emulator_lock(emu); tilem_keypad_press_key(emu->calc, key); tilem_calc_emulator_unlock(emu); record_key(emu, key); if (emu->dbg && emu->dbg->keypad_dialog) tilem_keypad_dialog_refresh(emu->dbg->keypad_dialog); } void tilem_calc_emulator_release_key(TilemCalcEmulator *emu, int key) { g_return_if_fail(emu != NULL); if (key == 0) return; tilem_calc_emulator_lock(emu); tilem_keypad_release_key(emu->calc, key); tilem_calc_emulator_unlock(emu); if (emu->dbg && emu->dbg->keypad_dialog) tilem_keypad_dialog_refresh(emu->dbg->keypad_dialog); } static gboolean refresh_kpd(gpointer data) { TilemCalcEmulator *emu = data; if (emu->dbg && emu->dbg->keypad_dialog) tilem_keypad_dialog_refresh(emu->dbg->keypad_dialog); return FALSE; } /* Timer callback for key sequences */ static void tmr_key_queue(TilemCalc* calc, void* data) { TilemCalcEmulator *emu = data; int nextkey; if (emu->key_queue_pressed) { if (emu->key_queue_len > 0 || !emu->key_queue_hold) { tilem_keypad_release_key(calc, emu->key_queue_cur); emu->key_queue_pressed = 0; emu->key_queue_cur = 0; tilem_z80_set_timer(calc, emu->key_queue_timer, 50000, 0, 1); } else { tilem_z80_remove_timer(calc, emu->key_queue_timer); emu->key_queue_timer = 0; } } else { if (emu->key_queue_len > 0) { nextkey = emu->key_queue[--emu->key_queue_len]; tilem_keypad_press_key(calc, nextkey); emu->key_queue_pressed = 1; emu->key_queue_cur = nextkey; tilem_z80_set_timer(calc, emu->key_queue_timer, 20000, 0, 1); } else { tilem_z80_remove_timer(calc, emu->key_queue_timer); emu->key_queue_timer = 0; } } g_idle_add(&refresh_kpd, emu); } static void queue_keys(TilemCalcEmulator *emu, const byte *keys, int nkeys) { byte *q; int i; q = g_new(byte, emu->key_queue_len + nkeys); for (i = 0; i < nkeys; i++) { q[nkeys - i - 1] = keys[i]; record_key(emu, keys[i]); } if (emu->key_queue_len) memcpy(q + nkeys, emu->key_queue, emu->key_queue_len); g_free(emu->key_queue); emu->key_queue = q; emu->key_queue_len += nkeys; emu->key_queue_hold = 1; if (!emu->key_queue_timer) { emu->key_queue_timer = tilem_z80_add_timer(emu->calc, 1, 0, 1, &tmr_key_queue, emu); } } void tilem_calc_emulator_queue_keys(TilemCalcEmulator *emu, const byte *keys, int nkeys) { g_return_if_fail(emu != NULL); g_return_if_fail(keys != NULL); g_return_if_fail(nkeys > 0); tilem_calc_emulator_lock(emu); queue_keys(emu, keys, nkeys); tilem_calc_emulator_unlock(emu); } void tilem_calc_emulator_release_queued_key(TilemCalcEmulator *emu) { g_return_if_fail(emu != NULL); tilem_calc_emulator_lock(emu); if (emu->key_queue_timer) { emu->key_queue_hold = 0; } else if (emu->key_queue_pressed) { tilem_keypad_release_key(emu->calc, emu->key_queue_cur); emu->key_queue_pressed = 0; emu->key_queue_cur = 0; } tilem_calc_emulator_unlock(emu); if (emu->dbg && emu->dbg->keypad_dialog) tilem_keypad_dialog_refresh(emu->dbg->keypad_dialog); } gboolean tilem_calc_emulator_press_or_queue(TilemCalcEmulator *emu, int key) { byte b; gboolean status; g_return_val_if_fail(emu != NULL, FALSE); tilem_calc_emulator_lock(emu); if (emu->key_queue_timer) { b = key; queue_keys(emu, &b, 1); status = TRUE; } else { tilem_keypad_press_key(emu->calc, key); status = FALSE; } tilem_calc_emulator_unlock(emu); if (emu->dbg && emu->dbg->keypad_dialog) tilem_keypad_dialog_refresh(emu->dbg->keypad_dialog); return status; } TilemAnimation * tilem_calc_emulator_get_screenshot(TilemCalcEmulator *emu, gboolean grayscale) { TilemAnimation *anim; g_return_val_if_fail(emu != NULL, NULL); g_return_val_if_fail(emu->calc != NULL, NULL); anim = tilem_animation_new(emu->calc->hw.lcdwidth, emu->calc->hw.lcdheight); tilem_calc_emulator_lock(emu); if (grayscale && emu->glcd) tilem_gray_lcd_get_frame(emu->glcd, emu->tmp_lcd_buffer); else tilem_lcd_get_frame(emu->calc, emu->tmp_lcd_buffer); tilem_animation_append_frame(anim, emu->tmp_lcd_buffer, 1); tilem_calc_emulator_unlock(emu); return anim; } void tilem_calc_emulator_begin_animation(TilemCalcEmulator *emu, gboolean grayscale) { g_return_if_fail(emu != NULL); g_return_if_fail(emu->calc != NULL); tilem_calc_emulator_lock(emu); cancel_animation(emu); emu->anim = tilem_animation_new(emu->calc->hw.lcdwidth, emu->calc->hw.lcdheight); emu->anim_grayscale = grayscale; tilem_calc_emulator_unlock(emu); } TilemAnimation * tilem_calc_emulator_end_animation(TilemCalcEmulator *emu) { TilemAnimation *anim; g_return_val_if_fail(emu != NULL, NULL); g_return_val_if_fail(emu->anim != NULL, NULL); tilem_calc_emulator_lock(emu); anim = emu->anim; emu->anim = NULL; tilem_calc_emulator_unlock(emu); return anim; } /* Prompt for a ROM file to open */ int tilem_calc_emulator_prompt_open_rom(TilemCalcEmulator *emu) { char *dir, *filename; GError *err = NULL; const char *modelname; if (emu->rom_file_name) dir = g_path_get_dirname(emu->rom_file_name); else dir = g_get_current_dir(); filename = prompt_open_file("Open Calculator", GTK_WINDOW(get_toplevel(emu)), dir, "ROM files", "*.rom;*.clc;*.bin", "All files", "*", NULL); g_free(dir); if (!filename) return 0; if (tilem_calc_emulator_load_state(emu, filename, NULL, 0, &err)) { modelname = emu->calc->hw.name; tilem_config_set(modelname, "rom_file/f", emu->rom_file_name, "state_file/f", emu->state_file_name, NULL); tilem_config_set("recent", "last_model/s", modelname, NULL); } g_free(filename); if (err) { messagebox01(GTK_WINDOW(get_toplevel(emu)), GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); g_error_free(err); return -1; } else { return 1; } } /* Run slowly to play macro (used instead run_with_key() function) */ void run_with_key_slowly(TilemCalc* calc, int key) { tilem_z80_run_time(calc, 5000000, NULL); /* Wait */ tilem_keypad_press_key(calc, key); /* Press */ tilem_z80_run_time(calc, 10000, NULL); /* Wait (don't forget to wait) */ tilem_keypad_release_key(calc, key); /* Release */ tilem_z80_run_time(calc, 50, NULL); /* Wait */ } tilem-2.0/gui/emulator.h000066400000000000000000000202511220200411600152360ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * Copyright (c) 2011 Duponchelle Thibault * * 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 3 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, see . */ /* Key binding */ typedef struct _TilemKeyBinding { unsigned int keysym; /* host keysym value */ unsigned int modifiers; /* modifier mask */ int nscancodes; /* number of calculator scancodes */ byte *scancodes; /* calculator scancodes */ } TilemKeyBinding; /* A single action */ typedef struct _TilemMacroAtom { char* value; int type; } TilemMacroAtom; /* All the actions */ typedef struct _TilemMacro { TilemMacroAtom** actions; int n; } TilemMacro; typedef struct _TilemCalcEmulator { GThread *z80_thread; /* Mutex controlling access to the calc. Use tilem_calc_emulator_lock()/unlock() rather than g_mutex_lock()/unlock() directly. */ GMutex *calc_mutex; int calc_lock_waiting; GCond *calc_wakeup_cond; TilemCalc *calc; gboolean paused; gboolean exiting; gboolean limit_speed; /* limit to actual speed */ /* Timer used for speed limiting */ GTimer *timer; gulong timevalue; /* Queue of tasks to be performed */ GQueue *task_queue; gboolean task_busy; gboolean task_abort; GCond *task_finished_cond; /* Sequence of keys to be pressed */ byte *key_queue; int key_queue_len; int key_queue_timer; int key_queue_pressed; int key_queue_cur; int key_queue_hold; GMutex *lcd_mutex; TilemLCDBuffer *lcd_buffer; TilemLCDBuffer *tmp_lcd_buffer; TilemGrayLCD *glcd; gboolean grayscale; gboolean lcd_update_pending; TilemAnimation *anim; /* animation being recorded */ gboolean anim_grayscale; /* use grayscale in animation */ char *rom_file_name; char *state_file_name; /* List of key bindings */ TilemKeyBinding *keybindings; int nkeybindings; struct _TilemMacro *macro; /* Link transfer state */ gboolean ilp_active; CalcUpdate *link_update; /* CalcUpdate (status and callbacks for ticalcs) */ GMutex *pbar_mutex; char *pbar_title; char *pbar_status; gdouble pbar_progress; gboolean pbar_update_pending; gboolean progress_changed; /* GUI widgets */ struct _TilemDebugger *dbg; struct _TilemEmulatorWindow *ewin; struct _TilemScreenshotDialog *ssdlg; struct _TilemReceiveDialog *rcvdlg; struct _TilemLinkProgress *linkpb; FILE * macro_file; /* The macro file */ gboolean isMacroRecording; /* A flag to know everywhere that macro is recording */ } TilemCalcEmulator; /* Errors */ #define TILEM_EMULATOR_ERROR g_quark_from_static_string("tilem-emulator-error") enum { TILEM_EMULATOR_ERROR_NO_ROM, TILEM_EMULATOR_ERROR_INVALID_ROM, TILEM_EMULATOR_ERROR_INVALID_STATE }; /* Create a new TilemCalcEmulator. */ TilemCalcEmulator *tilem_calc_emulator_new(void); /* Free a TilemCalcEmulator. */ void tilem_calc_emulator_free(TilemCalcEmulator *emu); /* Lock calculator so we can directly access it from outside the core thread. */ void tilem_calc_emulator_lock(TilemCalcEmulator *emu); /* Unlock calculator and allow emulation to continue. */ void tilem_calc_emulator_unlock(TilemCalcEmulator *emu); /* Load the calculator state from the given ROM file (and accompanying sav file, if any.) */ gboolean tilem_calc_emulator_load_state(TilemCalcEmulator *emu, const char *romfname, const char *statefname, int model, GError **err); /* Reload the calculator state from the most recently loaded file. */ gboolean tilem_calc_emulator_revert_state(TilemCalcEmulator *emu, GError **err); /* Save the calculator state. */ gboolean tilem_calc_emulator_save_state(TilemCalcEmulator *emu, GError **err); /* Reset the calculator. */ void tilem_calc_emulator_reset(TilemCalcEmulator *emu); /* Pause emulation (if currently running.) */ void tilem_calc_emulator_pause(TilemCalcEmulator *emu); /* Resume emulation (if currently paused.) */ void tilem_calc_emulator_run(TilemCalcEmulator *emu); /* Enable/disable speed limiting (TRUE means attempt to run at the actual CPU speed; FALSE means run as fast as we can.) */ void tilem_calc_emulator_set_limit_speed(TilemCalcEmulator *emu, gboolean limit); /* Enable/disable grayscale */ void tilem_calc_emulator_set_grayscale(TilemCalcEmulator *emu, gboolean grayscale); /* Press a single key. */ void tilem_calc_emulator_press_key(TilemCalcEmulator *emu, int key); /* Release a single key. */ void tilem_calc_emulator_release_key(TilemCalcEmulator *emu, int key); /* Add keys to the input queue. */ void tilem_calc_emulator_queue_keys(TilemCalcEmulator *emu, const byte *keys, int nkeys); /* Release final key in input queue. */ void tilem_calc_emulator_release_queued_key(TilemCalcEmulator *emu); /* If input queue is empty, press key immediately; otherwise, add to the input queue. Return TRUE if key was added to the queue. */ gboolean tilem_calc_emulator_press_or_queue(TilemCalcEmulator *emu, int key); /* Retrieve a static screenshot of current calculator screen. Returned object has a reference count of 1 (free it with g_object_unref().) */ TilemAnimation * tilem_calc_emulator_get_screenshot(TilemCalcEmulator *emu, gboolean grayscale); /* Begin recording an animated screenshot. */ void tilem_calc_emulator_begin_animation(TilemCalcEmulator *emu, gboolean grayscale); /* Finish recording an animated screenshot. Returned object has a reference count of 1 (free it with g_object_unref().) */ TilemAnimation * tilem_calc_emulator_end_animation(TilemCalcEmulator *emu); /* Prompt for a ROM file to open */ int tilem_calc_emulator_prompt_open_rom(TilemCalcEmulator *emu); /* Run slowly to play macro */ void run_with_key_slowly(TilemCalc* calc, int key); /* Task handling */ typedef gboolean (*TilemTaskMainFunc)(TilemCalcEmulator *emu, gpointer data); typedef void (*TilemTaskFinishedFunc)(TilemCalcEmulator *emu, gpointer data, gboolean cancelled); /* Add a task to the queue. MAINF is a function to perform in the core thread. If it returns FALSE, all further tasks will be cancelled. Tasks can also be cancelled early by calling tilem_calc_emulator_cancel_tasks(). After the task finishes or is cancelled, FINISHEDF will be called in the GUI thread. Task-finished functions might not be called in the same order the tasks were originally added to the queue. */ void tilem_calc_emulator_begin(TilemCalcEmulator *emu, TilemTaskMainFunc taskf, TilemTaskFinishedFunc finishedf, gpointer data); /* Cancel all pending tasks. If a task is currently running, this will attempt to cancel it and wait for it to exit. */ void tilem_calc_emulator_cancel_tasks(TilemCalcEmulator *emu); /* Macros */ /* Start to record a macro */ void tilem_macro_start(TilemCalcEmulator *emu); /* Add an action to the macro */ void tilem_macro_add_action(TilemMacro* macro, int type, char * value); /* Stop recording a macro */ void tilem_macro_stop(TilemCalcEmulator *emu); /* Print the macro (debug) */ void tilem_macro_print(TilemMacro *macro); /* Write a macro file */ void tilem_macro_write_file(TilemCalcEmulator *emu); /* Play a macro (loaded or recorded before) */ void tilem_macro_play(TilemCalcEmulator *emu); /* Load a macro from filename or if filename == NULL prompt user */ void tilem_macro_load(TilemCalcEmulator *emu, char* filename); tilem-2.0/gui/emuwin.c000066400000000000000000000440511220200411600147110ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "gui.h" #include "files.h" #include "msgbox.h" /* Set size hints for the toplevel window */ static void set_size_hints(GtkWidget *widget, gpointer data) { TilemEmulatorWindow *ewin = data; /* Don't use gtk_window_set_geometry_hints() (which would appear to do what we want) because, in addition to setting the hints we want, that function causes GTK+ to argue with the window manager. Instead, we call this function after the check-resize signal (which is when GTK+ itself would normally set the hints.) FIXME: check that this works as desired on Win32/Quartz. */ if (gtk_widget_get_window(widget)) gdk_window_set_geometry_hints(gtk_widget_get_window(widget), &ewin->geomhints, ewin->geomhintmask); } static void window_state_changed(G_GNUC_UNUSED GtkWidget *w, GdkEventWindowState *event, gpointer data) { TilemEmulatorWindow *ewin = data; ewin->window_state = event->new_window_state; } static gboolean window_maximized(TilemEmulatorWindow *ewin) { return (ewin->window_state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)); } static gboolean screen_repaint(GtkWidget *w, GdkEventExpose *ev G_GNUC_UNUSED, TilemEmulatorWindow *ewin) { GtkAllocation alloc; GdkWindow *win; GtkStyle *style; gtk_widget_get_allocation(w, &alloc); /* If image buffer is not the correct size, allocate a new one */ if (!ewin->lcd_image_buf || alloc.width != ewin->lcd_image_width || alloc.height != ewin->lcd_image_height) { ewin->lcd_image_width = alloc.width; ewin->lcd_image_height = alloc.height; g_free(ewin->lcd_image_buf); ewin->lcd_image_buf = g_new(byte, alloc.width * alloc.height); } /* Draw LCD contents into the image buffer */ g_mutex_lock(ewin->emu->lcd_mutex); ewin->emu->lcd_update_pending = FALSE; tilem_draw_lcd_image_indexed(ewin->emu->lcd_buffer, ewin->lcd_image_buf, alloc.width, alloc.height, alloc.width, (ewin->lcd_smooth_scale ? TILEM_SCALE_SMOOTH : TILEM_SCALE_FAST)); g_mutex_unlock(ewin->emu->lcd_mutex); /* Render buffer to the screen */ win = gtk_widget_get_window(w); style = gtk_widget_get_style(w); gdk_draw_indexed_image(win, style->fg_gc[GTK_STATE_NORMAL], 0, 0, alloc.width, alloc.height, GDK_RGB_DITHER_NONE, ewin->lcd_image_buf, alloc.width, ewin->lcd_cmap); return TRUE; } /* Set the color palette for drawing the emulated LCD. */ static void screen_restyle(GtkWidget* w, GtkStyle* oldstyle G_GNUC_UNUSED, TilemEmulatorWindow* ewin) { dword* palette; GtkStyle *style; int r_dark, g_dark, b_dark; int r_light, g_light, b_light; double gamma = 2.2; if (!ewin->skin) { /* no skin -> use standard GTK colors */ style = gtk_widget_get_style(w); r_dark = style->text[GTK_STATE_NORMAL].red / 257; g_dark = style->text[GTK_STATE_NORMAL].green / 257; b_dark = style->text[GTK_STATE_NORMAL].blue / 257; r_light = style->base[GTK_STATE_NORMAL].red / 257; g_light = style->base[GTK_STATE_NORMAL].green / 257; b_light = style->base[GTK_STATE_NORMAL].blue / 257; } else { /* use skin colors */ r_dark = ((ewin->skin->lcd_black >> 16) & 0xff); g_dark = ((ewin->skin->lcd_black >> 8) & 0xff); b_dark = (ewin->skin->lcd_black & 0xff); r_light = ((ewin->skin->lcd_white >> 16) & 0xff); g_light = ((ewin->skin->lcd_white >> 8) & 0xff); b_light = (ewin->skin->lcd_white & 0xff); } /* Generate a new palette, and convert it into GDK format */ if (ewin->lcd_cmap) gdk_rgb_cmap_free(ewin->lcd_cmap); palette = tilem_color_palette_new(r_light, g_light, b_light, r_dark, g_dark, b_dark, gamma); ewin->lcd_cmap = gdk_rgb_cmap_new(palette, 256); tilem_free(palette); gtk_widget_queue_draw(ewin->lcd); } static void skin_size_allocate(GtkWidget *widget, GtkAllocation *alloc, gpointer data) { TilemEmulatorWindow *ewin = data; int rawwidth, rawheight, scaledwidth, scaledheight; int lcdleft, lcdright, lcdtop, lcdbottom; double rx, ry, r; g_return_if_fail(ewin->skin != NULL); rawwidth = gdk_pixbuf_get_width(ewin->skin->raw); rawheight = gdk_pixbuf_get_height(ewin->skin->raw); rx = (double) alloc->width / rawwidth; ry = (double) alloc->height / rawheight; r = MIN(rx, ry); scaledwidth = rawwidth * r; scaledheight = rawheight * r; if (ewin->skin->width == scaledwidth && ewin->skin->height == scaledheight) return; ewin->skin->width = scaledwidth; ewin->skin->height = scaledheight; ewin->skin->sx = ewin->skin->sy = 1.0 / r; if (ewin->skin->image) g_object_unref(ewin->skin->image); ewin->skin->image = gdk_pixbuf_scale_simple(ewin->skin->raw, scaledwidth, scaledheight, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(ewin->background), ewin->skin->image); lcdleft = ewin->skin->lcd_pos.left * r + 0.5; lcdright = ewin->skin->lcd_pos.right * r + 0.5; lcdtop = ewin->skin->lcd_pos.top * r + 0.5; lcdbottom = ewin->skin->lcd_pos.bottom * r + 0.5; gtk_widget_set_size_request(ewin->lcd, MAX(lcdright - lcdleft, 1), MAX(lcdbottom - lcdtop, 1)); gtk_layout_move(GTK_LAYOUT(widget), ewin->lcd, lcdleft, lcdtop); ewin->zoom_factor = r / ewin->base_zoom; if (ewin->zoom_factor <= 1.0) ewin->zoom_factor = 1.0; } static void noskin_size_allocate(G_GNUC_UNUSED GtkWidget *widget, GtkAllocation *alloc, gpointer data) { TilemEmulatorWindow *ewin = data; int lcdwidth, lcdheight; g_return_if_fail(ewin->emu->calc != NULL); lcdwidth = ewin->emu->calc->hw.lcdwidth; lcdheight = ewin->emu->calc->hw.lcdheight; if (alloc->width > alloc->height) ewin->zoom_factor = (gdouble) alloc->width / lcdwidth; else ewin->zoom_factor = (gdouble) alloc->height / lcdheight; if (ewin->zoom_factor <= 1.0) ewin->zoom_factor = 1.0; } /* Used when you load another skin */ void redraw_screen(TilemEmulatorWindow *ewin) { GtkWidget *pImage; GtkWidget *emuwin; int lcdwidth, lcdheight; int screenwidth, screenheight; int minwidth, minheight, defwidth, defheight, curwidth, curheight; double sx, sy, s, a1, a2; GError *err = NULL; if (ewin->skin) { skin_unload(ewin->skin); g_free(ewin->skin); } if (ewin->skin_disabled || !ewin->skin_file_name) { ewin->skin = NULL; } else { ewin->skin = g_new0(SKIN_INFOS, 1); if (skin_load(ewin->skin, ewin->skin_file_name, &err)) { skin_unload(ewin->skin); ewin->skin = NULL; } } if (ewin->emu->calc) { lcdwidth = ewin->emu->calc->hw.lcdwidth; lcdheight = ewin->emu->calc->hw.lcdheight; } else { lcdwidth = lcdheight = 1; } if (ewin->lcd) gtk_widget_destroy(ewin->lcd); if (ewin->background) gtk_widget_destroy(ewin->background); if (ewin->layout) gtk_widget_destroy(ewin->layout); /* create LCD widget */ ewin->lcd = gtk_drawing_area_new(); gtk_widget_set_double_buffered(ewin->lcd, FALSE); /* create background image and layout */ if (ewin->skin) { ewin->layout = gtk_layout_new(NULL, NULL); pImage = gtk_image_new(); gtk_layout_put(GTK_LAYOUT(ewin->layout), pImage, 0, 0); ewin->background = pImage; screenwidth = (ewin->skin->lcd_pos.right - ewin->skin->lcd_pos.left); screenheight = (ewin->skin->lcd_pos.bottom - ewin->skin->lcd_pos.top); gtk_widget_set_size_request(ewin->lcd, screenwidth, screenheight); gtk_layout_put(GTK_LAYOUT(ewin->layout), ewin->lcd, ewin->skin->lcd_pos.left, ewin->skin->lcd_pos.top); g_signal_connect(ewin->layout, "size-allocate", G_CALLBACK(skin_size_allocate), ewin); emuwin = ewin->layout; defwidth = ewin->skin->width; defheight = ewin->skin->height; sx = (double) lcdwidth / screenwidth; sy = (double) lcdheight / screenheight; s = MAX(sx, sy); minwidth = defwidth * s + 0.5; minheight = defheight * s + 0.5; ewin->base_zoom = s; } else { ewin->layout = NULL; ewin->background = NULL; emuwin = ewin->lcd; g_signal_connect(ewin->lcd, "size-allocate", G_CALLBACK(noskin_size_allocate), ewin); defwidth = minwidth = lcdwidth; defheight = minheight = lcdheight; ewin->base_zoom = 1.0; } curwidth = defwidth * ewin->base_zoom * ewin->zoom_factor + 0.5; curheight = defheight * ewin->base_zoom * ewin->zoom_factor + 0.5; gtk_widget_set_can_focus(emuwin, TRUE); gtk_widget_add_events(emuwin, (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_DROP_FINISHED | GDK_DRAG_MOTION)); g_signal_connect(ewin->lcd, "expose-event", G_CALLBACK(screen_repaint), ewin); g_signal_connect(ewin->lcd, "style-set", G_CALLBACK(screen_restyle), ewin); g_signal_connect(emuwin, "button-press-event", G_CALLBACK(mouse_press_event), ewin); g_signal_connect(emuwin, "motion-notify-event", G_CALLBACK(pointer_motion_event), ewin); g_signal_connect(emuwin, "button-release-event", G_CALLBACK(mouse_release_event), ewin); g_signal_connect(emuwin, "popup-menu", G_CALLBACK(popup_menu_event), ewin); /* FIXME: this is rather broken; GTK_DEST_DEFAULT_ALL sends a successful "finished" message to any drop that matches the list of targets. Files/URIs we can't accept should be rejected, and we shouldn't send the "finished" message until it's actually finished. */ gtk_drag_dest_set(emuwin, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets(emuwin); g_signal_connect(emuwin, "drag-data-received", G_CALLBACK(drag_data_received), ewin); /* Hint calculation assumes the emulator is the only thing in the window; if other widgets are added, this will have to change accordingly */ ewin->geomhints.min_width = minwidth; ewin->geomhints.min_height = minheight; a1 = (double) minwidth / minheight; a2 = (double) defwidth / defheight; ewin->geomhints.min_aspect = MIN(a1, a2) - 0.0001; ewin->geomhints.max_aspect = MAX(a1, a2) + 0.0001; ewin->geomhintmask = (GDK_HINT_MIN_SIZE | GDK_HINT_ASPECT); /* If the window is already realized, set the hints now, so that the WM will see the new hints before we try to resize the window */ set_size_hints(ewin->window, ewin); gtk_widget_set_size_request(emuwin, minwidth, minheight); gtk_container_add(GTK_CONTAINER(ewin->window), emuwin); if (!window_maximized(ewin)) gtk_window_resize(GTK_WINDOW(ewin->window), curwidth, curheight); gtk_widget_show_all(emuwin); if (err) { messagebox01(GTK_WINDOW(ewin->window), GTK_MESSAGE_ERROR, "Unable to load skin", "%s", err->message); g_error_free(err); } } static void window_destroy(G_GNUC_UNUSED GtkWidget *w, gpointer data) { TilemEmulatorWindow *ewin = data; if (!window_maximized(ewin)) tilem_config_set("settings", "zoom/r", ewin->zoom_factor, NULL); ewin->window = ewin->layout = ewin->lcd = ewin->background = NULL; } TilemEmulatorWindow *tilem_emulator_window_new(TilemCalcEmulator *emu) { TilemEmulatorWindow *ewin; g_return_val_if_fail(emu != NULL, NULL); ewin = g_slice_new0(TilemEmulatorWindow); ewin->emu = emu; tilem_config_get("settings", "skin_disabled/b", &ewin->skin_disabled, "smooth_scaling/b=1", &ewin->lcd_smooth_scale, "zoom/r=2.0", &ewin->zoom_factor, NULL); if (ewin->zoom_factor <= 1.0) ewin->zoom_factor = 1.0; /* Create the window */ ewin->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(ewin->window, "window-state-event", G_CALLBACK(window_state_changed), ewin); g_signal_connect(ewin->window, "destroy", G_CALLBACK(window_destroy), ewin); g_signal_connect_after(ewin->window, "check-resize", G_CALLBACK(set_size_hints), ewin); gtk_widget_add_events(ewin->window, (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)); g_signal_connect(ewin->window, "key-press-event", G_CALLBACK(key_press_event), ewin); g_signal_connect(ewin->window, "key-release-event", G_CALLBACK(key_release_event), ewin); build_menu(ewin); tilem_emulator_window_calc_changed(ewin); return ewin; } void tilem_emulator_window_free(TilemEmulatorWindow *ewin) { g_return_if_fail(ewin != NULL); if (ewin->lcd) gtk_widget_destroy(ewin->lcd); if (ewin->background) gtk_widget_destroy(ewin->background); if (ewin->layout) gtk_widget_destroy(ewin->layout); if (ewin->window) gtk_widget_destroy(ewin->window); if (ewin->popup_menu) gtk_widget_destroy(ewin->popup_menu); if (ewin->actions) g_object_unref(ewin->actions); g_free(ewin->lcd_image_buf); g_free(ewin->skin_file_name); if (ewin->skin) { skin_unload(ewin->skin); g_free(ewin->skin); } if (ewin->lcd_cmap) gdk_rgb_cmap_free(ewin->lcd_cmap); g_slice_free(TilemEmulatorWindow, ewin); } void tilem_emulator_window_set_skin(TilemEmulatorWindow *ewin, const char *filename) { g_return_if_fail(ewin != NULL); g_free(ewin->skin_file_name); if (filename) ewin->skin_file_name = g_strdup(filename); else ewin->skin_file_name = NULL; redraw_screen(ewin); } /* Switch between skin and LCD-only mode */ void tilem_emulator_window_set_skin_disabled(TilemEmulatorWindow *ewin, gboolean disabled) { g_return_if_fail(ewin != NULL); if (ewin->skin_disabled != !!disabled) { ewin->skin_disabled = !!disabled; redraw_screen(ewin); } } void tilem_emulator_window_calc_changed(TilemEmulatorWindow *ewin) { const char *model; char *name = NULL, *path; g_return_if_fail(ewin != NULL); g_return_if_fail(ewin->emu != NULL); g_free(ewin->skin_file_name); ewin->skin_file_name = NULL; if (!ewin->emu->calc) return; model = ewin->emu->calc->hw.name; tilem_config_get(model, "skin/f", &name, NULL); if (!name) name = g_strdup_printf("%s.skn", model); if (!g_path_is_absolute(name)) { path = get_shared_file_path("skins", name, NULL); tilem_emulator_window_set_skin(ewin, path); g_free(path); } else { tilem_emulator_window_set_skin(ewin, name); } g_free(name); } void tilem_emulator_window_refresh_lcd(TilemEmulatorWindow *ewin) { g_return_if_fail(ewin != NULL); if (ewin->lcd) gtk_widget_queue_draw(ewin->lcd); } /* Display the lcd image into the terminal */ void display_lcdimage_into_terminal(TilemEmulatorWindow *ewin) { int width, height; guchar* lcddata; int x, y; char c; width = ewin->emu->calc->hw.lcdwidth; height = ewin->emu->calc->hw.lcdheight; FILE* lcd_content_file; /* Alloc mmem */ lcddata = g_new(guchar, (width / 8) * height); /* Get the lcd content using the function 's pointer from Benjamin's core */ (*ewin->emu->calc->hw.get_lcd)(ewin->emu->calc, lcddata); /* Print a little demo just for fun;) */ printf("\n\n\n"); printf(" r rr r rrrrr rrr r rrrrr r r rr r rr r \n"); printf(" r r r r r r r r rr rr r r r r r r r \n"); printf(" r r r r r r r r r r r r r r r r r r \n"); printf("rrrrr r r r r r r rrrr r r r r r r r rrrrr rrrrr rrrrr \n"); printf(" r r r r r r r r r r rrr r r r r r r \n"); printf(" r r r r r r r r r r r r r r r r \n"); printf(" r rr r r rrr rrrrr rrrrr r r r rr r \n"); printf("\n(Here is just a sample...)\n\n"); /* Request user to know which char user wants */ printf("Which char to display FOR BLACK?\n"); scanf("%c", &c); /* Choose wich char for the black */ //printf("Which char to display FOR GRAY ?\n"); //scanf("%c", &b); /* Choose wich char for the black */ lcd_content_file = g_fopen("lcd_content.txt", "w"); printf("\n\n\n### LCD CONTENT ###\n\n\n\n"); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { /*printf("%d ", lcddata[y * width + x]); */ if (lcddata[(y * width + x) / 8] & (0x80 >> (x % 8))) { printf("%c", c); if(lcd_content_file != NULL) fprintf(lcd_content_file,"%c", c); } else { printf("%c", ' '); if(lcd_content_file != NULL) fprintf(lcd_content_file,"%c", ' '); } } printf("\n"); if(lcd_content_file != NULL) fprintf(lcd_content_file,"%c", '\n'); } if(lcd_content_file != NULL) { fclose(lcd_content_file); printf("\n### END ###\n\nSaved into lcd_content.txt\n"); } } tilem-2.0/gui/emuwin.h000066400000000000000000000045571220200411600147250ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2012 Benjamin Moody * * 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 3 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, see . */ /* Root window view (widgets and flags) */ typedef struct _TilemEmulatorWindow { TilemCalcEmulator *emu; GtkWidget *window; /* The top level window */ GtkWidget *layout; /* Layout */ GtkWidget *lcd; GtkWidget *background; GtkWidget *popup_menu; GtkActionGroup *actions; GdkGeometry geomhints; GdkWindowHints geomhintmask; byte* lcd_image_buf; int lcd_image_width; int lcd_image_height; GdkRgbCmap* lcd_cmap; gboolean lcd_smooth_scale; char *skin_file_name; SKIN_INFOS *skin; gboolean skin_disabled; /* A flag to know if skinless or not */ gdouble base_zoom; gdouble zoom_factor; GdkWindowState window_state; int mouse_key; /* Key currently pressed by mouse button */ /* Host keycode used to activate each key, if any */ int keypress_keycodes[64]; int sequence_keycode; } TilemEmulatorWindow; /* Create a new TilemEmulatorWindow. */ TilemEmulatorWindow *tilem_emulator_window_new(TilemCalcEmulator *emu); /* Free a TilemEmulatorWindow. */ void tilem_emulator_window_free(TilemEmulatorWindow *ewin); /* Load a skin file. */ void tilem_emulator_window_set_skin(TilemEmulatorWindow *ewin, const char *filename); /* Enable or disable skin. */ void tilem_emulator_window_set_skin_disabled(TilemEmulatorWindow *ewin, gboolean disabled); /* New calculator loaded. */ void tilem_emulator_window_calc_changed(TilemEmulatorWindow *ewin); /* Redraw LCD contents. */ void tilem_emulator_window_refresh_lcd(TilemEmulatorWindow *ewin); /* Prompt for a ROM file to open */ gboolean tilem_emulator_window_prompt_open_rom(TilemEmulatorWindow *ewin); tilem-2.0/gui/event.c000066400000000000000000000262261220200411600145320ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "filedlg.h" /* Table for translating skin-file key number (based on actual position, and defined by the VTI/TiEmu file formats) into a scancode. Note that the TILEM_KEY_* constants are named according to the TI-83 keypad layout; other models use different names for the keys, but the same scancodes. */ static const int keycode_map[] = { TILEM_KEY_YEQU, TILEM_KEY_WINDOW, TILEM_KEY_ZOOM, TILEM_KEY_TRACE, TILEM_KEY_GRAPH, TILEM_KEY_2ND, TILEM_KEY_MODE, TILEM_KEY_DEL, TILEM_KEY_LEFT, TILEM_KEY_RIGHT, TILEM_KEY_UP, TILEM_KEY_DOWN, TILEM_KEY_ALPHA, TILEM_KEY_GRAPHVAR, TILEM_KEY_STAT, TILEM_KEY_MATH, TILEM_KEY_MATRIX, TILEM_KEY_PRGM, TILEM_KEY_VARS, TILEM_KEY_CLEAR, TILEM_KEY_RECIP, TILEM_KEY_SIN, TILEM_KEY_COS, TILEM_KEY_TAN, TILEM_KEY_POWER, TILEM_KEY_SQUARE, TILEM_KEY_COMMA, TILEM_KEY_LPAREN, TILEM_KEY_RPAREN, TILEM_KEY_DIV, TILEM_KEY_LOG, TILEM_KEY_7, TILEM_KEY_8, TILEM_KEY_9, TILEM_KEY_MUL, TILEM_KEY_LN, TILEM_KEY_4, TILEM_KEY_5, TILEM_KEY_6, TILEM_KEY_SUB, TILEM_KEY_STORE, TILEM_KEY_1, TILEM_KEY_2, TILEM_KEY_3, TILEM_KEY_ADD, TILEM_KEY_ON, TILEM_KEY_0, TILEM_KEY_DECPNT, TILEM_KEY_CHS, TILEM_KEY_ENTER }; /* Find the keycode for the key (if any) at the given position. If the keys overlap, choose the "nearest" (according to Manhattan distance to the midpoint.) */ static int scan_click(const SKIN_INFOS* skin, double x, double y) { guint ix, iy, nearest = 0, i; int dx, dy, d, best_d = G_MAXINT; if (!skin) return 0; ix = (x * skin->sx + 0.5); iy = (y * skin->sy + 0.5); for (i = 0; i < G_N_ELEMENTS(keycode_map); i++) { if (ix >= skin->keys_pos[i].left && ix < skin->keys_pos[i].right && iy >= skin->keys_pos[i].top && iy < skin->keys_pos[i].bottom) { dx = (skin->keys_pos[i].left + skin->keys_pos[i].right - 2 * ix); dy = (skin->keys_pos[i].top + skin->keys_pos[i].bottom - 2 * iy); d = ABS(dx) + ABS(dy); if (d < best_d) { best_d = d; nearest = keycode_map[i]; } } } return nearest; } /* Retrieve pointer coordinates for an input device. */ static void get_device_pointer(GdkWindow *win, GdkDevice *dev, gdouble *x, gdouble *y, GdkModifierType *mask) { gdouble *axes; int i; axes = g_new(gdouble, dev->num_axes); gdk_device_get_state(dev, win, axes, mask); for (i = 0; i < dev->num_axes; i++) { if (x && dev->axes[i].use == GDK_AXIS_X) *x = axes[i]; else if (y && dev->axes[i].use == GDK_AXIS_Y) *y = axes[i]; } g_free(axes); } /* Show a nice GtkAboutDialog */ void show_about() { GtkWidget *dialog = gtk_about_dialog_new(); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "2.0"); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "(c) Benjamin Moody\n(c) Thibault Duponchelle\n(c) Luc Bruant\n"); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "TilEm is a TI Linux Emulator.\n It emulates all current z80 models.\n TI73, TI76, TI81, TI82, TI83(+)(SE), TI84+(SE), TI85 and TI86 ;D"); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://lpg.ticalc.org/prj_tilem/"); /* Add the logo */ char* tilem_ban = get_shared_file_path("pixs", "tilem_ban.png", NULL); if(tilem_ban) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(tilem_ban, NULL); gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf); g_object_unref(pixbuf), pixbuf = NULL; } gtk_dialog_run(GTK_DIALOG (dialog)); gtk_widget_destroy(dialog); } void launch_debugger(TilemEmulatorWindow *ewin) { if (!ewin->emu->dbg) ewin->emu->dbg = tilem_debugger_new(ewin->emu); tilem_debugger_show(ewin->emu->dbg); } /* Press a key, ensuring that at most one key is "pressed" at a time due to this function (if pointer moves or is released, we don't want the old key held down.) FIXME: on multi-pointer displays, allow each input device to act separately */ static void press_mouse_key(TilemEmulatorWindow* ewin, int key) { if (ewin->mouse_key == key) return; tilem_calc_emulator_release_key(ewin->emu, ewin->mouse_key); tilem_calc_emulator_press_key(ewin->emu, key); ewin->mouse_key = key; } /* Mouse button pressed */ gboolean mouse_press_event(G_GNUC_UNUSED GtkWidget* w, GdkEventButton *event, gpointer data) { TilemEmulatorWindow* ewin = data; int key; key = scan_click(ewin->skin, event->x, event->y); if (event->button == 1) { /* button 1: press key until button is released or pointer moves away */ press_mouse_key(ewin, key); return TRUE; } else if (event->button == 2) { /* button 2: hold key down permanently */ tilem_calc_emulator_press_key(ewin->emu, key); return TRUE; } else if (event->button == 3) { /* button 3: popup menu */ gtk_menu_popup(GTK_MENU(ewin->popup_menu), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } else return FALSE; } /* Mouse pointer moved */ gboolean pointer_motion_event(G_GNUC_UNUSED GtkWidget* w, GdkEventMotion *event, gpointer data) { TilemEmulatorWindow* ewin = data; int key; if (event->is_hint) get_device_pointer(event->window, event->device, &event->x, &event->y, &event->state); if (event->state & GDK_BUTTON1_MASK) key = scan_click(ewin->skin, event->x, event->y); else key = 0; press_mouse_key(ewin, key); return FALSE; } /* Mouse button released */ gboolean mouse_release_event(G_GNUC_UNUSED GtkWidget* w, GdkEventButton *event, gpointer data) { TilemEmulatorWindow* ewin = data; if (event->button == 1) press_mouse_key(ewin, 0); return FALSE; } /* Find key binding for the given keysym and modifiers */ static TilemKeyBinding* find_key_binding_for_keysym(TilemCalcEmulator* emu, guint keyval, GdkModifierType mods) { int i; for (i = 0; i < emu->nkeybindings; i++) if (keyval == emu->keybindings[i].keysym && mods == emu->keybindings[i].modifiers) return &emu->keybindings[i]; return NULL; } /* Find key binding matching the given event */ static TilemKeyBinding* find_key_binding(TilemCalcEmulator* emu, GdkEventKey* event) { GdkDisplay *dpy; GdkKeymap *km; guint keyval; GdkModifierType consumed, mods; TilemKeyBinding *kb; dpy = gdk_drawable_get_display(event->window); km = gdk_keymap_get_for_display(dpy); /* determine the relevant set of modifiers */ gdk_keymap_translate_keyboard_state(km, event->hardware_keycode, event->state, event->group, &keyval, NULL, NULL, &consumed); mods = (event->state & ~consumed & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)); if (event->state & GDK_LOCK_MASK && (kb = find_key_binding_for_keysym(emu, keyval, mods | GDK_LOCK_MASK))) { return kb; } return find_key_binding_for_keysym(emu, keyval, mods); } /* Key-press event */ gboolean key_press_event(G_GNUC_UNUSED GtkWidget* w, GdkEventKey* event, gpointer data) { TilemEmulatorWindow *ewin = data; TilemKeyBinding *kb; int i, key; unsigned int hwkey; /* Ignore repeating keys */ for (i = 0; i < 64; i++) if (ewin->keypress_keycodes[i] == event->hardware_keycode) return TRUE; if (ewin->sequence_keycode == event->hardware_keycode) return TRUE; if (!(kb = find_key_binding(ewin->emu, event))) return FALSE; hwkey = event->hardware_keycode; if (kb->nscancodes == 1) { /* if queue is empty, just press the key; otherwise add it to the queue */ key = kb->scancodes[0]; if (tilem_calc_emulator_press_or_queue(ewin->emu, key)) ewin->sequence_keycode = hwkey; else ewin->keypress_keycodes[key] = hwkey; } else { tilem_calc_emulator_queue_keys(ewin->emu, kb->scancodes, kb->nscancodes); ewin->sequence_keycode = hwkey; } return TRUE; } /* Key-release event */ gboolean key_release_event(G_GNUC_UNUSED GtkWidget* w, GdkEventKey* event, gpointer data) { TilemEmulatorWindow *ewin = data; int i; /* Check if the key that was just released was one that activated a calculator keypress. (Do not try to look up event->keyval; modifiers may have changed since the key was pressed.) */ for (i = 0; i < 64; i++) { if (ewin->keypress_keycodes[i] == event->hardware_keycode) { tilem_calc_emulator_release_key(ewin->emu, i); ewin->keypress_keycodes[i] = 0; } } if (ewin->sequence_keycode == event->hardware_keycode) { tilem_calc_emulator_release_queued_key(ewin->emu); ewin->sequence_keycode = 0; } return FALSE; } static void place_menu(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) { GtkWidget *w = data; GdkWindow *win; GdkScreen *screen; int n; win = gtk_widget_get_window(w); gdk_window_get_origin(win, x, y); screen = gdk_drawable_get_screen(win); n = gdk_screen_get_monitor_at_point(screen, *x, *y); gtk_menu_set_monitor(menu, n); *push_in = FALSE; } /* Pop up menu on main window */ gboolean popup_menu_event(GtkWidget* w, gpointer data) { TilemEmulatorWindow *ewin = data; gtk_menu_popup(GTK_MENU(ewin->popup_menu), NULL, NULL, &place_menu, w, 0, gtk_get_current_event_time()); return TRUE; } /* Callback function for the drag and drop event */ void drag_data_received(G_GNUC_UNUSED GtkWidget *win, G_GNUC_UNUSED GdkDragContext *dc, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, GtkSelectionData *seldata, G_GNUC_UNUSED guint info, G_GNUC_UNUSED guint t, gpointer data) { TilemEmulatorWindow *ewin = data; gchar **uris, **filenames; gint i, j, n; uris = gtk_selection_data_get_uris(seldata); if (!uris) return; n = g_strv_length(uris); filenames = g_new0(gchar *, n + 1); for (i = j = 0; i < n; i++) { filenames[j] = g_filename_from_uri(uris[i], NULL, NULL); if (filenames[j]) j++; } filenames[j] = NULL; load_files(ewin, filenames); g_strfreev(filenames); } tilem-2.0/gui/filedlg.c000066400000000000000000000632631220200411600150210ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * Copyright (c) 2011 Thibault Duponchelle // FIXME : My work is based on yours benjamin. Should I put "portions"?! Or something else ? * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "gtk-compat.h" #include "filedlg.h" #ifdef GDK_WINDOWING_WIN32 # define WIN32_LEAN_AND_MEAN # include # include # include # include # include # ifndef OPENFILENAME_SIZE_VERSION_400 # define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAMEA) # endif struct fcinfo { const char *title; gboolean save; HWND parent_window; char *filename; char *dirname; char *extension; const char *filters; unsigned int flags; }; #define BUFFER_SIZE 32768 static char * file_chooser_main(const struct fcinfo *fci) { if (G_WIN32_HAVE_WIDECHAR_API()) { OPENFILENAMEW ofnw; wchar_t *titlew, *filterw, *initdirw, *defextw; wchar_t filenamew[BUFFER_SIZE + 1]; wchar_t *p; int result; int i; titlew = g_utf8_to_utf16(fci->title, -1, 0, 0, 0); filterw = g_utf8_to_utf16(fci->filters, -1, 0, 0, 0); for (i = 0; filterw[i]; i++) if (filterw[i] == '\n') filterw[i] = 0; memset(&ofnw, 0, sizeof(ofnw)); ofnw.lStructSize = OPENFILENAME_SIZE_VERSION_400; ofnw.hwndOwner = fci->parent_window; ofnw.lpstrTitle = titlew; ofnw.lpstrFilter = filterw; ofnw.nFilterIndex = 1; ofnw.lpstrFile = filenamew; ofnw.nMaxFile = BUFFER_SIZE; memset(filenamew, 0, sizeof(filenamew)); if (fci->filename) { p = g_utf8_to_utf16(fci->filename, -1, 0, 0, 0); if (p) { wcsncpy(filenamew, p, BUFFER_SIZE); g_free(p); } } if (fci->dirname) initdirw = g_utf8_to_utf16(fci->dirname, -1, 0, 0, 0); else initdirw = NULL; if (fci->extension) defextw = g_utf8_to_utf16(fci->extension, -1, 0, 0, 0); else defextw = NULL; ofnw.lpstrInitialDir = initdirw; ofnw.lpstrDefExt = defextw; ofnw.Flags = fci->flags; result = (fci->save ? GetSaveFileNameW(&ofnw) : GetOpenFileNameW(&ofnw)); g_free(titlew); g_free(filterw); g_free(initdirw); g_free(defextw); if (!result) return NULL; if ((fci->flags & OFN_ALLOWMULTISELECT)) { for (i = 0; i < BUFFER_SIZE; i++) { if (filenamew[i] == 0 && filenamew[i + 1] == 0) break; else if (filenamew[i] == '/') filenamew[i] = '\\'; else if (filenamew[i] == 0) filenamew[i] = '/'; } } return g_utf16_to_utf8(filenamew, -1, 0, 0, 0); } else { OPENFILENAMEA ofna; char *titlel, *filterl, *initdirl, *defextl; char filenamel[BUFFER_SIZE + 1]; char *p; int result; int i; titlel = g_locale_from_utf8(fci->title, -1, 0, 0, 0); filterl = g_locale_from_utf8(fci->filters, -1, 0, 0, 0); for (i = 0; filterl[i]; i++) if (filterl[i] == '\n') filterl[i] = 0; memset(&ofna, 0, sizeof(ofna)); ofna.lStructSize = OPENFILENAME_SIZE_VERSION_400; ofna.hwndOwner = fci->parent_window; ofna.lpstrTitle = titlel; ofna.lpstrFilter = filterl; ofna.nFilterIndex = 1; ofna.lpstrFile = filenamel; ofna.nMaxFile = BUFFER_SIZE; memset(filenamel, 0, sizeof(filenamel)); if (fci->filename) { p = g_locale_from_utf8(fci->filename, -1, 0, 0, 0); if (p) { strncpy(filenamel, p, BUFFER_SIZE); g_free(p); } } if (fci->dirname) initdirl = g_locale_from_utf8(fci->dirname, -1, 0, 0, 0); else initdirl = NULL; if (fci->extension) defextl = g_locale_from_utf8(fci->extension, -1, 0, 0, 0); else defextl = NULL; ofna.lpstrInitialDir = initdirl; ofna.lpstrDefExt = defextl; ofna.Flags = fci->flags; result = (fci->save ? GetSaveFileNameA(&ofna) : GetOpenFileNameA(&ofna)); g_free(titlel); g_free(filterl); g_free(initdirl); g_free(defextl); if (!result) return NULL; if ((fci->flags & OFN_ALLOWMULTISELECT)) { for (i = 0; i < BUFFER_SIZE; i++) { if (filenamel[i] == 0 && filenamel[i + 1] == 0) break; else if (filenamel[i] == '/') filenamel[i] = '\\'; else if (filenamel[i] == 0) filenamel[i] = '/'; } } return g_locale_to_utf8(filenamel, -1, 0, 0, 0); } } static gboolean wakeup(G_GNUC_UNUSED gpointer data) { gtk_main_quit(); return FALSE; } static gpointer file_chooser_thread(gpointer data) { struct fcinfo *fci = data; gpointer res = file_chooser_main(fci); g_idle_add(wakeup, NULL); return res; } static char * build_filter_string(const char *desc1, const char *pattern1, va_list ap) { GString *str = g_string_new(NULL); while (desc1 && pattern1) { if (pattern1[0]) { g_string_append(str, desc1); g_string_append_c(str, '\n'); g_string_append(str, pattern1); g_string_append_c(str, '\n'); } desc1 = va_arg(ap, char *); if (!desc1) break; pattern1 = va_arg(ap, char *); } return g_string_free(str, FALSE); } static char ** run_file_chooser1(const char *title, GtkWindow *parent, gboolean save, gboolean multiple, const char *suggest_name, const char *suggest_dir, const char *filters) { struct fcinfo fci; GThread *thread; GtkWidget *dummy; GdkWindow *pwin; char *fname, *p, *dir; char **result; int i; if (!g_thread_supported()) g_thread_init(NULL); fci.title = title; fci.save = save; if (parent && (pwin = gtk_widget_get_window(GTK_WIDGET(parent)))) fci.parent_window = GDK_WINDOW_HWND(pwin); else fci.parent_window = NULL; if (suggest_name && suggest_dir) { fci.filename = g_build_filename(suggest_dir, suggest_name, NULL); fci.dirname = NULL; } else if (suggest_name) { fci.filename = g_strdup(suggest_name); fci.dirname = NULL; } else if (suggest_dir) { fci.filename = NULL; fci.dirname = g_strdup(suggest_dir); } else { fci.filename = fci.dirname = NULL; } if (suggest_name && (p = strrchr(suggest_name, '.'))) fci.extension = g_strdup(p + 1); else fci.extension = NULL; fci.filters = filters; fci.flags = (OFN_HIDEREADONLY | OFN_EXPLORER); if (save) fci.flags |= OFN_OVERWRITEPROMPT; else { fci.flags |= OFN_FILEMUSTEXIST; if (multiple) fci.flags |= OFN_ALLOWMULTISELECT; } if ((thread = g_thread_create(file_chooser_thread, &fci, TRUE, NULL))) { dummy = gtk_invisible_new(); gtk_grab_add(dummy); gtk_main(); fname = g_thread_join(thread); gtk_widget_destroy(dummy); } else { fname = file_chooser_main(&fci); } g_free(fci.filename); g_free(fci.dirname); g_free(fci.extension); if (!fname) { return NULL; } else if (multiple && (p = strchr(fname, '/'))) { dir = g_strndup(fname, p - fname); result = g_strsplit(p + 1, "/", -1); for (i = 0; result[i]; i++) { p = result[i]; result[i] = g_build_filename(dir, p, NULL); g_free(p); } g_free(fname); return result; } else { result = g_new(char *, 2); result[0] = fname; result[1] = NULL; return result; } } static char ** run_file_chooser(const char *title, GtkWindow *parent, gboolean save, gboolean multiple, const char *suggest_name, const char *suggest_dir, const char *desc1, const char *pattern1, va_list ap) { char *filters; char **result; filters = build_filter_string(desc1, pattern1, ap); result = run_file_chooser1(title, parent, save, multiple, suggest_name, suggest_dir, filters); g_free(filters); return result; } struct dcinfo { const char *title; HWND parent_window; wchar_t *suggest_dir_w; char *suggest_dir_l; }; static int CALLBACK dir_chooser_callback(HWND hwnd, UINT uMsg, G_GNUC_UNUSED LPARAM lParam, LPARAM lpData) { const struct dcinfo *dci = (struct dcinfo*) lpData; if (uMsg != BFFM_INITIALIZED) return 0; if (G_WIN32_HAVE_WIDECHAR_API()) SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) dci->suggest_dir_w); else SendMessageA(hwnd, BFFM_SETSELECTIONA, TRUE, (LPARAM) dci->suggest_dir_l); return 0; } static char * dir_chooser_main(const struct dcinfo *dci) { LPITEMIDLIST idl; char *result = NULL; CoInitialize(NULL); if (G_WIN32_HAVE_WIDECHAR_API()) { BROWSEINFOW bifw; wchar_t dirnamew[MAX_PATH + 1]; memset(&bifw, 0, sizeof(bifw)); bifw.hwndOwner = dci->parent_window; bifw.lpszTitle = g_utf8_to_utf16(dci->title, -1, 0, 0, 0); bifw.ulFlags = (BIF_RETURNONLYFSDIRS | BIF_USENEWUI); bifw.lpfn = &dir_chooser_callback; bifw.lParam = (LPARAM) dci; idl = SHBrowseForFolderW(&bifw); if (idl && SHGetPathFromIDListW(idl, dirnamew)) result = g_utf16_to_utf8(dirnamew, -1, 0, 0, 0); } else { BROWSEINFOA bifa; char dirnamel[MAX_PATH + 1]; memset(&bifa, 0, sizeof(bifa)); bifa.hwndOwner = dci->parent_window; bifa.lpszTitle = g_locale_from_utf8(dci->title, -1, 0, 0, 0); bifa.ulFlags = (BIF_RETURNONLYFSDIRS | BIF_USENEWUI); bifa.lpfn = &dir_chooser_callback; bifa.lParam = (LPARAM) dci; idl = SHBrowseForFolderA(&bifa); if (idl && SHGetPathFromIDListA(idl, dirnamel)) result = g_locale_to_utf8(dirnamel, -1, 0, 0, 0); } if (idl) CoTaskMemFree(idl); CoUninitialize(); return result; } static gpointer dir_chooser_thread(gpointer data) { struct dcinfo *dci = data; gpointer res = dir_chooser_main(dci); g_idle_add(wakeup, NULL); return res; } static char* run_dir_chooser(G_GNUC_UNUSED const char *title, GtkWindow *parent, G_GNUC_UNUSED gboolean save, const char *suggest_dir) { struct dcinfo dci; GdkWindow *pwin; GThread *thread; GtkWidget *dummy; char *dname; if (!g_thread_supported()) g_thread_init(NULL); dci.title = "Select a folder to save received files."; if (parent && (pwin = gtk_widget_get_window(GTK_WIDGET(parent)))) dci.parent_window = GDK_WINDOW_HWND(pwin); else dci.parent_window = NULL; if (suggest_dir) { dci.suggest_dir_w = g_utf8_to_utf16(suggest_dir, -1, 0, 0, 0); dci.suggest_dir_l = g_locale_from_utf8(suggest_dir, -1, 0, 0, 0); } else { dci.suggest_dir_w = NULL; dci.suggest_dir_l = NULL; } if ((thread = g_thread_create(dir_chooser_thread, &dci, TRUE, NULL))) { dummy = gtk_invisible_new(); gtk_grab_add(dummy); gtk_main(); dname = g_thread_join(thread); gtk_widget_destroy(dummy); } else { dname = dir_chooser_main(&dci); } g_free(dci.suggest_dir_w); g_free(dci.suggest_dir_l); return dname; } #else /* ! GDK_WINDOWING_WIN32 */ /* Case insensitive filter function */ static gboolean filter_lowercase(const GtkFileFilterInfo *info, gpointer data) { GSList *list = data; const char *base; char *lowercase, *reversed; int length; gboolean matched = FALSE; if ((base = strrchr(info->filename, G_DIR_SEPARATOR))) base++; else base = info->filename; lowercase = g_ascii_strdown(base, -1); length = strlen(lowercase); reversed = g_memdup(lowercase, length + 1); g_strreverse(reversed); while (list) { if (g_pattern_match(list->data, length, lowercase, reversed)) { matched = TRUE; break; } list = list->next; } g_free(lowercase); g_free(reversed); return matched; } static void free_filter_info(gpointer data) { GSList *list = data, *l; for (l = list; l; l = l->next) g_pattern_spec_free(l->data); g_slist_free(list); } static void setup_file_filters(GtkFileChooser *chooser, const char *desc1, const char *pattern1, va_list ap) { GtkFileFilter *ffilt; char **pats; GPatternSpec *pspec; GSList *pspeclist; int i; while (desc1 && pattern1) { if (pattern1[0]) { ffilt = gtk_file_filter_new(); gtk_file_filter_set_name(ffilt, desc1); pats = g_strsplit(pattern1, ";", -1); pspeclist = NULL; for (i = 0; pats && pats[i]; i++) { pspec = g_pattern_spec_new(pats[i]); pspeclist = g_slist_prepend(pspeclist, pspec); } g_strfreev(pats); gtk_file_filter_add_custom(ffilt, GTK_FILE_FILTER_FILENAME, &filter_lowercase, pspeclist, &free_filter_info); gtk_file_chooser_add_filter(chooser, ffilt); } desc1 = va_arg(ap, char *); if (!desc1) break; pattern1 = va_arg(ap, char *); } } static gboolean prompt_overwrite(const char *fname, GtkWindow *parent) { GtkWidget *dlg; GtkWidget *button; char *p, *q; if (!g_file_test(fname, G_FILE_TEST_EXISTS)) return TRUE; if (!g_file_test(fname, G_FILE_TEST_IS_REGULAR)) return FALSE; p = g_filename_display_basename(fname); dlg = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "A file named \"%s\" already exists. " "Do you want to replace it?", p); g_free(p); p = g_path_get_dirname(fname); q = g_filename_display_basename(p); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG(dlg), "The file already exists in \"%s\". Replacing it will " "overwrite its contents.", q); g_free(p); g_free(q); gtk_dialog_add_button(GTK_DIALOG(dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); button = gtk_button_new_with_mnemonic("_Replace"); gtk_widget_set_can_default(button, TRUE); gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON)); gtk_widget_show(button); gtk_dialog_add_action_widget(GTK_DIALOG(dlg), button, GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { gtk_widget_destroy(dlg); return TRUE; } gtk_widget_destroy(dlg); return FALSE; } static char ** run_file_chooser(const char *title, GtkWindow *parent, gboolean save, gboolean multiple, const char *suggest_name, const char *suggest_dir, const char *desc1, const char *pattern1, va_list ap) { GtkWidget *filesel; GSList *filelist, *l; char *fname; char **fnames; int i, n; filesel = gtk_file_chooser_dialog_new(title, parent, (save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, (save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT); if (suggest_dir) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), suggest_dir); if (suggest_name) gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel), suggest_name); gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filesel), multiple); setup_file_filters(GTK_FILE_CHOOSER(filesel), desc1, pattern1, ap); while (gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) { if (save) { fname = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel)); if (!fname || !prompt_overwrite(fname, GTK_WINDOW(filesel))) { g_free(fname); continue; } fnames = g_new(char *, 2); fnames[0] = fname; fnames[1] = NULL; gtk_widget_destroy(filesel); return fnames; } else { filelist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(filesel)); if (!filelist) continue; n = g_slist_length(filelist); fnames = g_new(char *, n + 1); i = 0; for (l = filelist; l; l = l->next) fnames[i++] = l->data; g_slist_free(filelist); fnames[n] = NULL; for (i = 0; i < n; i++) if (!g_file_test(fnames[i], G_FILE_TEST_IS_REGULAR)) break; if (i < n) { g_strfreev(fnames); continue; } gtk_widget_destroy(filesel); return fnames; } } gtk_widget_destroy(filesel); return NULL; } static char* run_dir_chooser(const char *title, GtkWindow *parent, gboolean save, const char *suggest_dir) { GtkWidget *filesel; char *fname; filesel = gtk_file_chooser_dialog_new(title, parent, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, (save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT); if (suggest_dir) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), suggest_dir); while (gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) { fname = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(filesel)); if (!fname) { g_free(fname); continue; } gtk_widget_destroy(filesel); return fname; } gtk_widget_destroy(filesel); return NULL; } #endif /* ! GDK_WINDOWING_WIN32 */ char * prompt_open_file(const char *title, GtkWindow *parent, const char *suggest_dir, const char *desc1, const char *pattern1, ...) { char **result, *fname; va_list ap; va_start(ap, pattern1); result = run_file_chooser(title, parent, FALSE, FALSE, NULL, suggest_dir, desc1, pattern1, ap); va_end(ap); if (!result || !result[0] || result[1]) { g_strfreev(result); return NULL; } else { fname = result[0]; g_free(result); return fname; } } char ** prompt_open_files(const char *title, GtkWindow *parent, const char *suggest_dir, const char *desc1, const char *pattern1, ...) { char **result; va_list ap; va_start(ap, pattern1); result = run_file_chooser(title, parent, FALSE, TRUE, NULL, suggest_dir, desc1, pattern1, ap); va_end(ap); return result; } char * prompt_save_file(const char *title, GtkWindow *parent, const char *suggest_name, const char *suggest_dir, const char *desc1, const char *pattern1, ...) { char **result, *fname; va_list ap; va_start(ap, pattern1); result = run_file_chooser(title, parent, TRUE, FALSE, suggest_name, suggest_dir, desc1, pattern1, ap); va_end(ap); if (!result || !result[0] || result[1]) { g_strfreev(result); return NULL; } else { fname = result[0]; g_free(result); return fname; } } char * prompt_select_dir(const char *title, GtkWindow *parent, const char *suggest_dir) { char *dirname; dirname = run_dir_chooser(title, parent, TRUE, suggest_dir); if (!dirname) { return NULL; } else { return dirname; } } /**************** File entry ****************/ #ifdef GDK_WINDOWING_WIN32 typedef struct _FileEntry { GtkHBox parent; GtkWidget *entry; GtkWidget *button; char *title; char *filters; char *filename; } FileEntry; typedef struct _FileEntryClass { GtkHBoxClass parent; } FileEntryClass; static guint selection_changed_signal = 0; G_DEFINE_TYPE(FileEntry, file_entry, GTK_TYPE_HBOX); static void file_entry_finalize(GObject *obj) { FileEntry *fe = (FileEntry*) obj; g_free(fe->title); g_free(fe->filters); g_free(fe->filename); } void file_entry_set_filename(GtkWidget *entry, const char *filename) { FileEntry *fe = (FileEntry*) entry; if (filename && filename[0]) { if (!fe->filename || strcmp(filename, fe->filename)) { g_free(fe->filename); fe->filename = g_strdup(filename); gtk_entry_set_text(GTK_ENTRY(fe->entry), filename); g_signal_emit(fe, selection_changed_signal, 0, NULL); } } else if (fe->filename) { g_free(fe->filename); fe->filename = NULL; g_signal_emit(fe, selection_changed_signal, 0, NULL); } } char * file_entry_get_filename(GtkWidget *entry) { FileEntry *fe = (FileEntry*) entry; if (fe->filename) return g_strdup(fe->filename); else return NULL; } static void focus_changed(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GParamSpec *pspec, gpointer data) { FileEntry *fe = data; const char *text; text = gtk_entry_get_text(GTK_ENTRY(fe->entry)); file_entry_set_filename(GTK_WIDGET(fe), text); } static void browse_for_files(G_GNUC_UNUSED GtkButton *btn, gpointer data) { FileEntry *fe = data; GtkWidget *parent; char **result; char *bname, *dname; parent = gtk_widget_get_toplevel(GTK_WIDGET(fe)); if (fe->filename) { bname = g_path_get_basename(fe->filename); dname = g_path_get_dirname(fe->filename); } else { bname = dname = NULL; } result = run_file_chooser1(fe->title, GTK_WINDOW(parent), FALSE, FALSE, bname, dname, fe->filters); g_free(bname); g_free(dname); if (result && result[0]) file_entry_set_filename(GTK_WIDGET(fe), result[0]); g_strfreev(result); } static void file_entry_init(FileEntry *fe) { gtk_box_set_spacing(GTK_BOX(fe), 6); fe->entry = gtk_entry_new(); fe->button = gtk_button_new_with_label("Browse..."); gtk_box_pack_start(GTK_BOX(fe), fe->entry, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(fe), fe->button, FALSE, FALSE, 0); gtk_widget_show(fe->entry); gtk_widget_show(fe->button); g_signal_connect(fe->entry, "notify::is-focus", G_CALLBACK(focus_changed), fe); g_signal_connect(fe->button, "clicked", G_CALLBACK(browse_for_files), fe); } static void file_entry_class_init(FileEntryClass *class) { GObjectClass *obj_class; obj_class = G_OBJECT_CLASS(class); obj_class->finalize = file_entry_finalize; selection_changed_signal = g_signal_new("selection-changed", G_OBJECT_CLASS_TYPE(obj_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } GtkWidget * file_entry_new(const char *title, const char *desc1, const char *pattern1, ...) { FileEntry *fe = g_object_new(file_entry_get_type(), NULL); va_list ap; fe->title = g_strdup(title); va_start(ap, pattern1); fe->filters = build_filter_string(desc1, pattern1, ap); va_end(ap); return GTK_WIDGET(fe); } #else /* ! GDK_WINDOWING_WIN32 */ GtkWidget * file_entry_new(const char *title, const char *desc1, const char *pattern1, ...) { GtkWidget *btn; va_list ap; btn = gtk_file_chooser_button_new(title, GTK_FILE_CHOOSER_ACTION_OPEN); va_start(ap, pattern1); setup_file_filters(GTK_FILE_CHOOSER(btn), desc1, pattern1, ap); va_end(ap); return btn; } void file_entry_set_filename(GtkWidget *fe, const char *filename) { gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fe), filename); } char * file_entry_get_filename(GtkWidget *fe) { return gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fe)); } #endif /* ! GDK_WINDOWING_WIN32 */ tilem-2.0/gui/filedlg.h000066400000000000000000000075211220200411600150210ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* Run a file chooser dialog, allowing user to select a single existing file to open. TITLE is the title of the dialog (UTF-8.) PARENT is the "parent" (transient-for) window, if any. SUGGEST_DIR is the directory to start in (GLib filename encoding.) Remaining arguments are a series of pairs of strings describing the permitted file types. First string in each pair is the description; second is a pattern set (consisting of one or more glob-style patterns, separated by semicolons.) Patterns must be lowercase; they will be checked case-insensitively. The list is terminated by NULL. A pattern may be the empty string (""); if so, that file type is disabled. Result is NULL if dialog was cancelled; otherwise, a string in filename encoding, which must be freed with g_free(). */ char * prompt_open_file(const char *title, /* UTF-8 */ GtkWindow *parent, const char *suggest_dir, /* filename encoding */ const char *desc1, /* UTF-8 */ const char *pattern1, /* ASCII */ ...) G_GNUC_NULL_TERMINATED; /* Run a file chooser dialog, allowing user to select one or more files to open. Result is either NULL or an array of strings, which must be freed with g_strfreev(). */ char ** prompt_open_files(const char *title, /* UTF-8 */ GtkWindow *parent, const char *suggest_dir, /* filename encoding */ const char *desc1, /* UTF-8 */ const char *pattern1, /* ASCII */ ...) G_GNUC_NULL_TERMINATED; /* Run a file chooser dialog, allowing user to enter a new filename to be created. SUGGEST_NAME is a suggested name for the new file; note that this is UTF-8. */ char * prompt_save_file(const char *title, /* UTF-8 */ GtkWindow *parent, const char *suggest_name, /* UTF-8 (!) */ const char *suggest_dir, /* filename encoding */ const char *desc1, /* UTF-8 */ const char *pattern1, /* ASCII */ ...) G_GNUC_NULL_TERMINATED; /* Create a file entry or file-chooser button widget, allowing user to select a single existing file to open. */ GtkWidget * file_entry_new(const char *title, /* UTF-8 */ const char *desc1, /* UTF-8 */ const char *pattern1, /* ASCII */ ...) G_GNUC_NULL_TERMINATED; /* Set filename in a file entry. */ void file_entry_set_filename(GtkWidget *fe, const char *filename); /* filename encoding */ /* Get filename in a file entry. Result is NULL if no file is selected; otherwise, a string in filename encoding, which must be freed with g_free(). */ char * file_entry_get_filename(GtkWidget *fe); /* Run a directory chooser dialog, allowing user to select a directory. */ char * prompt_select_dir(const char *title, GtkWindow *parent, const char *suggest_dir); tilem-2.0/gui/files.c000066400000000000000000000142701220200411600145070ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #ifdef G_OS_WIN32 # include #endif #include "files.h" static char *program_dir; /* Set the name used to invoke this program */ void set_program_path(const char *path) { if (path && strchr(path, G_DIR_SEPARATOR)) program_dir = g_path_get_dirname(path); } /* Build a filename out of varargs */ static char *build_filenamev(const char *start, va_list rest) { char *args[10]; int i; args[0] = (char*) start; for (i = 1; i < 10; i++) { args[i] = (char*) va_arg(rest, const char *); if (!args[i]) break; } g_assert(i < 10); return g_build_filenamev(args); } #ifdef G_OS_WIN32 static char * get_special_folder(int csidl) { char lpath[MAX_PATH+1]; wchar_t wpath[MAX_PATH+1]; LPITEMIDLIST pidl = NULL; gchar *s = NULL; if (SHGetSpecialFolderLocation(NULL, csidl, &pidl)) return NULL; if (G_WIN32_HAVE_WIDECHAR_API()) { if (SHGetPathFromIDListW(pidl, wpath)) s = g_utf16_to_utf8(wpath, -1, NULL, NULL, NULL); } else { if (SHGetPathFromIDListA(pidl, lpath)) s = g_locale_to_utf8(lpath, -1, NULL, NULL, NULL); } CoTaskMemFree(pidl); return s; } #endif /* Get the default configuration directory. On Unix, this is $XDG_CONFIG_HOME/tilem2 (where $XDG_CONFIG_HOME defaults to $HOME/.config/ if not set.) On Windows, this is $CSIDL_LOCAL_APPDATA\tilem2 (where $CSIDL_LOCAL_APPDATA is typically "Local Settings\Application Data" in the user's profile.) Result is cached and should not be freed. */ static char * get_default_config_dir() { static char *result; if (!result) { #ifdef G_OS_WIN32 /* Do not use g_get_user_config_dir() on Windows, because the behavior of that function is not consistent across versions of GLib. */ char *s = get_special_folder(CSIDL_LOCAL_APPDATA); if (s) result = g_build_filename(s, "tilem2", NULL); g_free(s); #else result = g_build_filename(g_get_user_config_dir(), "tilem2", NULL); #endif } return result; } /* Search for an existing file. The default package configuration directory (defined above) is searched first; if the file is not found there, try to find the file that was installed along with the package, or (in case the package hasn't yet been installed) the copy included in the source package. */ static char * find_filev(GFileTest test, const char *name, va_list rest) { char *fullname, *dname, *path; const char *userdir; const char * const *sysdirs; fullname = build_filenamev(name, rest); dname = get_default_config_dir(); path = g_build_filename(dname, fullname, NULL); if (g_file_test(path, test)) { g_free(fullname); return path; } g_free(path); #ifdef G_OS_WIN32 if ((dname = g_win32_get_package_installation_directory(NULL, NULL))) { path = g_build_filename(dname, "share", "tilem2", fullname, NULL); g_free(dname); if (g_file_test(path, test)) { g_free(fullname); return path; } g_free(path); } #endif #ifdef UNINSTALLED_SHARE_DIR if (program_dir) { path = g_build_filename(program_dir, UNINSTALLED_SHARE_DIR, fullname, NULL); if (g_file_test(path, test)) { g_free(fullname); return path; } g_free(path); } #endif #ifdef SHARE_DIR path = g_build_filename(SHARE_DIR, fullname, NULL); if (g_file_test(path, test)) { g_free(fullname); return path; } g_free(path); #endif userdir = g_get_user_data_dir(); if (userdir) { path = g_build_filename(userdir, "tilem2", fullname, NULL); if (g_file_test(path, test)) { g_free(fullname); return path; } } sysdirs = g_get_system_data_dirs(); while (sysdirs && sysdirs[0]) { path = g_build_filename(sysdirs[0], "tilem2", fullname, NULL); if (g_file_test(path, test)) { g_free(fullname); return path; } sysdirs++; } g_free(fullname); return NULL; } /* Locate an existing configuration or data file */ char * get_shared_file_path(const char *name, ...) { va_list ap; char *path; va_start(ap, name); path = find_filev(G_FILE_TEST_IS_REGULAR, name, ap); va_end(ap); return path; } /* Locate an existing configuration or data directory */ char * get_shared_dir_path(const char *name, ...) { va_list ap; char *path; va_start(ap, name); path = find_filev(G_FILE_TEST_IS_DIR, name, ap); va_end(ap); return path; } /* Return the path to the user's configuration directory, where any new or modified config files should be written. Result is cached and should not be freed. */ static char * get_config_dir() { static char *result; char *fname; FILE *f; if (result) return result; /* If config.ini already exists, in any of the standard locations, and is writable, use the directory containing it. This will allow building the package as a relocatable bundle. */ fname = get_shared_file_path("config.ini", NULL); if (fname) { f = g_fopen(fname, "r+"); if (f) { result = g_path_get_dirname(fname); fclose(f); } g_free(fname); } /* Otherwise use default config directory */ if (!result) result = g_strdup(get_default_config_dir()); return result; } /* Get path for writing a new or modified configuration file */ char * get_config_file_path(const char *name, ...) { va_list ap; const char *cfgdir; char *fullname, *path; cfgdir = get_config_dir(); g_mkdir_with_parents(cfgdir, 0775); va_start(ap, name); fullname = build_filenamev(name, ap); va_end(ap); path = g_build_filename(cfgdir, fullname, NULL); g_free(fullname); return path; } tilem-2.0/gui/files.h000066400000000000000000000032621220200411600145130ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* Set the name used to invoke this program. Data files can be located relative to this path if the package is not installed */ void set_program_path(const char *path); /* Locate an existing configuration or data file. Arguments will be concatenated, separated by / or \, as with g_build_filename(). NULL is returned if the file isn't found. Free result with g_free(). */ char * get_shared_file_path(const char *name, ...) G_GNUC_NULL_TERMINATED; /* Locate an existing configuration or data directory. NULL is returned if the file isn't found. Free result with g_free(). */ char * get_shared_dir_path(const char *name, ...) G_GNUC_NULL_TERMINATED; /* Get the full path where a configuration file should be written; attempt to create the directory if it doesn't exist. This function will always return a valid filename (although it may not actually be writable.) Free result with g_free(). */ char * get_config_file_path(const char *name, ...) G_GNUC_NULL_TERMINATED; tilem-2.0/gui/fixedtreeview.c000066400000000000000000000103021220200411600162470ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "fixedtreeview.h" /* Style set on tree view; update column sizes */ static void ftv_style_set(GtkWidget *treeview, G_GNUC_UNUSED GtkStyle *oldstyle, G_GNUC_UNUSED gpointer data) { GtkTreeModel *template; GtkTreeIter iter; GList *cols, *cp; GtkTreeViewColumn *col; int width; template = g_object_get_data(G_OBJECT(treeview), "ftv-template"); if (!template) return; if (!gtk_tree_model_get_iter_first(template, &iter)) return; cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeview)); for (cp = cols; cp; cp = cp->next) { col = cp->data; gtk_tree_view_column_cell_set_cell_data(col, template, &iter, FALSE, FALSE); gtk_tree_view_column_cell_get_size(col, NULL, NULL, NULL, &width, NULL); gtk_tree_view_column_set_fixed_width(col, width + 2); } g_list_free(cols); } /* Widget destroyed */ static void ftv_destroy(GtkWidget *treeview, G_GNUC_UNUSED gpointer data) { GtkTreeModel *template; template = g_object_get_data(G_OBJECT(treeview), "ftv-template"); if (template) g_object_unref(template); g_object_set_data(G_OBJECT(treeview), "ftv-template", NULL); } void fixed_tree_view_init_with_template(GtkWidget *treeview, GtkTreeModel *template) { GtkTreeModel *oldtemplate; if (template) g_object_ref_sink(template); oldtemplate = g_object_get_data(G_OBJECT(treeview), "ftv-template"); if (oldtemplate) { g_object_unref(oldtemplate); } else { g_signal_connect(treeview, "style-set", G_CALLBACK(ftv_style_set), NULL); g_signal_connect(treeview, "destroy", G_CALLBACK(ftv_destroy), NULL); } g_object_set_data(G_OBJECT(treeview), "ftv-template", template); if (template && GTK_WIDGET_REALIZED(treeview)) ftv_style_set(treeview, NULL, NULL); } void fixed_tree_view_init(GtkWidget *treeview, int colgroupsize, ...) { GtkTreeModel *real_model; int ncols, i, col; GType *types; GtkListStore *store; GtkTreeIter iter; GValue value; gchar *error = NULL; va_list ap; g_return_if_fail(GTK_IS_TREE_VIEW(treeview)); g_return_if_fail(colgroupsize >= 0); real_model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); g_return_if_fail(real_model != NULL); ncols = gtk_tree_model_get_n_columns(real_model); g_return_if_fail(ncols > 0); if (colgroupsize == 0) colgroupsize = ncols; g_return_if_fail(ncols % colgroupsize == 0); types = g_new(GType, ncols); for (i = 0; i < ncols; i++) { types[i] = gtk_tree_model_get_column_type(real_model, i); if (i > colgroupsize) g_return_if_fail(types[i] == types[i - colgroupsize]); } store = gtk_list_store_newv(ncols, types); va_start(ap, colgroupsize); gtk_list_store_append(store, &iter); memset(&value, 0, sizeof(value)); col = va_arg(ap, int); while (col != -1) { if (col < 0 || col >= colgroupsize) { g_critical("missing sentinel"); break; } g_value_init(&value, types[col]); G_VALUE_COLLECT(&value, ap, 0, &error); if (error) { g_critical("%s", error); g_free(error); break; } for (i = col; i < ncols; i += colgroupsize) gtk_list_store_set_value(store, &iter, i, &value); g_value_unset(&value); col = va_arg(ap, int); } va_end(ap); g_free(types); fixed_tree_view_init_with_template(treeview, GTK_TREE_MODEL(store)); } tilem-2.0/gui/fixedtreeview.h000066400000000000000000000033511220200411600162620ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* Set up a tree view with fixed-size columns, where the column sizes are determined automatically based on a template. The template model must contain the same number and types of data columns as the tree view's data model. The first row of the template model will be used to compute column sizes; any additional rows are ignored. */ void fixed_tree_view_init_with_template(GtkWidget *treeview, GtkTreeModel *template); /* As above, but the template model is constructed automatically. The tree view must have a data model attached already. Arguments following COLGROUPSIZE are a sequence of (column, data) pairs, as you would pass to gtk_list_store_set(). The list must be terminated with -1. If COLGROUPSIZE is a positive integer N, then the template will be constructed by repeating the first N columns as many times as necessary. In this case, columns K and K+N must always have the same type. */ void fixed_tree_view_init(GtkWidget *treeview, int colgroupsize, ...); tilem-2.0/gui/gifencod.c000066400000000000000000000240261220200411600151630ustar00rootroot00000000000000/* Fast GIF encoder * taken from http://www.msg.net/utility/whirlgif/gifencod.html - go there for the algorithm explanation * * gifencode.c * * Copyright (c) 1997,1998,1999 by Hans Dinsen-Hansen * The algorithms are inspired by those of gifcode.c * Copyright (c) 1995,1996 Michael A. Mayer * All rights reserved. * * This software may be freely copied, modified and redistributed * without fee provided that above copyright notices are preserved * intact on all copies and modified copies. * * There is no warranty or other guarantee of fitness of this software. * It is provided solely "as is". The author(s) disclaim(s) all * responsibility and liability with respect to this software's usage * or its effect upon hardware or computer systems. * * The Graphics Interchange format (c) is the Copyright property of * Compuserve Incorporated. Gif(sm) is a Service Mark property of * Compuserve Incorporated. * * * Implements GIF encoding by means of a tree search. * -------------------------------------------------- * * - The string table may be thought of being stored in a "b-tree of * steroids," or more specifically, a {256,128,...,4}-tree, depending on * the size of the color map. * - Each (non-NULL) node contains the string table index (or code) and * {256,128,...,4} pointers to other nodes. * - For example, the index associated with the string 0-3-173-25 would be * stored in: * first->node[0]->node[3]->node[173]->node[25]->code * * - Speed and effectivity considerations, however, have made this * implementation somewhat obscure, because it is costly to initialize * a node-array where most elements will never be used. * - Initially, a new node will be marked as terminating, TERMIN. * If this node is used at a later stage, its mark will be changed. * - Only nodes with several used nodes will be associated with a * node-array. Such nodes are marked LOOKUP. * - The remaining nodes are marked SEARCH. They are linked together * in a search-list, where a field, NODE->alt, points at an alternative * following color. * - It is hardly feasible exactly to predict which nodes will have most * used node pointers. The theory here is that the very first node as * well as the first couple of nodes which need at least one alternative * color, will be among the ones with many nodes ("... whatever that * means", as my tutor in Num. Analysis and programming used to say). * - The number of possible LOOKUP nodes depends on the size of the color * map. Large color maps will have many SEARCH nodes; small color maps * will probably have many LOOKUP nodes. */ #include #include #include #ifdef MEMDBG #include #endif #define BLOKLEN 255 #define BUFLEN 1000 #define TERMIN 'T' #define LOOKUP 'L' #define SEARCH 'S' #define noOfArrays 20 /* defines the amount of memory set aside in the encoding for the * LOOKUP type nodes; for a 256 color GIF, the number of LOOKUP * nodes will be <= noOfArrays, for a 128 color GIF the number of * LOOKUP nodes will be <= 2 * noOfArrays, etc. */ typedef struct GifTree { char typ; /* terminating, lookup, or search */ int code; /* the code to be output */ unsigned char ix; /* the color map index */ struct GifTree **node, *nxt, *alt; } GifTree; char *AddCodeToBuffer(int, short, char *); void ClearTree(int, GifTree *); extern unsigned int debugFlag; extern int count; int chainlen = 0, maxchainlen = 0, nodecount = 0, lookuptypes = 0, nbits; short need = 8; GifTree *empty[256], GifRoot = {LOOKUP, 0, 0, empty, NULL, NULL}, *topNode, *baseNode, **nodeArray, **lastArray; void GifEncode(FILE *fout, unsigned char *pixels, int depth, int siz) { GifTree *first = &GifRoot, *newNode, *curNode; unsigned char *end; int cc, eoi, next, tel=0; //, dbw=0; short cLength; char *pos, *buffer; empty[0] = NULL; need = 8; nodeArray = empty; memmove(++nodeArray, empty, 255*sizeof(GifTree **)); if (( buffer = (char *)malloc((BUFLEN+1)*sizeof(char))) == NULL ) printf("No memory for writing"); buffer++; pos = buffer; buffer[0] = 0x0; cc = (depth == 1) ? 0x4 : 1<node = (GifTree **)malloc(256*sizeof(GifTree *)*noOfArrays)) == NULL ) printf("No memory for search nodes"); lastArray = nodeArray + ( 256*noOfArrays - cc); ClearTree(cc, first); pos = AddCodeToBuffer(cc, cLength, pos); end = pixels+siz; curNode = first; while(pixels < end) { if ( curNode->node[*pixels] != NULL ) { curNode = curNode->node[*pixels]; tel++; pixels++; chainlen++; continue; } else if ( curNode->typ == SEARCH ) { newNode = curNode->nxt; while ( newNode->alt != NULL ) { if ( newNode->ix == *pixels ) break; newNode = newNode->alt; } if (newNode->ix == *pixels ) { tel++; pixels++; chainlen++; curNode = newNode; continue; } } /* ****************************************************** * If there is no more thread to follow, we create a new node. If the * current node is terminating, it will become a SEARCH node. If it is * a SEARCH node, and if we still have room, it will be converted to a * LOOKUP node. */ newNode = ++topNode; switch (curNode->typ ) { case LOOKUP: newNode->nxt = NULL; newNode->alt = NULL, curNode->node[*pixels] = newNode; break; case SEARCH: if ( nodeArray != lastArray ) { nodeArray += cc; curNode->node = nodeArray; curNode->typ = LOOKUP; curNode->node[*pixels] = newNode; curNode->node[(curNode->nxt)->ix] = curNode->nxt; lookuptypes++; newNode->nxt = NULL; newNode->alt = NULL, curNode->nxt = NULL; break; } /* otherwise do as we do with a TERMIN node */ case TERMIN: newNode->alt = curNode->nxt; newNode->nxt = NULL, curNode->nxt = newNode; curNode->typ = SEARCH; break; default: fprintf(stderr, "Silly node type: %d\n", curNode->typ); } newNode->code = next; newNode->ix = *pixels; newNode->typ = TERMIN; newNode->node = empty; nodecount++; /* * End of node creation * ****************************************************** */ #ifdef _WHGDBG if (debugFlag) { if (curNode == newNode) fprintf(stderr, "Wrong choice of node\n"); if ( curNode->typ == LOOKUP && curNode->node[*pixels] != newNode ) fprintf(stderr, "Wrong pixel coding\n"); if ( curNode->typ == TERMIN ) fprintf(stderr, "Wrong Type coding; frame no = %d; pixel# = %d; nodecount = %d\n", count, tel, nodecount); } #endif pos = AddCodeToBuffer(curNode->code, cLength, pos); if ( chainlen > maxchainlen ) maxchainlen = chainlen; chainlen = 0; if(pos-buffer>BLOKLEN) { buffer[-1] = BLOKLEN; fwrite(buffer-1, 1, BLOKLEN+1, fout); buffer[0] = buffer[BLOKLEN]; buffer[1] = buffer[BLOKLEN+1]; buffer[2] = buffer[BLOKLEN+2]; buffer[3] = buffer[BLOKLEN+3]; pos -= BLOKLEN; } curNode = first; if(next == (1<BLOKLEN) { buffer[-1] = BLOKLEN; fwrite(buffer-1, 1, BLOKLEN+1, fout); buffer[0] = buffer[BLOKLEN]; buffer[1] = buffer[BLOKLEN+1]; buffer[2] = buffer[BLOKLEN+2]; buffer[3] = buffer[BLOKLEN+3]; pos -= BLOKLEN; } next = cc+2; cLength = (short) ((depth == 1)?3:depth+1); } } pos = AddCodeToBuffer(curNode->code, cLength, pos); if(pos-buffer>BLOKLEN-3) { buffer[-1] = BLOKLEN-3; fwrite(buffer-1, 1, BLOKLEN-2, fout); buffer[0] = buffer[BLOKLEN-3]; buffer[1] = buffer[BLOKLEN-2]; buffer[2] = buffer[BLOKLEN-1]; buffer[3] = buffer[BLOKLEN]; buffer[4] = buffer[BLOKLEN+1]; pos -= BLOKLEN-3; } pos = AddCodeToBuffer(eoi, cLength, pos); pos = AddCodeToBuffer(0x0, -1, pos); buffer[-1] = (char) (pos-buffer); fwrite(buffer-1, pos-buffer+1, 1, fout); free(buffer-1); free(first->node); free(baseNode); buffer=NULL;first->node=NULL;baseNode=NULL; #ifdef _WHGDBG if (debugFlag) fprintf(stderr, "pixel count = %d; nodeCount = %d lookup nodes = %d\n", tel, nodecount, lookuptypes); #endif return; } void ClearTree(int cc, GifTree *root) { int i; GifTree *newNode, **xx; #ifdef _WHGDBG if (debugFlag>1) fprintf(stderr, "Clear Tree cc= %d\n", cc); if (debugFlag>1) fprintf(stderr, "nodeCount = %d lookup nodes = %d\n", nodecount, lookuptypes); #endif maxchainlen=0; lookuptypes = 1; nodecount = 0; nodeArray = root->node; xx= nodeArray; for (i = 0; i < noOfArrays; i++ ) { memmove (xx, empty, 256*sizeof(GifTree **)); xx += 256; } topNode = baseNode; for(i=0; inode[i] = newNode = ++topNode; newNode->nxt = NULL; newNode->alt = NULL; newNode->code = i; newNode->ix = (unsigned char) i; newNode->typ = TERMIN; newNode->node = empty; nodecount++; } } char *AddCodeToBuffer(int code, short n, char *buf) { int mask; if(n<0) { if(need<8) { buf++; *buf = 0x0; } need = 8; return buf; } while(n>=need) { mask = (1<>need; n -= need; need = 8; } if(n) { mask = (1< #include #ifdef _USE_STRINGS_H #include #else #include #endif #ifdef _FOPEN_TXT_OR_BIN #define WRIBIN "wb" #define REATXT "rt" #define REABIN "rb" #else /* Usually there is no need to distinguish between binary and txt */ #define WRIBIN "w" #define REATXT "r" #define REABIN "r" #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* define constants and defaults */ /* Default amount of inter-frame time */ #define DEFAULT_TIME 10 /* If set to 1, Netscape 'loop' code will be added by default */ #define DEFAULT_LOOP 0 /* If set to 1, use the colormaps from all images, not just the first */ #define DEFAULT_USE_COLORMAP 0 /* Used in calculating the transparent color */ #define TRANS_NONE 1 #define TRANS_RGB 2 #define TRANS_MAP 3 #define DISP_NONE 0 #define DISP_NOT 1 #define DISP_BACK 2 #define DISP_PREV 3 #define DEFAULT_DISPOSAL DISP_NONE /* set default disposal method here to any of the DISP_XXXX values */ #define BIGSTRING 256 #define MAXVAL 4100 /* maxval of lzw coding size */ #define MAXVALP 4200 #define TERMIN 'T' #define LOOKUP 'L' #define SEARCH 'S' #define noOfArrays 20 /* defines the amount of memory set aside in the encoding for the * LOOKUP type nodes; for a 256 color GIF, the number of LOOKUP * nodes will be <= noOfArrays, for a 128 color GIF the number of * LOOKUP nodes will be <= 2 * noOfArrays, etc. */ /* define shorthand for various types */ #define LONG int #define ULONG unsigned int #define BYTE char #define UBYTE unsigned char #define SHORT short #define USHORT unsigned short #define WORD short int #define UWORD unsigned short int int chainlen = 0, maxchainlen = 0, nodecount = 0, lookuptypes = 0, nbits; short need = 8; unsigned int debugFlag, verbose; int count; /* definition of various structures */ typedef struct Transparency { int type; UBYTE valid; UBYTE map; UBYTE red; UBYTE green; UBYTE blue; } Transparency; typedef struct Global { Transparency trans; int left; int top; unsigned int time; unsigned short disposal; } Global; typedef struct GifScreenHdr { int width; int height; UBYTE m; UBYTE cres; UBYTE pixbits; UBYTE bc; UBYTE aspect; } GifScreenHdr; typedef union GifColor { struct cmap { UBYTE red; UBYTE green; UBYTE blue; UBYTE pad; } cmap; ULONG pixel; } GifColor; typedef struct GifImageHdr { int left; int top; int width; int height; UBYTE m; UBYTE i; UBYTE pixbits; UBYTE reserved; } GifImageHdr; typedef struct GifTable { UBYTE valid; UBYTE data; UBYTE first; UBYTE res; int last; } GifTable; typedef struct GifTree { char typ; /* terminating, lookup, or search */ int code; /* the code to be output */ UBYTE ix; /* the color map index */ struct GifTree **node, *nxt, *alt; } GifTree; GifTree *empty[256], GifRoot = {LOOKUP, 0, 0, empty, NULL, NULL}, *topNode, *baseNode, **nodeArray, **lastArray; /* define inline functions */ #define GifPutShort(i, fout) {fputc(i&0xff, fout); fputc(i>>8, fout);} #define GifGetShort(fin) (Xgetc(fin) | Xgetc(fin)<<8) /* forward declaration of the functions */ void CalcTrans(); void GifAddToTable(); void GifClearTable(); void GifComment(); void GifDecode(); void GifEncode(); ULONG GifGetCode(); void GifGetNextEntry(); void GifLoop(); void GifReadFile(); void GifScreenHeader(); UBYTE *GifSendData(); void ReadImageHeader(); void SetOffset(); void TheEnd(); void TheEnd1(); void Usage(); void WriteImageHeader(); UBYTE Xgetc(); void ClearTree(int cc, GifTree *root); char *AddCodeToBuffer(int code, short n, char *buf); tilem-2.0/gui/gtk-compat.h000066400000000000000000000010071220200411600154520ustar00rootroot00000000000000#if !GTK_CHECK_VERSION(2, 14, 0) # define gtk_dialog_get_content_area(d) ((d)->vbox) # define gtk_widget_get_window(w) ((w)->window) # define gtk_selection_data_get_data(s) ((s)->data) #endif #if !GTK_CHECK_VERSION(2, 18, 0) # define gtk_widget_get_allocation(w, a) (*(a) = (w)->allocation) # define gtk_widget_get_visible(w) GTK_WIDGET_VISIBLE(w) # define gtk_widget_set_can_default(w, v) g_object_set((w), "can-default", v, NULL) # define gtk_widget_set_can_focus(w, v) g_object_set((w), "can-focus", v, NULL) #endif tilem-2.0/gui/gui.h000066400000000000000000000306111220200411600141730ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #include "animation.h" #include "emulator.h" #include "skinops.h" #include "emuwin.h" #include "debugger.h" #include "gtk-compat.h" /* This struture is a wrapper for VarEntry with additionnal informations used by tilem */ typedef struct { int model; VarEntry *ve; /* Original variable info retrieved from calculator */ int slot; /* Slot number */ /* Strings for display (UTF-8) */ char *name_str; /* Variable name */ char *type_str; /* Variable type */ char *slot_str; /* Program slot */ char *file_ext; /* Default file extension */ char *filetype_desc; /* File format description */ int size; /* Variable size */ gboolean archived; /* Is archived */ gboolean can_group; /* Can be stored in group file */ } TilemVarEntry; /* Screenshot view (widgets and flags) */ typedef struct _TilemScreenshotDialog { TilemCalcEmulator *emu; GtkWidget* window; /* The window itself */ /* Buttons */ GtkWidget* screenshot; /* Grab button */ GtkWidget* record; /* Record button */ GtkWidget* stop; /* Stop button */ /* Screenshot menu */ GtkWidget* screenshot_preview_image; /* Review pixbuf */ GtkWidget* ss_ext_combo; /* Combo box for file format */ GtkWidget* ss_size_combo; /* Combo box for size */ GtkWidget* width_spin; /* The width of the gif */ GtkWidget* height_spin; /* The height of the gif */ GtkWidget* grayscale_tb; /* Toggle Button for enabling/disabling grayscale */ GtkWidget* animation_speed; /* A scale for the speed of the animation */ GtkWidget* background_color; /* Color chooser : Color used for pixel-off */ GtkWidget* foreground_color; /* Color chooser : Color used for pixel-on */ TilemAnimation *current_anim; gboolean current_anim_grayscale; } TilemScreenshotDialog; /* This struture is used by receive menu */ typedef struct _TilemReceiveDialog { TilemCalcEmulator *emu; GSList *vars; /* The list of vars */ GtkWidget* window; /* The window itself */ GtkWidget* treeview; /* The treeview to print the list of vars */ GtkTreeModel* model; /* The model used by the treeview */ /* Radio buttons */ GtkWidget* mode_box; GtkWidget* multiple_rb; /* Write multiple files */ GtkWidget* group_rb; /* Write a single group file */ gboolean refresh_pending; } TilemReceiveDialog; /* Handle the ilp progress stuff */ typedef struct _TilemLinkProgress { TilemCalcEmulator *emu; GtkProgressBar* progress_bar; /* progress bar (total) */ GtkLabel* title_lbl; GtkLabel* status_lbl; GtkWidget* window; } TilemLinkProgress; #define LABEL_X_ALIGN 0.0 /* ###### event.c ##### */ /* Dialog mesg */ void show_about(); /* Launch the debugger */ void launch_debugger(TilemEmulatorWindow *ewin); /* Button-press event */ gboolean mouse_press_event(GtkWidget* w, GdkEventButton *event, gpointer data); /* Pointer-motion event */ gboolean pointer_motion_event(GtkWidget* w, GdkEventMotion *event, gpointer data); /* Button-release event */ gboolean mouse_release_event(GtkWidget* w, GdkEventButton *event, gpointer data); /* Key-press event */ gboolean key_press_event(GtkWidget* w, GdkEventKey *event, gpointer data); /* Key-release event */ gboolean key_release_event(GtkWidget* w, GdkEventKey *event, gpointer data); /* Pop up menu on main window */ gboolean popup_menu_event(GtkWidget* w, gpointer data); /* Handle drag and drop */ void drag_data_received(GtkWidget *win, GdkDragContext *dc, gint x, gint y, GtkSelectionData *seldata, guint info, guint t, gpointer data); /* ###### emuwin.c ##### */ /* Display the lcd image into the terminal */ void display_lcdimage_into_terminal(TilemEmulatorWindow *ewin); /* Redraw the screen with or without skin */ void redraw_screen(TilemEmulatorWindow *ewin); /* ##### preferences.c ##### */ /* Run preferences dialog. */ void tilem_preferences_dialog(TilemEmulatorWindow *ewin); /* ##### address.c ##### */ /* Convert address to a displayable string. */ char * tilem_format_addr(TilemDebugger *dbg, dword addr, gboolean physical); /* Parse physical address expressed as page and offset. */ gboolean tilem_parse_paged_addr(TilemDebugger *dbg, const char *pagestr, const char *offsstr, dword *value); /* Parse an address or hex constant. If PHYSICAL is null, only a logical address (simple hex value or symbol) is allowed. If PHYSICAL is non-null, physical addresses in the form "PAGE:OFFSET" are also allowed. *PHYSICAL will be set to true if the user entered a physical address. */ gboolean tilem_parse_addr(TilemDebugger *dbg, const char *string, dword *value, gboolean *physical); /* Open a dialog box prompting the user to enter an address. PARENT is the transient-for window; TITLE is the dialog's title; PROMPT is a label for the input. */ gboolean tilem_prompt_address(TilemDebugger *dbg, GtkWindow *parent, const char *title, const char *prompt, dword *value, gboolean physical, gboolean usedefault); /* ##### tool.c ##### */ /* Get model name (abbreviation) for a TilEm model ID. */ const char * model_to_name(int model); /* Convert model name to a model ID. */ int name_to_model(const char *name); /* Convert TilEm model ID to tifiles2 model ID. */ CalcModel model_to_calcmodel(int model); /* Convert tifiles2 model ID to TilEm model ID. */ int calcmodel_to_model(CalcModel model); /* Get model ID for a given file. */ int file_to_model(const char *name); /* Get "base" model for file type support. */ int model_to_base_model(int calc_model); /* Check if calc is compatible with given file type. */ gboolean model_supports_file(int calc_model, int file_model); /* Create a frame around the given widget */ GtkWidget* new_frame(const gchar* label, GtkWidget* contents); /* The popup to choose what kind of rom you are trying to load (at startup)*/ char choose_rom_popup(GtkWidget *parent_window, const char *filename, char default_model); /* Convert UTF-8 to filename encoding. Use ASCII digits in place of subscripts if necessary. If conversion fails utterly, fall back to the UTF-8 name, which is broken but better than nothing. */ char * utf8_to_filename(const char *utf8str); /* Convert UTF-8 to a subset of UTF-8 that is compatible with the locale */ char * utf8_to_restricted_utf8(const char *utf8str); /* Generate default filename (UTF-8) for a variable */ char * get_default_filename(const TilemVarEntry *tve); /* ##### config.c ##### */ /* Retrieve settings from configuration file. GROUP is the configuration group; following arguments are a series of OPTION strings, each followed by a pointer to a variable that will receive the value. The list of options is terminated by NULL. Each OPTION is a string of the form "KEY/TYPE" or "KEY/TYPE=VALUE", where KEY is the name of the configuration property, and TYPE is either 'f' for a filename (char*), 's' for a UTF-8 string (char*), 'i' for an integer (int), 'r' for a real number (double), or 'b' for a boolean (int). VALUE, if specified, is the default value for the option if it has not been defined by the user. If no VALUE is specified, the option defaults to zero or NULL. Strings returned by this function must be freed by the caller (using g_free().) */ void tilem_config_get(const char *group, const char *option, ...) G_GNUC_NULL_TERMINATED; /* Save settings to the configuration file. Arguments are a series of option names, as above, each followed by the new value of the option. The list is terminated by NULL. */ void tilem_config_set(const char *group, const char *option, ...) G_GNUC_NULL_TERMINATED; /* ##### link.c ##### */ /* This structure is used to send a file (usually slot=-1, first=TRUE, last=TRUE)*/ struct TilemSendFileInfo { char *filename; char *display_name; int slot; int first; int last; char *error_message; }; /* This structure is used to receive a file */ struct TilemReceiveFileInfo { GSList *entries; char* destination; char *error_message; gboolean output_tig; }; /* Copy a TilemVarEntry structure */ TilemVarEntry *tilem_var_entry_copy(const TilemVarEntry *tve); /* Free a previous allocated TilemVarEntry */ void tilem_var_entry_free(TilemVarEntry *tve); /* Send a file to the calculator through the GUI. SLOT is the destination program slot (for TI-81.) FIRST must be true if this is the first variable in a series; LAST must be true if this is the last in a series. */ void tilem_link_send_file(TilemCalcEmulator *emu, const char *filename, int slot, gboolean first, gboolean last); /* The effective send file function. If there's no good reason, use tilem_link_send_file instead. */ gboolean send_file_main(TilemCalcEmulator *emu, gpointer data); /* Request directory listing. */ void tilem_link_get_dirlist(TilemCalcEmulator *emu); /* Get the calc model as needed by ticalcs functions */ int get_calc_model(TilemCalc *calc); /* Show error */ void show_error(TilemCalcEmulator *emu, const char *title, const char *message); /* Receive a variable and write it to a file. */ void tilem_link_receive_file(TilemCalcEmulator *emu, const TilemVarEntry* varentry, const char* destination); /* Receive a list of variables (GSList of TilemVarEntries) and save them to a group file. */ void tilem_link_receive_group(TilemCalcEmulator *emu, GSList *entries, const char *destination); /* Receive variables with names matching a pattern. PATTERN is a glob-like pattern in UTF-8. Files will be written out to DESTDIR. */ void tilem_link_receive_matching(TilemCalcEmulator *emu, const char *pattern, const char *destdir); /* ##### pbar.c ##### */ /* Create or update the progress bar */ void progress_bar_update(TilemCalcEmulator* emu); /* ##### animatedgif.c ##### */ /* Save a TilemAnimation to a GIF file. */ void tilem_animation_write_gif(TilemAnimation *anim, byte* palette, int palette_size, FILE *fp); /* ##### gifencod.c ##### */ /* Encode gif data */ void GifEncode(FILE *fout, unsigned char *pixels, int depth, int siz); /* ##### screenshot.c ##### */ /* create the screenshot popup */ void popup_screenshot_window(TilemEmulatorWindow* ewin); /* Take a single screenshot */ void quick_screenshot(TilemEmulatorWindow *ewin); /* ##### keybindings.c ##### */ /* Load the keybindings */ void tilem_keybindings_init(TilemCalcEmulator* emu, const char* model); /* ##### menu.c ##### */ /* Build the menu (do not print it) */ void build_menu(TilemEmulatorWindow* ewin); /* ##### sendfile.c ##### */ /* Load a list of files through the GUI. The list of filenames must end with NULL. */ void load_files(TilemEmulatorWindow *ewin, char **filenames); /* Load a list of files from the command line. Filenames may begin with an optional slot designation. */ void load_files_cmdline(TilemEmulatorWindow *ewin, char **filenames); /* Prompt user to load a file from PC to TI */ void load_file_dialog(TilemEmulatorWindow *ewin); /* ##### rcvmenu.c ##### */ /* Createe the popup dialog */ void popup_receive_menu(TilemEmulatorWindow *ewin); /* Create a TilemReceiveDialog */ TilemReceiveDialog* tilem_receive_dialog_new(TilemCalcEmulator *emu); /* Destroy a TilemReceiveDialog */ void tilem_receive_dialog_free(TilemReceiveDialog *rcvdlg); /* Update TilemReceiveDialog with directory listing. VARLIST is a GSList of TilemVarEntries; the dialog assumes ownership of this list. Display the dialog if it's currently hidden. */ void tilem_receive_dialog_update(TilemReceiveDialog *rcvdlg, GSList *varlist); tilem-2.0/gui/icons.c000066400000000000000000000034521220200411600145200ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "icons.h" #include "files.h" static const char * const custom_icons[] = { /* Disassembly icons */ "tilem-disasm-pc", "tilem-disasm-break", "tilem-disasm-break-pc", /* Debugger actions */ "tilem-db-step", "tilem-db-step-over", "tilem-db-finish" }; /* Set up custom icons. */ void init_custom_icons() { GtkIconTheme *theme; GtkIconFactory *factory; GtkIconSet *set; GtkIconSource *source; char *path; gsize i; path = get_shared_dir_path("icons", NULL); if (path) { theme = gtk_icon_theme_get_default(); gtk_icon_theme_append_search_path(theme, path); g_free(path); } factory = gtk_icon_factory_new(); for (i = 0; i < G_N_ELEMENTS(custom_icons); i++) { set = gtk_icon_set_new(); source = gtk_icon_source_new(); gtk_icon_source_set_icon_name(source, custom_icons[i]); gtk_icon_set_add_source(set, source); gtk_icon_source_free(source); gtk_icon_factory_add(factory, custom_icons[i], set); gtk_icon_set_unref(set); } gtk_icon_factory_add_default(factory); g_object_unref(factory); } tilem-2.0/gui/icons.h000066400000000000000000000013431220200411600145220ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ void init_custom_icons(void); tilem-2.0/gui/keybindings.c000066400000000000000000000142241220200411600157120ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "gui.h" #include "msgbox.h" #include "files.h" /* Get the associated calculator key name */ static int calc_key_from_name(const TilemCalc *calc, const char *name) { int i; for (i = 0; i < 64; i++) if (calc->hw.keynames[i] && !strcmp(calc->hw.keynames[i], name)) return i + 1; /* kludge: accept aliases for a few keys */ for (i = 0; i < 64; i++) { if (!calc->hw.keynames[i]) continue; if (!strcmp(name, "Matrix") && !strcmp(calc->hw.keynames[i], "Apps")) return i + 1; if (!strcmp(name, "Apps") && !strcmp(calc->hw.keynames[i], "AppsMenu")) return i + 1; if (!strcmp(name, "List") && !strcmp(calc->hw.keynames[i], "StatEd")) return i + 1; if (!strcmp(name, "Power") && !strcmp(calc->hw.keynames[i], "Expon")) return i + 1; if (!strcmp(name, "Stat") && !strcmp(calc->hw.keynames[i], "Table")) return i + 1; } return 0; } /* Parse a line of the group (model) in the keybindings file */ static gboolean parse_binding(TilemKeyBinding *kb, const char *pckeys, const char *tikeys, const TilemCalc *calc) { const char *p; char *s; int n, k; kb->modifiers = 0; kb->keysym = 0; kb->nscancodes = 0; kb->scancodes = NULL; /* Parse modifiers */ while ((p = strchr(pckeys, '+'))) { s = g_strndup(pckeys, p - pckeys); g_strstrip(s); if (!g_ascii_strcasecmp(s, "ctrl") || !g_ascii_strcasecmp(s, "control")) kb->modifiers |= GDK_CONTROL_MASK; else if (!g_ascii_strcasecmp(s, "shift")) kb->modifiers |= GDK_SHIFT_MASK; else if (!g_ascii_strcasecmp(s, "alt") || !g_ascii_strcasecmp(s, "mod1")) kb->modifiers |= GDK_MOD1_MASK; else if (!g_ascii_strcasecmp(s, "mod2")) kb->modifiers |= GDK_MOD2_MASK; else if (!g_ascii_strcasecmp(s, "mod3")) kb->modifiers |= GDK_MOD3_MASK; else if (!g_ascii_strcasecmp(s, "mod4")) kb->modifiers |= GDK_MOD4_MASK; else if (!g_ascii_strcasecmp(s, "mod5")) kb->modifiers |= GDK_MOD5_MASK; else if (!g_ascii_strcasecmp(s, "lock") || !g_ascii_strcasecmp(s, "capslock")) kb->modifiers |= GDK_LOCK_MASK; else { g_free(s); return FALSE; } g_free(s); pckeys = p + 1; } /* Parse keysym */ s = g_strstrip(g_strdup(pckeys)); kb->keysym = gdk_keyval_from_name(s); g_free(s); if (!kb->keysym) return FALSE; /* Parse calculator keys */ /* FIXME: allow combinations of simultaneous keys (separated by '+'); current TilemKeyBinding struct doesn't provide for this */ n = 0; do { if ((p = strchr(tikeys, ','))) s = g_strndup(tikeys, p - tikeys); else s = g_strdup(tikeys); g_strstrip(s); k = calc_key_from_name(calc, s); g_free(s); if (!k) { g_free(kb->scancodes); kb->scancodes = NULL; return FALSE; } kb->nscancodes++; if (kb->nscancodes >= n) { n = kb->nscancodes * 2; kb->scancodes = g_renew(byte, kb->scancodes, n); } kb->scancodes[kb->nscancodes - 1] = k; tikeys = (p ? p + 1 : NULL); } while (tikeys); return TRUE; } /* Parse a group (model) in the keybindings file */ static void parse_binding_group(TilemCalcEmulator *emu, GKeyFile *gkf, const char *group, int maxdepth) { gchar **keys, **groups; char *k, *v; int i, n; keys = g_key_file_get_keys(gkf, group, NULL, NULL); if (!keys) { printf("no bindings for %s\n", group); return; } for (i = 0; keys[i]; i++) ; n = emu->nkeybindings; emu->keybindings = g_renew(TilemKeyBinding, emu->keybindings, n + i); for(i = 0; keys[i]; i++) { k = keys[i]; if (!strcmp(k, "INHERIT")) continue; v = g_key_file_get_value(gkf, group, k, NULL); if (!v) continue; if (parse_binding(&emu->keybindings[n], k, v, emu->calc)) n++; else g_printerr("syntax error in key bindings: '%s=%s'\n", k, v); g_free(v); } emu->nkeybindings = n; g_strfreev(keys); /* Include all bindings from groups marked as INHERIT */ if (maxdepth == 0) return; groups = g_key_file_get_string_list(gkf, group, "INHERIT", NULL, NULL); for (i = 0; groups && groups[i]; i++) parse_binding_group(emu, gkf, groups[i], maxdepth - 1); g_strfreev(groups); } /* Init the keybindings struct and open the keybindings file */ void tilem_keybindings_init(TilemCalcEmulator *emu, const char *model) { char *kfname = get_shared_file_path("keybindings.ini", NULL); char *dname; GKeyFile *gkf; GError *err = NULL; g_return_if_fail(emu != NULL); g_return_if_fail(emu != NULL); g_return_if_fail(emu->calc != NULL); if (kfname == NULL) { messagebox00(NULL, GTK_MESSAGE_ERROR, "Unable to load key bindings", "The file keybindings.ini could not be found." " TilEm may not have been installed correctly."); return; } gkf = g_key_file_new(); if (!g_key_file_load_from_file(gkf, kfname, 0, &err)) { dname = g_filename_display_name(kfname); messagebox02(NULL, GTK_MESSAGE_ERROR, "Unable to load key bindings", "An error occurred while reading %s: %s", dname, err->message); g_error_free(err); g_free(dname); g_free(kfname); return; } g_free(emu->keybindings); emu->keybindings = NULL; emu->nkeybindings = 0; parse_binding_group(emu, gkf, model, 5); g_key_file_free(gkf); g_free(kfname); } tilem-2.0/gui/keypaddlg.c000066400000000000000000000172641220200411600153570ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "gui.h" #define NGROUPS 7 #define NKEYS 8 /* Check-button toggled */ static void group_toggled(GtkToggleButton *btn, gpointer data) { TilemKeypadDialog *kpdlg = data; TilemCalcEmulator *emu; int i; gboolean state; if (kpdlg->refreshing) return; g_return_if_fail(kpdlg->dbg != NULL); g_return_if_fail(kpdlg->dbg->emu != NULL); emu = kpdlg->dbg->emu; state = gtk_toggle_button_get_active(btn); for (i = 0; i < NGROUPS; i++) { if (GTK_WIDGET(btn) == kpdlg->output[i]) { tilem_calc_emulator_lock(emu); if (state) emu->calc->keypad.group &= ~(1 << i); else emu->calc->keypad.group |= (1 << i); tilem_calc_emulator_unlock(emu); tilem_keypad_dialog_refresh(kpdlg); return; } } g_return_if_reached(); } /* Key toggled */ static void key_toggled(GtkToggleButton *btn, gpointer data) { TilemKeypadDialog *kpdlg = data; TilemCalcEmulator *emu; int i, j, k; gboolean state; if (kpdlg->refreshing) return; g_return_if_fail(kpdlg->dbg != NULL); g_return_if_fail(kpdlg->dbg->emu != NULL); emu = kpdlg->dbg->emu; state = gtk_toggle_button_get_active(btn); for (i = 0; i < NGROUPS; i++) { for (j = 0; j < NKEYS; j++) { if (GTK_WIDGET(btn) == kpdlg->keys[i][j]) { k = i * 8 + j + 1; if (state) tilem_calc_emulator_press_key(emu, k); else tilem_calc_emulator_release_key(emu, k); return; } } } g_return_if_reached(); } /* Create a new TilemKeypadDialog. */ TilemKeypadDialog *tilem_keypad_dialog_new(TilemDebugger *dbg) { TilemKeypadDialog *kpdlg; GtkWidget *tbl1, *tbl2, *hbox, *vbox, *btn, *lbl; int i, j; char buf[20]; g_return_val_if_fail(dbg != NULL, NULL); kpdlg = g_slice_new0(TilemKeypadDialog); kpdlg->dbg = dbg; kpdlg->window = gtk_dialog_new_with_buttons ("Keypad", NULL, 0, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_signal_connect(kpdlg->window, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); tbl1 = gtk_table_new(NGROUPS, NKEYS, TRUE); hbox = gtk_hbox_new(TRUE, 0); vbox = gtk_vbox_new(TRUE, 0); /* Keypad buttons (labels will be filled in, and buttons shown/hidden, by tilem_keypad_dialog_calc_changed()) Buttons are displayed right to left, top to bottom; this way, the layout of groups 1-5 roughly corresponds to the physical layout of the keys, and the "input" value can be read across the bottom as a binary number. */ for (i = 0; i < NGROUPS; i++) { for (j = 0; j < NKEYS; j++) { btn = gtk_toggle_button_new_with_label(""); kpdlg->keys[i][j] = btn; gtk_table_attach(GTK_TABLE(tbl1), btn, NKEYS - j - 1, NKEYS - j, i, i + 1, GTK_FILL, GTK_FILL, 2, 2); g_signal_connect(btn, "toggled", G_CALLBACK(key_toggled), kpdlg); gtk_widget_set_no_show_all(btn, TRUE); } } /* Check buttons for key groups (output bits) */ for (i = 0; i < NGROUPS; i++) { g_snprintf(buf, sizeof(buf), "Group %d", i); btn = gtk_check_button_new_with_label(buf); kpdlg->output[i] = btn; gtk_box_pack_start(GTK_BOX(vbox), btn, FALSE, TRUE, 2); g_signal_connect(btn, "toggled", G_CALLBACK(group_toggled), kpdlg); } /* Labels for input bits */ for (j = NKEYS - 1; j >= 0; j--) { kpdlg->input[j] = lbl = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, TRUE, 2); } tbl2 = gtk_table_new(3, 2, FALSE); gtk_container_set_border_width(GTK_CONTAINER(tbl2), 6); gtk_table_set_row_spacings(GTK_TABLE(tbl2), 12); gtk_table_set_col_spacings(GTK_TABLE(tbl2), 12); lbl = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(lbl), "Scan Groups"); gtk_table_attach(GTK_TABLE(tbl2), lbl, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(lbl), "Keys"); gtk_table_attach(GTK_TABLE(tbl2), lbl, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new("Input Value:"); gtk_table_attach(GTK_TABLE(tbl2), lbl, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(tbl2), vbox, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(tbl2), tbl1, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(tbl2), hbox, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show_all(tbl2); vbox = gtk_dialog_get_content_area(GTK_DIALOG(kpdlg->window)); gtk_box_pack_start(GTK_BOX(vbox), tbl2, FALSE, FALSE, 0); tilem_keypad_dialog_calc_changed(kpdlg); return kpdlg; } /* Free a TilemKeypadDialog. */ void tilem_keypad_dialog_free(TilemKeypadDialog *kpdlg) { g_return_if_fail(kpdlg != NULL); if (kpdlg->window) gtk_widget_destroy(kpdlg->window); g_slice_free(TilemKeypadDialog, kpdlg); } /* New calculator loaded. */ void tilem_keypad_dialog_calc_changed(TilemKeypadDialog *kpdlg) { TilemCalc *calc; int i, j, k; GtkWidget *btn, *lbl; g_return_if_fail(kpdlg != NULL); g_return_if_fail(kpdlg->dbg != NULL); g_return_if_fail(kpdlg->dbg->emu != NULL); g_return_if_fail(kpdlg->dbg->emu->calc != NULL); calc = kpdlg->dbg->emu->calc; for (i = 0; i < NGROUPS; i++) { for (j = 0; j < NKEYS; j++) { btn = kpdlg->keys[i][j]; k = i * 8 + j + 1; if (k != TILEM_KEY_ON && calc->hw.keynames[k - 1] != NULL) { lbl = gtk_bin_get_child(GTK_BIN(btn)); gtk_label_set_text(GTK_LABEL(lbl), calc->hw.keynames[k - 1]); gtk_widget_show(btn); } else { gtk_widget_hide(btn); } } } tilem_keypad_dialog_refresh(kpdlg); } /* Refresh key states. */ void tilem_keypad_dialog_refresh(TilemKeypadDialog *kpdlg) { int i, j; byte keys[NGROUPS], inval, outval; TilemCalcEmulator *emu; GtkWidget *btn, *lbl; g_return_if_fail(kpdlg != NULL); g_return_if_fail(kpdlg->dbg != NULL); g_return_if_fail(kpdlg->dbg->emu != NULL); emu = kpdlg->dbg->emu; if (kpdlg->refreshing) return; kpdlg->refreshing = TRUE; tilem_calc_emulator_lock(emu); for (i = 0; i < NGROUPS; i++) keys[i] = emu->calc->keypad.keysdown[i]; outval = emu->calc->keypad.group; inval = tilem_keypad_read_keys(emu->calc); tilem_calc_emulator_unlock(emu); for (i = 0; i < NGROUPS; i++) { for (j = 0; j < NKEYS; j++) { btn = kpdlg->keys[i][j]; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), (keys[i] & (1 << j))); } } for (i = 0; i < NGROUPS; i++) { btn = kpdlg->output[i]; if (emu->paused) { gtk_widget_set_sensitive(btn, TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), !(outval & (1 << i))); } else { gtk_widget_set_sensitive(btn, FALSE); } } for (j = 0; j < NKEYS; j++) { lbl = kpdlg->input[j]; gtk_label_set_text(GTK_LABEL(lbl), (emu->paused ? (inval & (1 << j) ? "1" : "0") : "")); } kpdlg->refreshing = FALSE; } tilem-2.0/gui/link.c000066400000000000000000000773111220200411600143470ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include "gui.h" #include "emucore.h" #include "ti81prg.h" #include "msgbox.h" /**************** Internal link emulation ****************/ /* Open cable */ static int ilp_open(CableHandle* cbl) { TilemCalcEmulator* emu = cbl->priv; tilem_em_lock(emu); if (emu->ilp_active) { fprintf(stderr, "INTERNAL ERROR: cable already opened\n"); tilem_em_unlock(emu); return 1; } emu->ilp_active = TRUE; tilem_linkport_graylink_reset(emu->calc); tilem_em_unlock(emu); return 0; } /* Close cable */ static int ilp_close(CableHandle* cbl) { TilemCalcEmulator* emu = cbl->priv; tilem_em_lock(emu); if (!emu->ilp_active) { fprintf(stderr, "INTERNAL ERROR: cable already closed\n"); tilem_em_unlock(emu); return 1; } emu->ilp_active = FALSE; emu->calc->linkport.linkemu = TILEM_LINK_EMULATOR_NONE; tilem_linkport_graylink_reset(emu->calc); tilem_em_unlock(emu); return 0; } /* Reset cable */ static int ilp_reset(CableHandle* cbl) { TilemCalcEmulator* emu = cbl->priv; tilem_em_lock(emu); tilem_linkport_graylink_reset(emu->calc); tilem_em_unlock(emu); return 0; } /* Send data to calc */ static int ilp_send(CableHandle* cbl, uint8_t* data, uint32_t count) { TilemCalcEmulator* emu = cbl->priv; int timeout = cbl->timeout * 100000; tilem_em_lock(emu); while (count > 0) { if (tilem_em_send_byte(emu, data[0], timeout, TRUE)) { tilem_em_unlock(emu); return ERROR_WRITE_TIMEOUT; } data++; count--; } tilem_em_unlock(emu); return 0; } /* cool-down period required after receiving and before sending */ #define COOLDOWN 10000 /* Receive data from calc */ static int ilp_recv(CableHandle* cbl, uint8_t* data, uint32_t count) { TilemCalcEmulator* emu = cbl->priv; int timeout = cbl->timeout * 100000; int value; tilem_em_lock(emu); while (count > 0) { value = tilem_em_get_byte(emu, timeout, TRUE); if (value < 0) { tilem_em_unlock(emu); return ERROR_READ_TIMEOUT; } data[0] = value; data++; count--; } tilem_em_delay(emu, COOLDOWN, TRUE); tilem_em_unlock(emu); return 0; } /* Check if ready */ static int ilp_check(CableHandle* cbl, int* status) { TilemCalcEmulator* emu = cbl->priv; tilem_em_lock(emu); *status = STATUS_NONE; if (emu->calc->linkport.lines) *status |= STATUS_RX; if (emu->calc->linkport.extlines) *status |= STATUS_TX; tilem_em_unlock(emu); return 0; } /* Open a cable */ static CableHandle* internal_link_handle_new(TilemCalcEmulator* emu) { CableHandle* cbl; cbl = ticables_handle_new(CABLE_ILP, PORT_0); if (!cbl) return NULL; cbl->priv = emu; cbl->cable->open = ilp_open; cbl->cable->close = ilp_close; cbl->cable->reset = ilp_reset; cbl->cable->send = ilp_send; cbl->cable->recv = ilp_recv; cbl->cable->check = ilp_check; return cbl; } /**************** Automatic link menu ****************/ /* Run a key (wait, press, wait; release; wait) */ static void run_with_key(TilemCalcEmulator* emu, int key) { tilem_em_delay(emu, 50000, TRUE); tilem_keypad_press_key(emu->calc, key); tilem_em_delay(emu, 50000, TRUE); tilem_keypad_release_key(emu->calc, key); tilem_em_delay(emu, 50000, TRUE); } /* Automatically press key to be in the receive mode (ti82 and ti85) */ static void prepare_for_link_send(TilemCalcEmulator* emu) { tilem_em_lock(emu); tilem_em_wake_up(emu, TRUE); if (emu->calc->hw.model_id == TILEM_CALC_TI82) { run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_GRAPHVAR); run_with_key(emu, TILEM_KEY_RIGHT); run_with_key(emu, TILEM_KEY_ENTER); } else if (emu->calc->hw.model_id == TILEM_CALC_TI85) { run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_GRAPHVAR); run_with_key(emu, TILEM_KEY_WINDOW); } tilem_em_unlock(emu); } /* Automatically press key to be in the send mode (ti82 and ti85) */ static void prepare_for_link_receive(TilemCalcEmulator *emu) { tilem_em_lock(emu); tilem_em_wake_up(emu, TRUE); if (emu->calc->hw.model_id == TILEM_CALC_TI82) { run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_GRAPHVAR); run_with_key(emu, TILEM_KEY_ENTER); tilem_em_delay(emu, 10000000, TRUE); run_with_key(emu, TILEM_KEY_RIGHT); run_with_key(emu, TILEM_KEY_ENTER); } else if (emu->calc->hw.model_id == TILEM_CALC_TI85) { run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_MODE); run_with_key(emu, TILEM_KEY_2ND); run_with_key(emu, TILEM_KEY_GRAPHVAR); run_with_key(emu, TILEM_KEY_YEQU); run_with_key(emu, TILEM_KEY_GRAPH); tilem_em_delay(emu, 10000000, TRUE); run_with_key(emu, TILEM_KEY_ZOOM); tilem_em_delay(emu, 10000000, TRUE); run_with_key(emu, TILEM_KEY_YEQU); } tilem_em_unlock(emu); } /**************** Calc handle ****************/ static GStaticPrivate current_emu_key = G_STATIC_PRIVATE_INIT; /* ticalcs progress bar callback */ static void pbar_do_update() { TilemCalcEmulator *emu = g_static_private_get(¤t_emu_key); CalcUpdate *upd = emu->link_update; gdouble frac; if (upd->max1 > 0 && upd->max2 > 0) frac = ((gdouble) upd->cnt1 / upd->max1 + upd->cnt2) / upd->max2; else if (upd->max1 > 0) frac = ((gdouble) upd->cnt1 / upd->max1); else if (upd->max2 > 0) frac = ((gdouble) upd->cnt2 / upd->max2); else frac = -1.0; tilem_em_set_progress(emu, frac, upd->text); } /* Get the calc model (compatible for ticalcs) */ int get_calc_model(TilemCalc *calc) { return model_to_calcmodel(calc->hw.model_id); } /* Create a calc handle */ void begin_link(TilemCalcEmulator *emu, CableHandle **cbl, CalcHandle **ch, const char *title) { tilem_em_unlock(emu); *cbl = internal_link_handle_new(emu); emu->link_update->max1 = 0; emu->link_update->max2 = 0; emu->link_update->text[0] = 0; emu->link_update->pbar = &pbar_do_update; emu->link_update->label = &pbar_do_update; g_static_private_set(¤t_emu_key, emu, NULL); tilem_em_set_progress_title(emu, title); *ch = ticalcs_handle_new(get_calc_model(emu->calc)); if (!*ch) { g_critical("unsupported calc"); return; } ticalcs_update_set(*ch, emu->link_update); ticalcs_cable_attach(*ch, *cbl); } /* Destroy calc handle */ void end_link(TilemCalcEmulator *emu, CableHandle *cbl, CalcHandle *ch) { tilem_em_set_progress_title(emu, NULL); ticalcs_cable_detach(ch); ticalcs_handle_del(ch); ticables_handle_del(cbl); tilem_em_lock(emu); } /**************** Error messages ****************/ static char * get_tilibs_error(int errcode) { char *p = NULL; if (!ticalcs_error_get(errcode, &p) || !ticables_error_get(errcode, &p) || !tifiles_error_get(errcode, &p)) return p; else return g_strdup_printf("Unknown error (%d)", errcode); } static char * get_ti81_error(int errcode) { switch (errcode) { case TI81_ERR_FILE_IO: return g_strdup("File I/O error"); case TI81_ERR_INVALID_FILE: return g_strdup("Not a valid PRG file"); case TI81_ERR_MEMORY: return g_strdup("The calculator does not have enough free memory" " to load the program."); case TI81_ERR_SLOTS_FULL: return g_strdup("All calculator program slots are in use. " " You must delete an existing program before" " loading a new program."); case TI81_ERR_BUSY: return g_strdup("The calculator is currently busy. Please" " exit to the home screen before loading" " programs."); default: return g_strdup_printf("Unknown error code (%d)", errcode); } } void show_error(TilemCalcEmulator *emu, const char *title, const char *message) { if (emu->ewin) messagebox11(emu->ewin->window, GTK_MESSAGE_ERROR, "%s", title, "%s", message); else g_printerr("\n=== %s ===\n%s\n\n", title, message); } /**************** Sending files ****************/ /* Send a file to TI-81 */ static gboolean send_file_ti81(TilemCalcEmulator *emu, struct TilemSendFileInfo *sf) { TI81Program *prgm = NULL; FILE *f; int errnum; sf->error_message = NULL; f = g_fopen(sf->filename, "rb"); if (!f) { sf->error_message = g_strdup_printf ("Failed to open %s for reading: %s", sf->display_name, g_strerror(errno)); return FALSE; } if (ti81_read_prg_file(f, &prgm)) { sf->error_message = g_strdup_printf ("The file %s is not a valid TI-81 program file.", sf->display_name); fclose(f); return FALSE; } fclose(f); tilem_em_wake_up(emu, TRUE); prgm->info.slot = sf->slot; errnum = ti81_load_program(emu->calc, prgm); ti81_program_free(prgm); if (errnum && !emu->task_abort) sf->error_message = get_ti81_error(errnum); return (errnum == 0); } /* Get application name */ static gboolean get_app_name(const FlashContent *flashc, char *name) { int i; const unsigned char *data; unsigned int type, length; if (flashc->num_pages < 1 || flashc->pages[0]->size < 6 || flashc->pages[0]->data[0] != 0x80 || flashc->pages[0]->data[1] != 0x0f) return FALSE; i = 6; data = flashc->pages[0]->data; while (i < flashc->pages[0]->size && i < 128) { type = (data[i] << 8 | (data[i + 1] & 0xf0)); length = data[i + 1] & 0x0f; i += 2; if (length == 0x0d) { length = data[i]; i++; } else if (length == 0x0e) { length = (data[i] << 8 | data[i + 1]); i += 2; } else if (length == 0x0f) { return FALSE; } if (type == 0x8070) return FALSE; if (type == 0x8040) { memcpy(name, data + i, length > 8 ? 8 : length); return TRUE; } } return FALSE; } /* Try to delete an existing Flash app before we send a replacement */ static void try_delete_app(CalcHandle *ch, const FlashContent *flashc) { VarRequest vr; /* TI-73 does not support remote deletion */ if (ch->model == CALC_TI73) return; memset(&vr, 0, sizeof(VarRequest)); if (!get_app_name(flashc, vr.name)) return; /* Why does this use type 0x14 and not 0x24? I don't know. */ vr.type = 0x14; ticalcs_calc_del_var(ch, &vr); /* if an error occurs, ignore it */ } /* Send a file using ticalcs2 */ static gboolean send_file_linkport(TilemCalcEmulator *emu, struct TilemSendFileInfo *sf) { CalcModel model; FileClass cls; CableHandle *cbl; CalcHandle *ch; FileContent *filec; BackupContent *backupc; FlashContent *flashc; TigContent *tigc; CalcMode mode; int e; char *desc; model = get_calc_model(emu->calc); cls = tifiles_file_get_class(sf->filename); desc = g_strdup_printf("Sending %s", sf->display_name); /* Read input file */ switch (cls) { case TIFILE_SINGLE: case TIFILE_GROUP: case TIFILE_REGULAR: filec = tifiles_content_create_regular(model); e = tifiles_file_read_regular(sf->filename, filec); if (!e) { begin_link(emu, &cbl, &ch, desc); if (sf->first) prepare_for_link_send(emu); mode = (sf->last ? MODE_SEND_LAST_VAR : MODE_NORMAL); e = ticalcs_calc_send_var(ch, mode, filec); end_link(emu, cbl, ch); } tifiles_content_delete_regular(filec); break; case TIFILE_BACKUP: backupc = tifiles_content_create_backup(model); e = tifiles_file_read_backup(sf->filename, backupc); if (!e) { begin_link(emu, &cbl, &ch, desc); prepare_for_link_send(emu); e = ticalcs_calc_send_backup(ch, backupc); end_link(emu, cbl, ch); } tifiles_content_delete_backup(backupc); break; case TIFILE_FLASH: case TIFILE_OS: case TIFILE_APP: flashc = tifiles_content_create_flash(model); e = tifiles_file_read_flash(sf->filename, flashc); if (!e) { begin_link(emu, &cbl, &ch, desc); ticables_options_set_timeout(cbl, 30 * 10); prepare_for_link_send(emu); if (tifiles_file_is_os(sf->filename)) e = ticalcs_calc_send_os(ch, flashc); else if (tifiles_file_is_app(sf->filename)) { try_delete_app(ch, flashc); e = ticalcs_calc_send_app(ch, flashc); } else e = ticalcs_calc_send_cert(ch, flashc); end_link(emu, cbl, ch); } tifiles_content_delete_flash(flashc); break; case TIFILE_TIGROUP: tigc = tifiles_content_create_tigroup(model, 0); e = tifiles_file_read_tigroup(sf->filename, tigc); if (!e) { begin_link(emu, &cbl, &ch, desc); prepare_for_link_send(emu); e = ticalcs_calc_send_tigroup(ch, tigc, TIG_ALL); end_link(emu, cbl, ch); } tifiles_content_delete_tigroup(tigc); break; default: g_free(desc); sf->error_message = g_strdup_printf ("The file %s is not a valid program or" " variable file.", sf->display_name); return FALSE; } g_free(desc); if (e && !emu->task_abort) sf->error_message = get_tilibs_error(e); return (e == 0); } gboolean send_file_main(TilemCalcEmulator *emu, gpointer data) { struct TilemSendFileInfo *sf = data; /*emu->ilp.finished_cond = g_cond_new(); */ if (emu->calc->hw.model_id == TILEM_CALC_TI81) return send_file_ti81(emu, sf); else return send_file_linkport(emu, sf); } static void send_file_finished(TilemCalcEmulator *emu, gpointer data, gboolean cancelled) { struct TilemSendFileInfo *sf = data; if (sf->error_message && !cancelled) show_error(emu, "Unable to send file", sf->error_message); g_free(sf->filename); g_free(sf->display_name); g_free(sf->error_message); g_slice_free(struct TilemSendFileInfo, sf); /*g_cond_broadcast(emu->ilp.finished_cond);*/ } void tilem_link_send_file(TilemCalcEmulator *emu, const char *filename, int slot, gboolean first, gboolean last) { struct TilemSendFileInfo *sf; sf = g_slice_new0(struct TilemSendFileInfo); sf->filename = g_strdup(filename); sf->display_name = g_filename_display_basename(filename); sf->slot = slot; sf->first = first; sf->last = last; tilem_calc_emulator_begin(emu, &send_file_main, &send_file_finished, sf); } /**************** Get directory listing ****************/ /* Make a copy of a TilemVarEntry */ TilemVarEntry *tilem_var_entry_copy(const TilemVarEntry *tve) { TilemVarEntry *nve; g_return_val_if_fail(tve != NULL, NULL); nve = g_slice_new(TilemVarEntry); *nve = *tve; if (tve->ve) { nve->ve = g_slice_new(VarEntry); *nve->ve = *tve->ve; nve->ve->data = g_memdup(tve->ve->data, tve->ve->size); } if (tve->name_str) nve->name_str = g_strdup(tve->name_str); if (tve->type_str) nve->type_str = g_strdup(tve->type_str); if (tve->slot_str) nve->slot_str = g_strdup(tve->slot_str); if (tve->file_ext) nve->file_ext = g_strdup(tve->file_ext); if (tve->filetype_desc) nve->filetype_desc = g_strdup(tve->filetype_desc); return nve; } /* Free a TilemVarEntry */ void tilem_var_entry_free(TilemVarEntry *tve) { g_return_if_fail(tve != NULL); if (tve->ve) { g_free(tve->ve->data); g_slice_free(VarEntry, tve->ve); } g_free(tve->name_str); g_free(tve->type_str); g_free(tve->slot_str); g_free(tve->file_ext); g_free(tve->filetype_desc); g_slice_free(TilemVarEntry, tve); } struct dirlistinfo { GSList *list; char *error_message; gboolean aborted; gboolean no_gui; }; /* Convert tifiles VarEntry into a TilemVarEntry */ static TilemVarEntry *convert_ve(TilemCalcEmulator *emu, VarEntry *ve, gboolean is_flash) { TilemVarEntry *tve = g_slice_new0(TilemVarEntry); CalcModel tfmodel = get_calc_model(emu->calc); const char *model_str; const char *type_str; const char *fext; tve->model = emu->calc->hw.model_id; tve->ve = g_slice_new(VarEntry); *tve->ve = *ve; if (ve->data) tve->ve->data = g_memdup(ve->data, ve->size); tve->size = ve->size; tve->archived = (ve->attr & ATTRB_ARCHIVED ? TRUE : FALSE); tve->can_group = TRUE; tve->name_str = ticonv_varname_to_utf8(tfmodel, ve->name, ve->type); g_strchomp(tve->name_str); tve->type_str = g_strdup(tifiles_vartype2string(tfmodel, ve->type)); fext = tifiles_vartype2fext(tfmodel, ve->type); tve->file_ext = g_ascii_strdown(fext, -1); /* FIXME: the filetype_desc string is used as a description in the file chooser. It should be written in the same style as other such strings (e.g., "TI-83 Plus programs" rather than "TI83+ Program".) But this is better than nothing. */ model_str = tifiles_model_to_string(tfmodel); type_str = tifiles_vartype2type(tfmodel, ve->type); tve->filetype_desc = g_strdup_printf("%s %s", model_str, type_str); tve->can_group = !is_flash; return tve; } /* Convert a complete directory listing */ static void convert_dir_list(TilemCalcEmulator *emu, GNode *root, gboolean is_flash, GSList **list) { GNode *dir, *var; VarEntry *ve; TilemVarEntry *tve; if (!root) return; for (dir = root->children; dir; dir = dir->next) { for (var = dir->children; var; var = var->next) { ve = var->data; tve = convert_ve(emu, ve, is_flash); *list = g_slist_prepend(*list, tve); } } } /* Request directory listing using ticalcs */ static gboolean get_dirlist_silent(TilemCalcEmulator *emu, struct dirlistinfo *dl) { CableHandle *cbl; CalcHandle *ch; GNode *vars = NULL, *apps = NULL; GSList *list = NULL; int e = 0; begin_link(emu, &cbl, &ch, "Reading variable list"); prepare_for_link_receive(emu); if (ticalcs_calc_features(ch) & OPS_DIRLIST) { e = ticalcs_calc_get_dirlist(ch, &vars, &apps); if (!e) { convert_dir_list(emu, vars, FALSE, &list); convert_dir_list(emu, apps, TRUE, &list); } ticalcs_dirlist_destroy(&vars); ticalcs_dirlist_destroy(&apps); } end_link(emu, cbl, ch); dl->list = g_slist_reverse(list); dl->aborted = emu->task_abort; if (e && !emu->task_abort) dl->error_message = get_tilibs_error(e); return (e == 0); } /* Transfer variables non-silently using ticalcs */ static gboolean get_dirlist_nonsilent(TilemCalcEmulator *emu, struct dirlistinfo *dl) { CableHandle *cbl; CalcHandle *ch; FileContent *fc; VarEntry *head_entry; TilemVarEntry *tve; GSList *list = NULL; int e, i; begin_link(emu, &cbl, &ch, "Receiving variables"); prepare_for_link_receive(emu); fc = tifiles_content_create_regular(ch->model); e = ticalcs_calc_recv_var_ns(ch, MODE_BACKUP, fc, &head_entry); if (!e) { for (i = 0; i < fc->num_entries; i++) { tve = convert_ve(emu, fc->entries[i], FALSE); list = g_slist_prepend(list, tve); } } if (head_entry) tifiles_ve_delete(head_entry); tifiles_content_delete_regular(fc); end_link(emu, cbl, ch); dl->list = g_slist_reverse(list); dl->aborted = emu->task_abort; if (e && !emu->task_abort) dl->error_message = get_tilibs_error(e); return (e == 0); } /* Get TI-81 directory listing */ static gboolean get_dirlist_ti81(TilemCalcEmulator *emu, struct dirlistinfo *dl) { int i, slot; TI81ProgInfo info; GSList *list = NULL; TilemVarEntry *tve; int e; tilem_em_wake_up(emu, TRUE); for (i = 0; i <= TI81_SLOT_MAX; i++) { /* put Prgm0 after Prgm9, the way it appears in the menu */ if (i < 9) slot = i + 1; else if (i == 9) slot = 0; else slot = i; if ((e = ti81_get_program_info(emu->calc, slot, &info))) break; if (info.size == 0) continue; tve = g_slice_new0(TilemVarEntry); tve->model = TILEM_CALC_TI81; tve->slot = info.slot; tve->name_str = ti81_program_name_to_string(info.name); tve->slot_str = ti81_program_slot_to_string(info.slot); tve->file_ext = g_strdup("prg"); tve->filetype_desc = g_strdup("TI-81 programs"); tve->size = info.size; tve->archived = FALSE; tve->can_group = FALSE; list = g_slist_prepend(list, tve); } dl->list = g_slist_reverse(list); if (e && !emu->task_abort) dl->error_message = get_ti81_error(e); return (e == 0); } static gboolean get_dirlist_main(TilemCalcEmulator *emu, gpointer data) { switch (emu->calc->hw.model_id) { case TILEM_CALC_TI81: return get_dirlist_ti81(emu, data); case TILEM_CALC_TI82: case TILEM_CALC_TI85: return get_dirlist_nonsilent(emu, data); default: return get_dirlist_silent(emu, data); } } static void get_dirlist_finished(TilemCalcEmulator *emu, gpointer data, gboolean cancelled) { GSList *l; struct dirlistinfo *dl = data; if (dl->error_message && !cancelled) show_error(emu, "Unable to receive variable list", dl->error_message); else if (!cancelled && !dl->aborted && emu->ewin && !dl->no_gui) { if (!emu->rcvdlg) emu->rcvdlg = tilem_receive_dialog_new(emu); tilem_receive_dialog_update(emu->rcvdlg, dl->list); dl->list = NULL; } if (!dl->no_gui && emu->rcvdlg) emu->rcvdlg->refresh_pending = FALSE; for (l = dl->list; l; l = l->next) tilem_var_entry_free(l->data); g_slist_free(dl->list); g_slice_free(struct dirlistinfo, dl); } void tilem_link_get_dirlist(TilemCalcEmulator *emu) { struct dirlistinfo *dl = g_slice_new0(struct dirlistinfo); tilem_calc_emulator_begin(emu, &get_dirlist_main, &get_dirlist_finished, dl); } /**************** Receiving files ****************/ static gboolean write_output(FileContent **vars, FlashContent **apps, const char *filename, gboolean output_tig, char **error_message) { FileContent *group = NULL; TigContent *tig = NULL; int e, nvars, napps; for (nvars = 0; vars && vars[nvars]; nvars++) ; for (napps = 0; apps && apps[napps]; napps++) ; g_return_val_if_fail(nvars > 0 || napps > 0, FALSE); if (output_tig) { e = tifiles_tigroup_contents(vars, apps, &tig); if (!e) e = tifiles_file_write_tigroup(filename, tig); } else if (nvars > 1 && napps == 0) { e = tifiles_group_contents(vars, &group); if (!e) e = tifiles_file_write_regular(filename, group, NULL); } else if (nvars == 0 && napps == 1) { e = tifiles_file_write_flash(filename, apps[0]); } else if (nvars == 1 && napps == 0) { e = tifiles_file_write_regular(filename, vars[0], NULL); } else { *error_message = g_strdup ("Applications cannot be saved in an XXg group" " file. Try using TIG format or saving apps" " individually."); return FALSE; } if (e) *error_message = get_tilibs_error(e); if (tig) tifiles_content_delete_tigroup(tig); if (group) tifiles_content_delete_regular(group); return (e == 0); } static gboolean receive_files_silent(TilemCalcEmulator* emu, struct TilemReceiveFileInfo *rf) { CableHandle *cbl; CalcHandle *ch; FileContent **vars, *filec; FlashContent **apps, *flashc; GSList *l; TilemVarEntry *tve; int e, i, nvars, napps; g_return_val_if_fail(rf->entries != NULL, FALSE); i = g_slist_length(rf->entries); vars = g_new0(FileContent *, i + 1); apps = g_new0(FlashContent *, i + 1); nvars = napps = 0; begin_link(emu, &cbl, &ch, "Receiving variables"); for (l = rf->entries; l; l = l->next) { tve = l->data; if (tve->ve->type == tifiles_flash_type(ch->model)) { flashc = tifiles_content_create_flash(ch->model); e = ticalcs_calc_recv_app(ch, flashc, tve->ve); apps[napps++] = flashc; } else { filec = tifiles_content_create_regular(ch->model); e = ticalcs_calc_recv_var(ch, MODE_NORMAL, filec, tve->ve); vars[nvars++] = filec; } if (e) break; } if (e && !emu->task_abort) rf->error_message = get_tilibs_error(e); end_link(emu, cbl, ch); if (!e) e = !write_output(vars, apps, rf->destination, rf->output_tig, &rf->error_message); for (i = 0; i < nvars; i++) tifiles_content_delete_regular(vars[i]); for (i = 0; i < napps; i++) tifiles_content_delete_flash(apps[i]); return (e == 0); } static gboolean receive_files_ti81(TilemCalcEmulator* emu, struct TilemReceiveFileInfo *rf) { TilemVarEntry *tve; TI81Program *prgm = NULL; int e; FILE *f; char *dname; g_return_val_if_fail(rf->entries != NULL, FALSE); if (rf->entries->next) { rf->error_message = g_strdup ("TI-81 programs cannot be saved in a group file." " Try saving programs individually."); return FALSE; } tve = rf->entries->data; e = ti81_get_program(emu->calc, tve->slot, &prgm); if (e) { rf->error_message = get_ti81_error(e); return FALSE; } f = g_fopen(rf->destination, "wb"); if (!f) { e = errno; dname = g_filename_display_basename(rf->destination); rf->error_message = g_strdup_printf ("Failed to open %s for writing: %s", dname, g_strerror(e)); g_free(dname); ti81_program_free(prgm); return FALSE; } e = ti81_write_prg_file(f, prgm); if (fclose(f) || e) { e = errno; dname = g_filename_display_basename(rf->destination); rf->error_message = g_strdup_printf ("Error writing %s: %s", dname, g_strerror(e)); g_free(dname); ti81_program_free(prgm); return FALSE; } ti81_program_free(prgm); return TRUE; } static gboolean receive_files_nonsilent(TilemCalcEmulator *emu, struct TilemReceiveFileInfo *rf) { const TilemVarEntry *tve; FileContent **vars, *fc; int i, nvars; GSList *l; gboolean status; nvars = g_slist_length(rf->entries); vars = g_new0(FileContent *, nvars + 1); i = 0; for (l = rf->entries; l; l = l->next) { tve = l->data; g_return_val_if_fail(tve->ve != NULL, FALSE); g_return_val_if_fail(tve->ve->data != NULL, FALSE); /* avoid copying variable data */ fc = tifiles_content_create_regular(get_calc_model(emu->calc)); fc->entries = g_new(VarEntry *, 1); fc->num_entries = 1; fc->entries[0] = tve->ve; vars[i++] = fc; } status = write_output(vars, NULL, rf->destination, rf->output_tig, &rf->error_message); for (i = 0; i < nvars; i++) { if (vars[i]) { vars[i]->num_entries = 0; g_free(vars[i]->entries); vars[i]->entries = NULL; tifiles_content_delete_regular(vars[i]); } } g_free(vars); return status; } static gboolean receive_files_main(TilemCalcEmulator *emu, gpointer data) { struct TilemReceiveFileInfo *rf = data; TilemVarEntry *tve; g_return_val_if_fail(rf->entries != NULL, FALSE); tve = rf->entries->data; if (emu->calc->hw.model_id == TILEM_CALC_TI81) return receive_files_ti81(emu, rf); else if (tve->ve && tve->ve->data) return receive_files_nonsilent(emu, rf); else return receive_files_silent(emu, rf); } static void receive_files_finished(TilemCalcEmulator *emu, gpointer data, gboolean cancelled) { struct TilemReceiveFileInfo *rf = data; GSList *l; if (rf->error_message && !cancelled) show_error(emu, "Unable to save file", rf->error_message); g_free(rf->destination); g_free(rf->error_message); for (l = rf->entries; l; l = l->next) tilem_var_entry_free(l->data); g_slist_free(rf->entries); g_slice_free(struct TilemReceiveFileInfo, rf); } void tilem_link_receive_group(TilemCalcEmulator *emu, GSList *entries, const char *destination) { struct TilemReceiveFileInfo *rf; GSList *l; TilemVarEntry *tve; const char *p; gboolean output_tig = FALSE; g_return_if_fail(emu != NULL); g_return_if_fail(emu->calc != NULL); g_return_if_fail(entries != NULL); g_return_if_fail(destination != NULL); for (l = entries; l; l = l->next) { tve = l->data; g_return_if_fail(emu->calc->hw.model_id == tve->model); } p = strrchr(destination, '.'); if (p && (!g_ascii_strcasecmp(p, ".tig") || !g_ascii_strcasecmp(p, ".zip"))) output_tig = TRUE; rf = g_slice_new0(struct TilemReceiveFileInfo); rf->destination = g_strdup(destination); rf->output_tig = output_tig; tve = entries->data; if (tve->ve && tve->ve->data) { /* non-silent: we already have the data; save the file right now */ rf->entries = entries; receive_files_nonsilent(emu, rf); rf->entries = NULL; receive_files_finished(emu, rf, FALSE); } else { /* silent: retrieve and save data in background */ for (l = entries; l; l = l->next) { tve = tilem_var_entry_copy(l->data); rf->entries = g_slist_prepend(rf->entries, tve); } rf->entries = g_slist_reverse(rf->entries); tilem_calc_emulator_begin(emu, &receive_files_main, &receive_files_finished, rf); } } void tilem_link_receive_file(TilemCalcEmulator *emu, const TilemVarEntry *varentry, const char* destination) { GSList *l; l = g_slist_prepend(NULL, (gpointer) varentry); tilem_link_receive_group(emu, l, destination); g_slist_free(l); } /**************** Receive matching files ****************/ struct recmatchinfo { char *pattern; char *destdir; struct dirlistinfo *dl; struct TilemReceiveFileInfo *rf; }; static gboolean receive_matching_main(TilemCalcEmulator *emu, gpointer data) { struct recmatchinfo *rm = data; GSList *l, *selected = NULL; TilemVarEntry *tve; char *defname, *defname_r, *defname_l; GPatternSpec *pat; gboolean status = TRUE; if (!get_dirlist_main(emu, rm->dl)) return FALSE; /* Find variables that match the pattern */ pat = g_pattern_spec_new(rm->pattern); for (l = rm->dl->list; l; l = l->next) { tve = l->data; defname = get_default_filename(tve); defname_r = g_utf8_normalize(defname, -1, G_NORMALIZE_NFKD); if (g_pattern_match(pat, strlen(defname_r), defname_r, NULL)) selected = g_slist_prepend(selected, tve); g_free(defname); g_free(defname_r); } g_pattern_spec_free(pat); if (!selected) { rm->rf->error_message = g_strdup_printf ("Variable %s not found", rm->pattern); return FALSE; } /* Receive variables */ selected = g_slist_reverse(selected); for (l = selected; l; l = l->next) { tve = l->data; g_free(rm->rf->destination); defname = get_default_filename(tve); defname_l = utf8_to_filename(defname); rm->rf->destination = g_build_filename(rm->destdir, defname_l, NULL); g_free(defname); g_free(defname_l); rm->rf->entries = g_slist_prepend(NULL, tve); status = receive_files_main(emu, rm->rf); g_slist_free(rm->rf->entries); rm->rf->entries = NULL; if (!status) break; } g_slist_free(selected); return status; } static void receive_matching_finished(TilemCalcEmulator *emu, gpointer data, gboolean cancelled) { struct recmatchinfo *rm = data; get_dirlist_finished(emu, rm->dl, cancelled); receive_files_finished(emu, rm->rf, cancelled); g_free(rm->pattern); g_free(rm->destdir); g_slice_free(struct recmatchinfo, rm); } /* Receive variables with names matching a pattern. PATTERN is a glob-like pattern in UTF-8. Files will be written out to DESTDIR. */ void tilem_link_receive_matching(TilemCalcEmulator *emu, const char *pattern, const char *destdir) { struct recmatchinfo *rm; g_return_if_fail(emu != NULL); g_return_if_fail(pattern != NULL); g_return_if_fail(destdir != NULL); rm = g_slice_new0(struct recmatchinfo); rm->pattern = g_utf8_normalize(pattern, -1, G_NORMALIZE_NFKD); rm->destdir = g_strdup(destdir); rm->dl = g_slice_new0(struct dirlistinfo); rm->dl->no_gui = TRUE; rm->rf = g_slice_new0(struct TilemReceiveFileInfo); tilem_calc_emulator_begin(emu, &receive_matching_main, &receive_matching_finished, rm); } tilem-2.0/gui/macro.c000066400000000000000000000170151220200411600145060ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * * 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 3 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, see . * */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "gui.h" #include "filedlg.h" #include "emucore.h" /* Allocate a new TilemMacro structure which is empty */ static TilemMacro* tilem_macro_new() { TilemMacro *macro = g_new(TilemMacro, 1); macro->n = 0; macro->actions = NULL; return macro; } /* New or renew the table of actions (each TilemMacroAtom is an action) */ static TilemMacroAtom** tilem_macro_actions_new(TilemMacro *macro, int n) { TilemMacroAtom **atom; if(n == 0) { atom = g_new(TilemMacroAtom*, n); } else { atom = g_renew(TilemMacroAtom*, macro->actions, n); } return atom; } /* Try to destroy the TilemMacro if really allocated */ static void tilem_macro_finalize(TilemMacro* macro) { if(macro) { if(macro->actions) g_free(macro->actions); g_free(macro); } } /* Firstly free the memory then create a new TilemMacro */ void tilem_macro_start(TilemCalcEmulator *emu) { emu->isMacroRecording = TRUE; /* Firstly destroy the macro if exists */ tilem_macro_finalize(emu->macro); /* Then allocate a new one */ emu->macro = tilem_macro_new(emu); } /* Add an action to the macro. The action could be : * A keypress (type == 0) * A file load (type == 1) * Or something else if I implement it :) */ void tilem_macro_add_action(TilemMacro* macro, int type, char * value) { int n = macro->n; /* We want to allocate for 1 object, but index is 0 */ macro->actions = tilem_macro_actions_new(macro, n + 1); /* Then we need to save the action */ macro->actions[n] = g_new(char, strlen(value)); /* FIXME : gcc says : "assignment from incompatible pointer type" ??? */ macro->actions[n]->value = g_strdup(value); macro->actions[n]->type = type; macro->n++; } /* Stop the macro */ void tilem_macro_stop(TilemCalcEmulator *emu) { if(emu->isMacroRecording) emu->isMacroRecording = FALSE; } /* Print the macro actions content (debug) */ void tilem_macro_print(TilemMacro *macro) { int i = 0; printf("macro->n : %d\n", macro->n); for(i = 0; i < macro->n; i++ ){ printf("type : %d value : %s\n", macro->actions[i]->type, macro->actions[i]->value); } } /* Write a file using TilemMacro structure */ void tilem_macro_write_file(TilemCalcEmulator *emu) { char *dir, *filename; tilem_config_get("macro", "directory/f", &dir, NULL); filename = prompt_save_file("Save macro", GTK_WINDOW(emu->ewin->window), NULL, dir, "Macro files", "*.txt", "All files", "*", NULL); if(filename) { FILE * fp = g_fopen(filename, "w"); if(fp) { int i = 0; for(i = 0; i< emu->macro->n; i++ ){ printf("type : %d value : %s\n", emu->macro->actions[i]->type, emu->macro->actions[i]->value); /* Test if it's a key press or a file loading action */ if(emu->macro->actions[i]->type == 1) { char * lengthchar = g_new0(char, 4); int length = strlen(emu->macro->actions[i]->value); fwrite("file=", 1, 5, fp); sprintf(lengthchar, "%04d", strlen(emu->macro->actions[i]->value)); fwrite(lengthchar, 1, sizeof(int), fp); fwrite("-", 1, 1, fp); fwrite(emu->macro->actions[i]->value, 1, length, fp); g_free(lengthchar); } else { fwrite(emu->macro->actions[i]->value, 1, 4, fp); fwrite(",", 1, 1, fp); } } tilem_config_set("macro", "directory/f", g_path_get_dirname(filename), NULL); fclose(fp); } g_free(filename); g_free(dir); } } #define MACRO_KEYPRESS 0 #define MACRO_FILE 1 /* Play the macro (macro should be created or loaded before else it does nothing) */ static gboolean tilem_macro_play_main(TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data) { if(!emu->macro) { printf("Nothing to play\n"); return FALSE; } int i; for(i = 0; i < emu->macro->n; i++ ){ if(emu->macro->actions[i]->type == MACRO_FILE) { /* Type == 1 is load file */ struct TilemSendFileInfo *sf; sf = g_slice_new0(struct TilemSendFileInfo); sf->filename = g_strdup(emu->macro->actions[i]->value); sf->display_name = g_filename_display_basename(emu->macro->actions[i]->value); sf->slot = -1; sf->first = TRUE; sf->last = TRUE; send_file_main(emu, sf); } else { /* type == 0 is keypress */ int code = atoi(emu->macro->actions[i]->value); tilem_em_unlock(emu); run_with_key_slowly(emu->calc, code); tilem_em_lock(emu); } } return TRUE; } static void tilem_macro_play_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data, G_GNUC_UNUSED gboolean cancelled) { } /* Play the macro */ void tilem_macro_play(TilemCalcEmulator* emu) { tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL); } /* Load a macro (when finished, task manager will normally call tilem_macro_play) */ static gboolean tilem_macro_load_main(TilemCalcEmulator* emu, gpointer data) { char* filename = (char*) data; char c = 'a'; if(filename) { FILE * fp = g_fopen(filename, "r"); /* printf("filename : %s\n", filename); */ tilem_macro_start(emu); while(c != EOF) { char* codechar = g_new0(char, 4); fread(codechar, 1, 4, fp); if(strcmp(codechar, "file") == 0) { c = fgetc(fp); /* Drop the "="*/ char *lengthchar = g_new0(char, 4); fread(lengthchar, 1, 4, fp); c = fgetc(fp); /* Drop the "-"*/ int length = atoi(lengthchar); char* filetoload= g_new0(char, length); fread(filetoload, 1, length, fp); tilem_macro_add_action(emu->macro, 1, filetoload); g_free(lengthchar); g_free(filetoload); } else { int code = atoi(codechar); if(code <= 0) break; /*printf("code : %d, codechar : %s\n",code, codechar); */ tilem_macro_add_action(emu->macro, 0, codechar); c = fgetc(fp); } } tilem_macro_stop(emu); fclose(fp); } return TRUE; } /* When the macro is totally loaded, then we can play it ! */ static void tilem_macro_load_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data, G_GNUC_UNUSED gboolean cancelled) { tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL); } /* Load a macro from filename. * If filename == NULL prompt the user */ void tilem_macro_load(TilemCalcEmulator *emu, char* filename) { /* printf("tilem_macro_load : filename : %s\n", filename); */ if(!filename) { char *dir; tilem_config_get("macro", "directory/f", &dir, NULL); filename = prompt_open_file("Open macro", GTK_WINDOW(emu->ewin->window), dir, "Macro files", "*.txt", "All files", "*", NULL); if(dir) g_free(dir); } tilem_calc_emulator_begin(emu, &tilem_macro_load_main, &tilem_macro_load_finished, filename); } tilem-2.0/gui/memmodel.c000066400000000000000000000323531220200411600152060ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "gui.h" #include "memmodel.h" #include "charmap.h" /* GTK+ requires us to supply several property values for every byte, and we might have hundreds of bytes that need to be refreshed each time the window is repainted. To avoid locking and unlocking the calc for every call to tilem_mem_model_get_value(), we can retrieve information for an entire block of memory and keep it in cache. For each address, we cache the current byte value (8 bits), whether or not it is editable (1 bit), and its physical address (up to 22 bits for current calculator models), so everything fits in a guint32. For future models, this scheme might need to be modified. */ #define CACHE_BLOCK_SIZE 256 #define CACHE_NUM_BLOCKS 16 typedef struct { dword address; guint32 *info; } MemModelCacheBlock; /* Check if a given physical address is editable (i.e., located in RAM or in a non-protected Flash sector) */ static gboolean address_editable(TilemCalc *calc, dword a) { int start, end, i; if (a >= calc->hw.romsize) /* address is in RAM */ return TRUE; if (!(calc->hw.flags & TILEM_CALC_HAS_FLASH)) /* calc does not use Flash */ return FALSE; /* address is in Flash -> check if sector is protected */ start = 0; end = calc->hw.nflashsectors; while (start < end) { i = (start + end) / 2; if (a < calc->hw.flashsectors[i].start) end = i; else if (a >= (calc->hw.flashsectors[i].start + calc->hw.flashsectors[i].size)) start = i + 1; else return !(calc->hw.flashsectors[i].protectgroup & ~calc->flash.overridegroup); } g_return_val_if_reached(FALSE); } /* Copy calc memory contents into cache. */ static void fill_cache_block(TilemMemModel *mm, MemModelCacheBlock *cb) { TilemCalc *calc; dword i, addr, phys; byte value, editable; g_return_if_fail(mm->emu != NULL); tilem_calc_emulator_lock(mm->emu); calc = mm->emu->calc; if (!calc) { tilem_calc_emulator_unlock(mm->emu); return; } for (i = 0; i < CACHE_BLOCK_SIZE; i++) { addr = (cb->address + i) % mm->wrap_addr; if (mm->use_logical) phys = (*calc->hw.mem_ltop)(calc, addr); else phys = addr; editable = address_editable(calc, phys); value = calc->mem[phys]; cb->info[i] = (value | (editable << 8) | (phys << 9)); } tilem_calc_emulator_unlock(mm->emu); } /* Retrieve info for given address. */ static guint32 get_mem_info(TilemMemModel *mm, dword addr) { GList *l; MemModelCacheBlock *cb; dword start, index; start = addr & ~(CACHE_BLOCK_SIZE - 1); index = addr & (CACHE_BLOCK_SIZE - 1); for (l = mm->cache->head; l; l = l->next) { cb = l->data; if (cb->address == start) { if (l->prev) { /* Move this cache block to the start of the list */ g_queue_unlink(mm->cache, l); g_queue_push_head_link(mm->cache, l); } return cb->info[index]; } } /* Data not found in cache; drop the least recently used block and retrieve the requested block from the calc */ l = g_queue_pop_tail_link(mm->cache); g_queue_push_head_link(mm->cache, l); cb = l->data; cb->address = start; fill_cache_block(mm, cb); return cb->info[index]; } /* Get address's byte value. */ static byte get_value(TilemMemModel *mm, dword addr) { return (get_mem_info(mm, addr) & 0xff); } /* Get address's editability. */ static gboolean get_editable(TilemMemModel *mm, dword addr) { return ((get_mem_info(mm, addr) >> 8) & 1); } /* Get address's corresponding physical address. */ static dword get_phys_addr(TilemMemModel *mm, dword addr) { return (get_mem_info(mm, addr) >> 9); } /* Clear cache. This function should be called any time something happens that might affect memory contents. */ void tilem_mem_model_clear_cache(TilemMemModel *mm) { GList *l; MemModelCacheBlock *cb; g_return_if_fail(TILEM_IS_MEM_MODEL(mm)); for (l = mm->cache->head; l; l = l->next) { cb = l->data; cb->address = (dword) -1; } } /* Get flags for the model */ static GtkTreeModelFlags tilem_mem_model_get_flags(G_GNUC_UNUSED GtkTreeModel *model) { return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); } /* Get the number of columns */ static int tilem_mem_model_get_n_columns(GtkTreeModel *model) { TilemMemModel *mm; g_return_val_if_fail(TILEM_IS_MEM_MODEL(model), 0); mm = TILEM_MEM_MODEL(model); return (MM_COLUMNS_PER_BYTE * mm->row_size); } /* Get type of data for the given column. Currently all columns are strings. */ static GType tilem_mem_model_get_column_type(G_GNUC_UNUSED GtkTreeModel *model, int index) { index %= MM_COLUMNS_PER_BYTE; switch (index) { case MM_COL_ADDRESS_0: case MM_COL_HEX_0: case MM_COL_CHAR_0: return G_TYPE_STRING; case MM_COL_BYTE_PTR_0: return G_TYPE_POINTER; case MM_COL_EDITABLE_0: return G_TYPE_BOOLEAN; default: g_return_val_if_reached(G_TYPE_INVALID); } } /* Get an iterator pointing to the nth row */ static gboolean get_nth_iter(GtkTreeModel *model, GtkTreeIter *iter, int n) { TilemMemModel *mm; g_return_val_if_fail(TILEM_IS_MEM_MODEL(model), FALSE); mm = TILEM_MEM_MODEL(model); if (n >= mm->num_rows) return FALSE; iter->stamp = mm->stamp; iter->user_data = GINT_TO_POINTER(n); iter->user_data2 = NULL; iter->user_data3 = NULL; return TRUE; } /* Get row number for the given iterator */ static int get_row_number(GtkTreeModel *model, GtkTreeIter *iter) { TilemMemModel *mm; int n; g_return_val_if_fail(TILEM_IS_MEM_MODEL(model), 0); mm = TILEM_MEM_MODEL(model); g_return_val_if_fail(iter != NULL, 0); g_return_val_if_fail(iter->stamp == mm->stamp, 0); n = GPOINTER_TO_INT(iter->user_data); g_return_val_if_fail(n < mm->num_rows, 0); return n; } /* Get iterator for a given path */ static gboolean tilem_mem_model_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) { int *indices; if (gtk_tree_path_get_depth(path) != 1) return FALSE; indices = gtk_tree_path_get_indices(path); return get_nth_iter(model, iter, indices[0]); } /* Get path for an iterator */ static GtkTreePath * tilem_mem_model_get_path(GtkTreeModel *model, GtkTreeIter *iter) { int n; n = get_row_number(model, iter); return gtk_tree_path_new_from_indices(n, -1); } /* Get next (sibling) iterator */ static gboolean tilem_mem_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter) { int n; n = get_row_number(model, iter); return get_nth_iter(model, iter, n + 1); } /* Check if iterator has a child */ static gboolean tilem_mem_model_iter_has_child(G_GNUC_UNUSED GtkTreeModel *model, G_GNUC_UNUSED GtkTreeIter *iter) { return FALSE; } /* Get number of children (iter = NULL means get number of root nodes) */ static gint tilem_mem_model_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter) { TilemMemModel *mm; g_return_val_if_fail(TILEM_IS_MEM_MODEL(model), 0); mm = TILEM_MEM_MODEL(model); if (iter) return 0; else return (mm->num_rows); } /* Get nth child (parent = NULL means get nth root node */ static gboolean tilem_mem_model_iter_nth_child( GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { G_GNUC_UNUSED TilemMemModel* mm; g_return_val_if_fail(TILEM_IS_MEM_MODEL(model), FALSE); mm = TILEM_MEM_MODEL(model); if (parent) return FALSE; else return get_nth_iter(model, iter, n); } /* Get first child */ static gboolean tilem_mem_model_iter_children(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent) { return tilem_mem_model_iter_nth_child(model, iter, parent, 0); } /* Get parent */ static gboolean tilem_mem_model_iter_parent(G_GNUC_UNUSED GtkTreeModel *model, G_GNUC_UNUSED GtkTreeIter *iter, G_GNUC_UNUSED GtkTreeIter *child) { return FALSE; } /* Retrieve value for a given column */ static void tilem_mem_model_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value) { TilemMemModel *mm; dword n, addr, phys; TilemCalc *calc; char buf[100], *s; g_return_if_fail(TILEM_IS_MEM_MODEL(model)); mm = TILEM_MEM_MODEL(model); g_return_if_fail(mm->emu != NULL); g_return_if_fail(mm->emu->calc != NULL); n = get_row_number(model, iter); calc = mm->emu->calc; addr = (mm->start_addr + n * mm->row_size + column / MM_COLUMNS_PER_BYTE) % mm->wrap_addr; column %= MM_COLUMNS_PER_BYTE; switch (column) { case MM_COL_ADDRESS_0: s = tilem_format_addr(mm->emu->dbg, addr, !mm->use_logical); g_value_init(value, G_TYPE_STRING); g_value_set_string(value, s); g_free(s); break; case MM_COL_HEX_0: g_snprintf(buf, sizeof(buf), "%02X", get_value(mm, addr)); g_value_init(value, G_TYPE_STRING); g_value_set_string(value, buf); break; case MM_COL_CHAR_0: s = ti_to_unicode(calc->hw.model_id, get_value(mm, addr)); g_value_init(value, G_TYPE_STRING); g_value_set_string(value, s); g_free(s); break; case MM_COL_BYTE_PTR_0: phys = get_phys_addr(mm, addr); g_value_init(value, G_TYPE_POINTER); g_value_set_pointer(value, &calc->mem[phys]); break; case MM_COL_EDITABLE_0: g_value_init(value, G_TYPE_BOOLEAN); g_value_set_boolean(value, get_editable(mm, addr)); break; } } static void tilem_mem_model_init(TilemMemModel *mm) { int i; MemModelCacheBlock *cb; mm->stamp = g_random_int(); mm->row_size = 1; mm->cache = g_queue_new(); for (i = 0; i < CACHE_NUM_BLOCKS; i++) { cb = g_slice_new(MemModelCacheBlock); cb->address = (dword) -1; cb->info = g_new(guint32, CACHE_BLOCK_SIZE); g_queue_push_head(mm->cache, cb); } } static void tilem_mem_model_finalize(GObject *obj) { TilemMemModel *mm; MemModelCacheBlock *cb; g_return_if_fail(TILEM_IS_MEM_MODEL(obj)); mm = TILEM_MEM_MODEL(obj); while ((cb = g_queue_pop_head(mm->cache))) { g_free(cb->info); g_slice_free(MemModelCacheBlock, cb); } } static void tilem_mem_model_class_init(TilemMemModelClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = &tilem_mem_model_finalize; } static void tilem_mem_tree_model_init(GtkTreeModelIface *iface) { iface->get_flags = &tilem_mem_model_get_flags; iface->get_n_columns = &tilem_mem_model_get_n_columns; iface->get_column_type = &tilem_mem_model_get_column_type; iface->get_iter = &tilem_mem_model_get_iter; iface->get_path = &tilem_mem_model_get_path; iface->get_value = &tilem_mem_model_get_value; iface->iter_next = &tilem_mem_model_iter_next; iface->iter_children = &tilem_mem_model_iter_children; iface->iter_has_child = &tilem_mem_model_iter_has_child; iface->iter_n_children = &tilem_mem_model_iter_n_children; iface->iter_nth_child = &tilem_mem_model_iter_nth_child; iface->iter_parent = &tilem_mem_model_iter_parent; } GType tilem_mem_model_get_type(void) { static GType type = 0; static const GTypeInfo type_info = { sizeof(TilemMemModelClass), NULL, NULL, (GClassInitFunc) tilem_mem_model_class_init, NULL, NULL, sizeof(TilemMemModel), 0, (GInstanceInitFunc) tilem_mem_model_init, NULL }; static const GInterfaceInfo tree_model_info = { (GInterfaceInitFunc) tilem_mem_tree_model_init, NULL, NULL }; if (!type) { type = g_type_register_static(G_TYPE_OBJECT, "TilemMemModel", &type_info, 0); g_type_add_interface_static(type, GTK_TYPE_TREE_MODEL, &tree_model_info); } return type; } GtkTreeModel * tilem_mem_model_new(TilemCalcEmulator* emu, int rowsize, dword start, gboolean logical) { TilemMemModel* mm; g_return_val_if_fail(emu != NULL, NULL); g_return_val_if_fail(emu->calc != NULL, NULL); g_return_val_if_fail(rowsize > 0, NULL); mm = g_object_new(TILEM_TYPE_MEM_MODEL, NULL); mm->emu = emu; mm->row_size = rowsize; mm->start_addr = start; if (logical) { mm->use_logical = TRUE; mm->wrap_addr = 0x10000; } else { mm->use_logical = FALSE; mm->wrap_addr = (emu->calc->hw.romsize + emu->calc->hw.ramsize); } mm->num_rows = (mm->wrap_addr + rowsize - 1) / rowsize; return GTK_TREE_MODEL(mm); } tilem-2.0/gui/memmodel.h000066400000000000000000000054511220200411600152120ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #include /* TilemMemModel object: an efficient GtkTreeModel interface for viewing and editing calculator's memory */ G_BEGIN_DECLS /* Column numbers (repeated for each byte in a given row) */ enum { MM_COL_ADDRESS_0 = 0, /* Address (hexadecimal) */ MM_COL_HEX_0, /* Byte value (hexadecimal) */ MM_COL_CHAR_0, /* Byte value (character, converted to UTF-8) */ MM_COL_BYTE_PTR_0, /* Pointer to corresponding memory byte */ MM_COL_EDITABLE_0, /* TRUE if byte is editable */ MM_COLUMNS_PER_BYTE }; #define MM_COL_ADDRESS(n) (MM_COL_ADDRESS_0 + (n) * MM_COLUMNS_PER_BYTE) #define MM_COL_HEX(n) (MM_COL_HEX_0 + (n) * MM_COLUMNS_PER_BYTE) #define MM_COL_CHAR(n) (MM_COL_CHAR_0 + (n) * MM_COLUMNS_PER_BYTE) #define MM_COL_BYTE_PTR(n) (MM_COL_BYTE_PTR_0 + (n) * MM_COLUMNS_PER_BYTE) #define MM_COL_EDITABLE(n) (MM_COL_EDITABLE_0 + (n) * MM_COLUMNS_PER_BYTE) /* GObject stuff */ #define TILEM_TYPE_MEM_MODEL (tilem_mem_model_get_type()) #define TILEM_MEM_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TILEM_TYPE_MEM_MODEL, TilemMemModel)) #define TILEM_MEM_MODEL_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TILEM_TYPE_MEM_MODEL, TilemMemModelClass)) #define TILEM_IS_MEM_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TILEM_TYPE_MEM_MODEL)) #define TILEM_IS_MEM_MODEL_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), TILEM_TYPE_MEM_MODEL)) #define TILEM_MEM_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TILEM_TYPE_MEM_MODEL, TilemMemModelClass)) typedef struct _TilemMemModel { GObject parent; TilemCalcEmulator *emu; gint stamp; int row_size; int num_rows; dword start_addr; dword wrap_addr; gboolean use_logical; GQueue *cache; } TilemMemModel; typedef struct _TilemMemModelClass { GObjectClass parent_class; } TilemMemModelClass; GType tilem_mem_model_get_type(void) G_GNUC_CONST; GtkTreeModel * tilem_mem_model_new(TilemCalcEmulator* emu, int rowsize, dword start, gboolean logical); void tilem_mem_model_clear_cache(TilemMemModel *mm); G_END_DECLS tilem-2.0/gui/memory.c000066400000000000000000000037241220200411600147170ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include /* Memory management */ void tilem_free(void* p) { g_free(p); } void* tilem_malloc(size_t s) { return g_malloc(s); } void* tilem_realloc(void* p, size_t s) { return g_realloc(p, s); } void* tilem_try_malloc(size_t s) { return g_try_malloc(s); } void* tilem_malloc0(size_t s) { return g_malloc0(s); } void* tilem_try_malloc0(size_t s) { return g_try_malloc0(s); } void* tilem_malloc_atomic(size_t s) { return g_malloc(s); } void* tilem_try_malloc_atomic(size_t s) { return g_try_malloc(s); } /* Logging */ void tilem_message(TilemCalc* calc, const char* msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "x%c: ", calc->hw.model_id); vfprintf(stderr, msg, ap); fputc('\n', stderr); va_end(ap); } void tilem_warning(TilemCalc* calc, const char* msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "x%c: WARNING: ", calc->hw.model_id); vfprintf(stderr, msg, ap); fputc('\n', stderr); va_end(ap); } void tilem_internal(TilemCalc* calc, const char* msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "x%c: INTERNAL ERROR: ", calc->hw.model_id); vfprintf(stderr, msg, ap); fputc('\n', stderr); va_end(ap); } tilem-2.0/gui/memview.c000066400000000000000000000203401220200411600150510ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "gui.h" #include "memmodel.h" #include "fixedtreeview.h" static int get_column_index(GtkWidget *view, GtkTreeViewColumn *col) { GList *cols; int i; cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(view)); i = g_list_index(cols, col); g_list_free(cols); return -1; } /* Determine current position in the memory view. */ static void get_mem_view_position(GtkWidget *mem_view, dword *row_addr, dword *col_addr, gboolean *cur_hex) { GtkTreePath *path; GtkTreeViewColumn *col; GtkTreeModel *model; TilemMemModel *mm; const int *indices; int n; *row_addr = *col_addr = (dword) -1; *cur_hex = FALSE; gtk_tree_view_get_cursor(GTK_TREE_VIEW(mem_view), &path, &col); model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view)); if (!TILEM_IS_MEM_MODEL(model)) return; mm = TILEM_MEM_MODEL(model); if (!path) return; indices = gtk_tree_path_get_indices(path); *row_addr = mm->start_addr + indices[0] * mm->row_size; n = get_column_index(mem_view, col); if (n > 0 && n <= mm->row_size) { *col_addr = *row_addr + n - 1; *cur_hex = TRUE; } else if (n > mm->row_size && n < mm->row_size * 2) { *col_addr = *row_addr + n - mm->row_size - 1; *cur_hex = FALSE; } gtk_tree_path_free(path); } static void addr_to_pos(TilemMemModel *mm, dword addr, int *rownum, int *colnum) { if (addr < mm->start_addr) addr += mm->wrap_addr; addr -= mm->start_addr; if (rownum) *rownum = (addr / mm->row_size); if (colnum) *colnum = (addr % mm->row_size); } /* Move memory view cursor */ static void set_mem_view_position(GtkWidget *mem_view, dword row_addr, dword col_addr, gboolean cur_hex) { int rownum, colnum; GtkTreePath *path = NULL; GtkTreeViewColumn *col = NULL; GtkTreeModel *model; TilemMemModel *mm; model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view)); if (!TILEM_IS_MEM_MODEL(model)) return; mm = TILEM_MEM_MODEL(model); if (col_addr != (dword) -1) { addr_to_pos(mm, col_addr, &rownum, &colnum); path = gtk_tree_path_new_from_indices(rownum, -1); if (!cur_hex) colnum += mm->row_size; col = gtk_tree_view_get_column(GTK_TREE_VIEW(mem_view), colnum + 1); } else if (row_addr != (dword) -1) { addr_to_pos(mm, row_addr, &rownum, NULL); path = gtk_tree_path_new_from_indices(rownum, -1); } if (path) { gtk_tree_view_set_cursor(GTK_TREE_VIEW(mem_view), path, col, FALSE); gtk_tree_path_free(path); } } /* Cell edited in memory view */ static void hex_cell_edited(GtkCellRendererText *renderer, gchar *pathstr, gchar *text, gpointer data) { GtkTreeView *mem_view = data; TilemDebugger *dbg; GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; byte *bptr = NULL; int col; int value; char *end; value = strtol(text, &end, 16); if (end == text || *end != 0) return; dbg = g_object_get_data(G_OBJECT(mem_view), "tilem-debugger"); g_return_if_fail(dbg != NULL); col = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(renderer), "tilem-mem-column")); model = gtk_tree_view_get_model(mem_view); path = gtk_tree_path_new_from_string(pathstr); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(model, &iter, MM_COL_BYTE_PTR(col), &bptr, -1); g_return_if_fail(bptr != NULL); *bptr = (byte) value; tilem_debugger_refresh(dbg, TRUE); } /* Create the GtkTreeView to show the memory */ GtkWidget *tilem_debugger_mem_view_new(TilemDebugger *dbg) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *treeview; /* Create the memory list tree view and set title invisible */ treeview = gtk_tree_view_new(); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); g_object_set_data(G_OBJECT(treeview), "tilem-debugger", dbg); /* Create the columns */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("ADDR", renderer, "text", MM_COL_ADDRESS(0), NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); return treeview; } static void create_columns(GtkWidget *mem_view, int width) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; int i; for (i = 0; i < width; i++) { renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", MM_COL_HEX(i), "editable", MM_COL_EDITABLE(i), NULL); g_object_set_data(G_OBJECT(renderer), "tilem-mem-column", GINT_TO_POINTER(i)); g_signal_connect(renderer, "edited", G_CALLBACK(hex_cell_edited), mem_view); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_expand(column, (i == width - 1)); gtk_tree_view_append_column(GTK_TREE_VIEW(mem_view), column); } for (i = 0; i < width; i++) { renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", MM_COL_CHAR(i), NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_expand(column, (i == width - 1)); gtk_tree_view_append_column(GTK_TREE_VIEW(mem_view), column); } } static dword translate_addr(TilemCalcEmulator *emu, dword a, gboolean ptol) { if (!emu->calc || a == (dword) -1) return a; if (ptol) return (*emu->calc->hw.mem_ptol)(emu->calc, a); else return (*emu->calc->hw.mem_ltop)(emu->calc, a & 0xffff); } void tilem_debugger_mem_view_configure(GtkWidget *mem_view, TilemCalcEmulator *emu, int rowsize, int start, gboolean logical) { GtkTreeModel *model; dword row_addr, col_addr; gboolean cur_hex; GList *cols, *l; int old_rowsize; get_mem_view_position(mem_view, &row_addr, &col_addr, &cur_hex); model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view)); if (TILEM_IS_MEM_MODEL(model) && TILEM_MEM_MODEL(model)->use_logical != logical) { tilem_calc_emulator_lock(emu); row_addr = translate_addr(emu, row_addr, logical); col_addr = translate_addr(emu, col_addr, logical); tilem_calc_emulator_unlock(emu); } cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(mem_view)); old_rowsize = (g_list_length(cols) - 1) / 2; if (old_rowsize != rowsize) for (l = g_list_next(cols); l; l = l->next) gtk_tree_view_remove_column(GTK_TREE_VIEW(mem_view), l->data); g_list_free(cols); model = tilem_mem_model_new(emu, rowsize, start, logical); gtk_tree_view_set_model(GTK_TREE_VIEW(mem_view), model); g_object_unref(model); if (old_rowsize != rowsize) create_columns(mem_view, rowsize); fixed_tree_view_init(mem_view, MM_COLUMNS_PER_BYTE, MM_COL_ADDRESS_0, "DD:DDDD ", MM_COL_HEX_0, "DD ", MM_COL_CHAR_0, "M ", MM_COL_EDITABLE_0, TRUE, -1); set_mem_view_position(mem_view, row_addr, col_addr, cur_hex); } tilem-2.0/gui/menu.c000066400000000000000000000215141220200411600143500ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "gui.h" #include "msgbox.h" static void action_send_file(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; load_file_dialog(ewin); } static void action_receive_file(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; //tilem_rcvmenu_new(ewin->emu); //get_var(ewin->emu); popup_receive_menu(ewin); } static void action_start_debugger(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; launch_debugger(ewin); } static void action_open_calc(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_calc_emulator_prompt_open_rom(ewin->emu); } static void action_save_calc(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { TilemEmulatorWindow *ewin = data; GError *err = NULL; if (!tilem_calc_emulator_save_state(ewin->emu, &err)) { messagebox01(GTK_WINDOW(ewin->window), GTK_MESSAGE_ERROR, "Unable to save calculator state", "%s", err->message); g_error_free(err); } } static void action_revert_calc(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { TilemEmulatorWindow *ewin = data; GError *err = NULL; if (!tilem_calc_emulator_revert_state(ewin->emu, &err)) { messagebox01(GTK_WINDOW(ewin->window), GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); g_error_free(err); } } static void action_reset_calc(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_calc_emulator_reset(ewin->emu); } static void action_begin_macro(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_macro_start(ewin->emu); } static void action_end_macro(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_macro_stop(ewin->emu); /* tilem_macro_print(ewin->emu->macro); */ } static void action_play_macro(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_macro_play(ewin->emu); } static void action_open_macro(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { TilemEmulatorWindow *ewin = data; tilem_macro_load(ewin->emu, NULL); } /* I will improve macro creation by saving it firstly into a macro object * Save macro will only be done if user choose to save it */ static void action_save_macro(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { TilemEmulatorWindow *ewin = data; tilem_macro_write_file(ewin->emu); } static void action_screenshot(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; popup_screenshot_window(ewin); } static void action_quick_screenshot(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; quick_screenshot(ewin); } static void action_preferences(G_GNUC_UNUSED GtkAction *act, gpointer data) { TilemEmulatorWindow *ewin = data; tilem_preferences_dialog(ewin); } static void action_about(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { show_about(); } static void action_quit(G_GNUC_UNUSED GtkAction *act, G_GNUC_UNUSED gpointer data) { TilemEmulatorWindow *ewin = data; gtk_widget_destroy(ewin->window); } static const GtkActionEntry main_action_ents[] = {{ "send-file", GTK_STOCK_OPEN, "Send _File...", "O", "Send a program or variable file to the calculator", G_CALLBACK(action_send_file) }, { "receive-file", GTK_STOCK_SAVE_AS, "Re_ceive File...", "S", "Receive a program or variable from the calculator", G_CALLBACK(action_receive_file) }, { "open-calc", GTK_STOCK_OPEN, "_Open Calculator...", "O", "Open a calculator ROM file", G_CALLBACK(action_open_calc) }, { "save-calc", GTK_STOCK_SAVE, "_Save Calculator", "S", "Save current calculator state", G_CALLBACK(action_save_calc) }, { "revert-calc", GTK_STOCK_REVERT_TO_SAVED, "Re_vert Calculator State", 0, "Revert to saved calculator state", G_CALLBACK(action_revert_calc) }, { "reset-calc", GTK_STOCK_CLEAR, "_Reset Calculator", "Delete", "Reset the calculator", G_CALLBACK(action_reset_calc) }, { "start-debugger", 0, "_Debugger", "Pause", "Pause emulation and start the debugger", G_CALLBACK(action_start_debugger) }, { "begin-macro", GTK_STOCK_MEDIA_RECORD, "_Record", 0, "Begin recording a macro", G_CALLBACK(action_begin_macro) }, { "end-macro", GTK_STOCK_MEDIA_STOP, "S_top", 0, "Begin recording a macro", G_CALLBACK(action_end_macro) }, { "play-macro", GTK_STOCK_MEDIA_PLAY, "_Play", 0, "Play back the current macro", G_CALLBACK(action_play_macro) }, { "open-macro", GTK_STOCK_OPEN, "_Open Macro File...", "", "Load a macro from a file", G_CALLBACK(action_open_macro) }, { "save-macro", GTK_STOCK_SAVE_AS, "_Save Macro File...", "", "Save current macro to a file", G_CALLBACK(action_save_macro) }, { "screenshot", 0, "S_creenshot...", "Print", "Save a screenshot", G_CALLBACK(action_screenshot) }, { "quick-screenshot", 0, "_Quick Screenshot", "Print", "Save a screenshot using default settings", G_CALLBACK(action_quick_screenshot) }, { "preferences", GTK_STOCK_PREFERENCES, 0, 0, "Edit emulator settings", G_CALLBACK(action_preferences) }, { "about", GTK_STOCK_ABOUT, "_About", "", "Print some informations about TilEm 2 and its authors", G_CALLBACK(action_about) }, { "quit", GTK_STOCK_QUIT, "_Quit", "Q", "Quit the application", G_CALLBACK(action_quit) }}; static GtkWidget *add_item(GtkWidget *menu, GtkAccelGroup *accelgrp, GtkActionGroup *actions, const char *name) { GtkAction *action; GtkWidget *item; action = gtk_action_group_get_action(actions, name); g_return_val_if_fail(action != NULL, NULL); gtk_action_set_accel_group(action, accelgrp); item = gtk_action_create_menu_item(action); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); return item; } static GtkWidget *add_separator(GtkWidget *menu) { GtkWidget *item; item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); return item; } static GtkWidget *add_submenu(GtkWidget *menu, const char *label) { GtkWidget *item, *submenu; item = gtk_menu_item_new_with_mnemonic(label); submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); return submenu; } /* Build the menu */ void build_menu(TilemEmulatorWindow* ewin) { GtkActionGroup *acts; GtkAccelGroup *ag; GtkWidget *menu, *submenu; ewin->actions = acts = gtk_action_group_new("Emulator"); gtk_action_group_add_actions(ewin->actions, main_action_ents, G_N_ELEMENTS(main_action_ents), ewin); ag = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(ewin->window), ag); ewin->popup_menu = menu = gtk_menu_new(); add_item(menu, ag, acts, "send-file"); add_item(menu, ag, acts, "receive-file"); add_separator(menu); add_item(menu, ag, acts, "open-calc"); add_item(menu, ag, acts, "save-calc"); add_item(menu, ag, acts, "revert-calc"); add_item(menu, ag, acts, "reset-calc"); add_separator(menu); add_item(menu, ag, acts, "start-debugger"); submenu = add_submenu(menu, "_Macro"); add_item(submenu, ag, acts, "begin-macro"); add_item(submenu, ag, acts, "end-macro"); add_item(submenu, ag, acts, "play-macro"); add_separator(submenu); add_item(submenu, ag, acts, "open-macro"); add_item(submenu, ag, acts, "save-macro"); add_item(menu, ag, acts, "screenshot"); add_item(menu, ag, acts, "quick-screenshot"); add_separator(menu); add_item(menu, ag, acts, "preferences"); add_separator(menu); add_item(menu, ag, acts, "about"); add_item(menu, ag, acts, "quit"); } tilem-2.0/gui/msgbox.h000066400000000000000000000051301220200411600147040ustar00rootroot00000000000000/* * Tilem II * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ /* Message box macros */ #define messagebox00(prnt, mtyp, tprm, tsec) \ do { \ GtkWidget* mbx; \ mbx = gtk_message_dialog_new(GTK_WINDOW(prnt), GTK_DIALOG_MODAL, \ mtyp, GTK_BUTTONS_OK, tprm); \ gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mbx), \ tsec); \ gtk_dialog_set_default_response(GTK_DIALOG(mbx), GTK_RESPONSE_OK); \ gtk_dialog_run(GTK_DIALOG(mbx)); \ gtk_widget_destroy(mbx); \ } while(0) #define messagebox01(prnt, mtyp, tprm, tsec, aaaa) \ do { \ GtkWidget* mbx; \ mbx = gtk_message_dialog_new(GTK_WINDOW(prnt), GTK_DIALOG_MODAL, \ mtyp, GTK_BUTTONS_OK, tprm); \ gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mbx), \ tsec, (aaaa)); \ gtk_dialog_set_default_response(GTK_DIALOG(mbx), GTK_RESPONSE_OK); \ gtk_dialog_run(GTK_DIALOG(mbx)); \ gtk_widget_destroy(mbx); \ } while(0) #define messagebox02(prnt, mtyp, tprm, tsec, aaaa, bbbb) \ do { \ GtkWidget* mbx; \ mbx = gtk_message_dialog_new(GTK_WINDOW(prnt), GTK_DIALOG_MODAL, \ mtyp, GTK_BUTTONS_OK, tprm); \ gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mbx), \ tsec, (aaaa), (bbbb)); \ gtk_dialog_set_default_response(GTK_DIALOG(mbx), GTK_RESPONSE_OK); \ gtk_dialog_run(GTK_DIALOG(mbx)); \ gtk_widget_destroy(mbx); \ } while(0) #define messagebox11(prnt, mtyp, tprm, aaaa, tsec, bbbb) \ do { \ GtkWidget* mbx; \ mbx = gtk_message_dialog_new(GTK_WINDOW(prnt), GTK_DIALOG_MODAL, \ mtyp, GTK_BUTTONS_OK, tprm, (aaaa)); \ gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mbx), \ tsec, (bbbb)); \ gtk_dialog_set_default_response(GTK_DIALOG(mbx), GTK_RESPONSE_OK); \ gtk_dialog_run(GTK_DIALOG(mbx)); \ gtk_widget_destroy(mbx); \ } while(0) tilem-2.0/gui/pbar.c000066400000000000000000000104521220200411600143270ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "gui.h" /* Update the progress_bar */ static void progress_bar_update_activity(TilemLinkProgress *linkpb) { char *s; gdouble f; if (!linkpb->window || !linkpb->emu->pbar_title) return; gtk_window_set_title(GTK_WINDOW(linkpb->window), linkpb->emu->pbar_title); s = g_strdup_printf("%s", linkpb->emu->pbar_title); gtk_label_set_markup(linkpb->title_lbl, s); g_free(s); if (linkpb->emu->paused && linkpb->emu->pbar_status) { s = g_strconcat(linkpb->emu->pbar_status, " (paused)", NULL); gtk_label_set_text(linkpb->status_lbl, s); g_free(s); } else if (linkpb->emu->paused) gtk_label_set_text(linkpb->status_lbl, "(paused)"); else gtk_label_set_text(linkpb->status_lbl, linkpb->emu->pbar_status); if (linkpb->emu->pbar_progress < 0.0) { gtk_progress_bar_pulse(linkpb->progress_bar); } else { f = CLAMP(linkpb->emu->pbar_progress, 0.0, 1.0); gtk_progress_bar_set_fraction(linkpb->progress_bar, f); } } /* Callback to destroy the progress bar */ static void destroy_progress(G_GNUC_UNUSED GtkDialog *dlg, G_GNUC_UNUSED gint response, gpointer data) { TilemLinkProgress* linkpb = data; tilem_calc_emulator_cancel_tasks(linkpb->emu); gtk_widget_destroy(linkpb->window); linkpb->window = NULL; linkpb->progress_bar = NULL; linkpb->title_lbl = NULL; linkpb->status_lbl = NULL; } /* Create the progress bar window */ static void progress_bar_init(TilemLinkProgress* linkpb) { GtkWidget *pw, *parent, *vbox, *vbox2, *lbl, *pb; if (linkpb->emu->ewin) parent = linkpb->emu->ewin->window; else parent = NULL; pw = gtk_dialog_new_with_buttons("", GTK_WINDOW(parent), 0, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); linkpb->window = pw; gtk_window_set_resizable(GTK_WINDOW(pw), FALSE); vbox = gtk_dialog_get_content_area(GTK_DIALOG(pw)); vbox2 = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(vbox2), 6); lbl = gtk_label_new(NULL); gtk_label_set_width_chars(GTK_LABEL(lbl), 35); gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.5); gtk_box_pack_start(GTK_BOX(vbox2), lbl, FALSE, FALSE, 0); linkpb->title_lbl = GTK_LABEL(lbl); pb = gtk_progress_bar_new(); gtk_box_pack_start(GTK_BOX(vbox2), pb, FALSE, FALSE, 0); linkpb->progress_bar = GTK_PROGRESS_BAR(pb); lbl = gtk_label_new(NULL); gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.5); gtk_box_pack_start(GTK_BOX(vbox2), lbl, FALSE, FALSE, 0); linkpb->status_lbl = GTK_LABEL(lbl); gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 6); g_signal_connect(pw, "response", G_CALLBACK(destroy_progress), linkpb); progress_bar_update_activity(linkpb); gtk_widget_show_all(pw); } /* Create or update the progress bar */ void progress_bar_update(TilemCalcEmulator* emu) { g_return_if_fail(emu != NULL); g_mutex_lock(emu->pbar_mutex); if (!emu->linkpb) { emu->linkpb = g_slice_new0(TilemLinkProgress); emu->linkpb->emu = emu; } if (!emu->linkpb->window && emu->pbar_title) { progress_bar_init(emu->linkpb); } else if (emu->linkpb->window && !emu->pbar_title) { gtk_widget_destroy(emu->linkpb->window); emu->linkpb->window = NULL; emu->linkpb->title_lbl = NULL; emu->linkpb->status_lbl = NULL; emu->linkpb->progress_bar = NULL; } else { progress_bar_update_activity(emu->linkpb); } emu->pbar_update_pending = FALSE; g_mutex_unlock(emu->pbar_mutex); } tilem-2.0/gui/preferences.c000066400000000000000000000170511220200411600157060ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "filedlg.h" /* Convert to an absolute path */ static char *canonicalize_filename(const char *name) { #ifdef G_OS_WIN32 static const char delim[] = "/\\"; #else static const char delim[] = G_DIR_SEPARATOR_S; #endif char *result, **parts, *p; int i; if (name == NULL || g_path_is_absolute(name)) return g_strdup(name); result = g_get_current_dir(); parts = g_strsplit_set(name, delim, -1); for (i = 0; parts[i]; i++) { if (!strcmp(parts[i], "..")) { p = g_path_get_dirname(result); g_free(result); result = p; } else if (strcmp(parts[i], ".") && strcmp(parts[i], "")) { p = g_build_filename(result, parts[i], NULL); g_free(result); result = p; } } g_strfreev(parts); return result; } /* check if two file names are equivalent (of course, if this fails, it doesn't necessarily mean the files are distinct) */ static gboolean file_names_equal(const char *a, const char *b) { char *ca, *cb; gboolean status; if (a == NULL && b == NULL) return TRUE; else if (a == NULL || b == NULL) return FALSE; ca = canonicalize_filename(a); cb = canonicalize_filename(b); status = !strcmp(ca, cb); g_free(ca); g_free(cb); return status; } static void save_skin_name(TilemEmulatorWindow *ewin) { const char *model = ewin->emu->calc->hw.name; char *base, *shared; /* don't save pref unless skin was actually loaded */ if (!ewin->skin_file_name || !ewin->skin) return; /* if file is stored in shared skins directory, save only the relative path; otherwise, save the absolute path */ base = g_path_get_basename(ewin->skin_file_name); shared = get_shared_file_path("skins", base, NULL); if (file_names_equal(shared, ewin->skin_file_name)) tilem_config_set(model, "skin/f", base, NULL); else tilem_config_set(model, "skin/f", ewin->skin_file_name, NULL); g_free(base); g_free(shared); } static void speed_changed(GtkToggleButton *btn, gpointer data) { TilemEmulatorWindow *ewin = data; gboolean setting = gtk_toggle_button_get_active(btn); tilem_calc_emulator_set_limit_speed(ewin->emu, setting); tilem_config_set("emulation", "limit_speed/b", setting, NULL); } static void grayscale_changed(GtkToggleButton *btn, gpointer data) { TilemEmulatorWindow *ewin = data; gboolean setting = gtk_toggle_button_get_active(btn); tilem_calc_emulator_set_grayscale(ewin->emu, setting); tilem_config_set("emulation", "grayscale/b", setting, NULL); } static void smooth_changed(GtkToggleButton *btn, gpointer data) { TilemEmulatorWindow *ewin = data; gboolean setting = gtk_toggle_button_get_active(btn); ewin->lcd_smooth_scale = setting; tilem_config_set("settings", "smooth_scaling/b", setting, NULL); } static void skin_enable_changed(GtkToggleButton *btn, gpointer data) { TilemEmulatorWindow *ewin = data; gboolean enable = gtk_toggle_button_get_active(btn); if (ewin->skin_disabled == !enable) return; tilem_emulator_window_set_skin_disabled(ewin, !enable); tilem_config_set("settings", "skin_disabled/b", !enable, NULL); save_skin_name(ewin); } static void skin_file_changed(GtkWidget *fe, gpointer data) { TilemEmulatorWindow *ewin = data; char *fname = file_entry_get_filename(fe); if (fname && !file_names_equal(fname, ewin->skin_file_name)) { tilem_emulator_window_set_skin(ewin, fname); save_skin_name(ewin); g_free(fname); } } /* Run preferences dialog. */ void tilem_preferences_dialog(TilemEmulatorWindow *ewin) { GtkWidget *dlg, *vbox1, *vbox2, *frame, *slow_rb, *fast_rb, *grayscale_cb, *smooth_cb, *hbox, *skin_cb, *skin_entry; g_return_if_fail(ewin != NULL); g_return_if_fail(ewin->emu != NULL); dlg = gtk_dialog_new_with_buttons("Preferences", GTK_WINDOW(ewin->window), GTK_DIALOG_MODAL, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); vbox1 = gtk_vbox_new(FALSE, 12); gtk_container_set_border_width(GTK_CONTAINER(vbox1), 6); /* Emulation speed */ vbox2 = gtk_vbox_new(FALSE, 6); slow_rb = gtk_radio_button_new_with_mnemonic (NULL, "_Limit to actual calculator speed"); gtk_box_pack_start(GTK_BOX(vbox2), slow_rb, FALSE, FALSE, 0); fast_rb = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(slow_rb), "As _fast as possible"); gtk_box_pack_start(GTK_BOX(vbox2), fast_rb, FALSE, FALSE, 0); if (!ewin->emu->limit_speed) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fast_rb), TRUE); g_signal_connect(slow_rb, "toggled", G_CALLBACK(speed_changed), ewin); frame = new_frame("Emulation Speed", vbox2); gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0); /* Display settings */ vbox2 = gtk_vbox_new(FALSE, 6); grayscale_cb = gtk_check_button_new_with_mnemonic("Emulate _grayscale"); gtk_box_pack_start(GTK_BOX(vbox2), grayscale_cb, FALSE, FALSE, 0); if (ewin->emu->grayscale) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grayscale_cb), TRUE); g_signal_connect(grayscale_cb, "toggled", G_CALLBACK(grayscale_changed), ewin); smooth_cb = gtk_check_button_new_with_mnemonic("Use _smooth scaling"); gtk_box_pack_start(GTK_BOX(vbox2), smooth_cb, FALSE, FALSE, 0); if (ewin->lcd_smooth_scale) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(smooth_cb), TRUE); g_signal_connect(smooth_cb, "toggled", G_CALLBACK(smooth_changed), ewin); hbox = gtk_hbox_new(FALSE, 6); skin_cb = gtk_check_button_new_with_mnemonic("Use s_kin:"); gtk_box_pack_start(GTK_BOX(hbox), skin_cb, FALSE, FALSE, 0); skin_entry = file_entry_new("Select Skin", "Skin files", "*.skn", "All files", "*", NULL); gtk_box_pack_start(GTK_BOX(hbox), skin_entry, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); if (!ewin->skin_disabled) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(skin_cb), TRUE); if (ewin->skin_file_name) file_entry_set_filename(skin_entry, ewin->skin_file_name); g_signal_connect(skin_cb, "toggled", G_CALLBACK(skin_enable_changed), ewin); g_signal_connect(skin_entry, "selection-changed", G_CALLBACK(skin_file_changed), ewin); frame = new_frame("Display", vbox2); gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0); vbox2 = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox2), vbox1, FALSE, FALSE, 0); gtk_widget_show_all(vbox1); gtk_dialog_run(GTK_DIALOG(dlg)); gtk_widget_destroy(dlg); } tilem-2.0/gui/rcvmenu.c000066400000000000000000000474341220200411600150740ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include "gui.h" #include "disasmview.h" #include "memmodel.h" #include "files.h" #include "filedlg.h" #include "msgbox.h" #include "fixedtreeview.h" static GtkTreeModel* fill_varlist(TilemReceiveDialog *rcvdialog); TilemReceiveDialog* create_receive_menu(TilemCalcEmulator *emu); /* Columns */ enum { COL_ENTRY = 0, COL_SLOT_STR, COL_NAME_STR, COL_TYPE_STR, COL_SIZE_STR, COL_SIZE, NUM_COLS }; #define RESPONSE_REFRESH 1 /* Prompt to overwrite a list of files. */ static gboolean prompt_overwrite(GtkWindow *win, const char *dirname, char **filenames) { int i; char *dname; GString *conflicts = NULL; int nconflicts = 0; GtkWidget *dlg, *btn; int response; for (i = 0; filenames[i]; i++) { if (g_file_test(filenames[i], G_FILE_TEST_EXISTS)) { if (conflicts) g_string_append_c(conflicts, '\n'); else conflicts = g_string_new(NULL); dname = g_filename_display_basename(filenames[i]); g_string_append(conflicts, dname); g_free(dname); nconflicts++; } } if (!conflicts) return TRUE; dname = g_filename_display_basename(dirname); dlg = gtk_message_dialog_new (win, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, (nconflicts == 1 ? "Replace existing file?" : "Replace existing files?")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dlg), (nconflicts == 1 ? "The file \"%2$s\" already exists in \"%1$s\"." " Replacing it will overwrite its contents." : "The following files already exist in \"%s\"." " Replacing them will overwrite their contents:\n%s"), dname, conflicts->str); g_free(dname); g_string_free(conflicts, TRUE); gtk_dialog_add_button(GTK_DIALOG(dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); btn = gtk_button_new_with_mnemonic("_Replace"); gtk_button_set_image(GTK_BUTTON(btn), gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON)); gtk_widget_show(btn); gtk_dialog_add_action_widget(GTK_DIALOG(dlg), btn, GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); response = gtk_dialog_run(GTK_DIALOG(dlg)); gtk_widget_destroy(dlg); return (response == GTK_RESPONSE_ACCEPT); } /* #### SIGNALS CALLBACK #### */ /* Prompt to save a single file. */ static gboolean prompt_save_single(TilemReceiveDialog *rcvdialog, TilemVarEntry *tve) { char *dir, *default_filename, *default_filename_r, *filename, *pattern; default_filename = get_default_filename(tve); default_filename_r = utf8_to_restricted_utf8(default_filename); g_free(default_filename); tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL); if (!dir) dir = g_get_current_dir(); pattern = g_strconcat("*.", tve->file_ext, NULL); filename = prompt_save_file("Save File", GTK_WINDOW(rcvdialog->window), default_filename_r, dir, tve->filetype_desc, pattern, "All files", "*", NULL); g_free(default_filename_r); g_free(pattern); g_free(dir); if (!filename) return FALSE; dir = g_path_get_dirname(filename); tilem_config_set("download", "receivefile_recentdir/f", dir, NULL); g_free(dir); tilem_link_receive_file(rcvdialog->emu, tve, filename); g_free(filename); return TRUE; } /* Prompt to save a list of variables as a group file. */ static gboolean prompt_save_group(TilemReceiveDialog *rcvdialog, GList *rows) { char *dir, *default_filename, *pattern_desc, *pattern, *filename, *fext; int tfmodel; gboolean can_group = TRUE; const char *model_str; GList *l; GtkTreePath *path; GtkTreeIter iter; TilemVarEntry *tve; GSList *velist = NULL; tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL); if (!dir) dir = g_get_current_dir(); for (l = rows; l; l = l->next) { path = (GtkTreePath*) l->data; gtk_tree_model_get_iter(rcvdialog->model, &iter, path); gtk_tree_model_get(rcvdialog->model, &iter, COL_ENTRY, &tve, -1); velist = g_slist_prepend(velist, tve); if (!tve->can_group) can_group = FALSE; } velist = g_slist_reverse(velist); tfmodel = get_calc_model(rcvdialog->emu->calc); fext = g_ascii_strdown(tifiles_fext_of_group(tfmodel), -1); pattern = g_strconcat("*.", fext, NULL); default_filename = g_strdup_printf("untitled.%s", (can_group ? fext : "tig")); g_free(fext); model_str = tifiles_model_to_string(tfmodel); pattern_desc = g_strdup_printf("%s group files", model_str); filename = prompt_save_file("Save File", GTK_WINDOW(rcvdialog->window), default_filename, dir, pattern_desc, (can_group ? pattern : ""), "TIGroup files", "*.tig", "All files", "*", NULL); g_free(default_filename); g_free(dir); g_free(pattern_desc); g_free(pattern); if (!filename) { g_slist_free(velist); return FALSE; } dir = g_path_get_dirname(filename); tilem_config_set("download", "receivefile_recentdir/f", dir, "save_as_group/b", TRUE, NULL); g_free(dir); tilem_link_receive_group(rcvdialog->emu, velist, filename); g_free(filename); g_slist_free(velist); return TRUE; } /* Prompt to save a list of files. Input is a list of GtkTreePaths */ static gboolean prompt_save_multiple(TilemReceiveDialog *rcvdialog, GList *rows) { char *dir, *dir_selected, *default_filename, *default_filename_f; GList *l; GtkTreePath *path; GtkTreeIter iter; TilemVarEntry *tve, **vars; char **names; gboolean is_81, use_group; int i; is_81 = (rcvdialog->emu->calc->hw.model_id == TILEM_CALC_TI81); use_group = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rcvdialog->group_rb)); if (use_group && !is_81) return prompt_save_group(rcvdialog, rows); tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL); if (!dir) dir = g_get_current_dir(); dir_selected = prompt_select_dir("Save Files to Directory", GTK_WINDOW(rcvdialog->window), dir); g_free(dir); if (!dir_selected) return FALSE; tilem_config_set("download", "receivefile_recentdir/f", dir_selected, "save_as_group/b", use_group, NULL); vars = g_new(TilemVarEntry *, g_list_length(rows) + 1); names = g_new(char *, g_list_length(rows) + 1); for (l = rows, i = 0; l; l = l->next, i++) { path = (GtkTreePath*) l->data; gtk_tree_model_get_iter(rcvdialog->model, &iter, path); gtk_tree_model_get(rcvdialog->model, &iter, COL_ENTRY, &tve, -1); vars[i] = tve; default_filename = get_default_filename(tve); default_filename_f = utf8_to_filename(default_filename); names[i] = g_build_filename(dir_selected, default_filename_f, NULL); g_free(default_filename); g_free(default_filename_f); } vars[i] = NULL; names[i] = NULL; if (!prompt_overwrite(GTK_WINDOW(rcvdialog->window), dir_selected, names)) { g_free(vars); g_strfreev(names); g_free(dir_selected); return FALSE; } for (i = 0; vars[i]; i++) tilem_link_receive_file(rcvdialog->emu, vars[i], names[i]); g_free(vars); g_strfreev(names); g_free(dir_selected); return TRUE; } /* Event called on Send button click. Get the selected var/app and save it. */ static gboolean prompt_save(TilemReceiveDialog *rcvdialog) { TilemVarEntry *tve; /* Variable entry */ GtkTreeSelection* selection = NULL; /* GtkTreeSelection */ GtkTreeModel *model; GtkTreeIter iter; GList *rows, *l; GtkTreePath *path; gboolean status; /* Get the selected entry */ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rcvdialog->treeview)); rows = gtk_tree_selection_get_selected_rows(selection, &model); if (!rows) return FALSE; if (!rows->next) { path = (GtkTreePath*) rows->data; gtk_tree_model_get_iter(model, &iter, path); gtk_tree_model_get(model, &iter, COL_ENTRY, &tve, -1); status = prompt_save_single(rcvdialog, tve); } else { status = prompt_save_multiple(rcvdialog, rows); } for (l = rows; l; l = l->next) gtk_tree_path_free(l->data); g_list_free(rows); return status; } /* Dialog response button clicked */ static void dialog_response(GtkDialog *dlg, gint response, gpointer data) { TilemReceiveDialog* rcvdialog = (TilemReceiveDialog*) data; switch (response) { case RESPONSE_REFRESH: if (!rcvdialog->refresh_pending) { rcvdialog->refresh_pending = TRUE; tilem_link_get_dirlist(rcvdialog->emu); } break; case GTK_RESPONSE_ACCEPT: if (!prompt_save(rcvdialog)) break; default: gtk_widget_hide(GTK_WIDGET(dlg)); } } /* Selection changed */ static void selection_changed(GtkTreeSelection *sel, gpointer data) { TilemReceiveDialog* rcvdialog = data; int n = gtk_tree_selection_count_selected_rows(sel); gtk_dialog_set_response_sensitive(GTK_DIALOG(rcvdialog->window), GTK_RESPONSE_ACCEPT, (n > 0)); gtk_widget_set_sensitive(rcvdialog->mode_box, (n > 1)); } /* Row activated in tree view */ static void row_activated(G_GNUC_UNUSED GtkTreeView *treeview, G_GNUC_UNUSED GtkTreePath *path, G_GNUC_UNUSED GtkTreeViewColumn *col, gpointer data) { TilemReceiveDialog* rcvdialog = (TilemReceiveDialog*) data; gtk_dialog_response(GTK_DIALOG(rcvdialog->window), GTK_RESPONSE_ACCEPT); } /* #### WIDGET CREATION #### */ /* Create a new scrolled window with sensible default settings. */ static GtkWidget *new_scrolled_window(GtkWidget *contents) { GtkWidget *sw; sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(sw), contents); return sw; } /* Create the (empty) GtkTreeView to show the vars list */ static GtkWidget *create_varlist(TilemReceiveDialog *rcvdialog) { GtkCellRenderer *renderer; GtkWidget *treeview; GtkTreeSelection *sel; GtkTreeViewColumn *c1, *c2, *c3, *c4; gboolean is_81; g_return_val_if_fail(rcvdialog->emu != NULL, NULL); g_return_val_if_fail(rcvdialog->emu->calc != NULL, NULL); is_81 = (rcvdialog->emu->calc->hw.model_id == TILEM_CALC_TI81); /* Create the stack list tree view and set title invisible */ treeview = gtk_tree_view_new(); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE); /* Allow multiple selection */ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); /* Create the columns */ renderer = gtk_cell_renderer_text_new(); if (is_81) { c1 = gtk_tree_view_column_new_with_attributes ("Slot", renderer, "text", COL_SLOT_STR, NULL); gtk_tree_view_column_set_sizing(c1, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_sort_column_id(c1, COL_SLOT_STR); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c1); } c2 = gtk_tree_view_column_new_with_attributes ("Name", renderer, "text", COL_NAME_STR, NULL); gtk_tree_view_column_set_sizing(c2, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_sort_column_id(c2, COL_NAME_STR); gtk_tree_view_column_set_expand(c2, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c2); if (!is_81) { c3 = gtk_tree_view_column_new_with_attributes ("Type", renderer, "text", COL_TYPE_STR, NULL); gtk_tree_view_column_set_sizing(c3, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_sort_column_id(c3, COL_TYPE_STR); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c3); } renderer = gtk_cell_renderer_text_new(); g_object_set(renderer, "xalign", 1.0, NULL); c4 = gtk_tree_view_column_new_with_attributes ("Size", renderer, "text", COL_SIZE_STR, NULL); gtk_tree_view_column_set_sizing(c4, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_sort_column_id(c4, COL_SIZE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c4); g_signal_connect(sel, "changed", G_CALLBACK(selection_changed), rcvdialog); g_signal_connect(treeview, "row-activated", G_CALLBACK(row_activated), rcvdialog); return treeview; } /* Fill the list of vars. In fact, add all vars from list to a GtkListStore */ static GtkTreeModel* fill_varlist(TilemReceiveDialog *rcvdialog) { GSList *l; TilemVarEntry *tve; GtkListStore *store; GtkTreeIter iter; char *size_str; store = gtk_list_store_new(6, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); for (l = rcvdialog->vars; l; l = l->next) { tve = l->data; gtk_list_store_append(store, &iter); #ifdef G_OS_WIN32 size_str = g_strdup_printf("%d", tve->size); #else size_str = g_strdup_printf("%'d", tve->size); #endif gtk_list_store_set(store, &iter, COL_ENTRY, tve, COL_SLOT_STR, tve->slot_str, COL_NAME_STR, tve->name_str, COL_TYPE_STR, tve->type_str, COL_SIZE_STR, size_str, COL_SIZE, tve->size, -1); g_free(size_str); } return GTK_TREE_MODEL(store); } /* Create a new menu for receiving vars. */ /* Previous allocated and filled varlist is needed */ TilemReceiveDialog* tilem_receive_dialog_new(TilemCalcEmulator *emu) { TilemReceiveDialog* rcvdialog = g_slice_new0(TilemReceiveDialog); GtkWidget *scroll, *btn, *vbox, *lbl, *rb, *vbox2; int defheight = 300; gboolean is_81; gboolean use_group; g_return_val_if_fail(emu != NULL, NULL); g_return_val_if_fail(emu->ewin != NULL, NULL); g_return_val_if_fail(emu->calc != NULL, NULL); rcvdialog->emu = emu; emu->rcvdlg = rcvdialog; is_81 = (emu->calc->hw.model_id == TILEM_CALC_TI81); rcvdialog->window = gtk_dialog_new(); gtk_window_set_transient_for(GTK_WINDOW(rcvdialog->window), GTK_WINDOW(emu->ewin->window)); gtk_window_set_title(GTK_WINDOW(rcvdialog->window), "Receive File"); btn = gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window), GTK_STOCK_REFRESH, RESPONSE_REFRESH); if (is_81) gtk_widget_hide(btn); gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window), GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response(GTK_DIALOG(rcvdialog->window), GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order(GTK_DIALOG(rcvdialog->window), RESPONSE_REFRESH, GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); /* Set the size of the dialog */ gtk_window_set_default_size(GTK_WINDOW(rcvdialog->window), -1, defheight); /* Create and fill tree view */ rcvdialog->treeview = create_varlist(rcvdialog); /* Allow scrolling the list because we can't know how many vars the calc contains */ scroll = new_scrolled_window(rcvdialog->treeview); vbox = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(vbox), 6); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scroll), TRUE, TRUE, 0); rcvdialog->mode_box = gtk_hbox_new(FALSE, 6); lbl = gtk_label_new("Save as:"); gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), lbl, FALSE, FALSE, 0); rb = gtk_radio_button_new_with_mnemonic(NULL, "S_eparate files"); gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), rb, FALSE, FALSE, 0); rcvdialog->multiple_rb = rb; rb = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(rb), "_Group file"); gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), rb, FALSE, FALSE, 0); rcvdialog->group_rb = rb; tilem_config_get("download", "save_as_group/b=1", &use_group, NULL); if (use_group) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); if (is_81) gtk_widget_set_no_show_all(rcvdialog->mode_box, TRUE); gtk_box_pack_start(GTK_BOX(vbox), rcvdialog->mode_box, FALSE, FALSE, 0); vbox2 = gtk_dialog_get_content_area(GTK_DIALOG(rcvdialog->window)); gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0); /* Signals callback */ g_signal_connect(rcvdialog->window, "response", G_CALLBACK(dialog_response), rcvdialog); g_signal_connect(rcvdialog->window, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); gtk_widget_show_all(vbox); return rcvdialog; } /* Destroy a TilemReceiveDialog */ void tilem_receive_dialog_free(TilemReceiveDialog *rcvdialog) { GSList *l; g_return_if_fail(rcvdialog != NULL); gtk_widget_destroy(rcvdialog->window); for (l = rcvdialog->vars; l; l = l->next) tilem_var_entry_free(l->data); g_slist_free(rcvdialog->vars); g_slice_free(TilemReceiveDialog, rcvdialog); } void tilem_receive_dialog_update(TilemReceiveDialog *rcvdialog, GSList *varlist) { GSList *l; g_return_if_fail(rcvdialog != NULL); rcvdialog->refresh_pending = FALSE; for (l = rcvdialog->vars; l; l = l->next) tilem_var_entry_free(l->data); g_slist_free(rcvdialog->vars); rcvdialog->vars = varlist; rcvdialog->model = fill_varlist(rcvdialog); gtk_tree_view_set_model(GTK_TREE_VIEW(rcvdialog->treeview), rcvdialog->model); fixed_tree_view_init(rcvdialog->treeview, 0, COL_SLOT_STR, "PrgmM ", COL_NAME_STR, "MMMMMMMMM ", COL_TYPE_STR, "MMMMMM ", COL_SIZE_STR, "00,000,000", -1); gtk_widget_grab_focus(rcvdialog->treeview); gtk_window_present(GTK_WINDOW(rcvdialog->window)); } /* Popup the receive window */ /* This is the entry point */ void popup_receive_menu(TilemEmulatorWindow *ewin) { g_return_if_fail(ewin != NULL); g_return_if_fail(ewin->emu != NULL); g_return_if_fail(ewin->emu->calc != NULL); if (ewin->emu->rcvdlg && ewin->emu->rcvdlg->refresh_pending) return; /* TI-81 takes no time to refresh, so do it automatically */ if (!ewin->emu->rcvdlg || ewin->emu->calc->hw.model_id == TILEM_CALC_TI81) { tilem_link_get_dirlist(ewin->emu); } else { gtk_widget_grab_focus(ewin->emu->rcvdlg->treeview); gtk_window_present(GTK_WINDOW(ewin->emu->rcvdlg->window)); } } tilem-2.0/gui/screenshot.c000066400000000000000000000631061220200411600155640ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "filedlg.h" #include "msgbox.h" #define DEFAULT_WIDTH_96 192 #define DEFAULT_HEIGHT_96 128 #define DEFAULT_WIDTH_128 256 #define DEFAULT_HEIGHT_128 128 #define DEFAULT_FORMAT "png" struct imgsize { int width; int height; }; static const struct imgsize normal_sizes[] = { { 96, 64 }, { 192, 128 }, { 288, 192 } }; static const struct imgsize wide_sizes[] = /* actual aspect ratio is 92:55 or 1.673:1 */ { { 128, 64 }, { 128, 77 }, { 214, 128 }, { 256, 128 }, { 256, 153 }, { 321, 192 }, { 384, 192 } }; static void grab_screen(GtkButton *btn, TilemScreenshotDialog *ssdlg); static void begin_animation(GtkButton *btn, TilemScreenshotDialog *ssdlg); static void end_animation(GtkButton *btn, TilemScreenshotDialog *ssdlg); static gboolean save_output(TilemScreenshotDialog *ssdlg); static char* find_free_filename(const char* directory, const char* filename, const char* extension); /* Test if the calc has a wide screen (ti86) */ static gboolean is_wide_screen(TilemCalcEmulator *emu) { g_return_val_if_fail(emu != NULL, FALSE); g_return_val_if_fail(emu->calc != NULL, FALSE); return (emu->calc->hw.lcdwidth == 128); } /* Quick screenshot: save a screenshot with predefined settings, without prompting the user */ void quick_screenshot(TilemEmulatorWindow *ewin) { char *folder, *filename, *format; int grayscale, w96, h96, w128, h128, width, height; TilemAnimation *anim; GError *err = NULL; GdkColor fg, bg; tilem_config_get("screenshot", "directory/f", &folder, "format/s", &format, "grayscale/b=1", &grayscale, "width_96x64/i", &w96, "height_96x64/i", &h96, "width_128x64/i", &w128, "height_128x64/i", &h128, "foreground/c=#000", &fg, "background/c=#fff", &bg, NULL); anim = tilem_calc_emulator_get_screenshot(ewin->emu, grayscale); if (!anim) { g_free(folder); g_free(format); return; } if (is_wide_screen(ewin->emu)) { width = (w128 > 0 ? w128 : DEFAULT_WIDTH_128); height = (h128 > 0 ? h128 : DEFAULT_HEIGHT_128); } else { width = (w96 > 0 ? w96 : DEFAULT_WIDTH_96); height = (h96 > 0 ? h96 : DEFAULT_HEIGHT_96); } tilem_animation_set_size(anim, width, height); tilem_animation_set_colors(anim, &fg, &bg); if (!folder) folder = get_config_file_path("screenshots", NULL); if (!format) format = g_strdup(DEFAULT_FORMAT); g_mkdir_with_parents(folder, 0755); filename = find_free_filename(folder, "screenshot", format); if (!filename) { g_free(folder); g_free(format); g_object_unref(anim); return; } printf("screenshot saved : %s\n", filename); if (!tilem_animation_save(anim, filename, format, NULL, NULL, &err)) { messagebox01(ewin->window, GTK_MESSAGE_ERROR, "Unable to save screenshot", "%s", err->message); g_error_free(err); } g_object_unref(anim); g_free(filename); g_free(folder); g_free(format); } /* Look for a free filename by testing [folder]/[basename]000.[extension] to [folder]/[basename]999.[extension] Return a newly allocated string if success Return null if no filename found */ static char* find_free_filename(const char* folder, const char* basename, const char* extension) { int i; char *filename, *prefix; if(folder) prefix = g_build_filename(folder, basename, NULL); else prefix = g_build_filename(basename, NULL); /* I do not use a while and limit number to 1000 because for any reason, if there's a problem in this scope I don't want to freeze tilem (if tilem don't find a free filename and never return anything) Limit to 1000 prevent this problem but if you prefer we could use a while wich wait a valid filename... */ for(i=0; i<999; i++) { filename = g_strdup_printf("%s%03d.%s", prefix, i, extension); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { g_free(prefix); return filename; } g_free(filename); } g_free(prefix); return NULL; } /* Change the review image to set the current animation */ static void set_current_animation(TilemScreenshotDialog *ssdlg, TilemAnimation *anim) { GtkImage *img = GTK_IMAGE(ssdlg->screenshot_preview_image); int width, height; GdkColor fg, bg; gdouble speed; if (anim) g_object_ref(anim); if (ssdlg->current_anim) g_object_unref(ssdlg->current_anim); ssdlg->current_anim = anim; if (!anim) { gtk_image_set_from_animation(img, NULL); gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window), GTK_RESPONSE_ACCEPT, FALSE); } else { width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(ssdlg->width_spin)); height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(ssdlg->height_spin)); tilem_animation_set_size(anim, width, height); gtk_color_button_get_color (GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg); gtk_color_button_get_color (GTK_COLOR_BUTTON(ssdlg->background_color), &bg); tilem_animation_set_colors(anim, &fg, &bg); speed = gtk_spin_button_get_value (GTK_SPIN_BUTTON(ssdlg->animation_speed)); tilem_animation_set_speed(anim, speed); gtk_image_set_from_animation(img, GDK_PIXBUF_ANIMATION(anim)); /* Need to call gtk_widget_show because we hide it while recording */ gtk_widget_show(ssdlg->screenshot_preview_image); gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window), GTK_RESPONSE_ACCEPT, TRUE); } } static void dialog_response(G_GNUC_UNUSED GtkDialog *dialog, gint response, gpointer data) { TilemScreenshotDialog *ssdlg = data; if (response == GTK_RESPONSE_ACCEPT) { if (!save_output(ssdlg)) return; } gtk_widget_hide(GTK_WIDGET(dialog)); end_animation(NULL, ssdlg); set_current_animation(ssdlg, NULL); } static void set_size_spin_buttons(TilemScreenshotDialog *ssdlg, int width, int height) { gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->width_spin), width); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->height_spin), height); } enum { COL_TEXT, COL_WIDTH, COL_HEIGHT }; static void animation_speed_changed(GtkSpinButton *animation_speed, gpointer data) { TilemScreenshotDialog *ssdlg = data; TilemAnimation * anim = ssdlg->current_anim; gdouble value = gtk_spin_button_get_value(animation_speed); tilem_animation_set_speed(anim, value); } /* Combo box changed. Update spin buttons accordingly. */ static void size_combo_changed(GtkComboBox *combo, TilemScreenshotDialog *ssdlg) { GtkTreeModel *model; GtkTreeIter iter; int width, height; if (gtk_combo_box_get_active_iter(combo, &iter)) { model = gtk_combo_box_get_model(combo); gtk_tree_model_get(model, &iter, COL_WIDTH, &width, COL_HEIGHT, &height, -1); if (width && height) set_size_spin_buttons(ssdlg, width, height); } } static void size_spin_changed(G_GNUC_UNUSED GtkSpinButton *sb, TilemScreenshotDialog *ssdlg) { GtkComboBox *combo = GTK_COMBO_BOX(ssdlg->ss_size_combo); GtkTreeModel *model; GtkTreeIter iter; int width, height, w, h; model = gtk_combo_box_get_model(combo); if (!model || !gtk_tree_model_get_iter_first(model, &iter)) return; width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(ssdlg->width_spin)); height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(ssdlg->height_spin)); do { gtk_tree_model_get(model, &iter, COL_WIDTH, &w, COL_HEIGHT, &h, -1); if ((w == 0 && h == 0) || (w == width && h == height)) { gtk_combo_box_set_active_iter(combo, &iter); break; } } while (gtk_tree_model_iter_next(model, &iter)); set_current_animation(ssdlg, ssdlg->current_anim); } static void fill_size_combobox(GtkComboBox *combo, const struct imgsize *sizes, int nsizes) { GtkListStore *store; GtkTreeIter iter; int i; char *s; store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); for (i = 0; i < nsizes; i++) { s = g_strdup_printf("%d \303\227 %d", sizes[i].width, sizes[i].height); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, COL_TEXT, s, COL_WIDTH, sizes[i].width, COL_HEIGHT, sizes[i].height, -1); g_free(s); } gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, COL_TEXT, "Custom", COL_WIDTH, 0, COL_HEIGHT, 0, -1); gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store)); } /* This method is called when a color is set (foreground or background) * It set a new palette based on new custom colors * It refresh the screen to print new colors */ static void color_changed(G_GNUC_UNUSED GtkSpinButton *sb, TilemScreenshotDialog *ssdlg) { set_current_animation(ssdlg, ssdlg->current_anim); } /* Create the screenshot menu */ static TilemScreenshotDialog * create_screenshot_window(TilemCalcEmulator *emu) { TilemScreenshotDialog *ssdlg = g_slice_new0(TilemScreenshotDialog); GtkWidget *main_table, *vbox, *frame, *config_expander, *tbl, *lbl, *align; GtkCellRenderer *cell; ssdlg->emu = emu; ssdlg->window = gtk_dialog_new_with_buttons ("Screenshot", (emu->ewin ? GTK_WINDOW(emu->ewin->window) : NULL), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_resizable(GTK_WINDOW(ssdlg->window), FALSE); gtk_dialog_set_alternative_button_order(GTK_DIALOG(ssdlg->window), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(ssdlg->window), GTK_RESPONSE_ACCEPT); g_signal_connect(ssdlg->window, "response", G_CALLBACK(dialog_response), ssdlg); g_signal_connect(ssdlg->window, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); main_table = gtk_table_new(2, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(main_table), 6); gtk_table_set_col_spacings(GTK_TABLE(main_table), 12); gtk_container_set_border_width(GTK_CONTAINER(main_table), 6); /* Preview */ frame = gtk_frame_new("Preview"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); ssdlg->screenshot_preview_image = gtk_image_new(); align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0); gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0); gtk_container_add(GTK_CONTAINER(align), ssdlg->screenshot_preview_image); gtk_container_add(GTK_CONTAINER(frame), align); gtk_table_attach(GTK_TABLE(main_table), frame, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); /* Buttons */ vbox = gtk_vbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(vbox), GTK_BUTTONBOX_START); gtk_box_set_spacing(GTK_BOX(vbox), 6); ssdlg->screenshot = gtk_button_new_with_mnemonic("_Grab"); gtk_box_pack_start(GTK_BOX(vbox), ssdlg->screenshot, FALSE, FALSE, 0); ssdlg->record = gtk_button_new_with_mnemonic("_Record"); gtk_box_pack_start(GTK_BOX(vbox), ssdlg->record, FALSE, FALSE, 0); ssdlg->stop = gtk_button_new_with_mnemonic("_Stop"); gtk_box_pack_start(GTK_BOX(vbox), ssdlg->stop, FALSE, FALSE, 0); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), FALSE); gtk_table_attach(GTK_TABLE(main_table), vbox, 1, 2, 0, 2, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); /* Options */ config_expander = gtk_expander_new("Options"); tbl = gtk_table_new(7, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tbl), 6); gtk_table_set_col_spacings(GTK_TABLE(tbl), 6); ssdlg->grayscale_tb = gtk_check_button_new_with_mnemonic("Gra_yscale"); gtk_table_attach(GTK_TABLE(tbl), ssdlg->grayscale_tb, 0, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new_with_mnemonic("Image si_ze:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); ssdlg->ss_size_combo = gtk_combo_box_new(); cell = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ssdlg->ss_size_combo), cell, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ssdlg->ss_size_combo), cell, "text", COL_TEXT, NULL); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->ss_size_combo); gtk_table_attach(GTK_TABLE(tbl), ssdlg->ss_size_combo, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new_with_mnemonic("_Width:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); ssdlg->width_spin = gtk_spin_button_new_with_range(1, 750, 1); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->width_spin); align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0); gtk_container_add(GTK_CONTAINER(align), ssdlg->width_spin); gtk_table_attach(GTK_TABLE(tbl), align, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new_with_mnemonic("_Height:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 0, 0); ssdlg->height_spin = gtk_spin_button_new_with_range(1, 500, 1); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->height_spin); align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0); gtk_container_add(GTK_CONTAINER(align), ssdlg->height_spin); gtk_table_attach(GTK_TABLE(tbl), align, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new_with_mnemonic("Animation s_peed:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0); ssdlg->animation_speed = gtk_spin_button_new_with_range(0.1, 100.0, 0.1); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->animation_speed); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->animation_speed), 1.0); align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0); gtk_container_add(GTK_CONTAINER(align), ssdlg->animation_speed); gtk_table_attach(GTK_TABLE(tbl), align, 1, 2, 4, 5, GTK_FILL, GTK_FILL, 0, 0); /* Foreground color and background color */ lbl = gtk_label_new_with_mnemonic("_Foreground:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0); ssdlg->foreground_color = gtk_color_button_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->foreground_color); align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0); gtk_container_add(GTK_CONTAINER(align), ssdlg->foreground_color); gtk_table_attach(GTK_TABLE(tbl), align, 1, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0); lbl = gtk_label_new_with_mnemonic("_Background:"); gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5); gtk_table_attach(GTK_TABLE(tbl), lbl, 0, 1, 6, 7, GTK_FILL, GTK_FILL, 0, 0); ssdlg->background_color = gtk_color_button_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->background_color); align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0); gtk_container_add(GTK_CONTAINER(align), ssdlg->background_color); gtk_table_attach(GTK_TABLE(tbl), align, 1, 2, 6, 7, GTK_FILL, GTK_FILL, 0, 0); align = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0); gtk_container_add(GTK_CONTAINER(align), tbl); gtk_container_add(GTK_CONTAINER(config_expander), align); gtk_table_attach(GTK_TABLE(main_table), config_expander, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); g_signal_connect(ssdlg->screenshot, "clicked", G_CALLBACK(grab_screen), ssdlg); g_signal_connect(ssdlg->record, "clicked", G_CALLBACK(begin_animation), ssdlg); g_signal_connect(ssdlg->stop, "clicked", G_CALLBACK(end_animation), ssdlg); g_signal_connect(ssdlg->ss_size_combo, "changed", G_CALLBACK(size_combo_changed), ssdlg); g_signal_connect(ssdlg->width_spin, "value-changed", G_CALLBACK(size_spin_changed), ssdlg); g_signal_connect(ssdlg->height_spin, "value-changed", G_CALLBACK(size_spin_changed), ssdlg); g_signal_connect(ssdlg->animation_speed, "value-changed", G_CALLBACK(animation_speed_changed), ssdlg); g_signal_connect(ssdlg->foreground_color, "color-set", G_CALLBACK(color_changed), ssdlg); g_signal_connect(ssdlg->background_color, "color-set", G_CALLBACK(color_changed), ssdlg); /*g_signal_connect(config_expander, "activate", G_CALLBACK(on_config_expander_activate), ssdlg); */ vbox = gtk_dialog_get_content_area(GTK_DIALOG(ssdlg->window)); gtk_container_add(GTK_CONTAINER(vbox), main_table); gtk_widget_show_all(main_table); return ssdlg; } /* Popup the screenshot window */ void popup_screenshot_window(TilemEmulatorWindow *ewin) { TilemScreenshotDialog *ssdlg; int w96, h96, w128, h128, width, height, grayscale; GdkColor fg, bg; g_return_if_fail(ewin != NULL); g_return_if_fail(ewin->emu != NULL); if (!ewin->emu->ssdlg) ewin->emu->ssdlg = create_screenshot_window(ewin->emu); ssdlg = ewin->emu->ssdlg; tilem_config_get("screenshot", "grayscale/b=1", &grayscale, "width_96x64/i", &w96, "height_96x64/i", &h96, "width_128x64/i", &w128, "height_128x64/i", &h128, "foreground/c=#000", &fg, "background/c=#fff", &bg, NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb), grayscale); if (is_wide_screen(ewin->emu)) { fill_size_combobox(GTK_COMBO_BOX(ssdlg->ss_size_combo), wide_sizes, G_N_ELEMENTS(wide_sizes)); width = (w128 > 0 ? w128 : DEFAULT_WIDTH_128); height = (h128 > 0 ? h128 : DEFAULT_HEIGHT_128); } else { fill_size_combobox(GTK_COMBO_BOX(ssdlg->ss_size_combo), normal_sizes, G_N_ELEMENTS(normal_sizes)); width = (w96 > 0 ? w96 : DEFAULT_WIDTH_96); height = (h96 > 0 ? h96 : DEFAULT_HEIGHT_96); } set_size_spin_buttons(ssdlg, width, height); size_spin_changed(NULL, ssdlg); gtk_color_button_set_color(GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg); gtk_color_button_set_color(GTK_COLOR_BUTTON(ssdlg->background_color), &bg); grab_screen(NULL, ssdlg); gtk_window_present(GTK_WINDOW(ssdlg->window)); } /* Save the current (static) output */ static gboolean save_output(TilemScreenshotDialog *ssdlg) { char *dir, *format, *filename, *basename; TilemAnimation *anim = ssdlg->current_anim; GdkPixbufAnimation *ganim = GDK_PIXBUF_ANIMATION(anim); const char *format_opt, *width_opt, *height_opt; gboolean is_static; int width, height; GdkColor fg, bg; GError *err = NULL; g_return_val_if_fail(anim != NULL, FALSE); is_static = gdk_pixbuf_animation_is_static_image(ganim); width = gdk_pixbuf_animation_get_width(ganim); height = gdk_pixbuf_animation_get_height(ganim); gtk_color_button_get_color (GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg); gtk_color_button_get_color (GTK_COLOR_BUTTON(ssdlg->background_color), &bg); tilem_config_get("screenshot", "directory/f", &dir, "static_format/s", &format, NULL); if (!dir) dir = g_get_current_dir(); if (!is_static) { g_free(format); format = g_strdup("gif"); } else if (!format) { format = g_strdup(DEFAULT_FORMAT); } filename = find_free_filename(dir, "screenshot", format); basename = (filename ? g_filename_display_basename(filename) : NULL); g_free(filename); g_free(format); if (!is_static) { filename = prompt_save_file("Save Screenshot", GTK_WINDOW(ssdlg->window), basename, dir, "GIF images", "*.gif", "All files", "*", NULL); } else { /* FIXME: perhaps check the list of supported output formats (gdk_pixbuf_get_formats()) - e.g., tiff is usually supported, although it requires libtiff installed (png and jpeg also require external libraries, but we need those libraries anyway for other reasons) */ filename = prompt_save_file("Save Screenshot", GTK_WINDOW(ssdlg->window), basename, dir, "PNG images", "*.png", "GIF images", "*.gif", "BMP images", "*.bmp", "JPEG images", "*.jpg;*.jpe;*.jpeg", "All files", "*", NULL); } g_free(basename); g_free(dir); if (!filename) return FALSE; if (!is_static) { format = g_strdup("gif"); } else { basename = g_path_get_basename(filename); format = strrchr(basename, '.'); if (!format) { messagebox00(ssdlg->window, GTK_MESSAGE_ERROR, "Unable to save screenshot", "File name does not have a" " recognized suffix"); g_free(filename); g_free(basename); return FALSE; } else { format = g_strdup(format + 1); } } tilem_animation_save(anim, filename, format, NULL, NULL, &err); dir = g_path_get_dirname(filename); if (err) { messagebox01(ssdlg->window, GTK_MESSAGE_ERROR, "Unable to save screenshot", "%s", err->message); g_error_free(err); g_free(dir); g_free(filename); g_free(format); return FALSE; } if (is_static) format_opt = "static_format/s"; else format_opt = NULL; if (is_wide_screen(ssdlg->emu)) { width_opt = "width_128x64/i"; height_opt = "height_128x64/i"; } else { width_opt = "width_96x64/i"; height_opt = "height_96x64/i"; } tilem_config_set("screenshot", "directory/f", dir, "grayscale/b", ssdlg->current_anim_grayscale, "foreground/c", &fg, "background/c", &bg, width_opt, width, height_opt, height, format_opt, format, NULL); g_free(dir); g_free(filename); g_free(format); return TRUE; } /* Callback for record button */ static void begin_animation(G_GNUC_UNUSED GtkButton *btn, TilemScreenshotDialog *ssdlg) { gboolean grayscale = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb)); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->animation_speed), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->screenshot), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->record), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), TRUE); gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window), GTK_RESPONSE_ACCEPT, FALSE); tilem_calc_emulator_begin_animation(ssdlg->emu, grayscale); ssdlg->current_anim_grayscale = grayscale; /* You can choose to hide current animation while recording or not It's as you prefer... For the moment I hide it */ /*gtk_widget_hide(GTK_WIDGET(ssdlg->screenshot_preview_image)); */ //set_current_animation(ssdlg, NULL); } /* Callback for stop button (stop the recording) */ static void end_animation(G_GNUC_UNUSED GtkButton *btn, TilemScreenshotDialog *ssdlg) { TilemAnimation *anim; if (ssdlg->emu->anim) { anim = tilem_calc_emulator_end_animation(ssdlg->emu); set_current_animation(ssdlg, anim); g_object_unref(anim); } else { set_current_animation(ssdlg, NULL); } gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->animation_speed), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->screenshot), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->record), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), FALSE); } /* Callback for screenshot button (take a screenshot) */ static void grab_screen(G_GNUC_UNUSED GtkButton *btn, TilemScreenshotDialog *ssdlg) { TilemAnimation *anim; gboolean grayscale = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb)); anim = tilem_calc_emulator_get_screenshot(ssdlg->emu, grayscale); ssdlg->current_anim_grayscale = grayscale; set_current_animation(ssdlg, anim); g_object_unref(anim); } tilem-2.0/gui/sendfile.c000066400000000000000000000366671220200411600152140ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "gui.h" #include "emucore.h" #include "filedlg.h" #include "ti81prg.h" /* Send a series of files */ static void send_files(TilemCalcEmulator *emu, char **filenames, int *slots) { int i; for (i = 0; filenames[i]; i++) { tilem_link_send_file(emu, filenames[i], slots ? slots[i] : -1, (i == 0), (filenames[i + 1] == NULL)); /* FIXME: macros should record slot numbers */ if (emu->isMacroRecording) tilem_macro_add_action(emu->macro, 1, filenames[i]); } } static int string_to_slot(const char *str) { if (!g_ascii_strncasecmp(str, "prgm", 4)) str += 4; else if (!g_ascii_strncasecmp(str, "ti81_", 5)) str += 5; else return TI81_SLOT_AUTO; if (g_ascii_isdigit(str[0]) && !g_ascii_isalnum(str[1])) return TI81_SLOT_0 + str[0] - '0'; else if (g_ascii_isalpha(str[0]) && !g_ascii_isalnum(str[1])) return TI81_SLOT_A + g_ascii_toupper(str[0]) - 'A'; else if (str[0] == '@' || !g_ascii_strncasecmp(str, "theta", 5) || !strncmp(str, "\316\270", 2) || !strncmp(str, "\316\230", 2)) return TI81_SLOT_THETA; else return TI81_SLOT_AUTO; } /* Guess program slot for a filename */ static int guess_slot(const char *filename) { char *base; int slot; base = g_filename_display_basename(filename); slot = string_to_slot(base); g_free(base); return slot; } static int display_index_to_slot(int i) { if (i < 9) return i + 1; else if (i == 9) return 0; else return i; } struct slotdialog { int nfiles; char **filenames; int *slots; TI81ProgInfo info[TI81_SLOT_MAX + 1]; GtkTreeModel *prgm_model; GtkTreeModel *slot_model; }; static void slot_edited(G_GNUC_UNUSED GtkCellRendererText *cell, gchar *pathstr, gchar *text, gpointer data) { struct slotdialog *slotdlg = data; GtkTreeIter iter; int n, slot; char *end; slot = string_to_slot(text); if (slot < 0) return; n = strtol(pathstr, &end, 10); gtk_tree_model_iter_nth_child(slotdlg->prgm_model, &iter, NULL, n); gtk_list_store_set(GTK_LIST_STORE(slotdlg->prgm_model), &iter, 1, text, -1); slotdlg->slots[n] = slot; } /* Prompt user to assign program slots to filenames */ static void prompt_program_slots(TilemCalcEmulator *emu, struct slotdialog *slotdlg) { GtkWidget *parent, *dlg, *vbox, *vbox2, *sw, *tv, *lbl; GtkListStore *prgmstore, *slotstore; GtkTreeIter iter; GtkCellRenderer *cell; GtkTreeViewColumn *col; int i, j, slot; int used[TI81_SLOT_MAX + 1]; char *slotstr, *namestr; char *slotlabel[TI81_SLOT_MAX + 1]; if (emu->ewin) parent = emu->ewin->window; else parent = NULL; /* Generate list of existing programs */ slotstore = gtk_list_store_new(1, G_TYPE_STRING); slotdlg->slot_model = GTK_TREE_MODEL(slotstore); for (i = 0; i <= TI81_SLOT_MAX; i++) { slot = display_index_to_slot(i); slotstr = ti81_program_slot_to_string(slot); namestr = ti81_program_name_to_string(slotdlg->info[slot].name); if (slotdlg->info[slot].size == 0) { slotlabel[slot] = g_strdup(slotstr); used[slot] = 0; } else if (namestr && namestr[0]) { slotlabel[slot] = g_strdup_printf("%s (in use: %s)", slotstr, namestr); used[slot] = 1; } else { slotlabel[slot] = g_strdup_printf("%s (in use)", slotstr); used[slot] = 1; } gtk_list_store_append(slotstore, &iter); gtk_list_store_set(slotstore, &iter, 0, slotlabel[slot], -1); g_free(slotstr); g_free(namestr); } /* Assign default slots to files */ for (i = 0; i < slotdlg->nfiles; i++) { slot = guess_slot(slotdlg->filenames[i]); if (slotdlg->slots[i] < 0) slotdlg->slots[i] = slot; if (slot >= 0) used[slot] = 1; } for (i = 0; i < slotdlg->nfiles; i++) { if (slotdlg->slots[i] < 0) { for (j = 0; j <= TI81_SLOT_MAX; j++) { slot = display_index_to_slot(j); if (!used[slot]) { slotdlg->slots[i] = slot; used[slot] = 1; break; } } } if (slotdlg->slots[i] < 0) slotdlg->slots[i] = TI81_SLOT_1; } /* Generate list of filenames and assigned slots */ prgmstore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); slotdlg->prgm_model = GTK_TREE_MODEL(prgmstore); for (i = 0; i < slotdlg->nfiles; i++) { namestr = g_filename_display_basename(slotdlg->filenames[i]); slot = slotdlg->slots[i]; gtk_list_store_append(prgmstore, &iter); gtk_list_store_set(prgmstore, &iter, 0, namestr, 1, slotlabel[slot], -1); g_free(namestr); } for (i = 0; i <= TI81_SLOT_MAX; i++) g_free(slotlabel[i]); /* Create tree view */ tv = gtk_tree_view_new_with_model(slotdlg->prgm_model); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), TRUE); cell = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes ("File", cell, "text", 0, NULL); gtk_tree_view_column_set_expand(col, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); cell = gtk_cell_renderer_combo_new(); g_object_set(cell, "model", slotstore, "text-column", 0, "editable", TRUE, "has-entry", FALSE, NULL); col = gtk_tree_view_column_new_with_attributes ("Slot", cell, "text", 1, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); g_signal_connect(cell, "edited", G_CALLBACK(slot_edited), slotdlg); /* Create dialog */ dlg = gtk_dialog_new_with_buttons("Select Program Slots", GTK_WINDOW(parent), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); gtk_window_set_default_size(GTK_WINDOW(dlg), -1, 250); sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(sw), tv); vbox = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(vbox), 6); lbl = gtk_label_new("Select a slot where each program should be" " loaded. If a program slot is already in use," " its contents will be overwritten."); gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.0); gtk_label_set_line_wrap(GTK_LABEL(lbl), TRUE); gtk_label_set_width_chars(GTK_LABEL(lbl), 45); gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); gtk_widget_show_all(vbox); vbox2 = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0); if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_OK) send_files(emu, slotdlg->filenames, slotdlg->slots); gtk_widget_destroy(dlg); } /* Check status of existing programs */ static gboolean check_prog_slots_main(TilemCalcEmulator *emu, gpointer data) { struct slotdialog *slotdlg = data; int i; tilem_em_wake_up(emu, TRUE); for (i = 0; i <= TI81_SLOT_MAX; i++) ti81_get_program_info(emu->calc, i, &slotdlg->info[i]); return TRUE; } static void check_prog_slots_finished(TilemCalcEmulator *emu, gpointer data, gboolean cancelled) { struct slotdialog *slotdlg = data; if (!cancelled) prompt_program_slots(emu, slotdlg); g_free(slotdlg->slots); g_strfreev(slotdlg->filenames); g_slice_free(struct slotdialog, slotdlg); } #define PAT_TI81 "*.prg" #define PAT_TI73 "*.73?" #define PAT_TI73_NUM "*.73n;*.73l;*.73m;*.73i" #define PAT_TI82 "*.82?" #define PAT_TI82_NUM "*.82n;*.82l;*.82m;*.82i" #define PAT_TI82_TEXT "*.82s;*.82y;*.82p" #define PAT_TI83 "*.83?" #define PAT_TI83_NUM "*.83n;*.83l;*.83m;*.83i" #define PAT_TI83_TEXT "*.83s;*.83y;*.83p" #define PAT_TI83P "*.8x?;*.8xgrp" #define PAT_TI83P_NUM "*.8xn;*.8xl;*.8xm;*.8xi" #define PAT_TI83P_TEXT "*.8xs;*.8xy;*.8xp" #define PAT_TI85 "*.85?" #define PAT_TI86 "*.86?" #define PAT_TIG "*.tig" #define FLT_TI81 "TI-81 programs", PAT_TI81 #define FLT_TI73 "TI-73 files", PAT_TI73 #define FLT_TI82 "TI-82 files", PAT_TI82 #define FLT_TI83 "TI-83 files", PAT_TI83 #define FLT_TI83P "TI-83 Plus files", PAT_TI83P #define FLT_TI85 "TI-85 files", PAT_TI85 #define FLT_TI86 "TI-86 files", PAT_TI86 #define FLT_TIG "TIGroup files", PAT_TIG #define FLT_ALL "All files", "*" #define DESC_COMPAT "All compatible files" #define FLT_TI73_COMPAT DESC_COMPAT, (PAT_TI73 ";" PAT_TIG ";" \ PAT_TI82_NUM ";" \ PAT_TI83_NUM ";" \ PAT_TI83P_NUM) #define FLT_TI82_COMPAT DESC_COMPAT, (PAT_TI82 ";" PAT_TIG ";" \ PAT_TI83_TEXT ";" PAT_TI83_NUM ";" \ PAT_TI83P_TEXT ";" PAT_TI83P_NUM ";" \ PAT_TI73_NUM) #define FLT_TI83_COMPAT DESC_COMPAT, (PAT_TI83 ";" PAT_TIG ";" \ PAT_TI82_TEXT ";" PAT_TI82_NUM ";" \ PAT_TI83P_TEXT ";" PAT_TI83P_NUM ";" \ PAT_TI73_NUM) #define FLT_TI83P_COMPAT DESC_COMPAT, (PAT_TI83P ";" PAT_TIG ";" \ PAT_TI82_TEXT ";" PAT_TI82_NUM ";" \ PAT_TI83_TEXT ";" PAT_TI83_NUM ";" \ PAT_TI73_NUM) #define FLT_TI8586_COMPAT DESC_COMPAT, (PAT_TI85 ";" PAT_TI86 ";" PAT_TIG) static char ** prompt_link_files(const char *title, GtkWindow *parent, const char *dir, int model) { switch (model) { case TILEM_CALC_TI73: return prompt_open_files(title, parent, dir, FLT_TI73_COMPAT, FLT_TI73, FLT_TI82, FLT_TI83, FLT_TI83P, FLT_TIG, FLT_ALL, NULL); case TILEM_CALC_TI81: return prompt_open_files(title, parent, dir, FLT_TI81, FLT_ALL, NULL); case TILEM_CALC_TI82: return prompt_open_files(title, parent, dir, FLT_TI82_COMPAT, FLT_TI73, FLT_TI82, FLT_TI83, FLT_TI83P, FLT_TIG, FLT_ALL, NULL); case TILEM_CALC_TI83: case TILEM_CALC_TI76: return prompt_open_files(title, parent, dir, FLT_TI83_COMPAT, FLT_TI73, FLT_TI82, FLT_TI83, FLT_TI83P, FLT_TIG, FLT_ALL, NULL); case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return prompt_open_files(title, parent, dir, FLT_TI83P_COMPAT, FLT_TI73, FLT_TI82, FLT_TI83, FLT_TI83P, FLT_TIG, FLT_ALL, NULL); case TILEM_CALC_TI85: case TILEM_CALC_TI86: return prompt_open_files(title, parent, dir, FLT_TI8586_COMPAT, FLT_TI85, FLT_TI86, FLT_TIG, FLT_ALL, NULL); default: return prompt_open_files(title, parent, dir, FLT_ALL, NULL); } } /* Load a list of files through the GUI. The list of filenames must end with NULL. */ void load_files(TilemEmulatorWindow *ewin, char **filenames) { struct slotdialog *slotdlg; int i; g_return_if_fail(ewin->emu->calc != NULL); if (ewin->emu->calc->hw.model_id == TILEM_CALC_TI81) { slotdlg = g_slice_new0(struct slotdialog); slotdlg->filenames = g_strdupv(filenames); slotdlg->nfiles = g_strv_length(filenames); slotdlg->slots = g_new(int, slotdlg->nfiles); for (i = 0; i < slotdlg->nfiles; i++) slotdlg->slots[i] = TI81_SLOT_AUTO; tilem_calc_emulator_begin(ewin->emu, &check_prog_slots_main, &check_prog_slots_finished, slotdlg); } else { send_files(ewin->emu, filenames, NULL); } } static int get_cmdline_slot(const char *str, const char **name) { char *e; int n; n = strtol(str, &e, 10); if (*e == '=') { *name = e + 1; return n; } if (g_ascii_isalpha(str[0]) && str[1] == '=') { *name = str + 2; return TI81_SLOT_A + g_ascii_toupper(str[0]) - 'A'; } if (str[0] == '@' && str[1] == '=') { *name = str + 2; return TI81_SLOT_THETA; } if (!g_ascii_strncasecmp(str, "theta=", 6)) { *name = str + 6; return TI81_SLOT_THETA; } *name = str; return TI81_SLOT_AUTO; } /* Load a list of files from the command line. Filenames may begin with an optional slot designation. */ void load_files_cmdline(TilemEmulatorWindow *ewin, char **filenames) { struct slotdialog *slotdlg; int i; gboolean need_prompt = FALSE; const char *name; g_return_if_fail(ewin->emu->calc != NULL); slotdlg = g_slice_new0(struct slotdialog); slotdlg->nfiles = g_strv_length(filenames); slotdlg->slots = g_new(int, slotdlg->nfiles); slotdlg->filenames = g_new0(char *, slotdlg->nfiles + 1); for (i = 0; i < slotdlg->nfiles; i++) { slotdlg->slots[i] = get_cmdline_slot(filenames[i], &name); slotdlg->filenames[i] = g_strdup(name); if (slotdlg->slots[i] < 0) need_prompt = TRUE; } if (need_prompt && ewin->emu->calc->hw.model_id == TILEM_CALC_TI81) { tilem_calc_emulator_begin(ewin->emu, &check_prog_slots_main, &check_prog_slots_finished, slotdlg); } else { send_files(ewin->emu, slotdlg->filenames, slotdlg->slots); g_free(slotdlg->slots); g_strfreev(slotdlg->filenames); g_slice_free(struct slotdialog, slotdlg); } } /* Prompt user to load a file */ void load_file_dialog(TilemEmulatorWindow *ewin) { char **filenames, *dir; tilem_config_get("upload", "sendfile_recentdir/f", &dir, NULL); filenames = prompt_link_files("Send File", GTK_WINDOW(ewin->window), dir, ewin->emu->calc->hw.model_id); g_free(dir); if (!filenames || !filenames[0]) { g_free(filenames); return; } dir = g_path_get_dirname(filenames[0]); tilem_config_set("upload", "sendfile_recentdir/f", dir, NULL); g_free(dir); load_files(ewin, filenames); g_strfreev(filenames); } tilem-2.0/gui/skinops.c000066400000000000000000000155401220200411600150740ustar00rootroot00000000000000/* * skinedit - a skin editor for the TiEmu emulator * Copyright (C) 2002 Julien BLACHE * * 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 */ /* contra-sh : This file is a (quasi) perfect copy of the tiemu skinops.c file ... Thank's to rom's and JB for this wonderful work. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "skinops.h" #include #include #define SKIN_ERROR g_quark_from_static_string("skin-error") enum { SKIN_ERROR_INVALID }; /* Determine skin type */ int skin_get_type(SKIN_INFOS *si, const char *filename) { FILE *fp; char str[17]; fp = g_fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Unable to open this file: <%s>\n", filename); return -1; } memset(str, 0, sizeof(str)); fread(str, 16, 1, fp); if(!strncmp(str, "TiEmu v2.00", 16)) si->type = SKIN_TYPE_TIEMU; else if(!strncmp(str, "TilEm v2.00 ", 16)) si->type = SKIN_TYPE_TIEMU; else if(!strncmp(str, "VTIv2.1 ", 8)) si->type = SKIN_TYPE_OLD_VTI; else if(!strncmp(str, "VTIv2.5 ", 8)) si->type = SKIN_TYPE_VTI; else { fprintf(stderr, "Bad skin format\n"); return -1; } return 0; } /* Read TilEm skin informations (header) */ int skin_read_header(SKIN_INFOS *si, FILE *fp) { int i; uint32_t endian; uint32_t jpeg_offset; uint32_t length; char str[17]; /* signature & offsets */ fread(str, 16, 1, fp); if ((strncmp(str, "TilEm v2.00", 16)) && (strncmp(str, "TiEmu v2.00", 16))) { return -1; } fread(&endian, 4, 1, fp); fread(&jpeg_offset, 4, 1, fp); if (endian != ENDIANNESS_FLAG) jpeg_offset = GUINT32_SWAP_LE_BE(jpeg_offset); /* Skin name */ fread(&length, 4, 1, fp); if (endian != ENDIANNESS_FLAG) length = GUINT32_SWAP_LE_BE(length); if (length > 0) { si->name = (char *)malloc(length + 1); if (si->name == NULL) return -1; memset(si->name, 0, length + 1); fread(si->name, length, 1, fp); } /* Skin author */ fread(&length, 4, 1, fp); if (endian != ENDIANNESS_FLAG) length = GUINT32_SWAP_LE_BE(length); if (length > 0) { si->author = (char *)malloc(length + 1); if (si->author == NULL) return -1; memset(si->author, 0, length + 1); fread(si->author, length, 1, fp); } /* LCD colors */ fread(&si->colortype, 4, 1, fp); fread(&si->lcd_white, 4, 1, fp); fread(&si->lcd_black, 4, 1, fp); /* Calc type */ fread(si->calc, 8, 1, fp); /* LCD position */ fread(&si->lcd_pos.left, 4, 1, fp); fread(&si->lcd_pos.top, 4, 1, fp); fread(&si->lcd_pos.right, 4, 1, fp); fread(&si->lcd_pos.bottom, 4, 1, fp); /* Number of RECT struct to read */ fread(&length, 4, 1, fp); if (endian != ENDIANNESS_FLAG) length = GUINT32_SWAP_LE_BE(length); if (length > SKIN_KEYS) return -1; for (i = 0; i < (int)length; i++) { fread(&si->keys_pos[i].left, 4, 1, fp); fread(&si->keys_pos[i].top, 4, 1, fp); fread(&si->keys_pos[i].right, 4, 1, fp); fread(&si->keys_pos[i].bottom, 4, 1, fp); } if (endian != ENDIANNESS_FLAG) { si->colortype = GUINT32_SWAP_LE_BE(si->colortype); si->lcd_white = GUINT32_SWAP_LE_BE(si->lcd_white); si->lcd_black = GUINT32_SWAP_LE_BE(si->lcd_black); si->lcd_pos.top = GUINT32_SWAP_LE_BE(si->lcd_pos.top); si->lcd_pos.left = GUINT32_SWAP_LE_BE(si->lcd_pos.left); si->lcd_pos.bottom = GUINT32_SWAP_LE_BE(si->lcd_pos.bottom); si->lcd_pos.right = GUINT32_SWAP_LE_BE(si->lcd_pos.right); for (i = 0; i < (int)length; i++) { si->keys_pos[i].top = GUINT32_SWAP_LE_BE(si->keys_pos[i].top); si->keys_pos[i].bottom = GUINT32_SWAP_LE_BE(si->keys_pos[i].bottom); si->keys_pos[i].left = GUINT32_SWAP_LE_BE(si->keys_pos[i].left); si->keys_pos[i].right = GUINT32_SWAP_LE_BE(si->keys_pos[i].right); } } si->jpeg_offset = ftell(fp); return 0; } /* Read skin image (pure jpeg data) */ int skin_read_image(SKIN_INFOS *si, FILE *fp, GError **err) { GdkPixbufLoader *loader; gboolean result; guchar *buf; gsize count; struct stat st; // Extract image from skin fseek(fp, si->jpeg_offset, SEEK_SET); fstat(fileno(fp), &st); count = st.st_size - si->jpeg_offset; buf = g_malloc(count * sizeof(guchar)); count = fread(buf, sizeof(guchar), count, fp); // Feed the pixbuf loader with our jpeg data loader = gdk_pixbuf_loader_new(); result = gdk_pixbuf_loader_write(loader, buf, count, err); g_free(buf); if(result == FALSE) { g_object_unref(loader); return -1; } result = gdk_pixbuf_loader_close(loader, err); if(result == FALSE) { g_object_unref(loader); return -1; } // and get the pixbuf si->raw = gdk_pixbuf_loader_get_pixbuf(loader); if(si->raw == NULL) { g_set_error(err, SKIN_ERROR, SKIN_ERROR_INVALID, "Unable to load background image"); g_object_unref(loader); return -1; } si->sx = si->sy = 1.0; si->image = g_object_ref(si->raw); g_object_ref(si->raw); // Get new skin size si->width = gdk_pixbuf_get_width(si->image); si->height = gdk_pixbuf_get_height(si->image); g_object_unref(loader); return 0; } /* Load a skin (TilEm v2.00 only) */ int skin_load(SKIN_INFOS *si, const char *filename, GError **err) { FILE *fp; int ret = 0, errnum; char *dname; g_return_val_if_fail(err == NULL || *err == NULL, -1); fp = g_fopen(filename, "rb"); if (fp == NULL) { errnum = errno; dname = g_filename_display_basename(filename); g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum), "Unable to open %s for reading: %s", dname, g_strerror(errnum)); g_free(dname); return -1; } ret = skin_read_header(si, fp); if (ret) { fclose(fp); dname = g_filename_display_basename(filename); g_set_error(err, SKIN_ERROR, SKIN_ERROR_INVALID, "The file %s is not a valid skin.", dname); g_free(dname); return -1; } ret = skin_read_image(si, fp, err); fclose(fp); return ret; } /* Unload skin by freeing allocated memory */ int skin_unload(SKIN_INFOS *si) { if (si->image != NULL) { g_object_unref(si->image); si->image = NULL; } if (si->raw) { g_object_unref(si->raw); si->raw = NULL; } free(si->name); free(si->author); memset(si, 0, sizeof(SKIN_INFOS)); return 0; } tilem-2.0/gui/skinops.h000066400000000000000000000054711220200411600151030ustar00rootroot00000000000000/* Hey EMACS -*- linux-c -*- */ /* $Id$ */ /* * skinedit - a skin editor for the TiEmu emulator * Copyright (C) 2002 Julien BLACHE * * 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 */ /* From Romain Lievins(?) : Most of these definitions and code comes from the JB's SkinEdit which is based on TiEmu skin code. TiEmu skin code is also based on VTi's skin code. contra-sh : This file is a (quasi ?) perfect copy of the tiemu skinops.h file ... Thank's to Romain Lievins and Julien Blache for this wonderful work. */ #ifdef HAVE_CONFIG_H #include #endif #include #include /***************/ /* Definitions */ /***************/ #define LCD_COLORTYPE_LOW 0 #define LCD_COLORTYPE_HIGH 1 #define LCD_COLORTYPE_CUSTOM 2 #define LCD_HI_WHITE 0xb0ccae #define LCD_HI_BLACK 0x8a6f53 #define LCD_LOW_WHITE 0xcfe0cc #define LCD_LOW_BLACK 0x222e31 #define MAX_COLORS (256 - 16) // we need to keep 16 colors for grayscales #define SKIN_KEYS 80 #define SKIN_TI73 "TI-73" #define SKIN_TI82 "TI-82" #define SKIN_TI83 "TI-83" #define SKIN_TI83P "TI-83+" #define SKIN_TI85 "TI-85" #define SKIN_TI86 "TI-86" #define SKIN_TI89 "TI-89" #define SKIN_TI92 "TI-92" #define SKIN_TI92P "TI-92+" #define SKIN_V200 "V200PLT" #define SKIN_TI89T "TI-89TM" #define SKIN_TYPE_TIEMU 10 #define SKIN_TYPE_VTI 2 #define SKIN_TYPE_OLD_VTI 1 #define SKIN_TYPE_NEW 0 #define ENDIANNESS_FLAG 0xfeedbabe #define TIEMU_SKIN_ID "TiEmu v2.00" /*********/ /* Types */ /*********/ typedef struct { uint32_t left; uint32_t top; uint32_t right; uint32_t bottom; } RECT; typedef struct { int type; GdkPixbuf *image; int width; int height; GdkPixbuf *raw; // raw jpeg image double sx, sy; // scaling factor char calc[9]; uint32_t colortype; uint32_t lcd_black; uint32_t lcd_white; char *name; char *author; RECT lcd_pos; RECT keys_pos[SKIN_KEYS]; long jpeg_offset; } SKIN_INFOS; /*************/ /* Functions */ /*************/ int skin_load(SKIN_INFOS *infos, const char *filename, GError **err); int skin_unload(SKIN_INFOS *infos); tilem-2.0/gui/ti81prg.c000066400000000000000000000207241220200411600147040ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "ti81prg.h" #define tSpace 0x56 #define t0 0x10 #define t9 0x19 #define tDecPt 0x1A #define tA 0x59 #define tZ 0x72 #define tTheta 0x73 #define ramStart 0xE000 #define cxCurApp 0xE347 #define cxOldApp (cxCurApp + 1) #define DimX_old 0xEEF9 #define DimX_new 0xF12D #define prgm0Name 0xF1D3 #define prgm0Start 0xF2FB #define prgm0End (prgm0Start + 2) #define prgmThetaEnd (prgm0End + 36*2) #define progMem 0xF347 #define progMemEnd 0xFCA6 #define cxPrgmEdit 2 #define cxPrgmExec 10 #define cxMenu 11 TI81Program * ti81_program_new(int size) { TI81Program *prgm = tilem_new0(TI81Program, 1); prgm->info.slot = TI81_SLOT_AUTO; memset(prgm->info.name, tSpace, 8); if (size > 0) { prgm->info.size = size; prgm->data = tilem_new_atomic(byte, size); } return prgm; } void ti81_program_free(TI81Program *prgm) { if (!prgm) return; if (prgm->data) tilem_free(prgm->data); tilem_free(prgm); } static byte *get_byte_ptr(const TilemCalc *calc, dword addr) { if (addr < ramStart || addr > 0xffff) return NULL; return &calc->ram[addr - ramStart]; } static int read_byte(const TilemCalc *calc, dword addr) { const byte *p = get_byte_ptr(calc, addr); if (!p) return -1; else return *p; } static dword read_word(const TilemCalc *calc, dword addr) { const byte *p = get_byte_ptr(calc, addr); if (!p) return 0; else return (p[0] | p[1] << 8); } static void write_word(TilemCalc *calc, dword addr, dword value) { byte *p = get_byte_ptr(calc, addr); if (p) { p[0] = value & 0xff; p[1] = (value >> 8) & 0xff; } } static int check_busy(const TilemCalc *calc) { int cur, old; cur = read_byte(calc, cxCurApp); old = read_byte(calc, cxCurApp); if (cur == cxPrgmEdit || cur == cxPrgmExec) return 1; else if (cur == cxMenu && (old == cxPrgmEdit || old == cxPrgmExec)) return 1; else return 0; } static dword get_free_mem_end(const TilemCalc *calc) { const byte *p; int n, i; p = get_byte_ptr(calc, DimX_new); /* DimX is always a small positive integer, so the first byte must be between 80h and 82h, and the last five bytes must always be zero. On 1.1K, DimX_new is part of textShadow, so none of these byte values make any sense. */ if (p[0] < 0x80 || p[0] > 0x82 || p[7] != 0) p = get_byte_ptr(calc, DimX_old); if (p[0] < 0x80 || p[0] > 0x82) return 0; for (i = 3; i < 7; i++) if (p[i]) return 0; n = ((p[2] & 0xf) + ((p[2] >> 4) * 10) + ((p[1] & 0xf) * 100) + ((p[1] >> 4) * 1000)); for (i = p[0]; i < 0x83; i++) { if (n % 10) return 0; n /= 10; } return (progMemEnd + 1 - 16 * n); } int ti81_get_program_info(const TilemCalc *calc, int slot, TI81ProgInfo *info) { const byte *p; dword progstart, progend; if (slot < 0 || slot > TI81_SLOT_MAX) return TI81_ERR_INTERNAL; if (check_busy(calc)) return TI81_ERR_BUSY; progstart = read_word(calc, prgm0Start + 2 * slot); progend = read_word(calc, prgm0Start + 2 * slot + 2); if (progstart < ramStart || progend < ramStart || progend < progstart) return TI81_ERR_BUSY; info->slot = slot; info->size = progend - progstart; info->addr = progstart; p = get_byte_ptr(calc, prgm0Name + 8 * slot); if (!p) return TI81_ERR_INTERNAL; memcpy(info->name, p, 8); return 0; } int ti81_get_program(const TilemCalc *calc, int slot, TI81Program **prgm) { TI81ProgInfo info; const byte *p; int s; if ((s = ti81_get_program_info(calc, slot, &info))) { *prgm = NULL; return s; } *prgm = ti81_program_new(info.size); (*prgm)->info = info; if (info.size > 0 && (p = get_byte_ptr(calc, info.addr))) memcpy((*prgm)->data, p, info.size); return 0; } int ti81_load_program(TilemCalc *calc, const TI81Program *prgm) { TI81ProgInfo info; int slot = prgm->info.slot; int s, i; dword progs_start, progs_end, mem_end, x; byte *p; if (slot == TI81_SLOT_AUTO) { for (slot = 0; slot <= TI81_SLOT_MAX; slot++) { if ((s = ti81_get_program_info(calc, slot, &info))) return s; if (info.size == 0 && info.name[0] == tSpace) break; } if (slot > TI81_SLOT_MAX) return TI81_ERR_SLOTS_FULL; } if ((s = ti81_get_program_info(calc, slot, &info))) return s; /* move later programs forward/backward in memory */ progs_start = info.addr + info.size; progs_end = read_word(calc, prgmThetaEnd); if (progs_end < progs_start) return TI81_ERR_BUSY; mem_end = get_free_mem_end(calc); if (progs_end + prgm->info.size - info.size > mem_end) return TI81_ERR_MEMORY; if (prgm->info.size != info.size && progs_start != progs_end) { p = get_byte_ptr(calc, progs_start); if (!p) return TI81_ERR_INTERNAL; memmove(p + prgm->info.size - info.size, p, progs_end - progs_start); } /* update program pointers */ for (i = slot; i <= TI81_SLOT_MAX; i++) { x = read_word(calc, prgm0End + 2 * i); write_word(calc, prgm0End + 2 * i, x + prgm->info.size - info.size); } /* copy program data */ if (prgm->info.size != 0) { p = get_byte_ptr(calc, info.addr); if (!p) return TI81_ERR_INTERNAL; memcpy(p, prgm->data, prgm->info.size); } /* copy program name */ p = get_byte_ptr(calc, prgm0Name + 8 * slot); if (!p) return TI81_ERR_INTERNAL; memcpy(p, prgm->info.name, 8); return 0; } int ti81_read_prg_file(FILE *f, TI81Program **prgm) { byte buf[20]; unsigned int size, i; unsigned int sum = 0; TI81Program *p; *prgm = NULL; if (fread(buf, 1, 20, f) != 20) return TI81_ERR_INVALID_FILE; if (strcmp((char *) buf, "**TI81**") || buf[9] != 0x6e) return TI81_ERR_INVALID_FILE; size = buf[10] | buf[11] << 8; p = ti81_program_new(size); memcpy(p->info.name, buf + 12, 8); for (i = 0; i < 8; i++) sum += buf[12 + i]; if (fread(p->data, 1, size, f) != size) { ti81_program_free(p); return TI81_ERR_INVALID_FILE; } for (i = 0; i < size; i++) sum += p->data[i]; if (fread(buf, 1, 2, f) != 2) { ti81_program_free(p); return TI81_ERR_INVALID_FILE; } sum -= (buf[0] | buf[1] << 8); if (sum & 0xffff) fprintf(stderr, "warning: checksum incorrect\n"); *prgm = p; return 0; } int ti81_write_prg_file(FILE *f, const TI81Program *prgm) { byte buf[20]; unsigned int size, i; unsigned int sum = 0; memcpy(buf, "**TI81**\0n", 10); size = prgm->info.size; buf[10] = size & 0xff; buf[11] = (size >> 8) & 0xff; memcpy(buf + 12, prgm->info.name, 8); for (i = 0; i < 8; i++) sum += buf[12 + i]; if (fwrite(buf, 1, 20, f) != 20) return TI81_ERR_FILE_IO; if (fwrite(prgm->data, 1, size, f) != size) return TI81_ERR_FILE_IO; for (i = 0; i < size; i++) sum += prgm->data[i]; buf[0] = sum & 0xff; buf[1] = (sum >> 8) & 0xff; if (fwrite(buf, 1, 2, f) != 2) return TI81_ERR_FILE_IO; return 0; } char * ti81_program_slot_to_string(int slot) { char buf[50]; char *s; if (slot == TI81_SLOT_AUTO) strcpy(buf, "Automatic"); else if (slot < 0 || slot > 36) strcpy(buf, "?"); else if (slot < 10) sprintf(buf, "Prgm%c", slot + '0'); else if (slot < 36) sprintf(buf, "Prgm%c", slot + 'A' - 10); else strcpy(buf, "Prgm\316\270"); s = tilem_new_atomic(char, strlen(buf) + 1); strcpy(s, buf); return s; } char * ti81_program_name_to_string(const byte *prgname) { char buf[50]; char *s; int i, j; for (i = j = 0; i < 8; i++) { if (prgname[i] == tSpace) buf[j++] = '_'; else if (prgname[i] == tDecPt) buf[j++] = '.'; else if (prgname[i] == tTheta) { buf[j++] = '\316'; buf[j++] = '\270'; } else if (prgname[i] >= t0 && prgname[i] <= t9) buf[j++] = '0' + prgname[i] - t0; else if (prgname[i] >= tA && prgname[i] <= tZ) buf[j++] = 'A' + prgname[i] - tA; else buf[j++] = '?'; } while (j > 0 && buf[j - 1] == '_') j--; buf[j] = 0; s = tilem_new_atomic(char, strlen(buf) + 1); strcpy(s, buf); return s; } tilem-2.0/gui/ti81prg.h000066400000000000000000000063311220200411600147070ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2011 Benjamin Moody * * 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 3 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, see . */ enum { TI81_SLOT_AUTO = -1, TI81_SLOT_0, TI81_SLOT_1, TI81_SLOT_2, TI81_SLOT_3, TI81_SLOT_4, TI81_SLOT_5, TI81_SLOT_6, TI81_SLOT_7, TI81_SLOT_8, TI81_SLOT_9, TI81_SLOT_A, TI81_SLOT_B, TI81_SLOT_C, TI81_SLOT_D, TI81_SLOT_E, TI81_SLOT_F, TI81_SLOT_G, TI81_SLOT_H, TI81_SLOT_I, TI81_SLOT_J, TI81_SLOT_K, TI81_SLOT_L, TI81_SLOT_M, TI81_SLOT_N, TI81_SLOT_O, TI81_SLOT_P, TI81_SLOT_Q, TI81_SLOT_R, TI81_SLOT_S, TI81_SLOT_T, TI81_SLOT_U, TI81_SLOT_V, TI81_SLOT_W, TI81_SLOT_X, TI81_SLOT_Y, TI81_SLOT_Z, TI81_SLOT_THETA }; #define TI81_SLOT_MAX TI81_SLOT_THETA typedef struct _TI81ProgInfo { int slot; /* program slot number */ int size; /* size of program contents */ dword addr; /* address of program contents */ byte name[8]; /* program name, tokens */ } TI81ProgInfo; typedef struct _TI81Program { TI81ProgInfo info; byte *data; } TI81Program; /* Error codes */ enum { TI81_ERR_FILE_IO = 1, /* File I/O error */ TI81_ERR_INVALID_FILE, /* PRG file is invalid */ TI81_ERR_MEMORY, /* Not enough memory to load program */ TI81_ERR_SLOTS_FULL, /* No free program slots */ TI81_ERR_BUSY, /* Calculator is busy and unable to load/save programs */ TI81_ERR_INTERNAL }; /* Create a new TI81Program with the given size. */ TI81Program * ti81_program_new(int size) TILEM_ATTR_MALLOC; /* Free a TI81Program. */ void ti81_program_free(TI81Program *prgm); /* Get information about the program in the given slot. */ int ti81_get_program_info(const TilemCalc *calc, int slot, TI81ProgInfo *info); /* Retrieve a program from calculator memory. Free the resulting program with ti81_program_free() when you're done with it. */ int ti81_get_program(const TilemCalc *calc, int slot, TI81Program **prgm); /* Load a program into calculator memory. */ int ti81_load_program(TilemCalc *calc, const TI81Program *prgm); /* Read a program from a PRG file. Free the resulting program with ti81_program_free() when you're done with it. */ int ti81_read_prg_file(FILE *f, TI81Program **prgm); /* Write a program to a PRG file. */ int ti81_write_prg_file(FILE *f, const TI81Program *prgm); /* Convert program slot number into a UTF-8 string. Free the result with tilem_free() when you're done with it. */ char * ti81_program_slot_to_string(int slot) TILEM_ATTR_MALLOC; /* Convert program name to a UTF-8 string. Free the result with tilem_free() when you're done with it. */ char * ti81_program_name_to_string(const byte *prgname) TILEM_ATTR_MALLOC; tilem-2.0/gui/tilem2.c000066400000000000000000000211511220200411600145750ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2012 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "icons.h" #include "msgbox.h" /* CMD LINE OPTIONS */ static gchar* cl_romfile = NULL; static gchar* cl_skinfile = NULL; static gchar* cl_model = NULL; static gchar* cl_statefile = NULL; static gchar** cl_files_to_load = NULL; static gboolean cl_skinless_flag = FALSE; static gboolean cl_reset_flag = FALSE; static gchar* cl_getvar = NULL; static gchar* cl_macro_to_run = NULL; static gboolean cl_debug_flag = FALSE; static gboolean cl_normalspeed_flag = FALSE; static gboolean cl_fullspeed_flag = FALSE; static GOptionEntry entries[] = { { "rom", 'r', 0, G_OPTION_ARG_FILENAME, &cl_romfile, "The rom file to run", "FILE" }, { "skin", 'k', 0, G_OPTION_ARG_FILENAME, &cl_skinfile, "The skin file to use", "FILE" }, { "model", 'm', 0, G_OPTION_ARG_STRING, &cl_model, "The model to use", "NAME" }, { "state-file", 's', 0, G_OPTION_ARG_FILENAME, &cl_statefile, "The state-file to use", "FILE" }, { "without-skin", 'l', 0, G_OPTION_ARG_NONE, &cl_skinless_flag, "Start in skinless mode", NULL }, { "reset", 0, 0, G_OPTION_ARG_NONE, &cl_reset_flag, "Reset the calc at startup", NULL }, { "get-var", 0, 0, G_OPTION_ARG_STRING, &cl_getvar, "Get a var at startup", "FILE" }, { "play-macro", 'p', 0, G_OPTION_ARG_FILENAME, &cl_macro_to_run, "Run this macro at startup", "FILE" }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &cl_debug_flag, "Launch debugger", NULL }, { "normal-speed", 0, 0, G_OPTION_ARG_NONE, &cl_normalspeed_flag, "Run at normal speed", NULL }, { "full-speed", 0, 0, G_OPTION_ARG_NONE, &cl_fullspeed_flag, "Run at maximum speed", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &cl_files_to_load, NULL, "FILE" }, { 0, 0, 0, 0, 0, 0, 0 } }; /* ######### MAIN ######### */ /* Order of preference for automatic model selection. */ static const char model_search_order[] = { TILEM_CALC_TI81, TILEM_CALC_TI73, TILEM_CALC_TI82, TILEM_CALC_TI83, TILEM_CALC_TI76, TILEM_CALC_TI84P_SE, TILEM_CALC_TI84P, TILEM_CALC_TI83P_SE, TILEM_CALC_TI83P, TILEM_CALC_TI84P_NSPIRE, TILEM_CALC_TI85, TILEM_CALC_TI86, 0 }; /* Check if given calc model should be used for these file types. */ static gboolean check_file_types(int calc_model, const int *file_models, int nfiles) { /* Only choose a calc model if it supports all of the given file types, and at least one of the files is of the calc's "preferred" type. This means if we have a mixture of 82Ps and 83Ps, we can use either a TI-83 or TI-76.fr ROM image, but not a TI-83 Plus. */ gboolean preferred = FALSE; int i; calc_model = model_to_base_model(calc_model); for (i = 0; i < nfiles; i++) { if (file_models[i] == calc_model) preferred = TRUE; else if (!model_supports_file(calc_model, file_models[i])) return FALSE; } return preferred; } static void load_initial_rom(TilemCalcEmulator *emu, const char *cmdline_rom_name, const char *cmdline_state_name, char **cmdline_files, int model) { GError *err = NULL; char *modelname; int nfiles, *file_models, i; /* If a ROM file is specified on the command line, use that (and no other) */ if (cmdline_rom_name) { if (tilem_calc_emulator_load_state(emu, cmdline_rom_name, cmdline_state_name, model, &err)) return; else if (!err) exit(0); else { g_printerr("%s\n", err->message); exit(1); } } /* Choose model by file names */ if (!model && cmdline_files) { nfiles = g_strv_length(cmdline_files); file_models = g_new(int, nfiles); /* determine model for each filename */ for (i = 0; i < nfiles; i++) file_models[i] = file_to_model(cmdline_files[i]); /* iterate over all known models... */ for (i = 0; model_search_order[i]; i++) { model = model_search_order[i]; /* check if this model supports the named files */ if (!check_file_types(model, file_models, nfiles)) continue; /* try to load model, but no error message if no ROM is present in config */ if (tilem_calc_emulator_load_state(emu, NULL, NULL, model, &err)) { g_free(file_models); return; } else if (!err) exit(0); else if (!g_error_matches(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_NO_ROM)) { messagebox01(NULL, GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); } g_clear_error(&err); } g_free(file_models); model = 0; } /* If no model specified on command line (either explicitly or implicitly), then choose the most recently used model */ if (!model && !cmdline_files) { tilem_config_get("recent", "last_model/s", &modelname, NULL); if (modelname) model = name_to_model(modelname); } /* Try to load the most recently used ROM for chosen model */ if (model) { if (tilem_calc_emulator_load_state(emu, NULL, NULL, model, &err)) return; else if (!err) exit(0); else { messagebox01(NULL, GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); g_clear_error(&err); } } /* Prompt user for a ROM file */ while (!emu->calc) { if (!tilem_calc_emulator_prompt_open_rom(emu)) exit(0); } } int main(int argc, char **argv) { TilemCalcEmulator* emu; char *menurc_path; GOptionContext *context; GError *error = NULL; int model = 0; g_thread_init(NULL); gtk_init(&argc, &argv); set_program_path(argv[0]); g_set_application_name("TilEm"); menurc_path = get_shared_file_path("menurc", NULL); if (menurc_path) gtk_accel_map_load(menurc_path); g_free(menurc_path); init_custom_icons(); gtk_window_set_default_icon_name("tilem"); emu = tilem_calc_emulator_new(); context = g_option_context_new(NULL); g_option_context_add_main_entries(context, entries, NULL); g_option_context_add_group(context, gtk_get_option_group(TRUE)); if (!g_option_context_parse(context, &argc, &argv, &error)) { g_printerr("%s: %s\n", g_get_prgname(), error->message); exit (1); } if (cl_model) { model = name_to_model(cl_model); if (!model) { g_printerr("%s: unknown model %s\n", g_get_prgname(), cl_model); return 1; } } load_initial_rom(emu, cl_romfile, cl_statefile, cl_files_to_load, model); emu->ewin = tilem_emulator_window_new(emu); if (cl_skinless_flag) tilem_emulator_window_set_skin_disabled(emu->ewin, TRUE); else if (cl_skinfile) { tilem_emulator_window_set_skin(emu->ewin, cl_skinfile); tilem_emulator_window_set_skin_disabled(emu->ewin, FALSE); } gtk_widget_show(emu->ewin->window); ticables_library_init(); tifiles_library_init(); ticalcs_library_init(); if (cl_reset_flag) tilem_calc_emulator_reset(emu); if (cl_fullspeed_flag) tilem_calc_emulator_set_limit_speed(emu, FALSE); else if (cl_normalspeed_flag) tilem_calc_emulator_set_limit_speed(emu, TRUE); if (cl_files_to_load) load_files_cmdline(emu->ewin, cl_files_to_load); if (cl_macro_to_run) tilem_macro_load(emu, cl_macro_to_run); if (cl_getvar) tilem_link_receive_matching(emu, cl_getvar, "."); if (cl_debug_flag) launch_debugger(emu->ewin); else tilem_calc_emulator_run(emu); g_signal_connect(emu->ewin->window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_main(); tilem_calc_emulator_pause(emu); tilem_emulator_window_free(emu->ewin); tilem_calc_emulator_free(emu); menurc_path = get_config_file_path("menurc", NULL); gtk_accel_map_save(menurc_path); g_free(menurc_path); ticables_library_exit(); tifiles_library_exit(); ticalcs_library_exit(); return 0; } tilem-2.0/gui/tilem2.ico000066400000000000000000000560061220200411600151340ustar00rootroot00000000000000(h h ~ f  00'00 %^6( DDDDBDA3A"$ADDDDBDA@AAA!! AA!! AA !! AAAADDDD( YdhHUYOY^FSWxsJUZq}}Q^bCOS`mrNZ^JVY]kpO\a@MR=IMyXeiwvXcgYejķUchȲbnrDPTBNRO[_?LPn{BNS>JN?JNoy~N[`dqt[fjJW[KW[N9h47J*?,?D3H\; 2MJ[O,?%%%%# JN=IM>JN?LPJUZQ^bdqtxyXcgCOSYdhoy~vbnrKW[OY^xy@MRJW[JW[JW[JW[JW[JW[JW[JW[JW[JW[?JNxyUchJW[xyUchJW[xyUchJW[xyUchJW[xyUchJW[xyO\aJW[xyFSWXei]kp]kp]kp]kp]kp]kp]kp]kp]kpBNSxy[fjNZ^BNRLL dYxs\ LL LL LL (((((((((((((((((((((m LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL 4@ LL oEEEEEEEEEEEEEEEEEEE% LL LL LLMN-&vv}a,6nklLr*J!bQ=UU=|]B"LWWK.qL````K( @ ,JMTadjx{GSV]jmsO\_tesvݴ|JWZanqw=IL|S`ciwznvwFRU\ilrwN[^dru{@MPWdgm{~¶IVY`mpдv{ffkHc"" H"'5spKmmm.H;mmmm""- H8"'+mmmmvHCmmmm$HXX""&XX:HH"HyNN5H3(HFl(GxHHHH&HHHHH"HHHHHHHHHHHHHHHHHHHHHHHuHHHHH"HHHHHHHHHHHHHMMMMM+HHHHh HHHHHz"HHHMtldY{qg CIHHHH"hMWSH"M%9i bv*G"Yj44_444W^440444l^44U"iO qK7@._9"iU"i,"C,"CBo|o|o|o|o|o|o|owowowowowowo "CB|o|o|o|o|o|o|owowowowowowow "CBo|o|o|o|o|o|o|owowowowowowo "CB|o|o|o|o|o|o|owowowowowowow "CBo|o|o|o|o|o|o|owowowowowowo "B|o|o|o|o|o|o|owowowowowowow "Bo|o|o|o|o|o|o|owowowowowowo "B|o|o|o|o|o|o|owowowowowowow "Bo|o|o|o|o|o|o|o|o|o|o|o|o|o "Bwowowowowowowo|o|o|o|o|o|o| "Bowowowowowowo|o|o|o|o|o|o|o "Bwowowowowowowo|o|o|o|o|o|o| "Bowowowowowowo|o|o|o|o|o|o|o "Bwowowowowowowo|o|o|o|o|o|o| "owowowowowowo|o|o|o|o|o|o|o "rwowowowowowowo|o|o|o|o|o|o| "owowowowowowo|o|o|o|o|o|o|o "Y "Y "[ "1Og*ge JU U4=/Lnd0YY0#Q3A` , U2e PD`RX4u """"}<1D/6T)TT)e?(0` $XTzɉؿؿؿؿŸ̃˄̃̃̃̃ҝըըϕ̃̃̃̃̃Vfpwݲ߲߲ݲѴ[glLY\LY\P\aU`esO[_KW[P[_S_dm{{6wm{{6w½½½m{{6wɱɱɱɱôKW[ALPALPALPTaetALPALPALPALPm{{6wɱɱɱɱĴALPALPALPALPJVYfrwALPALPALPALPm{{6w}yx{x}m{{6wm{{6wm{{6w{rivzalqWdhNZ^EQU=HLJN|m{{6wkwz 101 ICON "@srcdir@/tilem2.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION BUILD_VERSION PRODUCTVERSION BUILD_VERSION FILEFLAGSMASK 0 FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "Linux Programmer Group" VALUE "FileDescription", "TilEm" VALUE "FileVersion", "@PACKAGE_VERSION@" VALUE "InternalName", "tilem2" VALUE "LegalCopyright", "Copyright \xa9 2012 The TilEm Project" VALUE "OriginalFilename", "tilem2.exe" VALUE "ProductName", "@PACKAGE_NAME@" VALUE "ProductVersion", "@PACKAGE_VERSION@" VALUE "Comments", "Licensed under the GNU GPLv3+ (see http://www.gnu.org/licenses/.)" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END tilem-2.0/gui/tool.c000066400000000000000000000243061220200411600143630ustar00rootroot00000000000000/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010 Benjamin Moody * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" /* Create a frame around the given widget, with a boldface label in the GNOME style */ GtkWidget* new_frame(const gchar* label, GtkWidget* contents) { GtkWidget *frame, *align; char *str; str = g_strconcat("", label, "", NULL); frame = gtk_frame_new(str); g_free(str); g_object_set(gtk_frame_get_label_widget(GTK_FRAME(frame)), "use-markup", TRUE, NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); align = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(align), 6, 0, 12, 0); gtk_widget_show(align); gtk_container_add(GTK_CONTAINER(frame), align); gtk_container_add(GTK_CONTAINER(align), contents); gtk_widget_show(frame); return frame; } /* Get model name (abbreviation) for a TilEm model ID. */ const char * model_to_name(int model) { const TilemHardware **models; int nmodels, i; tilem_get_supported_hardware(&models, &nmodels); for (i = 0; i < nmodels; i++) if (models[i]->model_id == model) return models[i]->name; return NULL; } /* Convert model name to a model ID. */ int name_to_model(const char *name) { char *s; const TilemHardware **models; int nmodels, i, j; s = g_new(char, strlen(name) + 1); for (i = j = 0; name[i]; i++) { if (name[i] == '+') s[j++] = 'p'; else if (name[i] != '-') s[j++] = g_ascii_tolower(name[i]); } s[j] = 0; tilem_get_supported_hardware(&models, &nmodels); for (i = 0; i < nmodels; i++) { if (!strcmp(s, models[i]->name)) { g_free(s); return models[i]->model_id; } } g_free(s); return 0; } /* Convert TilEm model ID to tifiles2 model ID. */ CalcModel model_to_calcmodel(int model) { switch (model) { case TILEM_CALC_TI73: return CALC_TI73; case TILEM_CALC_TI82: return CALC_TI82; case TILEM_CALC_TI83: case TILEM_CALC_TI76: return CALC_TI83; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: return CALC_TI83P; case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return CALC_TI84P; case TILEM_CALC_TI85: return CALC_TI85; case TILEM_CALC_TI86: return CALC_TI86; default: return CALC_NONE; } } /* Convert tifiles2 model ID to TilEm model ID. */ int calcmodel_to_model(CalcModel model) { switch (model) { case CALC_TI73: return TILEM_CALC_TI73; case CALC_TI82: return TILEM_CALC_TI82; case CALC_TI83: return TILEM_CALC_TI83; case CALC_TI83P: return TILEM_CALC_TI83P; case CALC_TI84P: return TILEM_CALC_TI84P; case CALC_TI85: return TILEM_CALC_TI85; case CALC_TI86: return TILEM_CALC_TI86; default: return 0; } } /* Get model ID for a given file. */ int file_to_model(const char *name) { const char *p; TigContent *tig; int model; p = strrchr(name, '.'); if (!p || strlen(p) < 4 || strchr(p, '/') || strchr(p, '\\')) return 0; p++; if (!g_ascii_strcasecmp(p, "prg")) return TILEM_CALC_TI81; if (!g_ascii_strncasecmp(p, "73", 2)) return TILEM_CALC_TI73; if (!g_ascii_strncasecmp(p, "82", 2)) return TILEM_CALC_TI82; if (!g_ascii_strncasecmp(p, "83", 2)) return TILEM_CALC_TI83; if (!g_ascii_strncasecmp(p, "8x", 2)) return TILEM_CALC_TI83P; if (!g_ascii_strncasecmp(p, "85", 2)) return TILEM_CALC_TI85; if (!g_ascii_strncasecmp(p, "86", 2)) return TILEM_CALC_TI86; if (!g_ascii_strcasecmp(p, "tig") || !g_ascii_strcasecmp(p, "zip")) { /* read file and see what tifiles thinks the type is */ tig = tifiles_content_create_tigroup(CALC_NONE, 0); tifiles_file_read_tigroup(name, tig); model = calcmodel_to_model(tig->model); tifiles_content_delete_tigroup(tig); return model; } return 0; } /* Get "base" model for file type support. */ int model_to_base_model(int calc_model) { switch (calc_model) { case TILEM_CALC_TI83: case TILEM_CALC_TI76: return TILEM_CALC_TI83; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return TILEM_CALC_TI83P; default: return calc_model; } } /* Check if calc is compatible with given file type. */ gboolean model_supports_file(int calc_model, int file_model) { calc_model = model_to_base_model(calc_model); file_model = model_to_base_model(file_model); if (file_model == calc_model) return TRUE; if (file_model == TILEM_CALC_TI82 && (calc_model == TILEM_CALC_TI83 || calc_model == TILEM_CALC_TI83P)) return TRUE; if (file_model == TILEM_CALC_TI83 && (calc_model == TILEM_CALC_TI83P)) return TRUE; if (file_model == TILEM_CALC_TI85 && (calc_model == TILEM_CALC_TI86)) return TRUE; return FALSE; } /* A popup which is used to let the user choose the model at startup */ char choose_rom_popup(GtkWidget *parent_window, const char *filename, char default_model) { const TilemHardware **models; GtkWidget *dlg, *vbox, *frame, *btn; GtkToggleButton **btns; char *ids, id = 0; int nmodels, noptions, i, j, defoption = 0, response; dword romsize; char *fn, *msg; tilem_get_supported_hardware(&models, &nmodels); /* determine ROM size for default model */ for (i = 0; i < nmodels; i++) if (models[i]->model_id == default_model) break; g_return_val_if_fail(i < nmodels, 0); romsize = models[i]->romsize; /* all other models with same ROM size are candidates */ noptions = 0; for (i = 0; i < nmodels; i++) { if (models[i]->model_id == default_model) defoption = noptions; if (models[i]->romsize == romsize) noptions++; } if (noptions < 2) /* no choice */ return default_model; dlg = gtk_dialog_new_with_buttons("Select Calculator Type", GTK_WINDOW(parent_window), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); vbox = gtk_vbox_new(TRUE, 0); /* create radio buttons */ btns = g_new(GtkToggleButton*, noptions); ids = g_new(char, noptions); btn = NULL; for (i = j = 0; i < nmodels; i++) { if (models[i]->romsize == romsize) { btn = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(btn), models[i]->desc); btns[j] = GTK_TOGGLE_BUTTON(btn); ids[j] = models[i]->model_id; gtk_box_pack_start(GTK_BOX(vbox), btn, TRUE, TRUE, 3); j++; } } gtk_toggle_button_set_active(btns[defoption], TRUE); fn = g_filename_display_basename(filename); msg = g_strdup_printf("Calculator type for %s:", fn); frame = new_frame(msg, vbox); g_free(fn); g_free(msg); gtk_container_set_border_width(GTK_CONTAINER(frame), 6); gtk_widget_show_all(frame); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); response = gtk_dialog_run(GTK_DIALOG(dlg)); if (response == GTK_RESPONSE_OK) { for (i = 0; i < noptions; i++) { if (gtk_toggle_button_get_active(btns[i])) { id = ids[i]; break; } } } else { id = 0; } gtk_widget_destroy(dlg); g_free(btns); g_free(ids); return id; } /* Convert UTF-8 to filename encoding. Use ASCII digits in place of subscripts if necessary. If conversion fails utterly, fall back to the UTF-8 name, which is broken but better than nothing. */ char * utf8_to_filename(const char *utf8str) { gchar *result, *ibuf, *obuf, *p; gsize icount, ocount; const gchar **charsets; GIConv ic; gunichar c; if (g_get_filename_charsets(&charsets)) return g_strdup(utf8str); ic = g_iconv_open(charsets[0], "UTF-8"); if (!ic) { g_warning("utf8_to_filename: unsupported charset %s", charsets[0]); return g_strdup(utf8str); } ibuf = (gchar*) utf8str; icount = strlen(utf8str); ocount = icount * 2; /* be generous */ result = obuf = g_new(gchar, ocount + 1); while (g_iconv(ic, &ibuf, &icount, &obuf, &ocount) == (gsize) -1) { if (errno != EILSEQ) { g_warning("utf8_to_filename: error in conversion"); g_free(result); g_iconv_close(ic); return g_strdup(utf8str); } c = g_utf8_get_char(ibuf); if (c >= 0x2080 && c <= 0x2089) *obuf = c - 0x2080 + '0'; else *obuf = '_'; obuf++; ocount--; p = g_utf8_next_char(ibuf); icount -= p - ibuf; ibuf = p; } *obuf = 0; g_iconv_close(ic); return result; } /* Convert UTF-8 to a subset of UTF-8 that is compatible with the locale */ char * utf8_to_restricted_utf8(const char *utf8str) { char *p, *q; p = utf8_to_filename(utf8str); q = g_filename_to_utf8(p, -1, NULL, NULL, NULL); g_free(p); if (q) return q; else return g_strdup(utf8str); } /* Generate default filename (UTF-8) for a variable */ char * get_default_filename(const TilemVarEntry *tve) { GString *str = g_string_new(""); if (tve->slot_str) { g_string_append(str, tve->slot_str); if (tve->name_str && tve->name_str[0]) { g_string_append_c(str, '-'); g_string_append(str, tve->name_str); } } else if (tve->name_str && tve->name_str[0]) { g_string_append(str, tve->name_str); } else { g_string_append(str, "untitled"); } g_string_append_c(str, '.'); g_string_append(str, tve->file_ext); return g_string_free(str, FALSE); } tilem-2.0/install-sh000077500000000000000000000325371220200411600144670ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tilem-2.0/installer/000077500000000000000000000000001220200411600144465ustar00rootroot00000000000000tilem-2.0/installer/win32/000077500000000000000000000000001220200411600154105ustar00rootroot00000000000000tilem-2.0/installer/win32/COPYING-PIXMAN000066400000000000000000000034711220200411600174420ustar00rootroot00000000000000License for pixman ------------------ Copyright 1987, 1988, 1989, 1998 The Open Group Copyright 1987, 1988, 1989 Digital Equipment Corporation Copyright 1999, 2004, 2008 Keith Packard Copyright 2000 SuSE, Inc. Copyright 2000 Keith Packard, member of The XFree86 Project, Inc. Copyright 2004, 2005, 2007, 2008, 2009, 2010 Red Hat, Inc. Copyright 2004 Nicholas Miell Copyright 2005 Lars Knoll & Zack Rusin, Trolltech Copyright 2005 Trolltech AS Copyright 2007 Luca Barbato Copyright 2008 Aaron Plattner, NVIDIA Corporation Copyright 2008 Rodrigo Kumpera Copyright 2008 André Tupinambá Copyright 2008 Mozilla Corporation Copyright 2008 Frederic Plourde Copyright 2009, Oracle and/or its affiliates. All rights reserved. Copyright 2009, 2010 Nokia Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tilem-2.0/installer/win32/COPYING-ZLIB000066400000000000000000000017721220200411600172100ustar00rootroot00000000000000License for zlib ---------------- (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu tilem-2.0/installer/win32/Makefile.in000066400000000000000000000122261220200411600174600ustar00rootroot00000000000000MAKENSIS = @MAKENSIS@ STRIP = @STRIP@ OBJDUMP = @OBJDUMP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ SHELL = @SHELL@ LN_S = @LN_S@ abs_builddir = @abs_builddir@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ main_program = tilem2.exe docs = README KEYS NEWS COPYING CHANGELOG THANKS extra_docs = COPYING-PIXMAN COPYING-ZLIB install_files = $(main_program) *.dll *.txt install_subdirs = etc lib share extra_gtk_files = lib/gtk-2.0/2.10.0/engines/libwimp.dll extra_dlls = GTK_BINDIR = @GTK_BINDIR@ TICALCS_BINDIR = @TICALCS_BINDIR@ DLLPATH = @DLLPATH@ PATH_SEPARATOR = @PATH_SEPARATOR@ system_dlls = advapi32.dll cfgmgr32.dll comctl32.dll comdlg32.dll dnsapi.dll \ gdi32.dll gdiplus.dll imm32.dll kernel32.dll msimg32.dll \ msvcrt.dll ole32.dll setupapi.dll shell32.dll shlwapi.dll \ user32.dll usp10.dll winspool.drv ws2_32.dll wsock32.dll all: install #### Build the installer dist: install installer.nsi rm -f files.nsi rmfiles.nsi rmdirs.nsi set -e ; for file in $(install_files) ; do \ name=`echo "$$file" | sed 's,/,\\\\,g'` ; \ echo "File \"$$name\"" >> files.nsi ; \ echo "Delete \"\$$INSTDIR\\$$name\"" >> rmfiles.nsi ; \ done set -e ; for dir in $(install_subdirs) ; do \ if [ -d $$dir ] ; then \ echo "File /r \"$$dir\"" >> files.nsi ; \ fi ; \ done set -e ; LC_ALL=C ; export LC_ALL ; \ for file in `find -L $(install_subdirs) | sort -r` ; do \ name=`echo "$$file" | sed 's,/,\\\\,g'` ; \ if [ -d $$file ] ; then \ echo "RmDir \"\$$INSTDIR\\$$name\"" >> rmdirs.nsi ; \ else \ echo "Delete \"\$$INSTDIR\\$$name\"" >> rmfiles.nsi ; \ fi ; \ done $(MAKENSIS) installer.nsi installer.nsi: installer.nsi.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status installer/win32/installer.nsi #### Install files into this directory install: install-bin install-data install-config install-extra install-libs # Install the program itself and data files install-bin: $(main_program) $(main_program): $(top_builddir)/gui/$(main_program) cd $(top_builddir)/gui && $(MAKE) install bindir=$(abs_builddir) $(STRIP) $(main_program) install-data: cd $(top_builddir)/data && $(MAKE) install prefix=$(abs_builddir) rm -rf share/mime rm -rf share/applications rm -rf share/icons set -e ; for file in $(docs) ; do \ sed 's/\r*$$/\r/' < $(top_srcdir)/$$file > $$file.txt ; \ done set -e ; for file in $(extra_docs) ; do \ sed 's/\r*$$/\r/' < $(srcdir)/$$file > $$file.txt ; \ done # Install GTK+ configuration install-config: $(INSTALL) -d -m 755 etc/gtk-2.0 $(INSTALL_DATA) $(srcdir)/gtkrc etc/gtk-2.0 # Install additional files install-extra: install-extra-stamp install-extra-stamp: set -e ; for file in $(extra_gtk_files) ; do \ rm -f $$file ; \ $(INSTALL) -d -m 755 `dirname $$file` ; \ for dir in `echo $(DLLPATH) | tr $(PATH_SEPARATOR) ' '` ; do \ if [ -d $$dir ] && [ -f $$dir/../$$file ] ; then \ $(LN_S) $$dir/../$$file $$file ; \ break ; \ fi ; \ done ; \ if ! [ -f $$file ] ; then \ echo "** Cannot find $$file **" ; \ echo ; \ echo " Directories searched: $(DLLPATH)" ; \ echo ; \ exit 1 ; \ fi ; \ done touch install-extra-stamp # Install required libraries install-libs: install-libs-stamp install-libs-stamp: $(main_program) install-extra-stamp rm -f dlls missing-dlls echo $(main_program) > binfiles ls $(extra_gtk_files) | grep 'dll$$' >> binfiles echo $(extra_dlls) > dlls set -e ; LC_ALL=C ; export LC_ALL ; \ while [ -s binfiles ] ; do \ for bin in `cat binfiles` ; do \ $(OBJDUMP) -p $$bin | \ sed -n '/DLL Name:/{s/.*DLL Name: *\([^ ]*\).*/\1/;p}' | \ tr A-Z a-z >> dlls ; \ done ; \ rm -f binfiles ; \ for lib in `cat dlls` ; do \ if ! [ -f ./$$lib ] && ! echo $(system_dlls) | grep -q $$lib ; then \ for dir in `echo $(DLLPATH) | tr $(PATH_SEPARATOR) ' '` ; do \ if [ -d $$dir ] && [ -f $$dir/$$lib ] ; then \ $(LN_S) $$dir/$$lib . ; \ echo $$lib >> binfiles ; \ break ; \ fi ; \ done ; \ if ! [ -f $$lib ] ; then \ echo $$lib >> missing-dlls ; \ fi ; \ fi ; \ done ; \ rm -f dlls ; \ done @if [ -s missing-dlls ] ; then \ echo "** Cannot find the following libraries **" ; \ cat missing-dlls ; \ echo ; \ echo " If these libraries are part of a standard Windows" ; \ echo " installation, add them to the list of 'system_dlls'" ; \ echo " in Makefile.in." ; \ echo ; \ echo " Directories searched: $(DLLPATH)" ; \ echo ; \ exit 1 ; \ fi touch install-libs-stamp clean: rm -f install-libs-stamp install-extra-stamp rm -f $(install_files) rm -rf $(install_subdirs) rm -f dlls missing-dlls binfiles rm -f files.nsi rmfiles.nsi rmdirs.nsi Makefile: Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(top_builddir)/config.status: $(top_srcdir)/configure cd $(top_builddir) && $(SHELL) ./config.status --recheck .PRECIOUS: Makefile $(top_builddir)/config.status .PHONY: all clean install install-bin install-data install-config install-libraries install-extra tilem-2.0/installer/win32/gtkrc000066400000000000000000000040721220200411600164500ustar00rootroot00000000000000gtk-icon-sizes = "gtk-menu=13,13:gtk-small-toolbar=16,16:gtk-large-toolbar=24,24:gtk-dnd=32,32" gtk-toolbar-icon-size = small-toolbar gtk-toolbar-style = GTK_TOOLBAR_ICONS # disable images in buttons. i've only seen ugly delphi apps use this feature. gtk-button-images = 0 # enable/disable images in menus. most "stock" microsoft apps don't use these, except sparingly. # the office apps use them heavily, though. gtk-menu-images = 0 # use the win32 button ordering instead of the GNOME HIG one, where applicable gtk-alternative-button-order = 1 # use the win32 sort indicators direction, as in Explorer gtk-alternative-sort-arrows = 1 # Windows users don't expect the PC Speaker beeping at them when they backspace in an empty textview and stuff like that gtk-error-bell = 0 style "msw-default" { GtkWidget::interior-focus = 1 GtkOptionMenu::indicator-size = { 9, 5 } GtkOptionMenu::indicator-spacing = { 7, 5, 2, 2 } GtkSpinButton::shadow-type = in # Owen and I disagree that these should be themable #GtkUIManager::add-tearoffs = 0 #GtkComboBox::add-tearoffs = 0 GtkComboBox::appears-as-list = 1 GtkComboBox::focus-on-click = 0 GOComboBox::add_tearoffs = 0 GtkTreeView::allow-rules = 0 GtkTreeView::expander-size = 12 GtkExpander::expander-size = 12 GtkScrolledWindow::scrollbar_spacing = 1 GtkSeparatorMenuItem::horizontal-padding = 2 engine "wimp" { } } class "*" style "msw-default" binding "ms-windows-tree-view" { bind "Right" { "expand-collapse-cursor-row" (1,1,0) } bind "Left" { "expand-collapse-cursor-row" (1,0,0) } } class "GtkTreeView" binding "ms-windows-tree-view" style "msw-combobox-thickness" = "msw-default" { xthickness = 0 ythickness = 0 } widget_class "*TreeView*ComboBox*" style "msw-combobox-thickness" widget_class "*ComboBox*GtkFrame*" style "msw-combobox-thickness" # work around issue with "list-style" cellrenderercombos not emitting # the "edited" signal - GNOME bug #317387 style "menu-style-combo" { GtkComboBox::appears-as-list = 0 } widget_class "*.GtkTreeView.GtkComboBox" style "menu-style-combo" tilem-2.0/installer/win32/installer.nsi.in000066400000000000000000000044341220200411600205320ustar00rootroot00000000000000Name "@PACKAGE_NAME@" OutFile "@PACKAGE_TARNAME@-@PACKAGE_VERSION@.exe" SetCompressor /solid lzma !define MULTIUSER_EXECUTIONLEVEL Highest !define MULTIUSER_MUI !define MULTIUSER_INSTALLMODE_INSTDIR "@PACKAGE_NAME@" !include "MultiUser.nsh" !include "MUI2.nsh" Var StartMenuFolder !define MUI_FINISHPAGE_RUN "" !define MUI_FINISHPAGE_RUN_TEXT "Create a desktop shortcut" !define MUI_FINISHPAGE_RUN_FUNCTION desktopicon !insertmacro MUI_PAGE_WELCOME !insertmacro MULTIUSER_PAGE_INSTALLMODE !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !insertmacro MUI_LANGUAGE "English" Function .onInit !insertmacro MULTIUSER_INIT FunctionEnd Function un.onInit UserInfo::GetAccountType Pop $MultiUser.Privileges ReadINIStr $0 "$INSTDIR\uninstall.ini" "Uninstall" "InstallMode" ${if} $0 == "AllUsers" call un.MultiUser.InstallMode.AllUsers ${else} call un.MultiUser.InstallMode.CurrentUser ${endif} FunctionEnd Function desktopicon SetShellVarContext current CreateShortCut "$DESKTOP\TilEm.lnk" "$INSTDIR\tilem2.exe" FunctionEnd Section SetOutPath "$INSTDIR" !include "files.nsi" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$StartMenuFolder" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TilEm.lnk" "$INSTDIR\tilem2.exe" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall TilEm.lnk" "$INSTDIR\uninstall.exe" WriteINIStr "$INSTDIR\uninstall.ini" "Uninstall" "StartMenuFolder" $StartMenuFolder !insertmacro MUI_STARTMENU_WRITE_END WriteINIStr "$INSTDIR\uninstall.ini" "Uninstall" "InstallMode" $MultiUser.InstallMode WriteUninstaller "$INSTDIR\uninstall.exe" SectionEnd Section "Uninstall" !include "rmfiles.nsi" !include "rmdirs.nsi" ReadINIStr $StartMenuFolder "$INSTDIR\uninstall.ini" "Uninstall" "StartMenuFolder" ${if} $StartMenuFolder != "" Delete "$SMPROGRAMS\$StartMenuFolder\TilEm.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall TilEm.lnk" RmDir "$SMPROGRAMS\$StartMenuFolder" ${endif} SetShellVarContext current Delete "$DESKTOP\TilEm.lnk" Delete "$INSTDIR\uninstall.ini" Delete "$INSTDIR\uninstall.exe" RmDir "$INSTDIR" SectionEnd