pax_global_header00006660000000000000000000000064131122307270014510gustar00rootroot0000000000000052 comment=4be5348c7dcc4598d7ba665241b0dddbf68d5daa ViTables-3.0.0/000077500000000000000000000000001311223072700132215ustar00rootroot00000000000000ViTables-3.0.0/.gitignore000066400000000000000000000003221311223072700152060ustar00rootroot00000000000000syntax: glob *.pyc *.svn *.leo_shadow *.leo *~ *.fo *.pdf *.e4* *.egg-info/ .metadata .project .pydevproject .settings .idea doc/api doc/html doc/index.rst doc/_build run_vitables.py MANIFEST TAGS build dist ViTables-3.0.0/.projectile000066400000000000000000000000061311223072700153560ustar00rootroot00000000000000-/doc ViTables-3.0.0/ANNOUNCE.txt000066400000000000000000000035441311223072700151760ustar00rootroot00000000000000========================= Announcing ViTables 3.0.0 ========================= After another long period retired from development activities I'm happy to come back and present ViTables 3.0.0, the latest release of this viewer for PyTables/HDF5 files. Definitely this release wouldn't have been possible without the unvaluable help of a bunch of contributors so THANKS to all of them. As it happens with the entire PyTables family, the main strength of ViTables is its ability to manage really large datasets in a fast and comfortable manner. For example, with ViTables you can open a table with one thousand million rows in a few tenths of second, with very low memory requirements. Also important is the fact that it is designed to be a multiplatform application, i.e., it runs flawlessly in Unix (and hence, GNU/Linux), Mac OS X and Windows. The fact that it runs on top of PyTables ensures its speed and memory efficiency. This release doesn't contain lots of new functionalities. There are bug fixes, some usability enhancements and new plugins included. The big news is that it supports the latest Python, PyTables and PyQt versions so major version has moved from 2 to 3. Platforms --------- At the moment, ViTables has been fully tested only on GNU/Linux and Windows platforms, but as it is made on top of Python, PyQt and PyTables, its portability should be really good and it should work just fine in other Unices. How to get it ------------- Install/download from PyPI_ or visit: http://vitables.org/Download and see what is available. Share your experience --------------------- I'm very interested in your feedback about ViTables. Please send your opinions, suggestions, bugs, etc. to the ViTables Users Group at http://tech.groups.yahoo.com/group/vitables-users. Thank you! Enjoy Data with ViTables, the troll of the PyTables family! .. _PyPI: https://pypi.python.orgViTables-3.0.0/ChangeLog.txt000066400000000000000000002155571311223072700156300ustar00rootroot00000000000000ViTables ChangeLog ================== ** May 27, 2017 ** Last minute changes prior to publishing. ** May 24, 2017 ** Packaging related files have been updated. The Users' Guide has been updated. Some .txt files have been updated. Calls to str(object, 'UTF-8') have been removed. Bug fixed: when navigating large views with the mouse wheel an error is raised. Bug fixed: sometimes new views are frozen and cannot be resized with the mouse. ** May 23, 2017 ** export_csv and import_csv plugins have been refactored and debugged. ** May 22, 2017 ** export_csv plugin has been updated and debugged. ** May 21, 2017 ** time_series plugin has been updated to support latest Pandas. dbs_tree_sort plugin has been improved. ** May 20, 2017 ** Management of logged messages has been cleaned. ** May 17, 2017 ** Bug fixed: moving nodes to a different file raises a tables.ClosedNodeError. ** May 15, 2017 ** Bug fixed: files cannot be opened by drag and drop into the tree view. ** May 14, 2017 ** Table queries slightly reworked: query ranges are now Python-like ranges i.e. the meaning of the start, stop and step parameters is the same as for Python slices. ** May 13, 2017 ** Bug fixed: zoomed views have rows and columns starting from 1. Bug fixed: displaying EnumCol columns is badly implemented. ** May 12, 2017 ** Bug fixed: tooltips for link nodes are not shown. Instead a verbose error message is logged. ** May 09, 2017 ** Bug fixed: if we close the Logger in the current session it won't be opened in future sessions. And if we float the Logger in the current session it will automatically be floated in future sessions. ** May 07, 2017 ** Fixed a bug in the File -> New operation. New files could not be created. ** May 06, 2017 ** The 'Thanks to' list has been updated. Copyright notice and release version have been updated. ** November 06, 2014 ** Project file (i.e vitables.pro) and translations have all been updated. ** December 12, 2013 ** Context menus on views are now allowed which is a good thing for plugins. ** November 19, 2013 ** First working version of the columnar_org plugin is available. I think I've fixed all serious bugs. ** November 15, 2013 ** Ungrouping arrays has been implemented in the columnar_org plugin. At the moment I just see one minor bug. All functionality has been implemented so its time for a final debug and refactor sessions. ** November 14, 2013 ** Code in the columnar_org plugin has been debugged and refactored. A small bug in the closing arrays process remains open. Ungrouping hasn't been implemented yet. ** November 13, 2013 ** Still working in the columnar_org plugin. Grouping arrays has been debugged and now it works well in most cases. Closing arrays has been implemented. More debugging and breaking-up the groups to recover their components are pending tasks. ** November 11, 2013 ** Still working in the columnar_org plugin. Grouping arrays has been debugged and now it works well in most cases. Closing arrays and breaking-up the groups to recover components remains to be done. ** October 23, 2013 ** Still working in the columnar_org plugin. Grouping arrays is working with some minor (I think) bugs. ** October 23, 2013 ** Still working in the columnar_org plugin. How the plugin should work is now clearer: select several arrays via their checkboxes and launch the command Join Arrays. If the selected collection of arrays cannot be joined in a unique view then the launch command is disabled. ** October 21, 2013 ** A new plugin, columnar_org, is being developed. It will allow to combine several Array views with the same number of rows to be combined in a unique view (it is a feature request). ** October 20, 2013 ** Minor changes have been done in vtapp, plugin_utils and vtgui modules. In addition, the docstrings of several modules have been fixed. ** October 14, 2013 ** The docstrings of csv, dbstreesort and timeseries plugins have been fixed. ** October 10, 2013 ** The Plugins manager has been debugged and made more robust. Also some typos in docstrings have been corrected. Revert the commit of time_series.py. A non working version was pushed by error to the repo. ** October 07, 2013 ** Added a new plugin for sorting the tree of DBs. ** October 06, 2013 ** Fixed a bug regarding unicode strings. Some minor changes (typos and similar things) have been done. The Plugins Manager has been debugged. The timeseries plugin has been debugged. Interpolation errors have been fixed. The development of a plugin for sorting the databases tree has started :) ** October 02, 2013 ** The package preferences has been analyzed with pylint. The package plugins has been analyzed with pylint. ** September 30, 2013 ** refactoring module names to follow PEP 8. Checking modules directly under the vitables package with pylint. The package docbrowser has been analyzed with pylint. The package h5db has been analyzed with pylint. The package nodeprops has been analyzed with pylint. The package vtwidgets has been analyzed with pylint. The package vttables has been analyzed with pylint. The package queries has been analyzed with pylint. ** September 25, 2013 ** Refactoring module names to follow PEP 8. nodeInfo.py -> nodeinfo.py Refactoring module names to follow PEP 8. linkPropDlg.py -> linkpropdlg.py Refactoring module names to follow PEP 8. leafPropPage.py -> leafproppage.py Refactoring module names to follow PEP 8. leafPropDlg.py -> leafpropdlg.py Refactoring module names to follow PEP 8. groupPropPage.py -> groupproppage.py Refactoring module names to follow PEP 8. groupPropDlg.py -> grouppropdlg.py Refactoring module names to follow PEP 8. attrPropDlg.py -> attrpropdlg.py Refactoring module names to follow PEP 8. attrEditor.py -> attreditor.py Refactoring module names to follow PEP 8. tnodeEditor.py -> tnode_editor.py Refactoring module names to follow PEP 8. tlinkEditor.py -> tlink_editor.py Refactoring module names to follow PEP 8. rootGroupNode.py -> rootgroupnode.py Refactoring module names to follow PEP 8. nodeItemDelegate.py -> nodeitemdelegate.py Refactoring module names to follow PEP 8. linkNode.py -> linknode.py Refactoring module names to follow PEP 8. leafNode.py -> leafnode.py Refactoring module names to follow PEP 8. groupNode.py -> groupnode.py Refactoring module names to follow PEP 8. dbsTreeView.py -> dbstreeview.py Refactoring module names to follow PEP 8. dbsTreeModel.py -> dbstreemodel.py Refactoring module names to follow PEP 8. bookmarksDlg.py -> bookmarksdlg.py Refactoring module names to follow PEP 8. browserGUI.py -> browsergui.py Refactoring module names to follow PEP 8. helpBrowser.py -> helpbrowser.py Refactoring module names to follow PEP 8. dbDoc.py -> dbdoc.py Fixed a typo made during the renaming of vtgui.py module. Removed some calls to methods non required with Python3. ** September 24, 2013 ** Several small typos have been fixed. Removed some non required code and fixed an small bug. Refactoring package names to follow PEP 8. docBrowser -> docbrowser Refactoring package names to follow PEP 8. nodeProperties -> nodeprops Refactoring package names to follow PEP 8. vtTables -> vttables Refactoring package names to follow PEP 8. vtWidgets -> vtwidgets Refactoring module names to follow PEP 8. vtSite -> vtsite Refactoring module names to follow PEP 8. vtGUI -> vtgui Refactoring module names to follow PEP 8. zoomCell -> zoom_cell Refactoring module names to follow PEP 8. rename_dlg.py -> renamedlg.py Refactoring module names to follow PEP 8. inputNodeName.py -> nodenamedlg.py Refactoring module names to follow PEP 8. scrollBar.py -> scrollbar.py Refactoring module names to follow PEP 8. leafView.py -> leaf_view.py Refactoring module names to follow PEP 8. leafModel.py -> leaf_model.py Refactoring module names to follow PEP 8. leafDelegate.py -> leaf_delegate.py Refactoring module names to follow PEP 8. dataSheeet.py -> datasheet.py Refactoring module names to follow PEP 8. queryDlg.py -> querydlg.py Refactoring module names to follow PEP 8. queriesManager.py -> querymgr.py Refactoring module names to follow PEP 8. pluginsLoader.py -> pluginsloader.py Refactoring module names to follow PEP 8. configException.py -> cfgexception.py Refactoring module names to follow PEP 8. aboutPage.py -> aboutpage.py ** September 23, 2013 ** Added support for raw strings attributes. ** September 21, 2013 ** Some modules regarding plugins have been debugged. Fixed a small bug in the timeseries plugin. ** September 19, 2013 ** Data presentation has been debugged and simplified. ** September 18, 2013 ** The use of range has been reviewed. A workaround for an annoying KDE bug has been applied. ** September 17, 2013 ** The tests folder has been removed. The node Properties dialog has been partially reworked. ** September 12, 2013 ** Fixed minor errors in several modules. Fixed some syntax errors in several modules. Fixed the use of the logger console by the logging module. New syntax used in a couple of methods in vtapp.py. The examples directory has been updated. ** September 11, 2013 ** Local branch python3-support has been added. Shebang lines updated. Old style u'some text' has been replaced with 'some text'. Calls to unicode() replaced with calls to str() Remaining old style unicode literals removed. ** September 03, 2013 ** Bug #22 has been fixed. Some minor mistakes have been fixed in the Users' Guide. ** February 10, 2013 ** The Import from CSV plugin uses the plugin utilities module now. Fixed a bug in the Export to CSV plugin. The plugin utilities module has been updated. ** February 07, 2013 ** Time series plugin support for soft/external links has been fixed. ** February 06, 2013 ** tab of the About ViTables dialog has been updated. Pandas time series support added to time series plugin. In addition, the plugin has been simplified and refactored. ** February 01, 2013 ** The shebang/encoding lines of all modules have been updated. The change ensure consistency with scripts/vitables launcher module. ** January 30, 2013 ** The processing of command-line arguments has been upgraded. The deprecated optparse module has been replaced with the argparse module. ** January 28, 2013 ** A selected cell rendering bug has been fixed. ** January 24, 2013 ** The license of plugins and some example scripts has been updated. Some more copyright notices have been updated. The copyright notice of the license has been updated. The launcher script has been modified. Now it can be launched by itself (instead of calling python in the command line) ** January 23, 2013 ** The leafView.py module has been revamped. Several data navigation bugs have been hopefuly fixed. The code has been refactored and simplified. ** November 28, 2011 ** Table navigation using the mouse has been debugged. Sometimes strange jumps occurred after a buffer fault (a certain amount of rows was skipped) making dataset browsing somewhat unpredictable. These jumps have been removed. ** November 18, 2011 ** The Makefile for building the Mac OS X bundle has been updated. The path to the standard Python has been fixed. The filename of the PDF version of the Users Guide has been updated. Also the Readme-MacOSX.rtf has been updated (reference to Carabos coop has been removed). ** October 27, 2011 ** The vitables launcher script has been updated. Following the suggestions made by Dav Clark in the Users Group, the usage of pythonw on MacOSX has been dropped. ** October 23, 2011 ** The abbility for creating the documentation has been removed from setup.py. As the distributed tarball contains the complete documentation there is no need for building it via setup.py. Now the documentation is built with a module not intended for distribution. In addition, the Users Guide has been updated. ** October 17, 2011 ** Merged a pull request from kisielk/master (a ViTables fork owner). The merge fixes problems with CRLF endings in the vitables launcher script (introduced probably when pushing changes to the repo under MSWindows). It also fixes a small bug in the message box for unsupported datatypes. ** October 06, 2011 ** The setup.py module has been debugged. In order to install the tarball the Sphinx documentation system for Python is not required anymore. ** October 05, 2011 ** The repo has been moved from BerliOS to GitHub and needs some tuning. .hgignore file has been renamed to .gitignore. ** March 24, 2011 ** The plugins management related stuff has been refactored and simplified. ** March 23, 2011 ** The packaging process for Windows has been adapted to use rst2pdf. ** March 22, 2011 ** The PDF version of the Users' Guide is now built with rst2pdf. ** March 21, 2011 ** The Menu plugin functionality is now part of the ViTables core. ** March 14, 2011 ** The NSIS installer script has been largely rewritten. ** March 09, 2011 ** The behavior of the current cell when browsing large views has been fixed. ** March 08, 2011 ** Bugs 330 and 359 have been fixed. ** March 07, 2011 ** Navigation of large datasets using the right scrollbar has been debugged. ** March 04, 2011 ** Subpackage nodeProperties has been reorganised and refactored. Bug 335 has been fixed. First implementation of soft/external links support is completed. ** March 03, 2011 ** Added a Properties dialog for both soft and external links. Added basic support for PyTables soft links and external links. ** February 26, 2011 ** Bug 338 has been fixed. ** February 25, 2011 ** Bug 333 has been fixed. ** February 24, 2011 ** Bug 334 has been fixed. Bug 340 has been fixed. ** February 22, 2011 ** Fixed bug 341. Fixed bug 348. ** February 16, 2011 ** Docs have been updated after checking that ViTables runs fine with Python 2.7. ** February 09, 2011 ** Issues specific to Windows Vista have been reworked in the NSIS installer script. ** February 05, 2011 ** Fixed a minor issue (specific to Windows Vista) in the NSIS installer script. ** February 02, 2011 ** Fixed a minor issue in the NSIS installer script. Fixed a minor issue in the setup.py module. The Users' Guide has been updated. Packaging procedure changed accordingly to recent changes in timeseries plugin. ** February 01, 2011 ** The timeseries and menu plugins have been enhanced. ** January 28, 2011 ** Fixed a bug introduced in the CSV plugin in r220. ** January 27, 2011 ** Fixed a bug in the initial configuration setup. ** January 26, 2011 ** Fixed a small drag & drop issue. Python strings and Unicode strings have been revisited. The Makefile file for building the MSWindows installer has changed. ** January 25, 2011 ** Several files (mainly example scripts) have been updated. ** January 24, 2011 ** Fixed a bug in the startup settings of ViTables. ** January 22, 2011 ** The process for building documentation has been refined. ** January 20, 2011 ** The copyright statement has been updated. The setup.py script has changed. Applied a workaround to a PyQt4 4.8.2 bug. Fixed some minor bugs regarding plugins. ** January 18, 2011 ** Fixed some minor issues in the creation of the Windows installer. ** January 17, 2011 ** Fine tuning the building process of the Windows installer. Updated several files required for building the Windows installer. ** December 18, 2010 ** More advances in the migration path to Python 3.0. ** December 11, 2010 ** More advances in the migration path to Python 3.0. ** December 09, 2010 ** String formatting is done via .format() method now. ** December 08, 2010 ** Moved to Python 2.6 :-) and preparing the migration path to Python 3.0. ** December 07, 2010 ** The project documentation has been updated. And now it is built via Sphinx. ** December 03, 2010 ** The node selection behavior of the tree of databases has been improved. ** December 01, 2010 ** Fixed some small problems in several files. ** November 30, 2010 ** Customised models have been debugged and fine tuned using modtest.py. ** November 28, 2010 ** The docstrings of the whole package have been updated. ** November 24, 2010 ** super() is used now in the ctor of all classes derived from PyQt4. The csv plugin has been debugged and refactored. ** November 20, 2010 ** The module vtapp.py has been split into 2 modules. ** November 17, 2010 ** Qt properties of QActions set via keyword arguments at creation time. ** November 16, 2010 ** Some improvements applied to vtapp.py module. Some small improvements have been made to several modules. Several methods renamed to shorter names. Fixed a small bug. Some minimal changes made to a several modules. ** November 15, 2010 ** Some improvements applied to the docBrowser subpackage. The logger.py module has been refactored. ** November 14, 2010 ** All old-style signal/lot connections replaced with new-style connections. ** November 05, 2010 ** Several modules refactored. Code for querying tables has been debugged. ** November 04, 2010 ** The Preferences dialog has been debugged and refactored. Signals and slots are connected via setUi method in several modules. ** November 03, 2010 ** The Preferences dialog has been improved. ** November 02, 2010 ** A couple of pure Python modules have been split in a Python part and a ui part. ** October 30, 2010 ** The utils.py module has been simplified. Some unwanted directories have been removed from the repository. Copyright statements updated in every source file. The method used for dynamically load UI files has been simplified. ** October 26, 2010 ** Information about version number and copyright has been updated. ** December 29, 2009 ** Module nodePropDlg.py has been refactored and simplified. Some code dealing with PyTables datatypes and numpy datatypes has been cleaned. ** December 28, 2009 ** Rows insertion/deletion in the tree view has been simplified and debugged. ** December 27, 2009 ** The import_csv and export_csv plugins have been improved. ** December 23, 2009 ** Inconsistencies in the spacing between lines have been fixed. Tree view usability improved. ** December 21, 2009 ** Added the new plugins_menu.py plugin. It show info about the loaded plugins. ** December 20, 2009 ** The code dealing with application setup has been debugged and refactored. ** December 19, 2009 ** The plugins framework has been debugged and refactored and has a new ui. ** December 15, 2009 ** The deprecated (in Python 2.6) sets module is not used anymore. ** December 14, 2009 ** The code dealing with the tree view has been debugged and simplified. ** December 11, 2009 ** Fixed a subtle bug in the automatic sync between tree view pane and workspace. ** December 10, 2009 ** In the tree view fixed a bug in the cut node + paste node sequence. ** December 09, 2009 ** The logger module has been refactored and simplified. Fixed a bug in the context menu of the logger. Fixed a couple of minor bugs. ** December 05, 2009 ** The documentation browser subpackage has been simplified. Several question like message boxes have been customised. ** December 04, 2009 ** Removed wild imports and other minor annoyances common to most modules. The time series plugin has been refactored. pluginsManager module has been refactored to improve some bizarre behavior. Usability of csv_import plugin has been improved with better dialog texts. ** December 03, 2009 ** Autodetection of tables headers has been added to the import csv plugin. ** December 02, 2009 ** Support for tables headers has been added to the import/export csv plugins. ** November 30, 2009 ** The import_csv.py plugin has been debugged, refactored and enhanced. ** November 28, 2009 ** New version of import_csv.py plugin added to repository. ** November 25, 2009 ** Minor problems introduced in recent changes have been fixed. ** November 24, 2009 ** Import capabilities added to the CSV plugin. vtapp.py module changed to make easier interaction with plugins. ** November 23, 2009 ** Layout of csv plugin changed to allow future additions; modules, icons,... Plugin export_csv.py enhanced: better code, reduced memory footprint. ** November 22, 2009 ** Memory footprint greatly reduced. ** November 20, 2009 ** Fixed a bug in the datasheet.py module apparent with pyqt < 4.6. ** November 13, 2009 ** Support for queries has been updated. dataSheet.py module has been refactored. leafView.py module has been refactored. Plugins have been updated. Querying functionality has been moved from vtapp.py to queriesManager.py. dataSheet.py module has been refactored. Circular references have been removed. Fixed a bug in the Preferences dialog. ** November 10, 2009 ** Fixed a bug in the Preferences dialog. ** November 08, 2009 ** Fixed a bug in the tree of databases that was not apparent in PyQt <=4.4.4. The path of the config. file on Unix systems now adheres to the Qt standards. ** September 25, 2009 ** Fixed a minor bug in the code for opening files via drag and drop. ** September 22, 2009 ** Last improvements in the documentation style applied to Windows platforms. Fixed an annoyance in the creation of PDF documentation. ** September 21, 2009 ** The User's Guide has been updated (and its custom layer has been recovered). ** September 20, 2009 ** Fixed a compatibility problem XP/Vista in the Windows installer. ** September 19, 2009 ** Applied several minor simplifications to styles management code. ** September 18, 2009 ** Windows installer upgraded for the next release. ** September 15, 2009 ** Fixed some minor bugs. Prepare things for the next release. ** August 24, 2009 ** Some icons have been updated. The zoomCell module has been debugged and refactored. ** August 22, 2009 ** The plugins framework has been debugged and its usability has been improved. The time_series plugin has been debugged and refactored. ** August 21, 2009 ** The examples directory has been reworked. ** August 20, 2009 ** A couple of modules have been sanitised (bad variable names changed). ** August 15, 2009 ** The docBrowser package has been reworked a little bit. Splash screen has been updated. ** August 13, 2009 ** Icons have been updated. About ViTables dialog enhanced with a Thanks To page. Fixed a bug introduced when the use of Qt resources was dropped. ** August 07, 2009 ** Makefile files and other unneeded stuff have been removed. ** August 06, 2009 ** The plugins framework has been made more robust. Fixed some small problems in the new build system. ** August 05, 2009 ** Last 2 commits backed out + Dima's patches merged + backed out commits restored ** July 29, 2009 ** Added support for packages to the plugins framework. ** July 28, 2009 ** A simple plugin framework has been implemented. ** July 21, 2009 ** The "Node properties" dialog is generated automatically (via Qt Designer) now. ** May 01, 2009 ** Added missing licensing information to several files. Sources of Users Guide are now distributed in the ViTables tarball. Procedure for generating the usersguide has been updated. INSTALL.txt and setup.py have been updated. HTML documentation uses utf-8 encoding now. ** March 11, 2009 ** Code for creating DBDoc objects was confusing and has been refactored. Added a couple of (subtle) usability improvements. ** March 10, 2009 ** The Preferences subpackage has been updated. Fixed a small bug in the "Select a file for opening" dialog. ** March 08, 2009 ** New utility function added to utils.py module. Table queries are done in a separated execution thread now. ** March 05, 2009 ** The "New query" dialog is generated automatically (via Qt Designer) now. ** March 04, 2009 ** Some subpackages have been reorganised. ** March 02, 2009 ** __tr method has changed. Attributes editing has been debugged and simplified. Unneeded encoding/decoding of strings has been removed. ** March 01, 2009 ** The main menu bar has been reorganised. ** Feb 26, 2009 ** New feature added: export a dataset to plain text file with CSV format. Fixed a unicode bug in the queries manager. ** Feb 24, 2009 ** The resources module has been added to the repository. A couple of Makefile files have been changed. ** Feb 23, 2009 ** setup.py has been updated. Code dealing with formatting time series has been refactored. **Feb 21, 2009** License files and license notes have been updated. Fixed a little bug in the time_series plugin. The examples foder has been reorganized. Support for unicode filenames has been improved. Fixed a silly bug in the time_series plugin. Focus indicators for the logger and the tree panel have been improved. The support for time series has been fixed and improved. ** Feb 11, 2009** An ubiquitous misuse of the Python unicode() built-in has been fixed. The recent fix to the windows installer is now in the repository. ** Jan 21, 2009** Fixed a bug in the support for unicode filenames in Windows. A better support for unicode filenames has been added. ** Jan 19, 2009** Fixed a small bug in the support for date/time. ** Jan 17, 2009** Date/time information is displayed now as legal time. ** Jan 16, 2009** Fixed a bug in the zoom cell feature. ** Jan 10, 2009** More improvements to installer for Windows. Fixed a serious bug in the installer for Windows. ** Jan 07, 2009** Code style of the vitables package has been improved. ** Jan 02, 2009** Code style of the h5db and docBrowser subpackages has been improved. Code style of the preferences, nodes and nodeProperties subpackages has been improved. Code style of the vtWidgets and vtTables subpackages has been improved. ** Jan 01, 2009** PyQt4 imports changed to remove unnecessary code verbosity. ** Dec 27, 2008** Fixed bug 014953. Strings are managed via unicode strings with utf-8 encoding. ** Dec 22, 2008** The User's Guide has been updated. Every str() call as been replaced by a unicode() call. ** Dec 19, 2008** Fixed a couple of minor problems. Fixed a bug that made impossible to open files by drag and drop in Windows. Fixed a bug introduced in the previous commit. The node copy/cut/paste mechanism has changed. Now it is much more efficient and simpler. ** Dec 18, 2008** The Copy Node operation has been greatly optimized. Fixed an encoding related problem in the file opening procedure. Fixed a minor issue with the vertical header of large tables. The procedure for creating a Windows installer has been changed in order to deal properly with PyQt4. ** Dec 16, 2008** Fixed some bugs regarding portability between different platforms ** Dec 15, 2008** Fixed a problem in setup.py. Applied several simplifications derived from the use of Qt resources system. Fixed some bugs regarding portability between different platforms. ** Dec 13, 2008** Project clean-up and final changes. ** Dec 12, 2008** The preferences package has been refactored. ** Dec 11, 2008** Zooming cells with string content has been fixed. Fixed an annoying bug introduced in changeset 184e748db458. ** Dec 10, 2008** A context menu has been added to the workspace. The User's Manual has been updated. The documentation browser has been updated. The module in charge of application configuration has been updated. Fixed a small bug in the Properties dialog. Changed the trigger for in-place renaming of nodes in the tree of databases pane. The Properties dialog has been debugged and improved. ** Dec 09, 2008** ANNOUNCE.txt and setup.py have been updated. Fixed a bug in scripts/vitables. Fixed a small l10n problem. ** Dec 08, 2008** Fixed a small bug in insertion of nodes in the tree of databases pane. ** Dec 05, 2008** Fixed a subtle bug in the datasets access process. A small bug has been fixed. File Save As... operation has been debugged. Enhanced the render of datasets with just one row/column. Fixed a small bug in the synchronisation of the workspace with the tree of databases pane. ** Dec 04, 2008** A minor problem found in tables queries have been fixed. The content of just created filtered tables is now automatically displayed. Fixed a bug in the access to datasets with two or more dimensions. Nodes copying has been updated: leaves whose dataset is not readable are not copied Deletion of views tied to overwritten nodes has been implemented. The status bar is properly updated now when a node is renamed in the Tree of databases pane. ** Dec 03, 2008** The 'Recover last session' feature is fully implemented now. Fixed a small bug in the splash screen. Added a label in the status bar for displaying info about the node currently selected in the Tree of databases pane. ** Dec 02, 2008** Implemented the capability for zooming cell contents. Dynamic entries under the Windows menu are now checkable and exclusive. ** Nov 30, 2008** Fixed a bug in the navigation of huge datasets. Now displayed data is properly updated when a slider drag ends and when the table is wheeled. ** Nov 13, 2008 ** Navigation of huge datasets is now fully implemented. Every navigation device (vertical scrollbar, keyboard and mouse wheel) seems to work fine and to update displayed data when a buffer fault occurs. ** Nov 04, 2008 ** Navigability of huge datasets has been enhanced. The selected cell is now properly updated when a buffer fault occurs. It means that navigating the table with the keyboard works fine now. ** Oct 31, 2008 ** Huge datasets can be displayed and navigated. Several things remain to be done (usability enhancements) but the feature seems usable and stable. ** Oct 24, 2008 ** Opening files by dropping their icons in the databases tree panel is fully implemented. Some annoying problems that arised when nodes were moved around in the databases tree panel have been fixed. I've started to implement the support for huge datasets. ** Oct 23, 2008 ** Opening files by dropping their icons in the databases tree panel has been partially implemented. Fixed a couple of bugs in the Properties dialog: data types are correctly shown now. In-place renaming of nodes has been debugged. Fixed a little problem with groups expansion in the tree view pane that was rather annoying: now pasting a node (or creating a new group) expands the parent group if it was closed. So user can see that the node has really been added. ** Oct 22, 2008 ** More progresses in the datasets displaying: - the workspace and the tree of databases are synchronized now: if a leaf with a view is selected in the tree then the view becomes active in the workspace. And viceversa, if a view is activated in the workspace its leaf is automatically selected in the tree - when a node with views is overwritten (because a group has been created, a node has been renamed or a node has been pasted/dropped) the views are closed - the drag and drop behavior has been debugged ** Oct 21, 2008 ** Fixed a bug in the application quitting process: the temporary database wasn't properly deleted. ** Oct 20, 2008 ** The Windows menu has been reimplemented. ** Oct 19, 2008 ** Datasets can now be displayed in the workspace. Still importants things remain to be done, mainly to add support for quickly navigate huge datasets. ** Oct 17, 2008 ** The buffer.py module has been refactored and modified. ** Oct 16, 2008 ** Fixed a bug in the node rename and file save as operations. A node/file cannot overwrite itself. ** Oct 13, 2008 ** Fixed a subtle bug in the code for renaming nodes. Fixed a bug in the dialog for entering the name of a node when a group is being created or a node is being renamed: empty strings are not valid names now :-) ** Oct 11, 2008 ** The code for renaming nodes has been refactored. Affected modules are vtapp.py, utils.py, inputNodeName.py and renameDlg.py. The setup.py has been updated. ** Sep 26, 2008 ** Fixed some minor bugs regarding the enabled/disabled state of toolbar buttons and menu items. Added new module inputNodeName.py. It is used instead of renameDlg.py for creating groups and entering the initial name in renaming operations. ** Sep 25, 2008 ** The behavior of the Open Recent File submenu is now a little bit more user friendly. ** Sep 24, 2008** Fixed a bug in the file opening procedure. Files with no PyTables/HDF5 format are properly managed now. Some code in the vtapp.py module has been reorganized to make it more readable. ** Aug 02, 2008 ** Fixed a couple of bugs in the File menu: * the Close All action wasn't enabled/disabled properly * the Save As... action didn't work ** Jul 23, 2008 ** The porting of the nodeProperties subpackage has finished. ** Jul 21, 2008 ** Merged r1054 and r1055 from trunk. Every modified file has been merged but VERSION. ** Jul 18, 2008 ** The nodeProperties subpackage is being ported. At the moment the GUI part has been ported. Next step will be porting the code for attributes validation. ** Jul 15, 2008 ** Fixed a nasty bug that crashed the application every time a node was expanded in the tree viewer. The reported Qt4 error was: QObject: Do not delete object during its event handling! I've been unable to locate exactly where the bug was. Apparently it was produced by a strange interaction between VTApp and VTGUI classes so I've embedded VTGUI in VTApp and removed the vtgui.py module. It seems to fix the bug. ** Jul 07, 2008 ** The porting of the nodeProperties subpackage has started. A new module, nodeDoc.py, has been added. It is in charge of the information collection about a given PyTables node. This module makes unnecessary the following ones: nodeDoc.py, tableDoc.py, arrayDoc.py, unimplementedDoc.py and groupDoc.py. All those modules have been removed from the project. ** Jul 03, 2008 ** The behavior of the Preferences dialog has been tuned. ** Jul 01, 2008 ** The porting of the documentation browser has been done. The behavior of the documentation browser has been tuned. ** Jun 26, 2008 ** Added svn:keyword property to dbsTreeModel.py leafNode.py nodeItemDelegate.py groupNode.py dbsTreeView.py rootGroupNode.py ** Apr 18, 2008 ** Added contextual menus to the tree of databases view. Also a couple of menu items in the Help menu are working now. Functionality for configuring the application has been reimplemented. ** Apr 16, 2008 ** Added code for enable/disable actions depending on the selected node in the tree of databases view. ** Apr 15, 2008 ** Thre new icons have been added. Command 'Delete All Queries' has been reimplemented. The Query toolbar has been added. Tables queries have been reimplemented. ** Apr 11, 2008 ** A couple of methods have been refactored and now have a new signature. Calls to these methods have been updated. The dbDoc.py module has been refactored. The nodeItemDelegate.py module has been moved to the h5db subpackage. ** Apr 08, 2008 ** Added support for renaming nodes inplace. The code for node editing operations has been refactored. ** Apr 07, 2008 ** Implemented Node --> Rename command with overwriting support. ** Apr 03, 2008 ** Fixed a bug in the algorithm for recovering last session. Now if a given node doesn't exist then the application reports it and doesn't crash. Implemented Node --> New Group command with overwriting support. ** Apr 02, 2008 ** The overwriting feature has been implemented in the drag and drop of nodes. Splash screen readability improved. Fixed a bug in DBDoc.pasteNode method of dbDoc.py module. The overwriting feature has been implemented in the Node Paste... command. The overwriting feature has been implemented in the File Save as... command. Added code for setting the application icon. ** Mar 31, 2008 ** Processing command line fetaure has been ported. The last session recovering feature has been ported. ** Mar 28, 2008 ** Splash screen module has been debugged: now messages are drawn at the proper position. The following files have been updated: INSTALL.txt, README.txt, setup.py and Makefile. Version number has changed to 2.0. A note has been attached to the start of every source file of ViTables. In this note it is specified how the ViTables program is licensed. ** Mar 27, 2008 ** Copyright statement of source files has been updated. ViTables logo has changed: now it doesn't contain the Carabos logo. I've done this because now ViTables is not developed by Carabos Coop. V.. Instead it is a free software project maintained by myself. The ViTables source code license has changed. From now on it has a GPLv3 license. ** Mar 26, 2008 ** Creating a branche for porting ViTables to PyQt4. Fixed a little problem in the drag and drop support of the tree of databases model/view. The treeEditor subpackage has been removed. The functionality of the File menu has been implemented. Only overwritting files during a File --> Save as... operation remains unimplemented. Fixed a couple of bugs in the tree of databases model: - the close database operation didn't remove the node from the tree view. - when opening a database fails the returned value was no specified. The configuration module has been rewritten. The configuration module has been rewritten. Small changes introduced in several modules: the name of some attributes has changed and some imports have been slightly modified. Small changes introduced in several modules: the name of some attributes has changed and some imports have been slightly modified. ** Mar 20, 2008 ** The vtgui.py module has been refactored and some small problems have been fixed: the size of the toolbars icons, the WhatsThis action setup, and the setup of the menu with entries for the toolbars. The vtgui.py module porting is done. The result is a module much shorter and clearer thant it was before. ** Mar 19, 2008 ** The porting of the vtgui.py module has started. It has been greatly simplified. The drag and drop behavior of the tree of databases view has been debugged a little bit. PyQt4.QtXXX libraries are now imported as QtCore and QtGui instead of qtCore and qtGui. In addition a couple of modules have some minor changes. ** Mar 18, 2008 ** Copy, cut, paste and delete operations have been implemented in the tree of databases model. Overwriting has not been considered yet. ** Mar 05, 2008 ** Basic drag and drop of the tree of databases model/view works! Nodes can be moved from one location to another (even in a different file). Nodes that belong to files opened in read-only mode cannot be dragged. Lazy population of the model works fine too. ** Mar 03, 2008 ** The basic model/view implementation for the tree of opened databases is done. Databases can be opened and closed. The object tree of a given database is populated in a lazy way so that performance is guaranteed when opening files with a large number of nodes. Finally, icons are tied to nodes in the tree view. ** Feb 29, 2008 ** Drag and drop support is being implemented. ** Feb 27, 2008 ** Added basic support for renaming nodes in-place. ** Feb 26, 2008 ** Added support for custom context menus to the tree of databases view. Some modules have been changed in order to keep internal consistency. Minor modifications made in several modules. ** Feb 22, 2008 ** The h5db subpackage has been updated. Calls to Qt3 methods have been moved to Qt4 equivalent methods. nodes subpackage has been updated. Calls to Qt3 methods has been replaced by calls to Qt4 methods. ** Feb 20, 2008 ** createIcons function changed: removed a line that was commented out. The nodes subpackage migration has started. Calls to Qt functions/methods have been adapted to Qt4. ** Feb 18, 2008 ** The following modules have been ported: * scripts/vitables * vitables/utils.py * vitables/vtsplash.py * vitables/vtSite.py * vitables/vtgui.py This module has been split in two modules: logger class is defined in a new module now. * vitables/logger.py The whole preferences subpackage has been ported: * vitables/preferences/vtconfig.py * vitables/preferences/preferences.py * vitables/preferences/configException.py The following tests have been ported: * vitables/preferences/preferencesGUI.py * tests/preferences/test_vtconfig.py * tests/preferences/test_preferences.py ** Dec 16, 2007 ** The Spanish translation has been updated. WhatsThis help texts and some About... texts have been reformatted in order to improve the code readability. ** Dec 14, 2007 ** The previous bug fix in the editing of the TITLE system attribute was incomplete. It has been corrected now (hopefuly). ** Dec 13, 2007 ** Fixed a bug in the editing of the TITLE system attribute (accents raised errors). Some trivial enhancements have been done. The editing of user attributes has been improved. Overflow cases are now properly detected and a ValueError is raised. Although this is not the default behavior of numpy arrays (which are silently converted to the apropriate dtype when an overflow occurs) it seems more adequated for an end user application as ViTables. ** Nov 29, 2007** Drag and drop of nodes has been debugged. Cut and paste has been improved. I hope that editing nodes is now implemented in a quite robust way. ** Nov 28, 2007** The behaviour of the documentation browser has been improved. A couple of bugs have been fixed: - canceling the Open File... command works fine now - opening a new documentation browser doesn't give errors due to not found documents - trying to open a document that doesn't exist don't shows a blank page but a page with the message 'Document Not found' A mess due to the use of backslashes still happened on Windows platforms, specially in the list of recent files and in the navigation browser history and bookmarks. This problem has been hopefully solved. The copy and paste operation has been enhanced. Now a node can be copied and pasted in its parent group. The overwrite dialog is raised, giving you the chance to rename the pasted node. If you decide to overwrite, the operation fails (a PyTable exception is raised) because a node cannot be overwritten by itself. ** Nov 27, 2007** The template script that generates the Windows installer has been updated. Now it takes care of the available translations. Unittests have been updated. The search method for locating the application settings has been improved on Mac OS X platforms. ** Nov 26, 2007** Spanish translation added. A couple of minor problems have been fixed: - the .vitables directory is not created on Mac OS X platforms anymore - the message raised when a directory is dropped on the tree viewer is now clearer The User's Guide has been updated. ** Nov 23, 2007** Displaying of objects in tables widgets has been enhanced. Now cell contents are dynamically adapted to the available room. It means that how the content of a given cell is displayed depends on the column width. As a consequence, the displaying of multidimensional objects has been greatly improved. Some changes aimed to improve the i18n have been done. ** Nov 21, 2007** Fixed a bug in the creation of user attributes with dtype float32. Errors raised during user attributes editing are displayed in the attributes editing dialog, not in the logger. This make easier to user to realise that an error has been raised. ** Nov 19, 2007** The release version has been updated. The User's Guide source has been updated. The DocBrowser behavior has been enhanced. Opening a file for the very first time in the DocBrowser uses the home directory as a working directory. Before it used the installation directory which was ugly. ** Nov 02, 2007** Fixed a bug in the access to VLArrays elements. The bug avoided the creation of views for VLArrays. VERSION has been updated in vtSite.py. This is required in order to run properly on Mac OS X platforms because on these platforms the module is NOT overwritten by setup.py. The temporary database is not removed when quitting ViTables because on Windows platforms a Permission denied error is raised. **Oct 31, 2007** Explicit support for addressing 64 bit space has been added. Now ViTables can display tables with more than 2**32 rows with no problem. A small bug has been fixed (hopefully) in the node paste operation: pasting a node on an expanded group doesn't refresh the object tree i.e. the pasted node is not visible. The whole unittest directory has been updated/refactored/debugged. I forgot to update tests/test_all.py in the previous commit :-( Fixed a small bug in the File Save As... procedure. The file extension of the new file was generated in a wrong way because the full filepath was used to determine the extension. The right thing is to use the filename. **Oct 30, 2007** The Users' Guide has been updated. A specific icons has been given to the toobar button in charge of opening files so that users can appreciate that it can show a popup menu now. Fixed a bug in File --> Close All and Query --> Delete All. Closing a set of non selected nodes caused a wrong update of the QAction in charge of closing all open files. Deleting a set of non selected filtered tables caused a wrong update of the QAction in charge of deleting all filtered tables. Fixed a bug in the procedure used to close a database. A race condition has been removed. A new icon has been added. Fixed a bug in the updating of query QActions. The bug couldn't be appreciated by users because it happened when the application was about to exit. **Oct 26, 2007** The VERSION file has been updated. A new usability enhancement has been added. The Open button of the File toolbar is able now to open the file of Recent files too. **Oct 22, 2007** Fixed a bug in the initial setup of the application. Fixed a bug in the Properties dialog of empty groups. Creating and renaming node operations have been made more robust. Fixed a small problem of name qualification when accessing to a couple of PyQt attributes. **Oct 19, 2007** Usability of Properties dialog has been improved by fixing the visual behavior of attributes editing. The format given to catched errors has changed again. Now the readability of Syntax Errors is better. In the Filter Table dialog ValueErrors are explicitely catched now. **Oct 18, 2007** Some classes still were instantiated via apply(qt.QSomeWidget.__init__, (self,args)). Now qt.QSomeWidget.__init__(self, args) is used. The behavior of tables shown in the Properties dialog has been improved. Tables have been resized so that they occupy all the available horizontal space leaving no (anoying) gaps. **Oct 17, 2007** Fixed a small bug in the console that produced a wrong color update in some situations. Wild imports have been completely removed. The examples directory has been updated. **Oct 16, 2007** The management of application preferences and configuration has been improved. The code has been simplified and a small bug has been fixed. Fixed a bug in the Preferences dialog that made the Cancel button useless. Some error and warning messages have been changed in order to ensure that all of them have a consistent format. **Oct 15, 2007** The resize mode of the Tree Viewer widget has been fixed so that the widget's header resizes properly its sections when the widget is resized. A subtle bug has been fixed in the setup of the default configuration of the application. **Oct 11, 2007** Some logger messatges have been changed in order to make them self-explanatories. The installer template script has been modified. The name of the installer includes the kind of license now. Fixed a small bug in the File Save As... command. It avoided open files overwriting on Windows platforms. The format used for display catched exceptions has changed. Now it is more readable (although provides less information). **Oct 10, 2007** The format of docstrings has been updated. Now every docstring has a restructured text format. Docstrings of every module have been updated. In particular the updated sections are those that listed the names of classes, methods, functions and global variables contained in the modules. Code for moving a node from one location to a different one has been changed in order to improve the performance. **Oct 04, 2007** Fixed a bug in the paste node procedure. **Oct 03, 2007** The behavior of the Query results node of the tree view has been setup accordingly to its aim. A subtle bug has been fixed in the dbView.py module. When dealing with nodepaths os.path.join should be avoided in favour of tables.utils.joinPath. The reason: in Windows platforms os.path.join can produce paths with a mix of slashes and backslashes. A small bug in the template installer script has been fixed. The uninstaller didn't remove completely the ViTables entry from the Start menu. Fixed a bug in the opening file process. When the open file dialog was called for the first time (i.e. application startup) and the dialog was cancelled then later calls of this dialog were unusable. The procedure for saving a file with a different name has been slightly changed to avoid a nasty HDF5 error. The error was raised when the new file name was filename (with no extension) and a filename.h5 file already existed. **Oct 02, 2007** As no evaluation versions are going to be distributed the dbManager template is not needed now. That's why it has been renamed to dbManager.py Unneeded and obsolete files have been removed. A small bug has been fixed in vitables/nodes/leafView.py. The bug was raised by a bug in the underlying PyTables 2.0.1 The ViTables configuration has been updated. The Startup option `start in current directory` is now `start in home directory` to avoid opening unexpected directories in Windows and Mac OS X when ViTables is launched by double clicking its desktop icon. Fixed a small bug that prevented to start ViTables in the home directory (when configured to do it) in Windows platforms. The template script for generating installers has been modified to add more items to the Start menu: links to documentation (in both PDF and HTML4 formats) and to the examples directory. **Oct 01, 2007** The users' guide has been updated. A check has been added to several methods in vtapp.py, to ensure that filepaths do not contain backslashes because they produce a real mess in the Windows registry and the list of recent files. **Sep 30, 2007** Added a button for group creation to the Node toolbar. **Sep 29, 2007** Fixed a bug in the drag and drop of a node from a read-only file to a read-write one. **Sep 28, 2007** QActions updating and synchronizating panels strikes back! The last approache has been discarded because it didn't encompass every possible case. The new approache seems to work better and it is simpler. Fixed a bug that prevented empty nodes to be added to the object tree when the tree was expanded. Fixed a bug in the creation of new groups. Now the new group can overwrite any node with the same name placed in its parent group. Before only groups could be overwriten. **Sep 27, 2007** The Help Browser history and bookmarks are now stored in the configuration file instead of in their own files. Fixed a bug in the updating of the QActions state. **Sep 26, 2007** The list of recent files is now stored in the configuration file (or in the Windows registry) instead of in its own file. The last session is now stored in the configuration file (or in the Windows registry) instead of in its own file. unittests have been updated. **Sep 25, 2007** The configuration file lastdir, used to store the last opened directory has been removed. Now this information is stored in the application configuration file (or in the Windows registry). **Sep 24, 2007** Fixed a small bug in the recovering last session process. **Sep 23, 2007** Unittests have been updated. **Sep 22, 2007** Added a new usability improvement: the tree view pane and the workspace keep now their selection state synchronized. Several keyboard accelerators added. **Sep 21, 2007** A couple of small usability improvements has been added. The action Node-->New group has a keyboard accelerator now. **Sep 20, 2007** The dialog raised when a node editing leads to a naming problem is now more readable a.k.a useful. Added permission to create groups under the Query results root node. Fixed a bug that appeared when a node was moved from one file to a different one. Fixed a bug that appeared when a node was copied from one file and pasted into a different one. **Sep 18, 2007** A small bug has been fixed in the renameDlg.py module. Fixed a bug in the implementation of tables queries. The bug caused wrong values to be displayed in the query indices field (if requested) when the range of rows to be queried was other than (start=1, stop=n, step=1).. **Sep 17, 2007** A small bug has been fixed in the dbView.py module. The unittests under tests/h5db have been updated. **Sep 13, 2007** The dialog raised when a naming problem appears has been enhanced. Now, detailed information about the operation being executed is displayed and buttons text is self-explanatory. Fixed a small bug that affected the File Save as... operation. Added support for overwriting nodes when a new group is being created. Docstrings of dbMananger_template have been updated. Fixed a small bug in renameDlg.py. **Aug 09, 2007** Fixed a serious bug in node deletions procedure. **Aug 08, 2007** New, clearer descriptions are used in the Properties dialog, in help texts and in buttons text. Unneeded messages are not passed to the logger anymore. Management of filenames extensions has been improved. The Query menu has been simplified. The HelpBrowser toolbar layout has changed. It is clearer now. **Aug 03, 2007** All unittest modules have been refactored and debugged. __init__.py files have been added to the tests directory and its subdirectories. test_all.py module has been added so that all unittests can be executed easily. testingHOWTO.txt has been updated and moved to the tests directory. **Jul 31, 2007** Unittest module test_query.py has been added. The tables query implementation has been modified in order to make it more suitable for testing it with unittests. Fixed a bug that was hitting every module in the tests/nodes directory. Unittests in the tests/preferences directory have been updated. Unittest module root_package/test_commandLine.py updated. **Jul 25, 2007** Updated Mac packaging instructions to avoid linking sip/PyQt against wrong Python. **Jul 24, 2007** INSTALL.txt and ChangeLog.txt have been updated. VTApp.slotHelpAbout method changed. The info displayed in the About tab has been updated. Support for VLArrays has been enhanced. VLArrays with pseudo-atom of kind vlunicode are now supported. Module zoomCell.py has been updated accordingly to the recoded cell formatting methods of utils.py **Jul 23, 2007** Use a `make.sh` script instead of `make` to build Mac OS X DMG images. The process is not complete yet, since the license is not shown on opening the DMG image. That's why the `SLA.*` files are still in place. Makefile_windows and the template NSIS installer script have been updated. Now they take care of the LICENSE.html file. Makefile for unix has been simplified. Added RTF readme to DMG image with important details for Mac OS X. Removed the files for the Mac OS X DMG resource fork. The license file in the DMG root is enough and easier to place. ;) The Linux packaging system has been updated so that licenses are properly managed. **Jul 21, 2007** Fix the Mac OS X app not finding the `qt.so` extension in the appdir. Thanks to Doug Anderson from the PythonMac-SIG list for the solution. **July 19, 2007** Added a bunch of tests for testing that the actions of menu items if File, Node and Query menus are properly enabled/disabled depending on the kind and number of selected nodes in the tree viewer. **July 12, 2007** The way of saving settings in the windows registry has changed. Now settings are stored under the key Carabos/Vitables/Version/PythonXX. No changes have been introduced for Unix and Mac OS X platforms. The management of application settings has been improved. Some annoyances regarding the geometry of the main window and viewer panels have been fixed. **July 06, 2007** Module subprocess.py has been removed. Since no packages for Python 2.3 are built now the module is not required. Bug fixed in scripts/vitables. The order of the import sentences was wrong. **July 03, 2007** Screenshots for the User's Guide have been updated. Support for personal and site licenses has been added. **July 02, 2007** Makefile_windows slightly modified to ensure that del behaves like rm. hpViewport.py module has been changed in order to fix the speed problem hitting PyQt >=3.16. The PNG file vitables_wm.png has changed. It has been converted from RGB to indexed mode. This way transparency is properly handled in Windows boxes. **June 28, 2007** The 3rd_party_licenses directory has been removed. The MANIFEST.in, LICENSE.txt and utils.py files have been modified accordingly. The User's Guide includes now a copyright notice for Qt and PyQt. **June 27, 2007** Package Mac OS X app as a semi-standalone application (incomplete). The PNG used in ViTables windows as application icon has been updated. References to the evaluation version have been removed from ANNOUNCE.txt and README.txt. **June 25, 2007** The docBrowser subpackage has been refactored and debugged. The script used to generate the treeSymbols.png image has been updated. The icon for compressed arrays has been included in the script. The image treeSymbols.png itself has been updated too. The xml source of the User's Guide has been updated. **June 20, 2007** The mingwm10.dll library must be included in the installed ViTables because qt and pyqt have been compiled dinamically with the MinGW compiler. The Makefile mswindows/Makefile_windows and the template NSIS script mswindows/vitables.nsi.in have been modified to take care of this dependency. **June 15, 2007** Added a Confirm Uninstall page to the template NSIS script. Several changes intended to allow for generating user's guide in a Windows box have been introduced. **June 14, 2007** A small inconsistency in the ViTables behavior has been fixed: files are now open in read-write mode by default. The template NSIS script for the Windows installer has been updated and refactored. **June 13, 2007** A working version of the new Windows installer is ready. Refactoring will start in brief :-) **May 29, 2007** A new set of unittests has been added to the h5db subpackage. **May 27, 2007** Some minor changes introduced in the h5db subpackage. **May 26, 2007** Unittests for the h5db subpackage has been refactored and debugged. **May 24, 2007** Unittests for the h5db subpackage has been rewritten from scratch. **May 21, 2007** The Windows installer making process is being updated. Compilation is done with MinGW. **May 18, 2007** The Properties dialog for files has been slightly enhanced: the access mode is shown now in the database groupbox. A small bug has been fixed in the dataspace groupbox. The bug produced bad dataspace groupboxes when the number of children of the group was zero. Class NodeDoc and its descendants have a new, simpler signature. The preferences subpackage has been slightly refactored. Unittests are being updated. **May 17, 2007** The operations Node Rename and File Save as... have been enhanced and debugged. The dialogs involved in node renaming and file saving have been modified to make them more suitable for the new behavior of those operations. **May 15, 2007** The File Save as... operation has been refactored. We have got rid of the `h5file` attribute of root nodes in the tree view pane. It is not needed anymore due to the recent changes in the code. We have got rid of the parent widget argument in most of the application dialog ctors because this widget uses to be the application main widget, which is always accessible through the qt.qApp.mainWidget method. **May 14, 2007** The methods for iterating over tree views have been refactored. The mechanism for querying tables has been refactored and reorganized. Some modules have moved to different locations, some methods have moved to different modules, etc. The result is much more consistent than the previous implementation. Functionality provided by the xxxEditor modules of the treeEditor subpackage has been moved to other modules. The xxxEditor modules have been removed from the project. **May 12, 2007** Fixed an annoying bug that produced lots of error messages when a new database was created/open. It was caused by a bad interaction between VTApp.slotUpdateActions and DBManager.openDB methods. Several internal operations have been simplified. The code of the whole application is now clearer. **May 11, 2007** The utils.py module has changed. The function getNode has been moved to dbDoc.py module. Several modules are affected by this change. A bug has been fixed in the NodeDoc.move method. The bug caused that views of small tables werent properly displayed after a drag and drop operation. The way of accessing the DBDoc instance tied to a given item of the tree view item (i.e tied to a TreeNode instance) has been simplified. **May 10, 2007** Node editing reimplementation has finished. After a new refactorisation everything seems to work fine now. **May 09, 2007** Drag and drop of nodes has been reimplemented. Now it takes care of properly overwriting nodes and updating views. **May 08, 2007** Node editing refactoring is still on. Delete and paste operations have been reimplemented. **May 05, 2007** The mechanism for renaming and deleting nodes has been enhanced and debugged. A translate method has been added to some modules that (due to recent changes) need it now. The mechanism for cutting and copying nodes has been reimplemented. Now it is simpler and more stable. **May 04, 2007** The coupling between leavesManager.py and dbManager.py modules has been removed. Started a heavy refactorisation of the treeEditor subpackage. The group creation and renaming of tree view items in-place have been completely recoded. **May 02, 2007** Fixed a bug in node deletion: deleting a group with views didn't close the views. Module nameConflictDlg.py strongly refactored. **Apr 30, 2007** Drag and drop management is now simpler: we have got rid of the nodeDrag module information about drags is now encoded via QTextDrag method **Apr 27, 2007** Some methods of treeView module have been moved to the utils module. The vtInputBox module has a changed. Now it can be called more easily and used in a more consistent way. The implementation of the model-view-controller in the leaves manager has been fixed for renaming and dropping operations. Some minor changes have been done to descendants of NodeDoc class. **Apr 23, 2007** The queries management has been enhanced in several ways. On the one hand performance of the filling of the result table has been increased when a column for selected indices is required by user. On the other hand usability of the query dialog has been improved in some aspects. **Apr 20, 2007** Added a help system to the user's attributes page of the node properties dialog. Also the query dialog has been enhanced with a help system. The splash screen has been updated. Management of configuration exceptions has been simplified by reducing the number of classes to deal with. **Apr 19, 2007** The support for complex queries has been enhanced. Now columns whose names contain blanks can be queried too. **Apr 18, 2007** The preferences subpackage has been refactored and simplified. **Apr 15, 2007** Added support for complex queries. **Apr 14, 2007** A couple of bugs have been fixed: - the action Close view is inactive when the selected item is a group. However there was a LeavesManager.closeGroup method designed for closing every opened view under the selected group when the Close view action was launched. - the icons dictionary was recreated every time an icon was required by the application. It caused the openRecentFile action not to work at all. On the other hand the nodeProperties subpackage has been refactored and simplified. **Apr 11, 2007** The nodes subpackage has been refactored and simplified. **Apr 10, 2007** The h5db subpackage has been refactored and simplified. **Apr 09, 2007** The application exiting code has been refactored. Applied a workaround to a bug that hangs the application during the quit process: calls to methods Table.where and Table.whereAppend have been replaced by calls to Table.readWhere. **Apr 07, 2007** The queryDlg.py module has been heavily refactored. **Apr 06, 2007** The management of tables queries is still under revision. **Apr 03, 2007** The tables query syntax has changed in PyTables 2.0. Methods involved in querying tables have been updated. **Mar 31, 2007** The module resources.py has been renamed to utils.py. **Mar 30, 2007** Management of the application icons have been simplified. **Mar 29, 2007** The code for opening a node from the tree view has been refactored and simplified. Management of empty datasets has been improved. **Mar 28, 2007** Added support for CArrays. Until now CArrays were managed as regular Arrays: they shared the same icon and looked the same in Properties dialogs. Now an icon has been created for CArrays and they are explicitely identified in Properties dialogs. The attributes editing stuff have been refactored and simplified. **Mar 27, 2007** The editing code of the TITLE system attribute has been simplified. The directory vtBoxes has been renamed to vtWidgets. It is aimed to contain widgets specifically designed for ViTables and widely used for it. The following modules have been moved to this directory: - zoomCell.py - vtTableItem.py **Mar 26, 2007** The VTTableItem class has been refactored. The getNodeInfo method has been changed in classes derived from NodeDoc. As a consequence a more convenient way to access the info returned by this method is achieved. It means that the code that use the returned info is now simpler. Several modules are affected by this change. The copyright line at top section of every python module of the project has been updated. The General page of the Properties dialog has been slightly refactored. **Mar 24, 2007** Most of calls to vitables.resources.getAttr have been changed. The simpler form, object.attribute, is preferred unless the attribute name is stored in a variable. In this case only the first form can be used. A bunch of modules is affected by these changes. vitables.resources.getNode function rewritten. The methods for dinamically building the object tree (tree view) of a given database have been refactored and greatly simplified. zoomCell.py module refactored. The management of empty databases has been debugged. Fixed a bugg in the management of UnImplemented datasets. **Mar 23, 2007** In PyTables 2.0 some Table attributes have been renamed, other have disappeared and other have been added. In order to see if a Table has nested field the colnames attribute cannot be used anymore. One can use the colpathnames attribute for that purpose. zoomCell.py and buffer.py modules refactored. **Mar 22, 2007** zoomCell.py and buffer.py modules refactored. The methods for painting cells in a table widget have been updated and optimised. Debugged management of VLArrays with vlstring and object atoms. **Mar 21, 2007** The properties dialog of leaves has been updated. Several issues concerning with PyTables 2.0 have been fixed. Management of PyTables scalar arrays improved in the buffer.py module. **Mar 20, 2207** Fixed several minor issues in some help texts. ViTables dependencies on numarray package are being removed. The numarray functionality is now provided by numpy. As a consequence numarray will not be included anymore in the ViTables installer for Windows. Instead numpy will be included so the numarray license has been substituted by the numpy one in the 3rd_party_licenses directory. The examples directory has been updated. Most of the .h5 files are now PyTables 2.0 files. **Mar 19, 2007** ViTables dependencies on numarray package are being removed. Management of PyTables user and system attributes has been updated. At the moment only PyTables.2.0 attributes are supported. The names of the supported data types are still outdated. **Mar 17, 2006** Ensure that both PyTables format version 1.x and 2.x are supported in the case of VLArrays. zoomCell.py module has been heavily refactored and debugged. **Mar 16, 2007** Starts the adaptation to PyTables 2.0. buffer.py module refactored. **June 01, 2006** Solved a couple of bugs that were apparent only on Mac OS X. Several usability enhancements added: warning messages are highlighted in orange color, files with read-only access permissions are automatically opened in read-only mode, improved bookmarks management in the documentation browser... **May 23, 2006** New splash screen behavior. Now it provides the users with feedback that the application is loading. **May 19, 2006** Application geometry is now kept between sessions. It includes the position and size of the application window and the sizes of the components of the viewing area, i.e. the tree viewer, the workspace and the logger. **May 18, 2006** A new indicator has been added to the status bar. The indicator permanently shows the path of the item currently selected (if any) in the tree viewer. **May 16, 2006** A view for the selected leaf (if any) of the tree viewer can be opened/closed by pressing the plus/minus keys, in the very same way that group nodes can be expanded/collapsed. **May 15, 2006** Keyboard focus indicators have been added to the tree viewer and the logger in order to improve the application usablility, specially if you are moving around using the keyboard instead of the mouse. **April 28, 2006** Added in-place node renaming capabilities. Now a selected node of a given object tree can be renamed in-place as well as via Rename dialog. **April 27, 2006** Several contextual menus enhanced and debugged. **April 26, 2006** Added support for the cut node operation. **April 19, 2006** A PDF version of the User's Guide has been added. **April 07, 2006** Files opening has been made easier. Now, a file can be opened by dragging it into the tree viewer. **March 14, 2006** The query dialog has been improved. Now it remembers the last entered query and uses it to set the initial values of the query if it applies. **March 10, 2006** Added support for any file extension to the File Browser. When a table is queried, if the result table is empty, a suitable message is logged. **March 08, 2006** Implemented a mechanism to ensure that, if an error occurs when a dataset is being accessed, the application cursor will not remain frozen in its clock shape. The tables query dialog has been debugged. Empty strings are not valid names for the column of indices. **March 01, 2006** Node renaming has been debugged. User's Guide has been updated. ViTables-3.0.0/INSTALL.txt000066400000000000000000000054461311223072700151010ustar00rootroot00000000000000System requirements ------------------- ViTables 3.0.0 has been tested against the latest versions of Python (2 and 3), PyTables and PyQt. You can try other versions at your own risk :). Installation on a conda environment ----------------------------------- Using conda you should be able to run vitables on any system, let it be linux, mac or windows. The following are instructions for linux-like systems. Install conda: http://www.conda.io Clone vitables... ```sh git clone git@github.com:uvemas/ViTables.git cd ViTables ``` ...or download it ```sh wget https://github.com/uvemas/ViTables/archive/master.tar.gz tar xzvf master.tar.gz rm -f master.tar.gz cd ViTables-master ``` You can use the provided ```environment.yml``` file to create a new environment with the minimal dependencies needed to run vitables: ```sh conda env create -n vitables -f environment.yml ``` Activate the environment whenever you want to run vitables ```sh source activate vitables vitables [whatever.h5] ``` Installation on Windows and Mac OS X platforms ---------------------------------------------- Currently there are no graphical installers available for these platforms. You have to install ViTables from the command line, using one of the methods described in the Linux section. Installation on Linux platforms ------------------------------- The Python setuptools are used to build and install ViTables. You can install the package from PyPI issuing the command:: $ pip install vitables This should install the ViTables wheel. If you experience problems installing the binary package you can install from sources (provided your system fulfills the requirements listed in the above section). Just download the tarball from PyPI, uncompress it, change to the distribution directory and execute (as root) $ python setup.py install If you are doing this on a MacOS X platform, please make sure that the DYLD_LIBRARY_PATH environment variable has been setup properly. By default ViTables will be installed in the system-protected area where your system installs third party Python packages so you will need superuser privileges. If you prefer to install the package in a different location (for instance, your home directory) so that the installation can be done by non privileged users, you can do it using the --prefix (or --home) tag $ python setup.py install --prefix=/home/myuser/mystuff Please, remember that installing Python modules in non-standard locations makes it necessary to setup properly the PYTHONPATH environment variable so that the Python interpreter can find the new modules. If you need further customizations, please have a look to the output of the command $python setup.py install --help to see all the available options. Complete information about them can be found in the Distutils documentation. ViTables-3.0.0/LICENSE.txt000066400000000000000000001047401311223072700150520ustar00rootroot00000000000000Copyright Notice and License Agreement for ViTables Application Software Copyright 2005-2007 by Carabos Coop. V. Copyright 2008-2017 by Vicent Mas 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 . ViTables-3.0.0/MANIFEST.in000066400000000000000000000000351311223072700147550ustar00rootroot00000000000000include *.txt *.yml VERSION ViTables-3.0.0/README.txt000066400000000000000000000014431311223072700147210ustar00rootroot00000000000000ViTables -------- ViTables is a graphical tool for browsing and editing files in both PyTables and HDF5 format. With ViTables you can easily navigate through the data hierarchy, view and modify metadata, view actual data and more. ViTables has been developed using Python and PyQt, a binding to Qt libraries, so it should run on any platform that support these components (this includes Windows, Mac OS X, Linux and many other Unices). The interface and features are the same in all platforms. At the moment, ViTables has been heavily tested on Linux and Windows platforms. For installation instructions see INSTALL.txt. Feel free to subscribe to the ViTables users group [1]_ and to report bugs and send suggestions or features requests. .. _[1]: http://tech.groups.yahoo.com/group/vitables-users/ViTables-3.0.0/TODO.txt000066400000000000000000000002101311223072700145200ustar00rootroot00000000000000Possible future additions ------------------------- * Python shell * Make datasets editable * Images support * Statistics and graphics ViTables-3.0.0/VERSION000066400000000000000000000000051311223072700142640ustar00rootroot000000000000003.0.0ViTables-3.0.0/doc/000077500000000000000000000000001311223072700137665ustar00rootroot00000000000000ViTables-3.0.0/doc/Makefile000066400000000000000000000131341311223072700154300ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build SPHINXAPIDOC = sphinx-apidoc # Variables needed to create build dependent index file MKDIR = mkdir -p CP = cp ACTUAL_INDEX = index.rst # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest .PHONY: builddir devhtml help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " devhtml to make HTML docs for developers" @echo " apidoc to regenerate api documentation rst file (use with caution)" clean: -rm -rf $(BUILDDIR)/* -rm -f index.rst html: htmlindex $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." devhtml: devindex apidocs $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/devhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/devhtml." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ViTablesUsersGuide.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ViTablesUsersGuide.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/ViTablesUsersGuide" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ViTablesUsersGuide" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." pdf: pdfindex $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf @echo @echo "pdf build finished; the PDF files are in $(BUILDDIR)/pdf." # targets that generate output specific index file htmlindex: indices/index_html.rst | $(BUILDDIR) $(CP) $< $(ACTUAL_INDEX) pdfindex: indices/index_pdf.rst | $(BUILDDIR) $(CP) $< $(ACTUAL_INDEX) devindex: indices/index_dev.rst | $(BUILDDIR) $(CP) $< $(ACTUAL_INDEX) # regenerate apidoc rst files .PHONY: apidocs apidocs: @echo "Building apidocs ..." $(SPHINXAPIDOC) -f -o api -H "ViTables API" ../vitables $(BUILDDIR): $(MKDIR) $(BUILDDIR) ViTables-3.0.0/doc/conf.py000066400000000000000000000172601311223072700152730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ViTables Users' Guide documentation build configuration file, created by # sphinx-quickstart on Tue Feb 15 19:12:51 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.todo', 'sphinx.ext.coverage'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'ViTables Users\' Guide' copyright = '2017, Vicent Mas' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '3.0' # The full version, including alpha/beta/rc tags. release = '3.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build', 'indices'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {'nosidebar': True} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'ViTablesUsersGuidedoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). # latex_paper_size = 'a4' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'UsersGuide.tex', 'ViTables Users\' Guide Documentation', 'Vicent Mas', 'manual'), ] latex_elements = {'babel': '\\usepackage[english]{babel}', 'classoptions': ', openany', 'papersize': 'a4'} # The name of an image file (relative to this directory) to place at the top of # the title page. latex_logo = 'images/title_page_plain.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. latex_appendices = ['usersguide-app1', 'usersguide-app2'] # If false, no module index is generated. latex_domain_indices = False # -- Options for PDF output via rst2pdf -------------------------------------------------- pdf_documents = [ ('index', 'UsersGuide', 'ViTables Users\' Guide Documentation', 'Vicent Mas'), ] pdf_stylesheets = ['users_guide', 'kerning', 'a4'] pdf_break_level = 1 pdf_breakside = 'any' pdf_inline_footnotes = True pdf_use_index = False pdf_use_coverpage = True pdf_cover_template = 'vitables_cover.tmpl' #pdf_appendices = ['usersguide-app1', 'usersguide-app2'] pdf_default_dpi = 96 pdf_page_template = 'cutePage' # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'vitablesusersguide', 'ViTables Users\' Guide Documentation', ['Vicent Mas'], 1) ] ViTables-3.0.0/doc/develop.rst000066400000000000000000000074671311223072700161740ustar00rootroot00000000000000Development Notes ================= To create development environment: .. code-block:: sh mkvirtualenv --system-site-packages vttest python setup.py develop To generate dictionary of all datasets in all example files change dir to ViTables folder and run: .. code-block:: sh for d in arrays misc tables timeseries; do d=examples/$d for f in `ls $d`; do f=$d/$f echo \'$f\': [ for n in `h5ls -r -S $f | grep 'Dataset' | sed s/\\\\\\\\\ /%/g | cut -f 1 -d ' ' | cut -c 2-`; do n=`echo $n | sed s/%/\ /g` echo " " \'$n\', done echo ],; done done Installation ------------ Windows +++++++ The easiest way to create a standalone windows installer is to use WinPython and InnoSetup. A good description of the process was written by `Cyrille Rossant `_. The installer will create a single folder in `Program Files` that contains Python and all required modules. There is currently a problem with PyQt installation. That is if a different version of PyQt is installed in the system then ViTables might crush on some functions. There is a version of ViTables already installed in WinPython so if old version is enough one can skip the steps below. Applied to ViTable the procedure has the following steps: 1. Download source a ViTables source distribution. It is also possible to make one from the develop branch by executing the following command: .. code-block:: sh python setup.py sdist 2. Install InnoSetup. 3. Download 32-bit version of WinPython that contains Python 2.7. ViTables might work with Python 3 but was not tested atm. 4. Create `ViTables` folder and install WinPython in it. 5. Configure WinPython using `WinPython Control Panel.exe` that can be found inside installed WinPython. Remove ViTables from the installation and new `.tar.gz`. 6. Copy `vitables_setup.iss` from `mswindows` folder of ViTables development branch into the folder that contains ViTables dir with WinPython. 7. Open `vitables_setup.iss` and replace WinPython and python version numbers in the line .. code-block:: text #define pydir "WinPython-32bit-2.7.6.4\python-2.7.6"`. 8. Compile `vitables_setup.iss`, the installer will be placed into `Output` dir. If Python 2.7 along with PyQt, future and numpy is already present in the system then it is possible to install ViTables directly: 1. Clone development branch or download a source distribution that is based on it. 2. Switch to ViTables folder and run .. code-block:: sh python setup.py bdist_wininst 3. The installer will be created in `dist` folder. It can be used to install ViTables on a system that have Python and required libraries. Plugins ------- i18n ++++ 1. Create module project file .. code-block:: text TRANSLATIONS = plugin_ru_RU.ts SOURCES = plugin/configure.py \ plugin/analyze.py 2. Run ``pylupdate4`` to create ``.ts`` file in top level folder: .. code-block:: sh pylupdate4 plugin.pro 3. Translate using ``linguist`` and store compiled version in, for example, ``i18n/plugin_ru_RU.qm``. 4. Create ``resources.qrc`` with resource description: .. code-block:: xml i18n/plugin_ru_RU.qm 5. Compile resource .. code-block:: sh pyrcc4 -o plugin/resources.py resources.qrc 6. Add the following to plugin class level code: .. code-block:: python locale_name = qtcore.QLocale.system().name() translator = qtcore.QTranslator() if not translator.load(':/i18n/plugin_{0}.qm'.format(locale_name)): translator = None ViTables-3.0.0/doc/images/000077500000000000000000000000001311223072700152335ustar00rootroot00000000000000ViTables-3.0.0/doc/images/browseDataset.png000066400000000000000000001221151311223072700205520ustar00rootroot00000000000000PNG  IHDR |sRGBgAMA a pHYsodIDATx^|E?wwzwk^zQ.gAFxVDЋH !{o I轚wwfggw̓4rZi^v˖q<1vpƶv;8õ3D#QhjVhLlx foGŨx#*V:12!FժiYG>V#1LOI9\P3+Tҗf$9E \R-ƓVtb<7qPk2XUTjF j;$'`@{8k[qJȜYYW5J(?t25tq"գ9Ol4$$c:FZ{q&}]@c`)>ߜ;Lj Isb?A>kFJDVx]={i{NIO:=1wfNUvmY2yiq֡<Ҽa\%#W2*|{iVV&oʥXٛI2#N*G%໫? W*E?'C  k o( +@!@!@ x`=H<$V4V4X++Zփ]\;/|o=7V974K\9|…  4py:tֶrJfj\`uz Gh|X-..޾};S`* ҥKǏ?s9h2dZ1cdddL4ik֬iʔ)iiiF;=3c'ɞ07gIs'˙>֛oL5nx7~̸ c3&˘H%cQO>&:Ӑw~O(vݻ7WXD=z.IE,JE|[BkС|[ѣG®Tl짲0EBPׯEѳiɴIhbJri9r$-!o2&5.IeP:y3r\ \X'L@W|כ4'9@ɇi={(#)5.ÖrKf 6#]re˖-/ҋ. .8"N_tB@1|K鏖.*hZmt]$ҤI>{^063r_Lzɏ7\lҿ?g<Kv@RӧS+^tbiψ{RcQ~YO6Xc` wg=yS[-m'ٰOzƬI۷~b#G*:%^@r6όɧw߈3~OcIûߋ3}vo~3QrT5LZmׁC)BuU۷Gݵx' JJInv>;wL$ X)R̞=Vk׮ԁwՐb &M&ڤFڵj*ޤeP9*{8qN9s͛GϼKL1}/D(.ʝÇ;fSv>u_4[%@߾)s9{o7TzWM6U4;:Cz7mDvi;\>^#?S~_'?/ZvZQW5T^Z*];'w7b=yD"[ Nԁ *^i{f5 :}tZw# vcO 9W{[y;uYêP EO_{7Wt;O;6p|(n[ڵ`G=/QWo_uՀN0qҖ4z9AO>ԈJ4F[YGOi߾}wk^ovQS۷~KّY#Uhi-kD\4o-,Ht=jԨ?3[ne3dF!0:ZBKAMCA_,|((z.ݩw?)^xFZ_7|7X3ɔ\\tQLUʧ5h [?b nU`e(ѕN(Q SD[wfd7>lލvm\pUPZuo+}t=F@<G֍.]S׮]Kzt(k׎Pz BEɘ0]r6l`Edރ9:ξ7O=:/vM}>lsqEK [{Fv=y7Q5\ oDB۪ u`6mEE7)eU(?9:j`=C'.KWZ5 =2Q`*?}7oï=:>-^idּ.y42wΧ΍7/>m9&:N,O&~ NJ47)4X&dSaA`/u`1VV"P:t#iӺE/r]{\{k&^cvӸߦS.dHt>B*]˨{gcDΝU[vT| NLyO\ɺٟy_>Ex#"dzO?3oݱcVY2+Zj]qCRWo.yhH:7)4FTg*;;BK߾}vڡCfL5>߲Jr| =tМt>쯃BHx'm;Y+Vz~Xge3OJavneSDs^Z[.s[_|mmnoᩧyݗS>:ǔV +e.{ ,sSlo9ssssrr,{4&C?jU۷SB:o޼cRf=z4UN:yd:.C<@Q:=N;֗=~}1vXNPwo:x6?ys}|U-V#+@さ@(NJMR#D6ёHz)ȃ #gNDDZ`xc@Aq[ +.?nW,7t"{WmBwn=/ҪuSSgsd}?5gʧ7O=ӫ6eפֿH;NǦ\|3>ՌyKs7SgRqBIeS㣚]R\M3H7|CԁOmҤIT 1`Bwb+=/vVU}B8y$ SGMPreΖg^m͚5| _rsgw^AǎQZ-|mo^{-O>p߿6<毾}yԙd-ZDxIQQъ+yџ~ZZCLwX)EXr֭Mm۶>8軯;կ~u{rG:n|ۂՅGF-۸';ov\ /ҊR@e}|T%V{3VaXZu5@E+7EU:{oZG?ȈȩA3F"#Ϻx=l~{ .aLP#D:aEhje1+em3miΟniML>1?62؋"~ӟ~AII "(`'U-z`\KY/̠|)4͛74INNmR# X+ U*0+@3ңJhQcs&|v'>M33?[עͶx+/?ܶ'W@mgԍuVbڵte@A*|wП ٳg  |Ȑ!mڴ+wHt7]to~;_XMP[Ұ,8hݡ{l}QV(ς Pԁ *^XiJ{O1b.42xSE~nzs7&\rߛ'qiAW .**JuUW?)?Oz-M6>yJV~EYw-mt%W_u~6w؟yV)=m]pɚB7 Qiĉ)QΠ;}v:t`j܀ '/_Ne˖O?tРA|GX`e1Ş y4oZ(PjV U =X,-|jILPq%zӢ_(~*W} g&l۶-}D WZEOg}n:|hJ+.38}.[;Ow)x3vgnCg>۽s Czn׶{󩊹izB8E1e:֧K}!lln4A~_~(#T%uRRiHR›>EG8{EV?>Th9 \}geb;n}mW_| ?eOw޿WkShy(RS.d1Oٳg4mQQі-[23~. & T1c9gG| _ݻwJOD \)RrĿe=?M?鶟'?G_Pϧn|@,t.X~oJ.ҫJoGڻwڵk_uU՟BsTwR Y蝯Jz5]Lh{éZD`?Jwvc/ 4I_7F@܆|8`a1w*Efi! {oU OvʴOf`ʫM~dC^Ni(˗?Or+*]s BxjDkرX,X0/F4?_]K,U߿Ν;t={ݱIO{FD`5 ]U~Yiy JM3R 瞻g?ӟ'{8ԲX˕Y.*1QF蛖ƍPTӧ-rW}πzl*zWѸe)NWܨO+}J4cg,צȩBX;T6u`Ҍ$I*r~jkC,}'#v|R9JYuƾOG4}? iMADѱw*_}:ь)SАCnnɓNlٲ;_4iw^>,r`PE|iZb;iΝ;JuĸFUi$mYxʱj-eYO=u~?-6sφ{jcd> "DU_~nksϽ)wRR״},ֿ%J{ U6 PyԁU(|z{U $h/)̛7oΜ9ƍ Nbܞ9H9G{; tv*ݦl1vBC(~2|(:#q;SZ7}܂>e\C_һ Fi+/߯>F_N B'Oq]}wI.Shyϟ?qDZvzbBC]p!(: ]v_W~DJZ4 .;" //cqV1Hݻ>Oዾs0}V;t@yXM/ݼysIIxtP]֜[oy N=5SWr?!G˻mgg?vڻ3_c. ̪s1֢+]E s__VXmлaFT5v&Z]~kZʬV_(hoO.]U4>R7Kyʮw_ݢc/>>P.KSK߹;q E3F=ڵvڍ78YVȲ\y%| J\W??vL<1c#wk[n/'h@4&4_'{lBuzttMl/C%hssʕl F,5=ȪsDDt+L)O:h(RT%\۵kGSy*]!4'$I.}51[]|믟_ϗzjgd}(mT*睷֞{SOgEM])4]TbBKkzz:o Xvň(* 0.n4S]'YUx= 1> r;}w3êo@eRVF`|@$ Ϝ9*`ٳgaz-)j{7vˏ>!TRW@;(gJq|f!#?]/^rifnذF˙~k.X׿Oߌ1r*4Jc :7=_x!"N֬YC!sh \n({՛5kC a^z}e˖lsԨQ1h~?ywّ+=G)鄩N}т PHJ(ZiӆfpVܳgaYPPz2*)Zry͸ig=XxK+vCZ]~~9ܻN;۽pNޡ'I}ram4:uTNxQ`pϭDI&OhjM=w=BCn^XE;J7o^zoX3IWoU2.ګ:tPn/ƿP/8|>ĉ)}R luV>Q_}qq1X^5{Y})X]yVzTZZJOݻ鄩e4PHJjՊ&h~ EN+V;o?9ygVCZsYxsCZU ]pAQ7#8p`ԩsEd6=a';oygA)^0_݌|{*+@SV+xɁ+Ѯ &Ξ=kΜ|@,vdpG[xLxWxWvw}ݏ?8N'R]kN1S%#7_4_m=Aׯ}ӧOϞ=v횒Ҷmۺ7ֹ+/믾\{_g`>3e7ߺu. gqw_5@*klQ=Ԏe`+`ɡcŊkܹsS6oޜꫯYnlw+W,jժ)b4uԼ<>E7E1`̥_yQ4R}KSXXXfp g}72a„}vit,\`;vw۷ۤI}u~!viIma)>2Ԣacӣx|Vu/@ !@!@!@ x`H<$X Vv`z2:Ej_*zbVJrOSJQPPPPBZe*VHe`5^ZFAAAA>*zbH_DAAAA+쯡tk WHRAf)AE+u`%j-h|ʻ ~9X񔠢XT+Yy\ma˥X[νYWTB]FrW_6Y*U3Vj <%XGqJ+n1KwrP/ rϧ>.?fyU9%xBpV_jXjJ-<ĂzaT##񍸢#F CU3hQ rVҔ+^[tK.{m/ŗ5^@_xcU.k3mzmoLs GAAAncbwoUf@,xJP EqU>V9E`l\r={v^RdGqqQA^aTl^s]QSW!g;29ֱ{Thf /=Uw8@uT|mQPpSn/w5=%"5t(F+6-Xu O *ZCzRNlT'IJ6T3TziFm s&]c=ǻyNx"~Q.t)]R4U=/(q[-i{FɂK諟Ϲ{ aȳwO}N]QW?94c]G!weFnYc~i~oxFKZo|=Ehf.tݝ_z0g;&?PqY| ~٫_ⷶ(U[_jO\w:!&ọN87x@x\xvtV'VkyP(UR(8n/w5,UT((cY1/ε(b{Ă!av,O=UHTy[.ܐgPO`g+v+ #::8@"%'fyn=X@֭{\}[Gs-hɻgߴqb]鞫]Q[6fXH#f)K׍X?+jvӑD*z5|UǢ)#113UwlhLt2Tt4?HCX#VE֬g$9XCdX]y®#3ae|cvc{)=='fu?(v&( /q7^VE$ꢸe: ]Fc <%hֽ "[f)"լyUM{Yhb5iz[Nэs[du]L.Xۿ?}i3vKaΗ{鶮2"k]SCd紦s GIlYGl {)hR;Qh VٶdIF灌]>g֌NfC'F4u aYr&X1]ț6R> _+mmMMs<(*Fpw7^bV+ꢸb^^R  TXYHb2`F֯1ͦ {G5f Uu oy;E`m\./^},fvtE3;]Y++3-KS^Z^s/Yز)tu^7Hq| ?novGhHN2:%ԍ(EޏЎyiOq>)+bs4Ux7H{::rYOƨmƛvd{UGJA7D{5R>sbփr$+^jwTc &<%h +Ù_oY,R0[zF~˭W=2o#%^; (-"(7YYӱ|)ړ Fvlso&L OL ڔvuXbu6bGa},ٙ'/{heݨdd#d|>3)sg!)=Rk<{*OAI`1cuw5mTX_D)AE+E` [. ZUc޾y]/r`aKt`AʁݎP˂N3Z^݋ak8JKH+6Y9ODa{ݮ5^Nu!4;vC{VzZs;g?o<[=٬s)Oh'Vk}P(/s7XUc@bSV`P1#˚fmݖ?[uή((+y.|^%'Rݍ宦7vg+ TpQ֦9(()V.LvWy 쉡$RyWӺɛvDZV# )AE+i豣f5V(TX^wHoS^So~!Zm)뇫PPPPPgA`r)A%uYg6Ϻ{6w_כߺY=Ӯ o]zQV[?@,xJPIh`=K{bO6&=[?k!ƾۮyaI풟Rn{\3 *W`}wiTU}E VR*O`}Siܸ1r䉴]]wyzeǖxn{y70xҒo4sU0R# ?D⅌qPkk)S'OL;v#G>|СC<`B`cRy5kׯ_^{-T;^yKt .gފo1fT>L&5<5 k `kk+W`U#B\KHYʹ+1 eZZń ]BJ $77J_[{cɽ?Kv}g3'6yjI3&n7f;2z&)_6jޫ?(%BK;eFWk7u{c\ݫ=JPM.;;o/>UKnX!%TJdʷ}:zh뎭|uɎJZWm>'˼'>8nmm?PDzPhfAZ˝ Vtq U Efp%ꜝakJ/PnŊ||aab^rc .! rxO|e[}9My[|>''>>}͌??̎V-"9лׇFR`^QXGJv7tvBoTM!L*V%7V԰aCV RJx`ڜ >ϲڎp#Gh'>7}v.HU;rbGy[Ube-yj S._o`A|o|9 ^rc o /ϿwRJt`}wo,Xi5/N|~\.V3rP"GC"vnCӉy4aU_jYSF:msϮ˖-X_[>_εXɁO>+裏X!%rt˴[VnYvt{XGv\f˿`BޟDmzȥ'E5.)]޲6yYYY|C^6uc0f/ǚbJkxb Fjuqt. Gmڪ㨮g}Կyϱxr`W`^(TJt!FIȻjfff D̶Ho׌>d֌e6V T5kF7Iݤ<\'DR>F 36v*' <++H$v )%:9g3_0 Пmk/\l%{wPVz tZfU9"rk-]oEXFao4Z rQO{Dg^+b,X,Z9% cP[we]jTL^ᾜfc\ Ewc/B`DbR+Lu_6no_VڑF  k-Yo(@jZʍՇzsLrFk<^E1y%Vy}nF3Mk%7VHRB`D{C/Av,{Z5 t3[x1߰*f\\.neX]{uic# ؞EF`&gCGFvk3X6.Kn\5ZfE``Rhܼ=S7|6l}Vm= U9~I>V&gݠu4nkĸw$jVKK$"vKz.sr\IY7*t!#y/`A XýW"uy& ڔ[`ソ*==}Μ9%,3-3LPqR M`:E#7RK]P@VVj߾}-IpQ s 7U&ߨ~kUl2e]v˖-PqR M`6״ vJJhUXwCw^ |b5DjXʷ8ZykUl\X֭[X!.%ߧҸqc#vw(9uO8p~bTMXcXwAF… Fy,iaKxcTᵒ {2Q8ת?ظ0^pc .!D5kԯ_^zZN-yyyG#k>rk>yZE{/3?"?njdΜ9||aab^rc .!DVBs><{/թޫ6Yw5)w~pW{G[6,}R_*@{u?kƁ>քRG:*{ɍ+$ |*}:o_-Ř]e/Gl>L0(FtEI`ͤi\@ cg/Ͼv+#D8 `N߇ݻq+ʄ҇WB`DbRVL_mVw}go=f5&9"ҪgPd^3Pٻn5N[R2-/>>>Vv )UY`IRM iOF)!ȇ Ii5鍤j!URB`kkB]BJFoxI[e)ԒGa7YJ-TU'o&hSG,OIg+)RLZgÉemxKzoebZg>7n6&3S!97o?j돐є,oZ3YmO9*># 2ź>? _ .!p>K>Ou.S un}Uz"u>;?bEks#'JZB#S>C}WrbyZV/ФM>9Q#>,F+dq·\Vgh6Us?yR2O@IkacG@\WFge&+X'/ը=tW×O)g@cDuj'J97*:+=HF}UGھ=wg8~L6*+{=vJr+JHU7_ڴ1\ bOO~rՍv{ңYL4+G"ђsJ2r+`ŏv`nXP )y~{ojƁRLjQ֒j7ʚ>7IԲǦ;|8}̖G:݂[+% m]" c-wd̬H85 ?'G`E^4aJJ+`ՒAK~Xe \XU~/݂mԙK̖kSFF!m61FWGSz#kSd2&L61 )+E/JVVX!%T)';<|dϷov#ozүctW<>,RKm D$UfXGv:t&۬HJc5#ƆW6} j&u;}GKQ >>>Vv )UzQFBVX_m0~nտO~=4]a.rDt$E`-*]u&f7\ ϧlV$ooV݂>>Vv )UZk^-?wޯ?׏u.]k쾯?g1xxb Fb5d6 Wb3l@i;@AgkB8@XGZRN嬾uQ7Y WbHOJۨN_mbk=Z_h,aa!B(KH&UIoհovhpDf ky6{7ah{Xʖ,+n^}?/e6L$!%eTq0fG/X]jguR>>Vv )UHգ~_>ð'C~H{a@;RggϤo{Ю\iMKFWK_x@V>EZur%TO`9*H#y`=R_Xc҇҇ .!Xf]6JiBnԾţ]RޡJtvJ0a.rtMbdMIOj^ jE*Uu]fa*ؗJ"duR>>Vv )UD5<] dȨG۷O!鏷k}?>0tyOyBU;S.MTkz[UR)RI$O#LJUJr73{ bj;ŊAvGXw)E/1ZZC`P`ROY:_woׯm>powx7-Ҿ7]8XBUAc`+#rtE]݇57X5 kLVVX!%T ߮pд! K4lc1CG-M3hXы3_跚uR޾KQ >>>Vv )UZܻ;,+%nbt谜:aWUBKQ kLVVX!%T+kM.1ZZC`P`V`cG[y!Ք`NX'+9T_h,aa!B(KH)Weٵo#O{Ozt;rCy'XkrA` JJ+X^wHoS^So~!Zm]kR>>Vv )%4NY>WYsQz~}ڵ]m+T/$P)z/>>>Vv )%4N˞}Vܥ_o'ɭp Vԟ}Icm׼vO[7%oxMrOB\V6Xw<>)o}( e=N"XZZC`P`Ry믿~Jƍy'Ox½S^+>]w;aĆ|ŧr?· ,EKu6f$_$@cX).{5+$X׬YS~zk:*O~3VΚ[zjM.9ʛg\znpɀ>V,}}13a΁59C?' A}VVX!%TJq{N-|_/t{iɺGg싫nu= 眿0+'s?^^];"?fM09kޣD3ޑ4jw+Rw9'a{$'m|ut.sSHs;,ǃ2 > }X+}X+} R*g`%> UJuN^Y{;Yk>c::@(!pVVX!%TJrrr+u衭;%;*i]گf- ีpC*j7B,9xOlGC|\WEl̰9Y>+I2v #zJ'#W \WwOTB]BJ jƋ-`+˶,rH˕r|`yON||x [F/7]iϠW$Nj,{pd(F"6 4XvΊQ XٱN7(-tdm$''i_sl}eHǰ9(7vjf-(H0摎asL͉DžvMVv )%<}mΆYgemGu8pGZ OYzrfrxWzW]$rW59T5D"y(.$.^dEpI 5&M?lnODYmݜߙnZm}lKy>.zA<}\n RJt`}wo,Xi5/N|~\.EDm7Ձcʈn4wauŪgٷ(<C0l9DKW^5 z<`pu ֌u|Ԁ,#Ⱥ<6sf9kG!.ĚuE͜jouuC`P`Rk-ӲnI[eey`qe/n̂ M{ʻ<pr|~W"mK= 3F_6 uO7KƃvJMZ,f,=ġ^+U*^7Vv )%:.dX Gt_P`=zhVGu>#{ǻR~X`<׏4y;U/Fe,+n*yW3l^ ' V,[up]q[X!%Оdn\~¼'O._nقՋK]GIXdݴo|e,Su{eӹjG|@Kݔu%oA}΁Y7Vv )%:BT+ݵo'h7>k[&ubjntQoq]73sXͱVU{] ^iF1r [7Vv )!B"HfYaa!B(KH)4unޞ>Ms?r$AR95Q:ki[Damєڔ3 BJJ+BX+fzшŻ,hR$PydIJ7I:m o:V1ml}eHǰX!XZZC`P`RhŽ ]çP<QR P UJW) &&4c@`Շ`kkB]BJ}*7=hwžS -PISXGZRN嬾uQ7Y WbHOJD U>>>Vv )%:Y~ջBuj=t_[[.) F,kUgYk郥 x+IkHrU= u&b6.1 CЇ҇҇ .!DVBs><{/թޫ6Yw5)w~pW{Vk]D`5~^QA6N*% )Ҫ+z4L nX!XZZC`P`RVRZTEWv~͇ *~%TG{b?V#[enK݌4LR)fgBJJ+&dʷ}ow3x;|60ADRn*)ЈT)rI$O#RJUJr73 bjg\uA`>>>Vv )UY`IRM iOF)!ȇ eֺ) bk<ֽBJJ+X,wSG%(J-Ԙ]BXk8 }X+}X+} R G`3]2ůPg>LB-_]EUVV V}VVX!%:yίFm14B}ZN?sCЇ҇҇ .!pM_;lF~eu;auw8!CЇ҇҇ .!p'N[̲}v̇A` pVVX!%wM.[}Uͥ+,җ= pB`Շ`kkB]BJ?f,ڰF٥ۢd{:z-l{Co8Pc7SgXAio6> n R?'G@7kkB]BJ5!&v-tҁKv\zEAWXw.uxKN]M鍬Miɘgf{V}VVX!%TB9U/v'}z}?*6u"If5=)RMY-vTj0FS췱aco&F`Շ`kkB]BJ5"*rXOnظR"~kO=ZY*!T3v5)s\ 5HyKUV}VVX!%TCf`ݵs/E"̖cå#V z<Ғ"uZ/g눺jwxFkFRTaa,aa!B(KHFVVXTer30yK:Z~v6LE`u,k-}ao%i )V.5=}$4\V9U>>>Vv )UJ9[.K57튿=w>;T)UpOV\ XaR`e V}VVX!%TCa$#o {O/t@~wKR`W!YjGjrUhǻi7Rb57fjvK=X!XZZC`P`R,_:?~3e[{/fCÃU }X+}X+} RUuQfD"| jr>"'T(Xk8 }X+}X+} RUΣҪ:2V&^(+> }X+}X+} R;VV[_˩Tή( ɓ>>Vv )!_V0B 4VVX!%T#++,*rf # U>>>Vv )U*NA`$LpB`Շ`kkB]BJ5!B/d+׼A`Շ`kkB]BJ?f,ڰF٥lwk=oԢ> J)?@/u ثqX!%T=綷lzVWo|Z[w⑖ 0+BHp7kkB]BJ?^+^[tK.{m/ŗ5^@_xcU.k3mzmMfaW⅌A`i,aa!B(KH֧ߵgώKJ(..*(+;JQqKv=n>&wăx!S~$A`Շ`kkB]BJ?3tuJѨWxmţ% /Iۢ~RL0_RS4b:IZ%^Ȕ 8NR`I}qjQ^̼`cȚA9aZ&8mx!c\h89>J+9zו`epW9Vp7KqƃXbZ7iQV)걂,s^WU/וcCU!B(KHw뵙/]N-jw֊oLnA_}ҔWmKˍ$L,+!-ux.i,gY_S{Y)rI>s&MnEFԩV_N)?p$Tո2 U\WwS=L|8e,hWu1\^&t>ZIsK݌Pp]Qk#w̺!B(KH?ޑE"~gd:w#>l[?R2zJYdY) S + Zn.$c48:[ vv 7˸]c>nMs]ҌVS ueg ܺ!B(KH/Jw7e],t`I#Y,H9jY`fCKSV{#0+z8 r,k >>Vv )Udi zdkŋ:P7̇A\UN`Mo߹hr-:msXctu476A&c2̊ XZZC`P`RPydIJ7I:m o:V1ml}eXP!V}VVX!% P UJWs% &&s4>> }X+}X+} RB`D#-)RrV_޺{gf'mTW U>>>Vv )&N^yŘ=-}[=t[!PYZi4JR\FGkf{D1IhͪBJJ+&6nx͚5|CK-:2TtPѰ{J,Mη刍/t{;B5ͽ?K_C8o T`W!YjGjrUhǻi7Rb57qV}VVX!%Te^z?pnn.o\5}gvV٥ό]vUwAX+_Vʕ& 8)qDW)8ꈡ&kjW=",aa!B(KH뽦|p5gm|o)3&C`Ruo8!CЇ҇҇ .!*W^ѽ?(MKWȇ(7Ȍߝgoߤgdh-5>>>Vv )b́/l[7 *H6~B>>Vv )UY`3_zv.-'jn>L3UoZ:v%g*EXV pVVX!%Te5eځ}lWR4Z`1 U>>>Vv )UM`}c9?{KX|į,9sa2DYEʫwXy/bSG,OI;,(!pVVX!%T55VYǻ9mޱeN R+(LV1F4RPGݻP&-h U>>>Vv )#.ZMNXf?} 0 ZN,aa!B(KH)u-#^fIMKߴy3Xk^ CЇ҇҇ .!pVG +`R  8VHR S`'‰+{tPr,k >>Vv )!B" pVVX!%:yckΓn=Io9 PXk8 }X+}X+} Rڸq~K-:2TtPѰ{J,3v=5n!1p|Oޟcf7\t4})ͲͻJY7i*o},v2{U+{; B(KH뽦|p5gm|o)3QyV# Rg4}ʼAQ`!g{gf%U4%MY0cUnU ͺ9Ee>U+if;scT!B(KH)~8|c|9`sB>|{ 2_bK\+WEr qU@}Wrrl*}Xe,nU ͺ*cO+iMڻ 2vW6Vv )UY`3_zv.-'jn>LF;`;i2i4-ՋO ? 'U`5~HU7%=WGEPnU ˺8'QsEYVyW)Xr %2Y=<3+ZA[7Vv )UM`}c9?{KX|į,9saRWӬV~JE?p8?*Y@X+}X+} RԬ]6XײJdžg)~ەxȽ(!{f"}K *'7Ct֐Ӷoi)) 2Y}B`>>>Vv )#.ZMNXf?} 8pZPydIJ7I:m o:V1mbB`Շ`kkB]BJ7o>x2KjZ͛mQ%V!]u%f7\FG_BJJ+X50@y%E^[u`pu IJ3:> }X+}X+} R S`gYkç x+IkHsU= u+O" .BJJ+Xyh@uQ)UpOV\ XÔUBJJ+XWY.\k&I?V#[enK݌4LO*%VsU>>>Vv )UA`5A@P)RI$O#MJUJr73| Ί>\BJJ+&ܹСC?ݻ׭[lٲyeddPhӦ cBF :7X!XZZC`P`R֡CRB*>Lɕ+ٳg=m۶7''qLH{CX\=Xk8 }X+}X+} RJt`7n\jjjy}!(.^xڴi]t1U#AuSVV V}VVX!%J_?*((C]6K-W˦X.ӡimP59g眎nI\ fgqy:H5>>>Vv )UM`dz?ʬ6m }X+}X+} R D`e聕Q"Ҥh,EF%m&wkFqkݔ>!5`yaBJJ_jidee *]BJt_B>;Ѩfl(QX_H2@(WXQZOtX%'? ng9S' wu?T2JaD=:(So5JJ_2߿]BJ Pc!pVVX!% Z!XZZC`P`+$`5>B*Ma>btu4e$[3؟\X-fYy晙 9*8ו8x-+X!{`5kfE'vWh6ďwDՍL LQnn##&U%U}|Gh8U B]BJ^H ={`rm2rTPEYV޺I iu]yOeX!% PSyZVEug4xFV`!X W X3)AG3s`puQ=RyFjrU!וŅ9Ϭ .!%VHJ/a +]7-]Aܾ7HΧS7X7K C-z G(>U/ו%q誁 .!%VHX.-uG Ô7QT2FU+:5*hkxW)GDSʆ .!%VHJ}a tOmRunzߧq!ޖ+fi }X+}X+} RB`DJJ:CGK^LMȤ<>V}VVX!% X.viI:uDd5;\]<#<قBJJ+X!+ؕDz҇OV֐28zX3#W$JU>>>Vv )!B"TJ`9RU'WQ0AЇ҇҇ .!%VHBZՎn媺.yw30oX\}U>>>Vv )!B"TJ`Mm_dH#vJiSʚr73 h{>V}VVX!% X> }X+}X+} RB`D@`,aa!B(KH ?J CЇ҇҇ .!%VHBJJ+X!pB`Շ`kk/^5ZfE``+$k `kkk>iҤX% Xw> }X+}X+}^+Jׯk֭[lA`c+$`- 'V}VVX!% Xk^ CЇ҇҇ .!%VHJ/u ثqX!% XOVLY@X+}X+} RB`D@`,aa!B(KH CЇ҇҇ .!%VH~u8kFrI` )uyKnJ>kcdkSd&Xon1(ε u%΄W@\WAY7Vv )!B"TjnO쮔lD\uGT0w(3Ye%}eɺIkUCw2ևw9. .!%VHz,*ߓ'[ &&cy}Pe孛4rdPHk{U/@וr!(Vcit/RB`DUܬ<7.ޡqg4)z`{[3)ATXʼnzNjwJ+~W"r<NG}youF239䛥XuÄ\'A_7Gx>Z]WQnUn RB`DUpܷܢ\6ϭN1ݧo~*fu&tfZy},>:㙷Y{Tr9s̴̖̲0!BűKH ? 'U`{uon:c #9ʺYJɋ@Һda7$NQ.>ޙ!-)"y/0V:eʔɓ'N`رc;>|СC<`B`c+$Bt"kaJ&w3fFAfYfMmc2ɻ늸Gہ[xVeZݿ?+X!+#Re ҇҇ .!%VH ;YCN:%RmkcF֦4dM&QΌBJJ+X!+.MHRYMOimVxdm$%ձFmbjfV}VV*Xu/`zҵkWV#v )!B"TB`heHGc% &&cTieU>>'N|'r`裏+X!+.-)RrV_޺{gg4ȍ,aa%?~7d7ޠX!% XŮ<>|0V}VVX;԰aC|*X!*% dȔ6WQ0wwV}VVX񏮠KH ?V#[enK݌4LjfV}VVX!% P)5!{~G8>nfJUQW,aa!B(KH ? 'V}VVX!% Z!XZZW`YX!.% X`PnRB`D/dX:A`rא +$+@ Ư!VHo`W4X|xJPA`DV?@,xJPA`DpV `)A񔠂 xJPA`D@`<% B" ?TX!XO *VHVS +$+)A񔠂 xJPA`D@`<% B" ?TX!XO * Pqz2 SJف !@!@!@!@!@!@!@!@!@!@!Tɓ<k!TPAc>V4V4V4V4V4V4Vm[BE'+eჾN.'Q͞ٲv햙| 6o*SiʲǥUX +ē72la[7:iVj0 ["[UuM*e jTf(-l,hIo;CuV*ojA` F"+Ub@`'4E$uʊnt*GĂ3S?"fR['WkA`IǶ7(~NOO` %W+05ߴ^V P*+@%C`@C`@u.@ ف `X X X X X *!ԭ7L=Q#b׍(h\+ Gr3*a27nz[dWHNΰjY*23:,{yh1]xOTQF%@֕y5#ڭ]Q>60XiFI9 mI7J]=i"w3дtV:Gr^JnJϫQC L{*VU ,I 銡:UjŘKSbFo\^-jDL)(y5ԊڍhaD.10k4y/`bhhhWU?^P Vt}т=Jg#*OV9 bxTbO=*pdد5HL#bnLJ:؁2ε$\j;DթqYDhĭhi8eYXi<ƜNT'U:T-' F ycbT( -FNl0b2\M"|0xWZvA8ÑhcGӫ"[iiQFdboV2)sMvoj<@XU&#?VmNX Ayx܇v)ygÇ^|܃ս-ܢiQ=nQ(:&1. |ґT4DndM&\"W$vj>7{[DM#YsXmN|E(Xc̹E:9ٜ`]#J`5+8ÐuV/Euyn#W$vj/;0I= 9-0Y WU:E}QE~FMc#b+Hj)GlDt,f[r^E6'6Ci8&p<E 5X3+5'GrGlqL(WoyrQBưd$ >cGHqE`n2=+8vg}^bڬiN@ٸ`}=-0Mzs:SL Y?i c<#u!֩1V8ikqDT Z6ob((۽)j?(G2SV^y3"{1#*@5T PX b >CVNEEt+3Fۥljj6Psa+mObۮ0gn_WTa?XC>=~{Ü` myKXgx&ZgU'RHj̐ e)G5;y )sʣD<@ՋXFIά (9y!Z\1--Q 'V@5~k?w5Xs9oγ#W8OlUrFy;[hیѿw/Th"Ye19OJ!NvdGoJ[F0¬w<dWJM=yը9{@bE gfk)FHu֫nJ[2x{~1x/Wpbtҧ{B 8P)Uzq*aV4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4V4G` X+++++++@djND 7'pmV ?qv;1rาEKh sc =tYhD飪Uƍ:S^!{^tyJ 1,A:!μ̖-:^]/q|e :|T/ݿr@=SDD{ɩ=sY8\W|}bAs13&. gXbeԗ}^LWvA<=FJHghP1S ]k>sj~9wŘٺ:1>cu8{YePb5;IQÚ8bQqP4N]7zҔ(BU~6dwg`Mbp<@9k bT5{rmX;-h< cDu,&1?*griQu=}b=ԨQA(Q{3qY1VXxv(+>6y84ՙNIGq6ס ΣS'c{JP@Dߣ I T E'7{>(sv56c][c#5TIU8'X6&:&ax=ѽ o㇋vV8. 2[)1Qm :8A`ډ:xtf/ƶbVVa;洶o$7*H28OUwNF9N@Y/<cz=Nb;F\gxW<(Cs6{}gcFCzVt&q 9nr(#I]P:F1t2sse0_sm s늓UH@Ћ3IO /|6[Fݹ׺KȽ1wѠ*wZ9}NnzO'5nwDeh{r=9}k*aQΙ{Gv8f{rQj#ʓGav4z~k:s.G]h "mݔuy]Tq)OB\&nzy3&**bb[ YQ8xagF;G=*@RccC<'`}S X'`Iz׈[(pF#=;sN.CF׃r>g\MvݨFt3#BYjLy Ě'?-O#3\89ՉD}Ade,?$fbBzhΎSb䙉kVR|,pU~qGsv$F_xbrI'߈2$XX>P5w~@TXjaX| GR +((((((((((->'Ε,IENDB`ViTables-3.0.0/doc/images/editingUserAttrs.png000066400000000000000000000321411311223072700212420ustar00rootroot00000000000000PNG  IHDReӋ8sRGBgAMA a pHYsod3IDATx^k^} ڢȋ][E F 4B $n E[/l0{DN$Gz#"%֕RdY-EYWmiy%qk kUʒ̙32g<L̜9y2s?w<ӻDCOKb@e<|&(?'0A) ( g~?&wt;xa1A|Fk]t)˲ۧN_G?J^W$ 駟Z7.%ُw~8/*gΜ_{ァEki% rH+$!=SZlV]ϝYyQs|ޮVcUmm^}ë%o}KΎ EYY؝䮃;/jP 6(G?7~G=}MmΝ;')bqĔʯ<|>}Cf?جC!(#%wOG_{ˠ|ҿ{Tfḳ^nRHE=ͼᙫߔF/b:: 8v.g̑ kP`|_ k}\Db7A%ȻȮ|d塟נtOohX.(}Ack8b&o,^Y$j(b@MXs[]:ĶS LīYp))=֚M8OfW/ &"&/?/~q o>CA&Q\IE~X@W3ԡvTthj:Dɬښ+X1+Ϝ9 JɗO۠7Ҳ;aИp2ߔ)Ds-0Vj(QճJM{4D;bV`16җS4!R"(~/$姲mDNT):(//ibOُ^i뚙 (L ʖ˥_nꅤGPDPJH ( '̾/h PAP@A &(Ϟ=5@A <ٙ3g0AۿZT<{&(%0AyZTf͟ _|qHP#({]z˻y쾑$(gzhhFPA2< sx;NV9 ʯ~CWfAǨSPF4)i]cSw A9xcJYnR;zA\tk{`N;w74382S~r=mtNnA⢟ڿ)WJk-wbE٥]ξ\mZ?Z$(xoٺ-i7]Py0jZAk^LPGƨE.ڧ %SP//ɥRԇV~ٗ\9h^kgeb+r$$;}\m1;7޴fCcuwGfhNA)sG?+^*aa_-8ALi|9A]K<[%}]'wɯzč2Ii:W(N{wle'!9ftFM>sd~^>ڢSP]_B5jW FWӲ&Εц!~A~ZkveɓA2tRӷL A9x(9YzǺ:"#(逸֚-+J$rvgxe, Aَ3gdKk$qo\ Y@A9x]R~~O#u/Ja>i5EP7 H4v=ݮe]Z3>=۵KPJHf?֚91ݮesc]˺d^kvn2rz91ݮe]RBrAS]@v-f݃Pcp]c9~vEa,[9mAkB3<㕃KK2^Z%(%$SNiوA)_u;mߕ97*z ?3:Ne_Q}v(NapӘr8[\sJ s(KK^R۵KPwAi"F𹻥>匌m+bBE5X{IbOd*9ZR•zGkY|':}\h(݇Id^2 =]/W4\jS9%o~Z%(~\hASj-„W;=[.A鏖tK}{}۵KP=t֚uJye|[\ )eOmNfW}-]9h^kg5jpJ*W@v->{P@ie6D},a2R!Vρ:1ݮe]|ؘr!sc]˺eOa$(sc]tu ʮHPtӣ@v-#( KP)Zנ՟֚KP֚KPC~iA `JHON֚u!U5(ό/sj~y0S<5(= DOGAռ%'zǬɷō7A(Ai>Z]{5 fc==Zk6Ay,:5CZu|<`+ >yB=xvs`Ξ=f wzo߾l][ZJ`Զϕ<ܮiwQRBrA>\ϖm[^>v3l+#ׯ_J<,5_{y E%x`Aoj%Ҿ#~.(͵lKJjm8ygvC~;ES>WڵkZvn˲뙯r~(G |0҃a1,eEn>?/)W2+-͊ S3K z oZRrGV|4\L 7JtV޸v3⏘FW ;זP+h 2)%E![9'~><MoBڗVV|Y+f;IeǬ͵آ(|ع2JDZ͖*A;>K? Wmw5~4R3]mOۤwAc0;F_ fg♕lH-~]PGCbvOٟZ A\9tVY ʰC b}k_ fgby;tpK_[zwA'^{_ f J һW#O'܃޾tݰY7n@PO'AHJnmm +CPO'AYx =!$S Ix =~ fD#BO3GPO'|P~@P O'"(ц.(eLŴ#w72({ FYv֜ l 7n.(eLŴ#sAZ[{ {ZdL|J]ۈ#(! GoLAp }@>doA;\Pʎ.]fq3YydS;Зv=a3L6T[Uqӹ-&MaŠ;xryͳR%y.;oEp7n? jPJ0eL><.MwboF Ghţ>sJUtMn -Fn/XoHp<̴ىƕ5/.Ms!rA);mgڑm--/|6` Ih=(';,tE}`/ݥh_6he}ܑ̉g)ՇT"6$џ,)JtʧkZANL(*v)Tux.qsطnc5[2/DP~ iaWP<VoɹUϲsچFs:BO=(+%z| +OPO'"(ц.(=%Lvy͹L7;mC5ำO^uto#)<3hT 0ATTD3WA򦸳\[1t`:tWc]S+3mJA鳣JYrPad_סVYyIՓys}9,hO':ՌEPM&1NIT0#-),ݑhxuhplX(o>c,7§̗ (Mf/iͣHR.ꡕR?tn壶%/ᄉ\ ᐙrA);]̂IcR\ti-f4Ͱy䑏V(Y (цlhS c,)Y#y {_c,Vf^_} z,t}JGPuO{,t&7-/|2tYoe)=a3{,ڦ./*lh[1ysYiǠv}֥n[haA=#xGpAiƜo~ݽAi"s弮< qP;fwGM[\iY>zC\cزn߯iIUd{1ߢ2:.P' 檈թLCa7qe{&YI:ɺgzɻ]Z\yQs=Me ʓ'Ojҷ8;K[NC ?c}@2a_4 Rn ]嚜JP:A\2.jqbib,Ayĉ&,G`uO~CcuEziK弃S ``ط#kGl5[Ֆ7$) BV~[orvwnOF}tgj"fѮ`nU K \I:S5-{o '@yJ/ک"{S%ସmfZFY&}ZkJsmJH ( zCRe J#%$@P@A %$,(] /9m 1lA))K/}zCBRe J g$4fS z)JP%$0Ay+ZNd&'ݛ]ٕZ9&W;#bUI2"5Jl|ϯ~Q0VHohK]^j rc>㦓I{OԱvoU=SAǑ{?Ag{8E.t.4()qv>.ή,,?}W;\[|GBLSj?诿~6W33}ieTNOً=~H: MKL٧ͫo[T?tcŃN'UU3E1a(; V F!;݉-LM1FݭKҨ$ZU`p) #E3*-<R^ZwxhP0"~A=E1ҐC[N?yˠ4nM{.3W+:Mqg-bdtu~9PǺrW.s1sR G9nм` y &4G|,qv{y*QL^{ )$nNa|vu6-ySѭ:W\i& շҵ8i2ZNatN~kPvXf}Qg>Ҹ>@vᨧou'IfǬ@Ͳu~EُibF#fX֘k^Q~@kv_`OZc?l6@&aX֘kFPo}ҊUm+G<= vy5]k5wkzwR̆]bU[Jngz9r}1 gnWίvx-ٿgsiZ֘k+66ɞn.Fܔ-8 D[2W*ϵngiOZcAFZ77-/Eʴ2rx<+nU+A;[ojq6b67^czHqh5h|}\ҹalzw62Ֆ`eR6kxV x/-:w]n Gaȯ5{ *s EcFA-;gufwel:)-A)!bߝ$!b~a7Wg#>Xj :-ڡ%ipZrNMfSPJH`!miQUT[JnBC^mie2J.gV2[Vm,ͦGr]R1[[ sT"l%j.HnkP$(dz}®\ҷYr6oZ:x_IO_ ͖Ge~୞s{k"|9fDCFCP{ ldAsJz!yfSPRć$(W[YrMA)2hr<k&9&7()7xwye9Xrf@/DA[lmmIDJnPnpNP_|Q^jMIW^&7%%A %$@P@ J>\ Z<+Jhff&(?+JhfrA9`R~i PA;jg?Z0oΞ쫙@>IENDB`ViTables-3.0.0/doc/images/groupCreation.png000066400000000000000000001363451311223072700205760ustar00rootroot00000000000000PNG  IHDR |sRGBgAMA a pHYsodzIDATx^|? %o B -`d@%BWcST7E1\$^nٖeM-ɽ0yvvޝfvvfܖV')駟i^ϯ=oȐ!w«zvʰmAڧ7m{.^xWH^}׷A;vثg^z%PL D`S! &kN׮<2"уBF!C@ȈڧOoJ_Z}o~&om\PkCUgT$# 8'^'̊PD`;<JS#GYҚm=};99)¡z@*{JmV=Wr"TRSϬ"߯YhUEU*kT)T3:&5t'[kfNxoPs1r`ˑmDlPU? hX#R"7{X=8ctǘ#e*5gҴ'DR륗5V,[㚋q-2(sƽ{,Q۞5,``z@D41jV&xF5Ap u3\t.xp  OX9w!Vچ Ɓu-@(q` 8%V5V5GB B Bf;/|Ѩ.ssϽ|o,~c<;m2>; =眹Z\e=&ߣIG ,8|0OrԀ)//5nI9p͛7nܸaÆu֭]jx^M[tںE͚5ks̡wmK,Y.q4y#G=zܴ%Vr|ʉsVNjܕS歚:7t@J"Qt<vJSu}zkM/*\?e%ND % nlV*,\-_Ov?͛oիl={.kڴOZƏ͛0.B^/^'LO?Cz#LmsuϞkz&!CPYC`~Q*#U| l_IǎƪWrx㍇~TRwW_MGb׮]J)nڴiΝI)N4R]^^V:JKKwرg*Xb9eVhСC`Ņsx͜kf-Z=ca+5y^Y^V+l--++//߶};݅*+vUwFox S/>ŁCxxƏeVJkQk `̙۶rp=y}soys.Oϯy晍3{pBUQz:vZo/URX)god6W>G? ocşv/hA=.ߍCO`ώr灢{Oh4VGnM遏 u֫OяYWpq7hw.Jn?{ܷQ\٨ 4{~yl"kڕy7xoſNĭU{[hټikG"B4*WE ^==h}GLRRR*@TIhߪʀ(қ#GR|ͥLsQ{L /+Kx&M4n{y[HתU+W|ud!kw+wdlz:_m|um,ユٔ\ ~2~u! 6P^w"Ѿڴi֭[)ө@Q4ǟ˖-Ko4 7n VZz zu!z7O:/_;{j@}ﯧBm?mí7x8,)fV3e.Xm8!&L0Ӫ*V#"*y}Sg~E׼!wR`VQi{ҡ-T}1c9i)lNIdџ#ٶsZ&Y|MdD>:$"YY5nҴC+|t׫؍^eow.8=kЋ^裫ww,U={CM]kzJxZ j Euԩ ̂٤UP?HǨa. ]vAsv+\iU yئ +EUVyoٺh#S"Hk[Y(2k L?-2?!Ⱥ<%v>2}X7tTz믏}1ߏ "_~=pe;v=z* lv駟~쯃 _.F?pO_}x>%]=ȟo\d6mh@"\K!lѢEj(z=M;V걭[対ѿ;fo {7{φ_ UV,Evaa!m۶R [nݼy3URep(ߟb%ܾ};%Tsܹƍ:f*L2eҤI@]SNv/~N:nm_w){wޒ&sVX5+EDQ`O'gTI#}N1Hnw#W 0tȭ "LDFZ'6J+ogU{pvrN'zV[iZYÇw}/2΋Y&W.id̉':.{5[Jg#G?o~oƇ?'_0}՛*1uɺ \ ujǣG{tjGy&NRCJaÆ[n "`ARի@cرcԑG??0m;UX5[p!]W<Ү]+MiOmkHc[{6}ז7ޘuԘ0:gWXA&)VP27Jw tNޣidk޽uFᕒ1L]sҥgqg?6?nzҵGFmwm9#+y^q8vTV7EU}+nN:8AG9Ȉ #g|aO#DE~37{QؠF>npՎ]fPAT (Z#ƝLfZgt c#~Ȕo{VUUQ\vwNzTQ\^+,߷y~.tY/QVo~ϝwQ+. {D5g|EzOyV3{tf~.X/|v6ؖ-[>ګ'{UV$UDJgXVQ #A ``~ڶmKɵe˖"%YJv^=3+}PZmZooղu׶o/R*t? /|6oެp%wkiqkw-n]~gO<ѪCN ֕_v~kt]G;Z}5'~'ޣ!?7rhp]~yD YUf6td%?SrƔ3:`G?M]]W=k*L.oV\(: bS]+gϞ[Ə?uT*O>]풋.W;nqw|%旿|xI7[oKCT?[޼w=1xocw\9| ?;y9׌ؐW@Xx1EF@{֭: W`{#iӦWVhѢI&Dh`ݱzO/_޻yZնmevS8pE_TP\~E:PN}7iLyyyKKKy^ٳ祗^zg?m{?(^V~ml_]zߟTPNmcC=5YQ.>S?r.*@MzB8E1N}3]}Oc uQ}M{>6v룊}a>{Mԥy/.ၢ)^N۾O %!"{qх~myk.o~㷎:3θ醿6uŗyqu^eύ8|l֫NkxD̚5Pۊ[.YE~;(RAIH0 u!bz[lټysJ<%Q=~ق xx ?/pC)lw\qַ_*oxmSEEEϵ)zjР7>ڟBOR5dlg{>hګ^e P}+ԍA(}Ǔo7{[VRzO};dշ.w/^!{ E;O*}MҒڜ ~-WƜr[}|Z]sժuEFr+c{ uu/CjwIŋٳg'Mz#;|cj2``{)6i҄=ܣ5Z" X)/W\_bw߮8'|?oQjJ~uyRUﺐʅ j-[ ԅhsUW]xᅧvM h}{ۛЫgC=+l޻2_e>T5Sբώ:QPk*}?$@4-znڸ/qw&::^W^ԥYҦ='-}Uz婞쓿H`9 ;~鍖j~iI8n999k$_uU]xGEI&OڼwY0u'̊ Ps8ʟ>̂W~~>ERŋUj(QJVլ&wW\ŠE_~l s{;zQkXQ^y5ӬoڴSfΤ[;s~ztV6'SZ_.?8o_s5P2i$cǎ 믹@1ޣwSc~7S潶b_(Qn?яRU͛}f|4YRRB- ФB3f {DD+W\!HӦMu@4;;T`55{6^5d{!~Y^:ߝ}'WϣcTzqƊkY_8KmS4Z9l#V~ek>^xFzռK߇D`?]v-ZTGΜqFc-ذjՍ.;_l|?#(R9r$O?+_{gdܒ-lh&}-zob7ſoڍܮ]o}[C Q={}}jrU9ja婧wGGmP꠨Jeϟ[o3رcǴё7g1릞v~w'\_QOGqnP ԃU ,CGE^^}aӵ 48o}n-WaC{8kQ}*gRT`%< 5?N2E=/ 8ʼO8&͛;m4ؒmcZ'.}7, XiӢ?XYvi%KO0c?vѠٹOԪ.BʩCO зo_q+.sνv-gy&@ha>ќ] Kޛo.JUHRZhEKJJ(Rr@tһ#6O޽{ʕT3wޜyqn&vEZ7o`cde˖Q5g̘$*=qƴ?qƯ=iU N?}vVւ .M N?=Ѵ}|K?czC~_w.W~oC=JOXMzsϤp\E`y Ơ ^f`;fO&L|֬gرs3K?:p_WpW ӟ|wp~bV.4k]Ig$sGՈ-{jR>t:~ɧׯۧO=z|999;wntEE_ξ‹pg̙37n|5ٳgxܹVjܺu38gBz_m۶]vY UrW_{аaCo`ch]yy˲fO !g1 ?;,0*~M4BB:ؼysguEo.DC_6j?oxj]6;n?s6KYb߭{@q`ݗU M['`6|xU2|\wuVy(>s :֭+vZ/Y[nցͻ_z /Ю]^z_s=_~N/jIs;TƘ HJ 3c>ܻG>i3]F=3{zN|Ni(JVZu/@(!@!@!@q`JX'փ@!@!@!@!@!@!@!@!@T>oK|D,|u\ _&Z`Ug_iy)+Jg1zuyepf'P` 5JYj30`p;@33`p;25rJ(~aVS00{eY{]_bVZQW'~*} GR tq)w05=cBcni._̿ܿ:玜@0uuW+ )OutˈK÷ լju\2XyN݄p7]"Pu֩Bd^u74}oyL*w6=mKڰ_ :SS^'P`=0䎷w^i ?]18eN ~-"YWD;r:C 3,c` @D aU0F<[ݗ'$oɼ>/~{={v^UjGeeEi.mU۷W\N b^<[ݗ'$oS^'P`=j-U]qmY%C.:ShګueV'~%|<{ˏ}$O!ոmN .<[wR}5bp  FR\Q?,yk4ѱHY\ޑN 9Y[Kz^f5:)Ƙj (o`$kpZVu_5oN-H=Ks$T|7Ƿ2肞A]6oެ f_`pઌ֗[ϰ辚̫y¯7-zβX~{+zٖnߙgU3I]l>[ع({RdfbSj9qB-S9۷{U/ a}5bp  F6S^&⤭HM̲i9alvрL8ƜKlW3v([d,փNt~s7J\WDuWtr,<]2|7F:< uٺu*}0U"UUWy}^d-:ÌFf;~fO[=쾕nrWOS[ع(s2V}j: յ%ǩW|Oآg2Z_E^-Wt_2?>" :,vhi6\Fs΢Q9ZuV&~slfXҫuȁGq;ݳn]+/9q3(TbcxevwƬX6w:=Qg {ESsm]15+U߾lTE;i{dpUF}ƸʠjtA8% X: oi~oٞ5t,.m߀hR4T tCQJF_l8f*jAyv]N|FA [-q":EPA3˚ՒVvو蹞9T+c&9q+]QJ!< u)))Q/.\q: ɼ>/|u'Ec9>̣gmYEDvNϣ[ع@{>lgv;]6]mH1[6: 84DZToKFV?řDKٹhf3D-UxvehyO޸dpUFK ϰ]18eN ~1g12&|jgEMQkofLYմXw&d^O3kA&y@0Z;Aܭ +`U\%QdƘ(t _nϱ-/TtlCKZg ?h{.9@?*'i-;Vc3\<̈kRsp}|p$.]̏>-͑-f±8SI5c,AT j?x/OHW+ )OJ Z3no_ޤMjh%], 5$9M̏X3|aͬv>K4B- zuٶm*I_MUy̐ WdaHiy{e~Rad ?,y'OJG&<찍-&%]88u3߲ԢgQ52 3̲1}͍:ޖzhgLƀnM-z\QVW'~*}5bp [ Xw&p: .Fs\;w^ Un8n(WƿMZ C0Cio%wP:ɼ>/ڍX͎x{ۑs`q#T3݃KZnov/l7|-w ;h$IhBYD|ƬhŪh߲($sPfzZrb7\YZ/kk] íNTjtAhD({ ;q B&C QܹS꤯&ۓv_`c5 jLo y"LBbaQW'~*}5bp [ XX3 e7/kz@uWy}^@P$'phW,DOBW Ny63@nG8lE*Pʟ]o_ET3tes7*2HS=S8+"uuW+b3?X=rӚVڷ܇_ޥF _W ;xF3N2|f <#`p'b-6pJSuڂ˟W}d7>)ڶv]eۃzwCxΚK ɼ+b3oZ <߾ԫV[6oht~c>{郷Ko㦐YR )O֩+g_>pN+-xqSV7}e-V6s!=kUڥ8QbEYZ۰r֧z*Uf[,?>8/ .uP y(j|%Xy䑛nݚ[W#׏Y4n)F\v- /vy7κl fy%kV}Mc 51a1uc ^r{p^7Vēj_cǨL|G=rÇ:t!oEmduno/*SMQQ3i?;p{ ޱ슿.9\9'qل (3wS!5;>ܘރA` ^Vߴ~d>@~;տTh |ytƞqM\{ҋoXpgg^u{`+jY(CJY#],h懘vMh7~v6K3l#JR*+sݘރ󢾡%'Wa]zJi2Ff=[X9OwF&M)|7-uƔ~&/s7MDM?Dh#hy,Z!g<})3ރ^\rJ2~_!jj|CWOvv61:zlGYֿ9 {o_TZ|sK7ZV edTcEol,XՑO#Ka })3ރ^Pb 2~_!jj|Xp֋ղ^Ҿpꢭ^㢢%w~u[adD+nF㋹F`^^;g })ޘGT_%4|kҐޓy:t8G nX/Oeg НYk͛5kj_7|qc˶,<ˁ=aXµ~oxb"O@QXU-lnS\7f:2[DZ]e@r{R;/B(Ŕ˗vHLWռڶmƍ?mڴA`j;>S_\MK9~qÈW/jyK>onb>%PTcFCgU/ҡl|0Ȣ&z`5ׯ/ ȥ:geu^iuI#:W1fS-[!1o_U:_+yXǴt中# vQ][6h'K4E<[* 1})3}NYYVDnH\.׽'"䓕JL5iŔK{G_NeTufLc_swir|k8xw9NT'&:I=.;{wӁGM41+ywXImF<3#6+#^zˣ uæ|k=I1F3XE? 1uc0:.牑XGr ݸ=D}JƜmV/׍'F64etr^JEjYr=Bc[vh黟o5;Cun̻%׽Ew^ a<ϚF" ZS[Y*n Vk˖-oӢE nŇS[ Ȑ1^-?2`_}j Ց7"&un̻%׽EB x"o7>̔2} VMm/馛,TnEiPM1^m6`2eĎ rEvzuyQTUU͞=' W:_u-[r-WT󢸯k;<—_~}n#_RbY4UVi/>9Ms ~KYQ1\W|u7tU\e6Pd?V4FU|%UI13]cnuc*: ~$q^N}ē US[~uӦM_)5uճ]iiUԢ'Uw.J),(Jƌ d=I!S58z߹dB`[pGm|TuOX-p77ȚVNH s]6V7QčwA0+kzև?zWohж/jpw߲V=ʛ,*?aUĕ":bMQ;Q1?aV>ӍT_G"rFղ8jpcp¬ڄzսnk|}2X5u#6~[R!1lSPtqj`Еԇ G$naE`wsYQ'US[+ /}ǶG[? oyMOtے36,+p7VS1a5J^>VuW'OIm)5V4:oPW51+ڝIA`S ?6m==B*zQç?>Ϋxf:wj1uc>.V> NVp}wڳgǎUU۪*vTVVVQVY}{ծ{ޞjj/ssLwcm_!``NΫFղjU,Հ8 u@` 5kYS15=Ϊ~Mt>j-U]qmY%C.:Sh{wc~Kר MI}irGNY\:twA0q:F>m TռyVV\DUhND1qT 58V-zzC,J5mV5M~[>i϶%7,?/v$E`u0nF d udPȜQا+vjp!"f~`}ߺK;odvg;qY[9ƹo|+'|ٯ?%Z`UXҫuȁGq;ݳn]+/96 "aJ2z] f{r5j2>׍yff#=e! Oq,Ie? 4cڮqé0XX3?>:u'Ec9>̣gmYEDvNon.fiҕ8*Υb 1%yǵn Bj?›CO'b*jp!"f~`}/V⃋wΊW.yoKr.G+z]8=;=1]qiUiѓ1*3>׍yp;pi>! O> :,%QU6K;4ZCo}Ŵjp!"f~`'6۽U{Ëg7STr)&޲c);O.sp}k7kuA_~bU@cLw ${OrEX5u ֭nƿXL5EE~~A~~_ѿ?V5yn}xzt#Fpu`M1uc/f⢻ 3uI!%'W o_BeyQt#ܹ17wM7 ⊁^szy䓻'{ncǾ?q7dbœìF99!$ᲷcP?Nڽ..;[婂ިыUx "_0V* })Iܘq !"&իWz뭔V_*smt￿UW-&?7 \<`@Q^?V>묕{hРCVV옦J:i^g;lcy .bla/NM_׫ԔjD$Ucb=O X ;})Iܘq !"CWVΦy:#U{͛ǎ{-XhҤC3g=zs[7nVqA^䅒m=Y=T2(j`l'QpiVgd jj|v`ڴiQޓ|sC=rdX۶kX=pS?tdӡmhH32 FO>Dm E;KW/s US[+-|7kz|z|-q9OH.%ܓV Vm@ql0mڴѣGKT~TzUC*i M>U_o֪"JxG5QB\sɉ/@%Jz2+WOX\;k,uOO%*Ss*ԭB-?PcN:j(*^,\Ƀ?Q9].6рK@cҴwd(8Pm E;k.bEˬ|,3FY2; bǤ܆ޖAU># .CVu&RnUUS Uit+S-jĈ%*^Ьd z .jwfଠْzG6j^Wq%uRW$^Ul%flՙU]t"T~DzUC6%#<]|id%7WL~)j`Sq%uˑ..S:ͬ| 3Vϖ9RIJ՘9ӕ9]-ETUpusLX)^D 5Xʹ:UUUǴ*OT!CKTDfO/Q%/N*FsN̖tQȽ}%W54kMzѣ@w.ԕG]rD%bEU=sKά JV2$8F@iJ*zm)rž8*8p`P1O'@ڵkITn)QѳNvB\s)6V̪>z J=yªb( ֯0+jzn*bVU-*2ҕ|c:@%Kee%}o>ՓiXU(J!Oǫv>+dmٲKUUeVڛ.kOwiX#v`n\)VX %kÆ \sN[?dE`M_:_PX}рUUUt @`4B7R|]B隆X5u,->Yp끊G߻<B,v`@*U}UVy:X %pÆ ꓬSt kB`JjkTq}f7?/{Kna;VP].*VTT]VXnݺ-[E.eUS[+m V~{~4YNﵾMWlcJ:~iĕvܹ}v:i7Y˷q@ Kֲe֮]i&0ҥl߾}tq?wX5u&vS"+΂/~uK|wmh}#_qk؁ht~72gΜٳgϚ5kƌӧO:u*]&N?f̘]5Lȵ^{^o Z3j]8tQFitqK]ryRUS[+=Ǟ{TD}n[[~]e u;<קBMX * x:ڱc[lI +H$ry3-=)9+d-Yd7n,//K +]CV)(q)!jj|G`fZ{b}uv=űG<ܬ7azl¼ۿ*Z3FU W^YBXPu͉VVF)|5-~sx 6t=c=zgZnUUOfD蒵xb3ݻ5!jj|G`7wF&}Eﱿ_uثQp/^iC?aş0Y`]ۥa.k/XI4Y}n˳v-&odؒ]\,1X t/((Jَο+VBw>[ US[+=U?]Md7?|BG$]{[]7UO>Nj<?mmԓN͙/E6/G^8hy ő/zs Kx&rJ&#fk(VMm^]D~_Ѷӿ&mo"}uJ'/z5<@]-E>`Ej83IJٸjN5|+M ^|;_ة]4_|~udȱ_ސ8HgT_"X種'j)w4Rզxw-_0Sm$;ZMڲQds"ru,C0V2ܙxYi=Qtd&tg3Tf5SFz;K"YW%n;"ϰ:>O Qqܧ]M4їX)#֫r8R$OfEi1VGN+r{<~x}M`}~k̡zg#PHM7H_]$g*:O8E9qޖ,'<3Xr3%ZW (OnȥG"ڵ6."cq0s2™t6m:aSI:G 1׬(qc_Uv,R_c|1[h[Gn :xx.JH/;v~+j QTzȨlY.N?g49Į/nʺYEͽzJ%ޑ5zXc|4CN 0JtDs3 &+:,]п%#|y9j둒[1љ,U/}R6̑)# XKS+c_š#_U>|w Nm423d75ίQ!؁.q9W/ɶ+hZ+]׉Jy5ϰ.lw%os`-oy(qGK+)7rJ^m7t+{d-hvU<1}"Zm^|Vxbfuֹ54VV`/^H\=k\WkaZ"9;W6+?gEL~>j\WhNx?9mY^NU;xg>[|ug~f⢊^cKxwEPk<_ r+n]a}`U4l*' ?9`ff6ecL_:z_iXzCq+smc_;EmU.v`=X_k_*Z:jk"7&UuR]g itM 1^iXV":#/Ot zA$XWu#YWMQnoE+:쥼n|yqoƍU;sSyMƫF6-Ip}6]~9 %v`CnV)i(~`9cݗFd^ uێ=Ҽck D/xx}S`Ua5%Xm+;eY`L R vu5H kٞݪ3D?svY1Zy)+FzYc{,W/\V% kDZݴ| ͛7p՛vVm5e˖b<>;*D;T֝_%z jCJ9YY"+@rG5t5H3v&sXDR1jc&W^TZ͌A|Tj{(ZDiO kV-\MK֖ɚW'FXQ1V |>aO^jGjWx;7Y$2@`@`uˊb"tZ)~)Q3m*t({:Yce ԦjkJ6 E+oVJQ,t/WH5_j*DՐx`uU &>{g9?ˌO5~,\!cX@>LUU}@V{/*JOн\!|ؓ) Ŭ>bV K;44谔VL ?t~ H v~8?XܐF/ ^Vi]z5i+t kI_s̔V`s5('G<&6\t JcJV VW *"dp`J*hG4 G^Hȩ\zr4%g@e}=]ybg,Xk'TSQ?]-Ux,t/WH5_#ARdu`elIB5f5RTv^QٹC`H+d Ut<]QޤTyèȠV5:gʮ(_^ut8Ub =VWɌ~x}eVElΫ'TIXOX-eYNR9zot*4iX7B`/O Vͷ>sJaVXfݒ"IRJJ 2.VVWɌ~x}էZQ`\QX7B`/OzUҁ#@`@`ux!ꗎW+K:~$*VtI?>2ɓKJJCYY֭[͔vfuO Mc++kFB`B`ڠ1ߏP ͛7W3gٳg͚5cƌiӦM:. мܮ].] 0`F]ʦLB7х.wG@B:@`B`ڠ1ߏ|V5T@x OX3WVeQp})I@`H:_iXקBMGd": 9 kFB`JʏRFl`*z1ߏE6.V7^[u`k4*AoAF-߻ cw`õ΢ڽYqmg8w~0:_xZضcYGV})Iqd`5jzPq"Zjk=Oߔ,vU3"%P8%37ƻ#?T&B`J*| ;iQ^)0kQNp18q(ە>|?@ٸ*$]oP6]Vcr; ռHBX5Ut؞=KhU/էUjthdɩUM@]xuy1VڞOYGviذcE]9(F ] 715^{For6n-LliaeeOXcJ_^e[PF>|?"il<ګj7U fí:?Dnw-J#UQʐ Q$VLDT!F}iw)-lz͋fՅuxVG[XJRbc7+u H"YW%2*>j1w\adV{0{=[AUE64Y?Aim=zÇ͋$zV:_?#O ՘GtU<5hqW9+q9p;M"5dںKW5H%pٗq$O=5.Hu7[><߈N~gdHq=a҄_J7 7r(x7V;<4Aߠ!jj|M`Cl)20*<䢔, ρl4ևhZ+X鴌?ˈQ#3;#W'A+ߥPSF%}SUT7<6k8bү \wSQc,GsTq5i z+XU\RuvO>BiZCUٱMҿG-J*Jt j@WKzQ!;:TG&[qhs0a 1VҜeL1eMCE3,Up%Qh X}Yw=>bESk65bWjs_ki2kZVHߓ)+CF~[5޹ƻ|F=dݟIA`?OXHG?6h՛mwKv6R ȅ~@cJw)> ے^ѼyOX%)*{kT.&֨8hoL|7v5IV\hXsYu.TkۓT2 5PY׸ //Wbd3Qf&]Am_Z+Zs\+fWF_nCFr -6WGn7>jfsdW/]fֆ#N{H7VU_Ҹ~%4jg}_Չ6xgd=ZQi=US[+-+QpA +qEH@T|:lO/];孡FkE5ljfi1ie r}j,l*SaH5;kYpj]sդYIeF]\bx{1j&TEDmM$Qsgp%'\b WFscͨc|1F2vj@,̃Uʫ|QU$Xs["WUa`Kᛑ[(jmQxү^"ꌆW%H P%:ykwegc\9մ;_~I\a mdQ#7J1FH5A`H:_X'pI,rG8a`$tϮjM,49iɯH~Ai֌6]~9 %v`cyGSաFou#(ܪ.$GV2ֱCx!f$VMmt *"؁(F6du\&J US[ jCU$f#E5#!jj|S`/g6}'͡"MK;4T74Pe1X5u&&M VS-͆s]Vߟ}NUXNxn+@MB`H:_iX]OXcOrj(_#v` n\uXufԄ ؉?X[{XjkFB`J*(bOr'⩝#/ìF99!)ᲷcPW53AVcHJe|,'SZ{#!=5Wka13kMΪ,mHr,"$3YK9X5uG`5$*0Ȗ^?#5&=@tbVU- UD.WROf1VڛsiA͒u1WTSnoUfI1OC^ kYvAU=@(֌NUNr'.!221Y&<1"-+ƣA,*O1u٬T|;f'J11=&; - <֌65EHJ7Uʤƪ]vEQuN53 G$Ƭ*oh3ˊ\o33aU9j5ut&=c҆ ֌6 5ym}TI#UR1VoKY%V.zzA 5#my3+kZU +@X3Rnnĉ4YB`E` 7^by"F]寯ѿQpǍM֮#e4#sJ%%%tWl֭#_ 5  u76n| Q#Yo:UQVT`϶"Qr.6a"%G/Jgުsnw8:IX5u&&NL6寴2+@>;.i>Z~$`m =VԕMzW 172oW6ֶl?ճX5u kI:cP:4 :o`,y%]ּ#*]U5ox;ڄXM jQژ3dqݟ C`J*(bOr'MlP+;:^a(YӍrrmmT:b"Vԝwy.tT`]f]Pޠ4=H6-HM8uqVv7mޑMOJ{US[~VW%:]_Fe[%SXRz:IKF8ٷ) zۄ`n܌}6] s8oX5u)WId4>SLs~UM+@uk "M{Xs{ݝ}KMOP2VwbnwdcٟA`Jˋ&:OTUa|p5V貫,kMfwN+@:" \{XV;Y\Ÿ&jl>k{E۰n힑yj{US[+Cz^>ζ~P_k8>n)sKYV@,̃NUQUpMz^~iPb6l[rX+: f$VMmXkXDXRX5u)w%W XRX5u&&pA`HkFB`B`ڀ :֌65g\/V!f$VMmt *"#V!f$VMm/V C`H:_X˙M}_8}*4V!f$VMm ⩡jzVV!f$VMm ''S 5X_ˊ( :֌NU&Q.ĞNxeV`u?9⯰r.<<jA`HkFB`T͓^SbMz,oAC^uB`HkFB`J_q'ʔ2H@)S)3hBA=y*̞ P X3W_^7)Ur^0*2,u,ʨʫH>XRX5u&&=/39z)'R f[ʲ0cXRX5u)0 IˏH֣P+拟,K5VFqjG#ѻC`HkFB`O& K. KcB`H:_PXÀ*v@I\5#!jj|M` 5 N{‡P>W{y_X8?*-F*iUpiaWpO`! w`õz+?m~zRcoFv2FW:VFXk 6|Fwcj>a4]9e[d7~YzM5k+Ԅ.4xsaOXd^ݠ$%fnabVc3֙m5uUZs;UW斲,')@ʀWaQ>5kT~X)xլ7 f36*`nw3`+q|PC,Ā+k:VFU5yQT]wVu;%G,|ݒ4-)LM[ѪA3J`5.#RWwWAO&?ǯ{ 濲vVXc@`E`O&Ѝؾ+CTXշM ߰g73tzb(w5߰܇ 2J:otxK*9| ƀNUW-;6)ȥ"#*VzIR(AgPl6nk +jT)¦EFLwI)]oճUA_1 "M`Mց5c؁5VVV a f1 "M` 5 X 5Vt *"#0:u*:C\5#!jj|!BmXkiyyyƍ;vѣG5bĈaÆ ڶm6mڴnnժU˖-yB5#!jj|ՏjI*UfJ]RY6鱼X&t+8]jNz[ !f$VMmt w;L/ՙRRF5ftNWKQŃ*+@X3Rnn622]B`?tE)RP*S jEK]j)2#HC`H'O6YuQz[>LEX bdv*Sɒz[ʲ$V̝;w3myx= b kt2`5*//.SL1cƬYfϞ=gæ?)@pVߴ~L GKQ)ToS3k:s%W;X]5V$PBGrƣE˛m(QF[hm)ovtxšX5uS` cy!$!??z670uTXX3W:VNz^U \Of &l@˛kFҁ[nM4i,=hXI_.IP#Ҭz"H`}y_X8?ϔn^^HQW?Y65? #w`ڵƢZVgKcuF{nP_| /*PX@ޣmfJs3^zcj>a#Q}L8}ApﯵkqNu㱒1# p %#[gm63wVC`J''S ZAK5+@T`6yK;4ha)OXJ*+lR]|ۧ,F`U7D<f3Uvu4 G63:" \{XV_#W5dVc=wVcDNn?ޑucy\Uݶ gXcOr'<O5h46kQN8 -_ 5 +@(߿I 74h' tYVFwsjE-[u F6~zA|2տ§&&YAku֧O2dṹcǎ?~ zK&B Jo .IId)(yw|#A-(S&!B GG,O$k HS5m:_+Ę+(VՁ63Z`V|h 5A54i|Ḁ .9v7qs?$׏Ќ3.\lٲիWoܸf[ҲrAݚ={6݉$op<#V)S)3YRA]y'zkV$Pۻw/)Zmo-ٲ3ʤjiSRU)OftڦYA?͚5ha؃jd3k, 65eFJ?)2$uN,ʨΫA`Hp.XC5P`{֣G.y jj|eVlU4r$c=ae9aO1⭩gX@םmf?OL Cn@Z&M^|EpB`J¨*&=/?"\ZBo qa3Y:S%WXE-[S!$2ܮ]px+@XeαcN?Z-1V-mUvܑjtkO`ߥoe3I jӓ$Ԣh5Jtjˆe\U:`&'֟VQz4~L-uko1LiNdRdi>AtTl,N!źjE "8B$V3u~ST(8\cjHn`ԉ>EӋf U֨BuL&P wՉϽ\hVԻDuGW5Pg,NELCJnthhsr`W uT[h8 *ژLy¨hr|]v"V -Cvs6c nQ. C"D *hՋت,:j\3ZȾ!ǴxzLWVoE]ь ;"&^"7Fj#QFg*Q2dg2phj|ڨA<3V: >5Ta쳐@c26e \RuٻjzIdrejKJD\TnO J<΢]ɨjHTgUPK9kWFAm=5v7¥`c:U;c1ffkUF[t],":+ C %z/#5D_( qS(/x"W2Pj!@%X}n5$ԭ[a;O7F[c:ugbV7Y5̡0P *ٿ-JMœ?o+*@. nrTi; <55#GM'VUaU38 ,+5fh``)c|*c6ƑX6y2|T׶.:ff-=} i ).gߖosFNTH/&YOmrwwCSDD@*֋>To}uQ}Y6T¡C*A֙lX nIor?T^DMѶ1-6$;EtM |XӘ2yCUbo͊wH!,!$+N;qsrH ѲiS0^+ͅZP]Mٍj, sqX%=]ea7f$0K qw TeP+c^."\3${}\{s]5bd(r.ڷ֚XD ,kq0]&j\s2V\F!fY;xevwm1˽iQ75cL4T@`H&|onMGL蛈c=i6f؇j*wcbTY*z(K,:Pk5F\%,zƐFBE^ͬX Ԝchf.{ (JTcs}1z%fђ*pF\YEѵyFG_U`X3.F}D8VX%)nyg"֤qM,jL܋Pkͥ86{6עsBsHLxWo|nn! 7`mO[yfg|F^g\1Q{fK*2UcˑmHcc nvt p=k ҽC4GE[,Z9@d"!$D s[tϨ-Mƴ@oӬb,JpnHD+[NfAߍQby.}6J΂=ק{ Y)D_wmucG'oh#ߞdpYfTԓ (>+G[1f ߣ̡? n"MB}{"[&Qvεff+EhƞEMڵx ]vU:WؚiŊwyƢ\czvSKfVry*V(P@̻5k|1o(xR-Ϊ=ԈfKeVK^9X' ~ǷfJך{7g9fYw~TCLαoٻz\XULc"+@ĝŢo(ྗ Fk}o7 jn)8"ZwI1dY{ѬhZ{M.o+twE==œkfs|ҵQ4W1]?=i9Fe̳!']6ثe|Ϛ ugmoECLqv/۱v50f60!T;GjF-,":_j[Q]l&c"leLʌ?tGjL IhK(Vu@|I]@`j'=V31> @ݣHRi+綾^֭M@O:tХ;|_>x裏:v8dV|]5'JIENDB`ViTables-3.0.0/doc/images/helpBrowser.png000066400000000000000000001663141311223072700202500ustar00rootroot00000000000000PNG  IHDR9o pHYs+%tEXtDescriptionWindow Class: vitables.pytEXtTitleDocumentation browserD IDATx]w|Efw%Kj( 񥩈JQU`ﯾ 7Qذt$'\ߝ{;7[r)(?G3<3eN:0 +5HU% $/XYrA[CfQbX1B` pHK!1@sx?Q)W?cj]2"[0]e@hyQk׭#|0 òΖ8Wͥg58CyYoTlirUѧ *XuR^#I+dTAItqTLT!*QRM8 Fd~Jy; ETS5"H63 V5A*u0ƈa@(iQjj[.HE?#i<dT7+8-b0nCPU_nFͫ5ZfҦn!, UyR*p"mZ~ }Qm sLY5 jPd1TᚤTC??Wp 2Mj_'XuM0@o d_yy s{^l+aP9|5"8*H8lW0TjQTiw0/@ Q(\DFPHʍJR;yEF=ph2 }2(Ӻ@HIhh7a g'W: s%|"+Q-R"?{-kNPB~F@>CPKiPj:CLSʔk!z*l4꺚l80f9:&cXv_iAz=999eeNb1GDD5JnaƗg}!XWƿhٱ LEABV"ѨZiH~$[!uSbV棵4T<3(:U$DMBLGzHyY!2lTuBbТzR152M$0SaE.#d yHU + = b$%aSuىRj /)5K&RwԃDOiڽLA (e03W֣j!>oŋeev;"GDDόբ¸=e91w>܈mfh3->BeҒcqɊ*AB5:eVi5jBAs0Ktz4#:TXۃʊ$P V*RہBXKP##tLJAsvȓ*//&F%ЧT ɢ V.ސ’Ȃ@wQJntBUW8k,e@/g$$X@̠c8`BN.J.D/Н1d$U@r%eԚ/4 # Zrh!GH*;ٜN=%Ҁ!֖)E[OBJe1e[!eGE1ȌF#SAF;j [DP.Z-OnT}! -))>vX("$΢XxG5jq1:tV3GҤ4 /^8xpV։Ĥ.]&7Jr8v3۴NܥeVuݮo|ݣmz8{}߾='Of<{fl;v:}'nBLl\V/ OAAVO85dn!ƀPر?@U Z۷dzLqHRBiie^4\OuJ4!Ȕ.U 9"BkYuWxOUI!: ,eD9 ^RD"S^RZG5MO BZzODV!#i፩yȓ2 V8eX,mA OPl2xz1H+Hc2K@9;!\ tw4H 1AC :})ŖQc*WV jZ}`WBdFfKH%$ttv6 xAiDHYMogjݻo5 .;?/mSDRYYY'FѵK6o~w={S^7Dӝ;wܹS.z[-ZTQQQSg"*"JiK5CS!2$R`ɍ44ibA%aafvF(fv"IHd'A\;PXG8y4U!zR[ `'Ode9bD׮]e} @ٺ@/?s S޽{EHMqk^k%q<,˖W>|u-[ѫѣ4mڬaFÇ~K{ovqq;`N#jr0V\CD./'Usv'U,"HV ? 2IMhD25 )Aa/ #Ty7 N/}BGp^UÃ#8Po ;Ӑ, "i$pF#6( hK. P K4R3eR`Dk!Mn\M[2>P="o $6I?0x dSS*Ab]L10S_6(x~a㿋-iLR?+ TlӦVXd((NQ(dEƯ_pAU# x3R* CHXb,+ & ,h=Iw$#yz@k$"IMM}ꩧ322&cp1q;{ _;ڇ~8**0=x+WzfQ߱cN2E@|Dh3@n҃;e+HK97IK9V$L47qҤI3g$5BF͜9ŋ LgҲe˖.[ЃG%(uMa0wk Ʊ be  Ng"#fd|5xȐ^z?< U^{&3m7x7^Lm^p̀K d@Xx';uxw:yǟHOOKD^z…#FxV^ڢENxau˭>cv3gy/{o =F&4ājժů-tϤ3g.~}k_;e ![_~f?S۷o4ㄉx`ů]&f5k64v?pDd$\bѢ'M9kk_["пNM911ĉc?80+++111==;%oȑW,_!&(V+r܊+^]I&;{챈)0CN5 &=D>x+Pd'dhf'0L Db!b#F̘1c=˖X/HLL "57_~W8qblf„ 7xcϞ={}p]05؃b,ڽxnxf0qC'YPYY~۵=0xQQVa UUU'Lp:11|/A@Yix`&i„u>-((/]Fɚ|Cj c*|nv)ͥ'%%`jӭ:ڢNr8"AyY-lS2l6Z_ 4%4l6XPXTDظ8r;x . 4hMGٹsQ1~A0d`ٳxӦ))MyѡCbŮ2d0i4%z$.>)ܹ*XBJ6:Z֪S>8wnaa[oէO_Aw&-4UT|ZP\\X\T@G@OKKJl РAQ={FEE睲^{cWZFEEe)?~رcO8gϯgPFr.^eMd\ ,30X$@L Bm()&Wi^olB9m"$ MI[8Ȣ֮-5 &Os"W5˹$@ (&`T]L$v8G?HlF  %ќ)AwBE$#(OCdʱbUoظqɣnj !Rg6H8^kgku_jիfϚ=fwy7 a%(/7]?oשK=jx}蘔gΝԡS02y 5F[Νoymk)))3f o+V~3֯] 6J4q/W{+?M\zd["e0KӋW^^G{1Cyg+U7j99H9(jxozhb#FX|ڵ3g\f 5ZA#;ԠYfY׭] oINC7|ٲ5k̚5KlnԨbc2/`0ffd` cV 3Lc3NwZ`u?n/[0ǟxeك[nժ BJK!J(N "iF.w1*hvSoP'rX1^XT#3 3&'RjBV8^S.YG*J?!#&PQ UfTFOjB2fTritѧr)y%k{D!R^&`Ir,߃+9ZN^?D=ݩcg}7p6mڈ^EHuSBJjgk0yyV5cQ <םwb,,[캡C%*kaHx= BUy>}nټq" }믿eg ;F>SDKl }w'&&N>cdMwylްqСC? c{sΡw Xjƙ̦M6 pdҵ  ]/K߾c_~套^8a:3-}cPL%&&Μ1s*8)nK,Fk׮]vd[O&Ojy>u&%&Μ9kԩU JBdtt4YTkJpyl&a[?HH]!Cw8@_~2j9ش^[o{ڃ^_4fy}۷/v?p =[vi^z芬Az!)_醤+Ny78z9A!*3 Q6\c@r9&  4̯QaݫKiwv0#xpx;<_qi45" 5$,/ CxDN=[WU=(IJi(H}aZ b7!Z6(To $_$o`NҾQV,,V%%?j"msFa ?g0 1B HI[oؿCX2XGfO |?v>ZBH@L؇%Կ;HnbDQ z4"e ~XE45! CN #>X2)@8 X@ Y;DbݡBUgYj>uد'F aK65.]2,ͷߴk׾IJhǤ*,,:~kUVJFP 8X =F NLd 'dNqV&BZMQOG08{U jB'4֎V,rJZPG_0Zt*LS1&7$e~n_S`6/h oDF&(9(HIxP^#L$y@>R3 ue‚jl(7JIsEz9C]CUgWqEokn` ism5e*GFELŸ~ܹ3/DFE9N"g^qqqnp(\ihyTYd&8Ք5IV#(ejK&t* Ice|?d $@d%DGDEb (L^ѦBɛ28"VQsT!A=&UBdN_~U,U_3r:dfY*+^%H2է,?jwVm1HnZ).>9 Щfc$ݷF\L%Y񂆭LT*D4ʌYK2tHJHU++dZCKkC4PG"Ey? dErFȰCg$sk@TC<(qyI0JP%TgiUC*[$ѯUf-M.q7"] WUwa JW!d2X\.Z ́Elu5b=PWSAisbV;]xLh4sXu%@r^DlP_P aU7zYqAs]JL IVӠP]AuFBHWR 7C ]W9^ !m.y 1KPMlBL;Pۊ&#Ej22QfyLo=H@γ5]L4RfR,j̄TD "ƯyU: T50. m#4CfQUP*j)JbV A<{Һȼ0!I֮liEB|o#3QBzZ@ob`|< d![EH"( )I /@%_Ogj-L|UO?CREBP!Ju@~S*r#j)r#҉"VPf$y } x dxX,hQScBuСC!̬vAߋ#KPNgӡC:t# #9fBСC:t%:tСCU=AѡC:t\u:tСCU=AѡC:t\u%##XWWO^=СC?5KP2+9>\]c}чf:yٳ ЧOI&}wȜذwޓL>u_PwСCjxZ qCrs¼Çqx7 O1c!C>~|՗ۄh~O>d2סC:_xs_|'p85bh4o6х{n39Vn9PPPYXXΝeȚr助S>jϟ/^x(rKޮ)sn{-:5nn߾ᇷi}]lC=yFlyy/.~}HԩS-˰op:SLϝ=+Uْa2O{9sbcB07LE%e 6|뢻z 3xD;=C_s7:tq@-}@ ƌcAmhu;KJWw8G #Gt\G{j*]^^$4NN7.).օ -_,nذa;oO3+G 17^?qKt%&&|_?Պ+/zֺۆ3x5$':tСIH0V%$Y&)).LR4IKKpvR4 ɔҴ-۷ooZۥmڼ)55h4B ѭ{ם?e-KyyH.הB[oͷ }gøDžJ>}֮Y۫W/ٻ5kk|2%oWUUU^ҐC^]tCZ+p۶mkҤqh!m|Ŋ}f5L&17 慠T3'Ϝ90<_pϢW.\]_СC2aX͚M4Ѝ&&&._yߔ)Sm駟^p#<8nܸ_Xky/4kVE8'kcN@:t\%@xzZit?[8:tСO`85#C:tqEHHpM+Bs`/0iS_^rB\iСC)xtСC 8'))ѡC:t#E:tqAOPtСCWE:tqAϡ*9tСCpdAeo aY:tСCpă$CmoСC:t E:tqܙΜsDOZաC?կ$7nܬy Uzퟦ:fWl(?OZաC?[< F'.)7oOq4}?M_:tqu5xX\U>55 ҤˣWN*{ 3;S8`U^ӡC"WB|YX S/ y^#a00`6Fc=6AZxmg['[^Vrɰ;t$[նv:T^Vޮ]ZÆ W6>_Wpʎx,˚ff2nՠUR^eǎn{&qՋ 9u< &0QMy-F/~ګlt n`1qF|a+a0g=Ejj^j)t`^CNgYYŹXPVcf]RbcVk݅U9\?=*wKMأyrrbB|<˲uo%L}//~?ko9P ?ߛӬk={qrRS!dr]7|{ۧ=ָeJn#c# +),ɾs#sԶz#@EQػk⍭ڴjP)1ƧϜ9wb' @lu{bpK2S[HZ}/9b,U=J tsscFP^{qӉ 㩙FGGMnYaAѣ֣k?|9fXԖ-;-PVj<.;fV\<;Y5\?3["ێRo;z<‚EE.}<1nۦu_,v}Ғŭ͇|~CVmK[G.VZZ BYYמ ` ݻu;u*#..^q덷qg\ ` Y /V:+7k_kDj}nPm$x*8[㶧>zMPW q[o >aƒXq\ /<ϰdyi(ZGJ*]qF#wtE1i07Ƹz":q}3gϝ)?x|W)XeaHl7 :}hkv.]j'>}m3gok4Eptj0boɍqRh}U8N]veP`a~O~_թ4nբB,xO t:i5j۵KMwCvu7r!tٹ>kkԨQzt&hwkp55}߼y3ıKӔ&9{rd5ŵ¼cRUzi6:֗a=YxNJk',닎|~q-&d`Ec0" . 8u]@[sU seN2F\*&a/ q6[8?5 @^Jeף[ ld0 =gb. ؚle4Mk[˭j[Ew8]%R'(Np멬Kw ketBcC!^0ؙCEGGVV9 ຬ` TԱS%%]һ婙|'3rV޽ww\#‚ʂ]{6Ij@pC?pUl3q*s58Qy^6H57Ej*w__'t }sx,Y[{ V6ܜK.;22R|0~ۤ2͜A΃oL}]YAСñcy%d#WPtcA3gEDU岊 +Mvf&%&,ѯS׾QW++kࠤJ6E|kNA2/;;WJiݨ,BZQ;B;]2p:]Gt$_#e1X$ȓSzn11ocbaY궂E<]˖-rssܹ3gϨZHXgl1U{xu]v/9 s~fZ:`VtbS2ZUn/KB_^"CjƼnqyFh&eokjd`Ę Ϫ8KŹUYlK5fQ7φΟ/OEZc,SUpޏp\% IDATGK^ csi(!aQ]9~9Vꖣ2IV0X1u"o6A ?٥kFkypҥ¢¸Hw쌉e;۬.k.cjp5`b``x70^sxtW /+k}bk#lMa8" N#1p1D7}^OynEUVY;U/!PII 0qqq>k :5-.-[vbm`mSbC{3fΚ5^0LYdzyZ'(aAѤyh6;g[?[`ݺuOXxZ҇zhʕa Q^# PxFcL##nXxd KsC^a08֛d#""l%n`#9dfC6wwcA3kIjrT9Gx xŗgwЩ)D0k"6/U_r8N/0F 0X1A}>c`0k6m;th_7sOGGWVVK ^c=v)57dlv%o k~߳KF?0G_$`|1`3 `0A6 8+Z E};{ b ߼3,0/`>JJ?{𻈸6gϟ-//CZl?QZvm>3 w лsMV4V\1uÇ;O/{cuיƧy6tu 72 Wu}ߖ5l Y.;W\4 1 q#d-аARNΥ({!# Lb^fq:*<*Vv!7uv;,0`p~V Yֱ=c˿!&ƀb'X#JxwO[+Woτte!ڴN8$ڔ{օRKڦhPn/eddb}e˗o?wY?쳥K%%%>H.=cbƏ[rXt:fxlX"H8ybof H6n矻{y/ F_P\yy<ݻw&}Ud2G8nȇ;z邜RĀYg4j<4݊쳗Od_:w\ѥRO[NrQx0 ˲Dz'&XݻedfԈ-B(&:rW U″#_)/gW8+^ :z[^C("&i1Eq7혯|x\v ./x ^дY72IG4jk8ى62ԅG;~f.EHcO bo-%SĎ}}) +Z_IVP8RSymFˮmj.//O/4NN&"`ܰEEEɊBM&IR1k߿s^z饦MS x*D"dbzG3T8@Lw%G4oZ ^P.]r9\؛[vyh]Sk5>>C4ʪbϥBOIT4UyO.%2vM(L_pTU-wojS#0B^/v*_ nPM'njܤ 3p,g@   &9"*2.+(  c r!17AE:tH6yyyfhX`wAӜ-8*r. Ɛ`rr. rQqڲeǎEfW۟|W^y}v VXA_PGľ}`߾}jjCGo,ŋ99-q^Q"lnnVVV=xvQ6lhrWeGZ,N*5{,**|oÆaÇKkWTTP)i8:UfNP]j<'' eeEDXikǖ ޝw}||q-aYe9g4"## {Pğb)--&vۙ`&aVg?{rٽ8>ܻcf "_R)!5n\mKTFO  ŦBؕs D, V=hf+2@F1x'aއ} q&Rb"7>>.7׿۩C'jAPθ0:s3߭l6 )SOa1[o4\2tȫ <0 CA8+O=bYr9s4aÖ.Y/%Knf|ㆍ6ozͷRS{w^vɩj=w\f44`fd]d޽r=AwE= 6mrAhbÏ֮Y=fXİJk艌ޭ*+NaRTT\Ώ??/--y 6[~Z}JTRFղ+/{F. !;(V˒ƾ[vOϸ&6&wPAAH2)zΝk۶MFFF]~;p\q+v,0`gȱFY~'|rr `.\f|4^{CHIi[c8x xRiWʋ6pE \Q0|N$0 A&<@< P[ַabüeWG4kݺ… zyaۥ{uBi_~#F!?Z|Ix㍻LrI?OGyo eMcǎ!8#hλƏt:W5p6 5=AwE]⡁X,&M>vg ҸqyEEIc٘YO˲#GرV_CqQall r9 7WMsm6ZK:;].pPA7S۩WZ.a0u܃"&y>/Bii _ӿ95f3{nۓކel0vb w1_D2 dHI(E[Z_JKQKUK"JRJ^v bTdA$Hf9?t2f9sf2I&g>ϙ9s@ichGG+‡MوQh5p@HG'UdHahH nd(y^AnR׽[0'O$H!i qJ0QK$Dm흁[&ӟQNmk\aуܫ=~P#an ..~ī\+w֛̏??nQ futt>} :{a×L|شCYa 6݃*.*nԨ7[_'''' o/tnɱ;A9cw>3oI,{Z88h/hZVjvZt7*H#VL.v';MK'i'mCmI2ʡi1bCi6Vd$r)9k-8qR*~ag>7:?vHJUjN $ $8488IH,jUU5g<۬i3f rvo&>zRȔiã$VQ(i2?O*1ahc㹲iӦ_z ?\:5NW´Z={$%J1uVofzK;}eVLҦ<~R=,َ[8ܜǕH:;;+ʳg4j8f0[NX.)銣SggGGi'e%M˕P9h.NV^%߅N4J>mvwg>027pk*ux;AǴyS a-JgS᝻ku|P - $ZY~bT+HztՠA:JvNvx&͵F#qrjZVw^NNnÆ NM*l Tg.uMSm]FHux,Ҹq}O:_XXx̙]啿 ݽwcݺuSRݞ%PuFIzi|h,-N grܢo64hhՕI-!!QK!c[H@Çۏ^?9Nۄ82hX^lnpqϔf{X'|a=e(-/7-GC¢W5πM3וY o]6ptqr,su~uH`e?)+Uk?f{'һWC#t`ZG6j*ը_XO5ֵSZ-{6sZ;wГGcF[.q6ry5JҀD0VPM~cWGRR* /R4,OJ|W;ڼҺ쥛Eݬ"޾Uڼ 7&ZjÆ |ҡ'>wg?zH6lֲ_@o {qpҺe嗔٪WSN. $. daN2:HZeqvlԲR˕/95&[>aO;w JticE"ʿՓZې7jM;2'ޞ~.T%E5ZwH`[~UQ-R>}*2G C2U~^B. -چZO\6ȺTPP ;t UT_RZYQ Fn4սr{YIg#gOkÊhTe \e?a"A]b(+gã'O<}ɓ'?.*..++ssukܸqƍ7jԸq Z}gΝ;A2lZx Bj;[cf]C?_uC}V_BH=aU_:uC}V_BHg8A_:uC}V_BHQE[}kzE)B!*e)B!\N\!BHե\ң5w} B<ϞZu{^$B!_>=.LPIjj/!BH3vv0HB;23.'_b6fDS:zB!… \sp1!BlhE3΅ZA!BH `?O{H';hR)^z UH!BLiDxv I-;3r$ڴ͛(*¢E.!BxEMP*TjTb8Cmqdg99p&ڶ}f_vB"XLHR,L2~;t ƍ!":\ ??88pE!2n@֭c2orrp6 w".qY1h3g nϙ(̞t3I:OGA؊IIHNV˱!BlH? l.3~V2V?@t4N{1u*'m&Ԍ܉'Ox9 {WSiB!T ; 1  1;A+5%?@@#ÑǝowutנiLOB" IDAT.4j'iEhqB!u%(o-#x}Qv jn;;0jN|> H3GYKi)8qΜY|OchvB!X&AԼ9VC00XNN()m+f"b;{9|8LAv6Z !ۨ8HMȑB_ƫ, <'JJD.- x)B*EFB!Ĕݭ|z+ F!&Sش ww쉾}yAy9؁?hƢaC郞=-.*!B8U~EEB!Y׌.}B!*bW<rBTA13AgB!XʢDEE׌RS<B1!BHM!B*_Aaobg1bGظR)p`F!CU0?mNFf3HH;T*e[]{ 舳gm !R5(# Έ@J.PF"bD|3VaDH m[ ;7Ѷ-`"pcƠaC`rm0f y۶UJ$X~~ppcz: AƐJ{02!Rfź'S x\df5i~EE1i3q8=x`>8~*X\T$$pHΝxm*U[IIHN=QP| 6|B!uu+(LHT*UfFp_*O''vV͛d2u>+V`@<?B!uϯv]_jNDo'$[[jDիѪn%9͜)S0XւD1>`,^ElH|16m}uȏ?bhlZ'̘!xJ!"#s-!R\NIYp ~1 d? zWQGHpuE$"b h5?BCѽ;40mƎ}&T(yyy999߿{nFF5(ׇ.y!=A!Q _pAYYVjFkFٶm{ʕ6{׷=g <|<|1B!kP3wVmߏ+#G[BWLPB!կ!BHmAB!B!B!v&(B;4A!Bݡ !BMP!bwhB!CB!ԱB! Ug ǟ]%ڸ#Fpi:E!LńmOw|&03 xz"!R%ggDD %E`lx{ #GcH$X~~ppJA8e'o \ 'B*XALm[ܺpp@Nܼm5*6!RwHLÇx\dfJ*) jR0Ig^>zƤIL$:'N=pq}p8 2a !zHRr/{j5P%ΝѦ oݺbC?8s/F aC܊艩!RK:xۧNJ8n_8K;:`g͛#+ j5403c<=ѳ'fDл7>/dLO7o^'O_W!]bb͚N@EtÇcdgCEQQPHO^BH7n?{\A4q"Əǝ;P#cЧc*~3bҐLƛ-q$lҥ(/T,Ea! 1cFB*Tgf3c࣏p>=ŒՋB^jII /) v]Rk&(}^+psèQ6t(ѫ"6Ő!,L  e'XxÆaC̚UcfzcG_| ܲh}gϊ }{#0ՋBW$**dߨdk/{ !_${`}_jO?G&\Ëdd !RgŐSHPxMՂf! V_Rc&BB!;tp)=zp|;5(BB]bwqm !BPAᜈT/!R7E4 B:u 3"" h0{6憑#Jwwcx(R +srHr%` I!Լ:r 'S,x\dfJjC^xa(pGH*,Y AA //E[  ;!Bl'(Fg^:8`ldf 1;)Vز(.Ɩ-puts?6 -[ ݾOB!UOPjʌxyyc j>B! @3wVmߏ+͇ B!2 HkVB!F)B!-B!B!v&(B;4A!Bݡ !BMP!bwhB!CB!B!B!v&(B;N`}BZA!Bݩ G-JTjdaCzyz5XWJ^ lH_x{E5ު_F XTO5&uβkErE\a4= մV2kRyuz:5sGaT:YAy憇WOal:zQƉ/O[ٷO޽]K5k8ME#/'2~0ʹ<.n^HHpPu '[1\.[fuv!~-NLYZFxѢv!!~-['ONa^e{k4^yyyn߾|.(abR*S&Ok١}5kV+Rf̘: u@*ʨ /A=PY꣏~}8_9G0j4Vۗ//4<=1lG?P(i}ζϘS /OWjڡWZ6(C'Oơ~C/$/ hZ*Ӧ>ȈojV]l6◮kjYwZdi8(\YrLʕ+:nܰ">f̲H>x3eggF»LȈojV],3Ih#uM-r`bwG8LqfgQйV|bÇF lW'L0ں~uS)ibVgyz4oF6QLRaC333t}:vs1Ԩ|ɗ!@ʩ4} |u!|° +bZU`p%0"gfftTVV0̏?޵kiF/9Id-}U*ᶘp] p^Xf2"g+bG46=%P*Z6͋3kƤ ?Ja/;KӯεE ͛;vHNNþx'=|@d߿ݬ̌;i 5,l~BT*-p ѣF 2ohwӂ1 SZZ%*ɓ'Am=z6MIIIDDgR)!)QCQQi/Ay)'_9GEŴȑca}wΝjݻ=_ZZ*:"sۗs87[wJk #E~Z v#_GmhF|崴}'"MJ;׺oDEF.^􅘬-:W J %""bǏ?޼ח˾\7dYYY"S{>xk32ܽ{ݸw2rʕBLT&p˖6m vqq@--u4 =++<0w1>~u! 3rւS6np….]JRձ:G>"a%KbuQ+YGh%.899<0MJhc+|Mma&ca7e5"{ /3ˊ~ݝGݺu߰Z10bٟ)**7opjJE*J]͊}H7oB!W(}pvwcgP7_7JoVݧ}|jUWOM$3l 11s̑r|Μ1ÆpPL^Æ\.;g:rFxz_dwsǢ!Ԡŋaȏ֔qXɒX]TKw4j:MJv1g$44tߖΜ1gjGjp[]}*~uHݳwߏ;vZJL=mO|bE+?7vٽ>2^={;z49sf j&u넓ߣ"#e^;mڸ0իiײŔɓ؅2j4+WFto#{Wݻv ԔuOf^0̵k,fH$URRĉ-[ ^}dlxiiԩh?uGS f/ACF ȗ!R9y҇lk֬6#ĢQbZo_ !w h̶9rF6;|Ʊitf2"v7b|WG9p&p) ֵa/;Kӯε!e~~~ݢþx?#Q)֋bLM0jvds^ߕq#G\l ֶm[2/XP!UTanwns .(++jZVh h4۶mO&#x-Y7 B uq5T]\:vqwwv htYH.5rÝkWzqB!ՉNB! !BSMB!uPFFFevwnYIBHѹmGN005BB!k*"2U@ 1k)_rȑ{my?fEBBZ7'OD `7T*Ռ[1CR#lȈξ}}Z@jBN Lx`SS#BH+ h4W4/?_.Wlrժoܱe5?}{"sڵsI|ҥ_ڵS_5om)bR#BHmv>_uA6077W>2oWr@d@VZۭZ*,,ԿմiSvUVIB!5+(/ =zdԩ^@&8xyb"syyyݽ{+B IDATu<==(!BGu7֭[ è56pwcgP7_7ȜzCcbΙ#r9c s&QP8::zyyjժChh|*ͷzR&BC˗/y5RɾT߿~bbB!lB d"vv21cJ>}~B!u+(e׮7CBB۾9,fy/O/O/!C;xyzu e_^xн4 .)}I>`s=8f؃?i·KT222LS(--=v!!>2o15"Bjʯ~jǍ`'NxP:uj }j@6rbb̌|yyyYYFWEL98Of^OK3eaTwxo۷oFDNZhfeu~ݽ@PPБDzsr=ݻn J"sgw?{3c)+ /#e_!b `jo_~{\|ɓ'f(/Wvky=g\?z n>yT~A!pʄBH-b+(?#;;;/l {Iwkڴ)sjsgj )\yyyRRf͚u}0p~:Օ}yͯ/ǛzНs Fټys''f͚M6 7\Y[WBC+7BHQ+( ֭[F׮]m]GG~())|rҹs&O ٳ)/ׯE%YS|iJʕŋ?O?)&_avC7څ4yyz(,,4)BBH-cUun~u;w6l8zۮiii}KJi1a69{O߾l Ϙ1=!!Aj÷^]*_`B!Yb0!`vCm}uvv}6]tqqq҇8;;}2+yvAbݱvcMYwYwE\ʄBHbנt֧\z<5O?Fƍ{H/ֽ;R={lԨp^=q`Cdҋ_-_~L"G}[le777''>"\~5"Bj_b;ɾgϞ_W1|khLر_'NԤ[w8ӣG4HkBB| ݸ~Xn.Jgϙ+&#FlٲρFa bR4B!f [o/7mѱiӦ/woڴG+}S.]tUU"˖5p@0۵oձcV#zc+(.Zd'5h3W}lĤL!._A(ʻ[^c [ B!)g' _\(KvwV@B!XfLw #BiƄB!6D+(B;B!C+(B;B!C+(B;B!C+(B;YAa܄Bì[Aa 6hB!6VR5(B9A)--z*@ !BX0RiN\]]iB!6V_0 B!؜נxJKKiB!6f kpWWWZA!BU>( !Bl hm+(^F՜:u|뭪˗}ݻ:oGcPFh*-īgZb)/OW7 }U*gmoml<=LѺl&氘툿seEDxw/\ticy[_$}pm۶WJU4h_}3m~1-L'nWdDg>}zv-lpR9e$Fk֬63)F3g!z,8W;<= ڽ{WTT̻k.qXۅtSNNZ6l}DEȼ{x!11t//OΡne|t6]` 3_WYO&͛7}iӦΟۨlq8::Z0=1-iQS=`[z6bbBd18_ôYD~byky!!Am׭[Y#D QVeVPX&(۷l1 _$/7I/Ͼ4>^֥Kǎ/(5Jj9sN? 9sc=jԄo͛AAAq晖I&bboξLHH ޮ;ٗEEEv|%3gO'$&_N),(rF;ZʕcǏ߸yK*~lɓf,3+k}/]lLk?f˯oӽ 4~BHrӧOܨeQy@bbI9(ΗwhLjof ڷ a;mڴ);;4}YraL‡u :--3/Ζ1/1evlpaC333tL 8qeٳ2 V 0\^&m 3S)leẅ]Ika  TGK xJ23 siOfO|G]^^YT-iQS2lOC"?6;_8G@DôTCWX%w|f1--(qΦsL6ܮ!žtaD;dְ Iii 0+z!2o/Zn=|瓒ӣG3vv;viݞ/--5*jzzzD򲲲c< G-y{y{y~ܸ/S8 #Ika+*6_սוa }mopE1lS!zKf]AI|."l8D΃9]YCeŋ ~f<=}ݿK2]RYP(Od^8y6\pK׮R֭[w_w֭Mn/:_}ݻeL&r%/ PЯEDDǛrٗg"vSxooo}>{!Ζ#NNN죴n?~ܸ[n\F#٘Ĕߐ^|6Mrz1/BCC~miiinn̙oa=P((|_0յ߮80ZL񜝝ݽP>AAAjtrrg÷l\Vڶu[.BWʺukT!ҷc?CI°.a7Ev^~~~|oYՋ/w^#69fiOz.W f;EUYF9Y999EEE嬑EdCZGu^jӇNQ@+VS~_Gty{uiFw hn(z_+|W]H_S&OR*F;j4+WFto#{Wݻvvyw==jZ6} fcrFzŊV~ۍs/+ɓ>l·]H59[^ҧwowDRuxJJJ>8ʯn#3-Q%hF Z}a u{+2!!Oۅ޵uZh4-|޵+8]\~] 76|ׄ6C]d^]:hZ`CIkaӚf-6|㙯+Vǎy+//[6v;Fq 4yҬYefeٻ⥋I>|h˖5~v>ٕ}WgϜ=|9˥_SSEuivi5jĉ7ou͠ dz0_!¬H>x`c_NI9t.³LQ"F#P^x5ڜ9s'WXXr9s8_Y~e($_Ϫa|[7o?~R圜U(KCC;?,:uIb$pQJ6buLt H-:Y9ެG,|_:fY S=tJ\̝jJ+W=g]}-U3 ީakNa:vs!---c(C _Dt}6]PPо])lӦMFm޼chd' Y_;wt EVs>^ڤ#0_  #f:fff^T|1T*p[_<+^r)Px2|t 똖fWeM͛=6ݲe@k{t19 40l|ogCq׆X: q7lCbF2ߗgk=tt%_f'LX'Ndo)xEӇݹZ{ʼj5nyy9ߧH˛e>[%hƞCa&99yQm"#!8inǏ?+Q.|u| {׮"V[\\̗pδ93ҿ _9'("l/(m DV3Ao7o׬YzxD̘d=O.g!ECX"bxMeP𵡘E uh6#K3lZoʯOTTS/>|24&f9r\.ϙ3;f06<44tߖΜsTÆ7oB!sчnj}7֭[Pٻ;VZņ#[B>o7>|=n[c3۶RtJRwbcy!. IDATZXX̰a(ޝEUfMٗu%A3,of-mQf{Y}Ybv]^K@h$2ðY8?isΜY`|=[YY0<Ц.zyM7n޴geKdz GIf씳K*&DN=>Vz&_s)noV{Zv֬CCCCgzfsSS|zN7ck}zGJfssszzzbB|Cdg;w!:d~uuA?a>Ӑ )+?+{:-GG wAL̞]v)|e qkΗ=S|0(ۯ*{?z_̎_G>"2 ڴ#xSNIӖ1L fÆee .lіKȤ'ݧN}.:p\SOvu [{9m}nR[>iMz-2_RS#)1!0xjjQQ@fJ'?lhHp'TSSsBR`0RxeMx⋕1}A}fz`Лmh_\_^+ d,Z>42"{X":*cǎ &J,oy+zo^6~zĉlǏ{y׿eM <yϜU-lC*8]pF 5Es{ijsKKo56[3{ee3 Yr&qFܤ$TJݖھRQO')u'_tȑTVV~~/+/C >+l,hN9{ M.pX'v@J W\aTrmm-B|-}<:ak׾ҋl/mݺ|5E5MW`TUUqOe[`S6zd%lGqk֬ 59% qaz+;{VS .# 7nɷ>...ͶzV0ev^etqT1Iء-V3VT}򪪪C5ۛ}н{w(_Nz䑱!A2$8Om2qÇj4M͑Ç٥5jsT*نve[.]>LjcG OMQ*ֱLNHHhbR?|0Ln58}1;HYH)_SbtuuuHHYZ CBBjَ _6e'.jOdׯ]ƕ9{FZVhw(BL/ԗ]Pk2 Cի׃ںm֭[GݫW/T5˹ d2gl/۞Z}\[Ky)11q-.qo&gƌYLN֭MS _J &~~~eee1pY*++{Oo/ &,HKhj5w_xooΞ]ZZb4xqڴly^M 쳛6nܼi3>+\S|5fyČ6×KV[UUo ŽLM|rSS0f&( ϻZl٤IO > T|$ɧzw+++ϟ>6~skjjjjj} &fM8{jjj͝˕pۯjށ}}ǖ777'&?tHNv6[٧Q6{MڵK+K[mҒ"\@͕+?+{:Ή%/ϟ盘먛SƗ|c{2CK0wLJ}j /xf sߏ_jY^  5uVk#cDW܏:nl|J\kPl[,ʕ+O=dAVp ֗-XՁO{O)@{QPP`ӻ<~l@Qw?^}}JZü\X)h_moX% Yveɒ"xܵxZ<6jv0n3(v0n3(v0n3(v0n3(v0n3(vnE&8(u {2f~]'8>b}az<"G T],|}5KNT9: J|,[>@Y`Avv6!dݺW\_NijjzhhBEI%*l"7Y;0GƪT*pΝJwAyyyV;+GFƪ0<[jiixА`"SBp+m1ңGBСC>"PQ9BͽAlFCE` gz_|wzMZN'O^x.\0AWKJ todYsrEεY1)+-+pq/ػ%Aɟ.v_hSBp+ϠN{׋WlJB^fرcCJ|y2ѣG_|o ü[?f<}ƌ?HB.]6oaVfLm5sgށ\y}}O]]=#w~A_˜̬,ѸcǎiS^,W({]WW۳gO1ڗe῜:EEٴy̙3oܨ .JV*Jʻvի \xɫglΜ9׮XavݰqS*Ϡte%%',,,bLz2p d:(~G} i0 ̠i,Wk=016$sѰxejշ5VӈL/Pj6ˣ !rypŪo5kGN97T;³ɸGfK:|E-wHm1plBȺu_\@MΝ; œl"7YEgϞrBQTT(wjԄǵ9zԃ !---<P$m677GGEȈN ##cUDx\]N[X__w v`:I%^P3(=zo :#7֬^QpѢysBz_|wzM梅 `2O0LYiYх˗/_Ie2"{D9>Bt:-qlJB^6[1رcCJ|y2q|qyy9u  e+h4 Ԩb/:z/az맓'.4S*qRDxb5HZͶiF  |mI&X /uVkRw;0@*I ܹsZ(p./-0ƭ] HZaÆHINN~WlCmԔa))N8=ztxjjpP>E 4YʸA%J7nܰu :sh<˩mݜ'!D&B}6OMx΄//nݺ6 ! 8%x>;^Q\3g8e/K ^}2}ƌ3O inn&q%111YY2}iS36{˿]v:Wf_u !^^%e4jҥK|\͛<G;q 5j/W]tV^IYv߰~R,5xjBKMI4kd Kʳ2  ɬG6iKMInjjZNiS\jkPvٿ_T/ݻpZaa9aa) ?_Rطo/[377wxjjL_yNv 3;'O8АVek' w`rnnD^7Rci]v{d8{dgGGG LV^xQMjԄ01;߇%+\HQk2'&+|K7ak נte%%`e⤃E i9I%msѸcǎuk?p vd͎Sbph͸aHw%KJJn~}$yphصxZwcc;v`0ƮX!tÕ; f۾qV! _] ٳM];*Wz;n#J01f n3(v0n3(v0n3(v0n3(v0n3(v0n3(v0n3(v0n3(v0nP&̲P&8}Gj4"G'!aRe \|ٲP]q= Jeeر =k儐ށ V( seRJI%ܔ lŲQ|sNB;d𠼼bĂiAɟ.v_hW)Qh)mvܹǟ|el7gfʅ͛;׎@kǏʫ]v6mڏ?ȕO{]>gΜ5nj---~Ǎkee%[xw:xjԨG3moA!xyy744p2u-[kۛ0 [uۿSS ;qℭ;AHW]WW۳gO[kRLLLfVhܱcǴS/ѮAIMI4kd Kʳ2 ɦtr\MK~aΝ-.pOm1pѢ//Ykpݰqi5k׍3gϞ?| ##|mZz̙sZyPPpS J'N[VR0q"ɴcTkTJ ʒ%E%%7><84 kl-Lf n ;e9駟NBFysZ&-WTԧqϠN{׋WlJB^f5oM72 sE StNlҙ3gpBC}晚۷ْȈ} fڲTcK/lRN|/Ly-I۷w6>.^tl$ˤ.u qle<ܩSNH*a{zzsǝz4'>>aŊtVwL:n@~ϟkjjڶm[\v-JlYgrzSk{L͒L*YxNK'&>nk7-#j&=>hYZPCt#c2  _ZraǍ[hZgP=cI0:*R0 SS6*;wtO>ܲe#Qjm3:*S[[0LSSL*5Y&Wlݺa7||;J|nܸ0F  5-7;ԣʆT^^nj9h4r5N'z!L{95jWS̎ealFw֭[;st1F'QoPH-  txS (TW.qi 3q KIv x}||!^^ \7!ӓ0×dY&YP{1!d=W d2!֭[fǝz4! IDAT!f͚m~ᩩA}M˻vJҥ`>l8-&5KillT|2^zB99s͝;ysVVU{DzQu.ҥK|\͛<<۲wIi[FʴO?]u+ӧϘ6u@<^uuFcr$ +Ξ=T*U׺ڞ={wѼWjf61ٳg_ʵׅzC|BLZRWW{=7$ݤz6jZ&_H993gζ*ǯAqnjGUc<ĕ@F*A7=~aΝKMI4kd KqZwGܣGϻ<_9#kii=[n-dee M7)m!ڶMׯZ622h4nٲr@#L|BH{>e2١Cz}zgϺk 8ݤl٬׭[+&5C͛VUU):]tV^g^0J;?WV0>0ށɹ\廿S*~2Bo^[XQQИс[YYi Z×dpgƮ].'wH*C/Zϡ~OM+^~䇭fݦi7  Ύ3 -Kͽr&+'TȬĄxyt={zF6!MyӧO3 ?i\Ifڵ_L{&kP:tڲv2q"lQtD2{;v[fN FAAM񒒛nn>nw_;v`]sWGS$ #'={ܸi6^w A7p;.J-eӎ}Z/if p8sBmd$^`zw#~99v8C5O\6ᑑ*"f{Dm9:*ruFFdDxTd7lvTʣvVA?䤟~:I1e GN\v'YT-Z7ŭ-fzzƷ^ETdDAAASSӾ}{S c I~-[/)3 3N:5u/0ExwfC1IT{nTА`Q,t;\SSӶmbgkN||ŠZ9p _2)%nIHOOu}\Խ_t鑱cjꂂ$ @Gd_A^~ص5MxXh^~妅|IV Ԩ"[ney _~,icV'. J|t:TF;/#ȵ\xGLۤf)"<-w֭[;st@~~McxӶtߦ ,NّLFuqv0[85eXJʰ'NpI!xyy */&ݻãJR5 _"l3k׮.]p%Q=ztxjjpPF///BH``mZ{Ef2ߙ3gܹ'?'9܁>(qi!M;/(_"rCCw]]mϞ=m #b׸6u%j%Fa_l|ٝ?0fC\'U!QΘ=8jT}ݍs骿{DmGlj$d̜93;;Q>(˓[EcYY~M=0bÇ=<<;w:)~͚a)=zxYk.HKqݺuޝًꎨS Zmddhܲe';"?`m+?_aGmR%$$lٲYׯ[֎nVVV:thJ1бdA>Z!ꎨ+SUJ|~d[;N>B+S*e IxhGƎd gƮ].'wXݝrQ5N6;CML<077wxjjL_yNv 3;'O8АVMj {`4ڤ}ϝ>}aIH2dkP:tڲv2q"ɴ{C }ndR n} a Zv] ƘAYG9y-9sunw_;v`]sWG`ǯAqmA1w;CzqfWG(f n>p;Ai;w"g_^N}hb9acNi%\1L*ٴi#!]S-0ށkF=ϛnn\ qCK.=tpх 1>p[floN:=z>n~8,%+WG}5Ru̬>Xv9P]̑GzZy9[H]^{NNB盬T8-hj&Mzw`=ܹSP<(//OL*1J"8@ !ePnRQɷL*QTS{+W*EE5Y4l;RJ|}sD21!F0JJLLjΜ93zԃfK/lRN|/Ly-GO]z.%N7555m۶-v@|k.[D޽{EEF455۷7e0BfYaАgyF}m[IeOM)J,^?쉉 ԤfIwVKK%>Ν\a{ mdzBd;5HZ0LM::*-G/~{7LHc4њ Bb?rӚBf؉ls7؜5ӚRύ7#jRdɦI~~E[< ,'E+ FԩYaKKKΝ|G}||!^^ l!u=z W'm~ᩩA}MvTmVZHm*..NM2ĉQׯͩݤS|5e2!ۧQ&5K66q 4[8 RPT TWW'+f秦XnުGGGTWWGGGa!UUUmR1)ꄴFߩwݾ}[יnNW+<:j! PIEͧf?RkJ%>HdD6Ͳ$hتfP1[6o6 [s1OUTT,[p ˓Z3FBIMI4kd Ka S7psƐ!CziWIY?^Rr#̓Cd (@;b-gκ:sG̠@p;n1wVV[W|#b֣w"lu$@Ռm2G͛.L=m=zI2 .Aᑑ*"O/ЦLʝuqV wuŔhf%:*R0 SS+n0Luuussƍ v$2 $J#rsg|\'\^^.rs3Qj ):*#njjj,[ |m֔J|nܸ&PwjDeyerCwꎸ65MxX@4:Ϸ-GOM ߪ;jhhGGɤr7)/&ݻãJRu_ބOOOarsd KIv [7gq&xyy744غyccc^!B'_MLFillI;5m%wmzyyݺuKMOZ>I5_={߮\~Uw]RZƮ|gϞ*Zy|3WEmu+ӧϘ6u!y{B4 C=zj+2լ's=5}&-dη#6uu={Mp PZmddhܲeguuu+h22V o>G.gZvAZZ֭p]tV^EoF ?rGxxx:bBJMI4kd Ku [l֭ Nj[`oXALI;5Y2Ӧ,Y/(++`oڸIlsN kAW:##Oo&~ ' w`rnn.fƮ].'wڵkWLPb6߿OPʔ ž}{BxhGƎ4j {`4,$˚ͽr&+/^W$ d,N, ^qH*C 6m=isN:Lta2t#J.Ϭ/)aNЎ)w0}I:0̠ ̠ ̠ ̠ ̠ ̠ ̠q|p23_5-1@';s̙g-ZhEn} L*1{rruVonUț}Z/E|8RbG'-"Lg-[>@I%WcxjU\z-\aFu)~livwlk;;7kھ {#ߋV:R_:f j׭[+/ͳ5Dgdު*er3Xվf5¶{ѾT+c;mC`a ot_ztφ |I555l:$0?)1aMl!76ojjJK/GGFgdnT}}\]p˹|ٳ  }sl^oG;BI%#)1!0xjjQQe|⋕1}A}fz`o˖.+=m[n D/JIeR@DmM+Ͳj-0%plJ#"VI6i,eO-/p gjN7s>b~Joq,e,e" wfioxÇ yyy<4<?ȈbݻbŊb;& &KϠ0@t֮.}g^yKҥȴ3{ee3 ߬O>KG-8}R)S^^^Ə߸q#cnnnRRT*~>Qu/?z~(k߯;ٳ-O;}ZhGls>rKudbXBF#+l?_1CM"" N>rD6m,eO-/jƨ͛7Ϝ={"7~J-YX5E|}Ĺiox.Z6h4͟Q/,;w+/OSUgϝ;w^Z*PS!iWuH0BHXX 鴗~Ʈ$eϤ+$8ܹs۷oˣqk֬0k};زjSVҒ80otC űLѾPkkkr?_|z*>NLr XR De(Z:Bm Z`:&JWUUe}37QSYmiUп}|UZݔeXNmJF%f~Y /^}uժ/Wgd,Zr+P^gw7=rdxjRطoYS!!!f|M MLJ=C[}VVs Qbk_ݻF2=PF IDATT㪪C&BQYΕpGDP!PǦDGD`_.MިGY Z=vT*U>A㠠 nI%G~-ֈ-O{]1M{ϣmټ93g}-'KM@Mpks$rܬ\.;g{'0 };NvvCCCKK͛7F---׬꿆|MY>=S?.RdT0s%|,[wKpck}m7"&ZsRo_9_YA)o"X:r̢kV *;Z x=覍23_}&["O(q¦,hK JUe/fP6oص[nݺ|yڴ˗/7551 c=SneeeCC󄛲P(0 s:#C)zqC6gZYϚVeϟ?7<571!Q3/T™Y>gΘĄ/ \ug~mw8Lձ5Qb,+&oԣ,2ZG[F-p^}O> Mycb/SP5*Snxڋɀ`3G O<1'PSaxWagPJK~͠te%I &FVvٰa}Yiق ?dRIE!Urʕzഫ psvg-,--Za 6=QRr#0ս7o~zixNl@?^}}JZWdK\ ߶i@Tm}Nl@[  ށzn̘{}WngӞ({tnzԑ+/򊫣psv'1!aÆ+=hVG]ئiڋE~Dc"ʢ@hiiZZ Y P0˧~Vc~Vqqյx0@VB._^|Yb@0\xrEhfBb G(b/I%vo {2f~Z:2"<"Olą=h |Zlذ^.&;Bm#4B}aX3.]z M -w-1! 6&&$X[,\ ;;n+W~.Pށׯ_'455=4f4[H}fU*S99 EoRy~={bʕ EQQ+++ǎ}w`#UTlΝ; mnnNJJ|`n:BHF\[[K}vDxXFCX&GöP__w u2W*A}"G/1)11!aÆV-[iI JK;s̙gEE@Y*FS+{}ozY?^Rr#C(ɲ/ZPLV-Z !!aJ[ﵞl mrE [ZZn\VV=6 PQQA)+- ^L)S߰ac PX~4HLw}{BFmc`glk# rp_o߾mc Ailm} Ws 0Bwhll1\ῳyv>88ٴQHB3AgqwzMqqq+B Pr9_d0@`?v2,eͳOEFF:rU(/^ׯ_d P8}ƾ@03("_-xb+]!-Xjd PX V=_;w6϶֛=UXXzWHٳ Hڀ_;w6ώ֟={U_mqAAfP/v<_;w6϶sO Ws ܨ _م3x 3(.A-n0M aJLJ_dc`glkA$&$,ZxʔŷҪj;_;{߰a#hDvbgYĄM-![{'&$8R !N-cLˇ_ vD*)^C4C 4S=0"7:Wݺ(0q0׆` p;(v0@  P5Y{ P,G'p!ntkZ נ뙍Np `m::5(2|\!0:5("G'Z`m脽E՞?^ztյ@&ft^ҽ{x//N7*+*\7!Dv=wo㿪t$ { N PqFn24:6N׽{bƃN[96ۭ??W wNйG/?klKlA|IENDB`ViTables-3.0.0/doc/images/mainWindow.png000066400000000000000000001500331311223072700200570ustar00rootroot00000000000000PNG  IHDR |sRGBgAMA a pHYsodϰIDATx^`N D3 6 `51 $L5D,B c lm66 w˽X]Mٽm'Nwcg̬Yo   y AAAGgʃ  ◠`EAA  _AAkP"  ~MGܕe>P܄   ަ/^jJ{{fGAAjժ+W>x+7v_tlZe0 xs,zꍫ&~==4yGݺTAAk<:Fg$j>牿tZEAA|`ㅕS;}paU  қ /zt"  }YAA@  5(XAA+  נ`EAA  _AAkP"  ~ VAAįA  5(XAA+  נ`EAAcZcq^P#*92#VYMEy|TVEb kzXFyn[N6ii@ JѮ=,xWڊ6*tF(͗ת} ӄ4I<+}w<КS* Qb-ciUMK+  ȬYz=!PSnZ H{x9eA<:^Êe򜳽" 5(Xs̢lAA@0 )YA5P"  ~ t[3y AAAo\1˗/1c BV  _A|P|5As}}<l$+ /Qae7;E=Ys[; i k銙=zwYx ?QǎuO G5p8- CBBƏjm۶'N&7@7o8q"7rѵk;='@ۻDa駟>{TQQQ__u0ja&ha,Cp>hA|KAe E=~N.: L&m-|X05{(и#|_pݿݱc5ĚB +dI%AEwuvM9'zXexq,KssG}4lذ$&@x=xW_ŒtҔ't7lٲdYfq!| 5aN i}+]_|(cPx, YKXڵ箻Fjرܤm qƅ1*;w?~j%119r.xw8:<./###eoݺSNGYB#,W":,p]G'=Q!'_ ! (P V/EU|קqD@_Ibp_EC ɘoo.|VW ?ܳs՛B,!4'^3`KZ_ x56l8A@yEnϼQ_z%9r˫r1c\̙=;/7oёL(Ii!o݉U.|@:7|3qcǎ]~` m687x#;曩S LOOk\P ׮]k uΜ9LJH8o^n߾}Lq  0^3fLrr2 Fwvۤ^_OC$ۯj /ZzzX8PSSU7xGV&Lʂ];tP444҉'v;S7SO=wȐ!sbG*8-mpa]18 AQ3Kq4CVk]Gs[Ձ-,-GU㇏>4Ыկ2./}z{^g ZH5iFDܛk9u|u%2dxTT5xnMhoޛw7f5o>*}N"j7tk?)H0#Z[[+Jf4&!!a׮]]vٺu븉Q0*HM&Mv-Z)666>>~xG! Z ѣǎ;n8|3wy Uw|wo*uVʸ$p spr 8p`c !rI'w^x'3jq!UUUaaaӦMzg^xᅠkCUWW;.$>.tl}qFwMh;k䈡|cCMxH[AG!X~'у)CBS`Ǫ+7/߾kՕ?/ߴiaF]vnsiCBCC/T0/?9z(k{mߡe۶m!Yh{&=cG#G K:w$IZ3gدqhSio_ݼjV3>|8oϠ[cі>o>A Y nw Y8> *D#G@(]cf@39` chMhraJURǏjVA>_9Ko7I|'pA}A2dꫪy\?a[6ezL@)͙i_Ƌ^q+F 6lp駃LgcǏHNNj9K8-ħ#ϜOr ֨_sQqɶd?ϭC?R_<~ޮ vړ8mƧ]gg'>IE<Ga„ >v&= RԼ qqq7ttҴPW]uX>믿~;s$}X-Ym_8ahSO=Qaݹ͕n̙c}=&oC`ΜqpCQ{KKDҤOXʀ8QaGǏunnn 0ζ@X˷1ΊUVq-l0(TH w޼y ', O_,(( illrΊ ::,>&b҈?Ό+="E'|{ 'Ntvv5u|]Z'/?]=hogwBJ%n 4h1Ux6 ͙g# `4iOd( E *@3BJ JMMv`Ȁ q#GYh99osԪ.ѕl3ٳoM8rAkK9bȨu`C VFRRR}}=8bSSI f)l?._n;$ollw[[ZCkWS['͕v_ VsI*߹Im73d/mJ]? i瞓/oUPzء\>_+;c 4ly1퐎zYxX ~ꩧ傩SN0̀ 3!99 $555۶mG=9/dV,"de9! @O|GD52 ղc߾֐ظsN6[eV-1116GCFAx„ ڮnOHH lٲyfЬ` r޵k|'&&rGJ+8XެoĄ["B:vs+GY+ H3i]@R8e\Pkhy':-V9Hes!=jI\ˋn੟~{_^_?gƳ~Ca9`9u>|u0qզEOCM_,`QJ, g'M1vKV#Æ om Ш .+? a|Xu0`}pرq AA1bƌ| V@ݱcǏ?xUWZ$X]*EGGlǯ~~DG}ݽjf(P*/!WcJ6ovD Bu2 A :Էvipdw 7ʔ5;006bqDFG%24&. (!Bx#"T\Hr<# """TG:i;kmv?dqdE0n qt?z67 }ڵ9!AuylC"̢xC ݐ8yO]KAC9j9z7N=u'v dap@P‰ѓ{gsZTBZ"5:!%X jU-HTǏ籅A@!Xi47}X3J_!IeĀHGGQot%:BZ]bFDCQ!!t 3r#ee0TĉMMnH޻C>,+[rm~䑿?E/۵g'(gg@mt02MCA 5k|w}}ݷsnϟ?oX8|3sHm`Fa 1zxH#DRq4ڵn&uUW<b<)82bFt?޾fͨg&|c@hQ2ͺh'.kAmbLeE FԷ}XĀ?_H677oݺͺu֮]|&>9z()KTXWdXgT#&ibXiú6s: @Ĵo۶m{k}d[[ j"3xUZ o[ΚD8r#G:thTbAC) y1h(+E)`5V}\p^qfz뭷M t}ك޵kk rss!?76Djj9(&  G}|HRnR۷o߻w/αc h s̙Əo߱6=i8 :vaٟ9յ|O^wUf4k7w pPwqGpⅅ0ZeitiWa[CRR'bA$ P"tM},e˖ɓ'O2eԩ`OJr#уC-BgDH{dhGdhWtUFEXB k#Aڒ;lM® :yqOLt{ 8W>^#:6Wd@lptӎn2;qzj XAOa㢋. R/e>+r}c={n$Y̩@o~,&U% 0@C#F`}y@ᮻB##'N48*p?.]zWٺFlk[jjb y.0sY"0^׬Wnafp8L]t5.'%ϮN2?Y0 v @ J> 7]@m(?[NcIZi K,ğ\@hmkdae&QHRA9'&\~QtI)+~BhEGGȨ{rgjhwu9;:FV'S@?0SӧO>qDq)׬L6{뭷J}rÆ< VYX+Xܹsy[#~Y$X@]]g co!ӽuvEB>_`E'+ H?A!XI4p$ wֵkל8tgnI ˺:aro$sdw]<3~navUgٱq+ƍmr/޼.5辿 K4a8SV@- : V`&; >&SOB8///33E\v$`Q9 2bĈDNʭb;m 5\[fRM hWV`liia=z4!!A*Wc>`M%)2zto?˖m߽a $|֭ƇA ]:eʔ /P~D<Ak3 Khx”\կl`]޽aEAdg;n8pc(ooo?묳cDGDE lrycs\Ρ<@dMk۞&?tܫm-mo>Z9~ͻ3~޼} &M49[E|zhUVM6M*- @/c|% ->Tݾ> 'X>}Psxl;qDGKhSTvҿG!6-ADYo?f: =F=~xv#@(1p_}I'ͯkYf͌3x{@CIHHrҁ${l4+S΃jՋxtXkhhhp>|СC#..n}S<(.ۻw/`!1 ]l+$L / V;iԤp A釼psB2`SS">@;x" }Vu !AI#A1   } VAAį!}X3AAğX   >F= AAA   _AAkP"  ~ VAAįA  5(XAA+  ׸p˯.!u Q C  PWWC^̽`}\A=.p`EAc]AA+  נ`EAA  _AAkP"!//AAg,Ǣ" 0AA3Q蠔f iv*MCYNfQviEI7u*jVAAN>pab6g^H 5??_f~8A9s "}!&/] BQQj0 ݖWAd(H8WuUf+2-??5o +ڙl,H1u^XZҬ%,g4U 'q%X%2P"HRb\|ɥNb܊ ֖7ox_r8([MY^^=<׮m(dC) dd%)ZjVն"&TDdPߒ2*˓?y2ABWւAP ;&!I?;v5|aa]_HR$Z !9@yB1)e:TZp٩J&(=RIVs!AaqqUW=sMGDIB\?q5>N JZ$z(XdKukVZm&L%ڙ@3˖ N_TSRRFͭҿ~ݺCpk3g_v/xA=WNVP=HU.LspJ7ĤN kŚH$E X(Fb~3~.XAtM^{s "iLfӋN8xA=N3[oD_ VHAJaJUAP$$/ečӲ*y*5\KrHbE4zpu K/7X#䤴w& |-{8Դ6To~X{A'Op0"qa(X`=sy#yA==7'y?+[QTpi#7<5tS)Q+5`ݰa`ҤI>|Ac< Ϛ&޽{{N`kfͼh}{/zS!LH$ (Xzs%~_PgO dK9%:)%؁_-Gʋ$|ʥwR̍sƄgO_n&Xkq$ogϼH/!K}}eAKq`9IH%)yj|(X̀~.Xڧ޿#~ȷ_|vɶ<=[K.oJ[?;3*/RSќ_qJi2Ǜuہ<5/=^J.]i6.b ߮ SΛ6}:h)NE*(e-O y^Tr5\(i`XU$J8b V3`E ח`*[Cw9 /3zhϿ:-c&}SnSlbHIͽMvUcon{`Q\8֮Qm _+ ̺Xc {A}$% J)xwzG4\woryG4hKyX٩I;"\s]Y睷o{z J0| V3 V  _nra8K0s98CH,_}%hS)_`/$gg9+aFN8qh;>x晈ۯ[_{Q_I1a?\k^Z.~ڂ-b:ZWm?Z`*|9|aRߺm""7y)?[?B ?Oe7U V,<-dE\^VdG4oX{wv6?bDkw_}CCɍ^gnx_XKGLy W<6bJ]hKEQm۝F.jJ nzE9_ W\2q%s+vs#j"r})M$@Tpb<|s/H,  I*n!oX)̈VNkB2$"bfFƔܼO?mxe[Z#|CXS^Hsw~ Q.`gL Pm]菟eW]Jع~\To$ \c+EntRF!j$XSJvxX-aS|Ywp[cN|`x]zɔ]r3:;CB6ksyh3Agmyŷv$ºE</ O#YUx撏.mak?3IѭVW]8b?rᣯYV^I`B:/<֪8-rJrq[*|;Oj?KXCJ3^(\xRs*/^wЮQ l8v,qȐG/,,v$ 7{%|wλʎ#v|Y(+uj0sSAFOԹO oUgYޫIG*le),L0[p 4$ɖ9ѿҢK sH˚O?=uTYZ… a-O?k͞RWzDKSmkiiihh/WDMA%GraCݍ5zqBڔL!O}os+1{uCm<PعEBA2ѡq,|idNsM˿ZɢzkmB,g?[Xge^b;'Tg+ʔٲ([h-aaQQKH U/-d./%"*Jwq[*| #oY)p:GĆKX١ Rբdt+؄Qy,sRG"DǎI 8{ 'r 1z0~∉N8 J\wToXܠA&Mz晨fI Jb++)ʞ+}L6){KSyUs!^HšLI t5R;4ʮ_\eJ1D2 ,Nf')a6rlU aZ2FS^YLz KX*? <+>X= ZS/ҨD=o-,^0Q'J-[{b"a=Y]vCîXJ/_ [I)pcXl\8]bX?0, bZ4%S(U|X vCKHhH[ݾnڱ_4l~~{ێ[Y~~~G k*/i >,qO]5sm59_čl可~VxlȁSӯW1 1is]!mFMC B/ep\H@-c1K,Xi-MH\VR$9#~MIyŏ=#2f*\w17曧w_rC on7.ݬsȰaQ11|KK\Pe9stЇI5<>[ZXURE)g*:9 W*N* ,LYqj6'@sKTEH/sht7|̆ x&M޻nqʀx{s9֭[]-˘}Ax^ 7L/vN}8G~?=Ox9cUc`;Yx66[l$ւ7[k7H[gZ O٪iW̻ܲfTܶ[.{9s[>d'm^-tv !!!,,4jqwŞ|gMɷDƆoY+=!**όp0"14:[o;4psY7+޺¸]wյV^wϝ?~VOΙr]JKZmQrWж$6RT >UJTtW9l,tU7 V]Xz*ogz&fU-w>y^{,og9/[k ^z!X@ULJrmJ)-cd'} b,dsX~Hɼ{n~7O$R? 2/#'3Z:V'%06|ڌ'izD[)X4t2xuwXBY}\ utk8 pC(X`,X= _ڼZmǏ[]]#'L%**#l̬ʒʬ 5˖^ʌjMAyQUV8" ZpTE@Aղ 5jρvaȇU斱](IҕgH\p g8ti"RRZImUcyz8ҳHam_-QQѵ{N}YJܰ?&^quW'\qur/, iY) 4'P/3 Lw<o"##wC!RjsO4%.zI{a=u AH zX[]zjRWWȑ{E@.S.uVAXۗ^}}]^{ :Y~˸->(|$Uvqg'8|K;%`ZVo~ vm<$[nXt)#.#;x㍤i8t՟D75 =5kffνn'^u_uSEcPX~Aq?9>d-pyr?9_ V7D|j3y~k#TWwÆpAt8'OX,v{]!K $~ gY.t](Xl+` DHvU_L" Vxq8Z-ByHUSb`[k  ոǡK Vx@|; ~uKk0me`V>t  #XAAI'_~5 gkFxQ `eW@YaA)˱Ik+`c!X{UrGr&grE| zD^>K-wAWQDEJk~/†xzAADsamJEr&ӨA H]%..*aⲬ({4їԼE4EE^\O_šLI y->Lf.-k&+Ini!Ke@,a6)lD DNJI136f*2rqYVR?_6t¥]YM4zyXRT~7۩w(3o שYQ]} BF!uh(* ̖iGMrlK(me@4|Z_pb䥖ֲWfJS{9S K_:dϯq z5k  *O+Uz)O7JgGDR,JESDor}0>br$ Mj+nTQe'kA 'x&JSCsAJF$]DeIBğeK*%z) Tl>wg'HJN AzV%^ާ =S.F d3?!l $dЕ[b-]M)?~ϫJ5]$5QRH[^qAאTC"U"-=t}-j #bڐ> baS#6bGya!vy:%->[,8WIFWhKE|z xdFv!OlBNLzV~B=] t'~n'/ ]= 9ϥNn2e8]CȎۧߢ{bH"o"Y7|Pڱ1`tWinTGfC_XAx AE٢<;M- 4?iF/A@ Kade_ :C7ϑy B\"`<} *@$.  _0՛j SA D^!X9W43 *xqU}FY 48^eao"vi0 H ó,GtNYa]hW&))BԘQ(#WU} UO3 ⇃ǩӺ;(M ȫ q,Wؠuv\qrx=21uX{@EZL~z}5 29`N)d_}M|, Lp:dϯUvn[~iܪ~Jv7RUcL4 },SBU>ʖZ*zUi"osF=k MDpV͂^`+$g> m4rиG[83&2$26Tr(@SI6mxiJku_BG\:rӨSa|tK#)QHX[fgy&Sw?<&pb!2L r QEⶐ SUR5kČC mVH^RXd6]WqFDj+$3>hrV]529qKEͲ% ;X(~pۦaF@ b'aK%y? E0)lɎ"%S@救zΙW#2aI`(Y4tĤl ޠ՚ ddUKOZa\Rc uQ n;n'4tC| aU_Q37gi-9nItӚ勩D͋pqN0 'C<^'r36S,6;7OMlt @ݺ5;>n8{o~2n e"C3 $B5$)5y:@۶caưm9ݚSۆmn^ޤ: ABVos XSTR'ÎiM<lnR/wN7 t>a zkIVqn̔}ϱJ趭XImugw+^jn^<!X`^ _Awָ۫R^B;5 eƢG]%VffJپ$Н{UBӶ:D7Ό&Z7m @+h7 2't{%0,Lک1cљbP$5ULEF&o7{U۶XOm[Rvmnw(:8@q+ˑB<))BԨׂ_۫-)9LҘhd.I^f<3䤗M^UL@^Ӷ:Dmjʂ$F&Gj[UEF^"}& ,z7O/ryXe%ӣ,`id#p#/Xh~u_o胋A+fu]W]>r7"=Ú0Pч#~ׇG1"AÒ>>&H]`YVVj`EAaLYj3ٳ}"JzsSQJٶ#H:dϯq zUv/mI{d|UdUW%qYʨ4 cs/]* A^}n5˖h_Z2Y&p2eA0,H'u^@N~6򕮰=à+,QUrn^J"33E-ѯ @&Oa_zxsye=km0#ȗ?x D F*Uncl 8Ҡ_(d|OD ZW`{AWn!HX ?AryUƢD?%:3dڳT rgo&oc#Şs+.`n ܺb7Y; {w)dYԯP+b]1S("!L')Gya!vy:%qr'7ߖ=3KsG\ *WݺL%}!/ίAWd\7\+/f]?5w'B_lRBR? _ t' -Hwf7gsv\_DĞLAv!xvQJ7ȭ@a .vop.&?XF.Zop_{z屃D:TRۺ2 20誯חMgfG[JXOnE+:x(2Im!+MqQA/A޽Ў JJ!d- b#?t@>J\g2qΥ AC7/ oCBOF#ҿ kw@{ZUdBA`AAį 5k?HHkAZAҜ+w"؛}A1ZVA" ]GlO6Ww: "H?O. A ϤX#Ӭ0Cv( nҜ2yXR)TxS5s+c䢐Mn3X#1`v 08h<-Mȫ qs* kR2U||$PRilhlKCK"H?/ A@teU1˲J$if|lڢf *11GCn  m۶'˫g"GDFX_e9FJW3c8)dPdbZq\AQfCB|Z>JTAZ[9 '<*.'Zh>Q"чѵe_s3G {eȨ1a|5+h~txQFVG40?BAީZnLb#ܦǸn %@{k-4k`LepZYd8ۊM^dT݂*ɖk 0zÊ ]<[` >22DZ=*% DlȲOW}XA}X'AWwhm|c_ĠG2"kQ炕`FC2]hWȲR$ht"gIIvI+R,'䡋f,SY},i\\%h48 pЕ;2n۶GD 3+ePzL0 ~[ݫ߱9xY°l)loɚ,[Bi5ƒ[FHۖd+.H?aB;IGg-1AԊ*;PJ)zk]#D(N<1x֦p:y?#ⷉ;Z0sFKpxrߺ_f,hTWMua 2;mEtMLk]e&[,BeRHπ݅TƁ&k<$J‡ 3?l& ޶Q L< С4!"z iM~;Yb@'q\ iQ0`CDµc{KcD,TX3qkSG4Ămb`lj܄,uXAhXwJdO=-.f5ulTv7uw'SxF:fPF^G/\ Cbw 3^V'g)ƶ\[]si)6h-$JcAփ`}dV:6uq\2Ri DI+zH?UU/n,5uT }BO&/.t6Fń ;_fe_?N GEvrU|JaӺ'.IcS%+ I؁,?ҷ`2h#DDtgs[Ǡ(؀eNK)I/wjf+s 3D'Y uͶwb6ve۵IW;}ʠ#-bn/]{ȸD[A1{ r>cZͰ)ckhHl[O݊|>VLBbZ θ\uJ8[F2}).+)[L\15%3@Q'GO njIbJy7h=NuFJʏc)Չ]Y_OAQܦd~Lmڏ:jhWXGHThHt5&ܚ:, L>4eCF=f>Grf RA w}V#zq2 {s0s+*Q.0,;TIeK-j-Z&ކ(,k OghcR 6TPJzuP{2&rQkk@+{Y&xzAB 81,]bHf8sͮ!?4#GZ<*ˀ3 0yt%*!$:<> I>6xonVo0w̳~޳g#-UoA(X3Sx;2CB&zV`Z[ˆZ7twVP6fd2?&kDkAZF|R_54zȘᑱ!Ш֮P͐9$I-sByXR)Ia8 !5(:E87R*9Gs;{nUYpҾh,n!&ZE*YVd3官4fǕQL_q+M튼K-RoƷKgݚ +8 R>BwDE M뻄'u867 2<~/}?N=f尛 v2h~{f'޾%z jhXf>Hũۅ /ح7n=VDŽ I!֖kNraCP֤eC+#0Q0'U]l 5as y 2֫9+jځ7]!Hc"Ipd]Nj/+5e'D|d?r҄ ӟZ~L2$ 6 pD2*>6>&iE%42W3,C aku7& 0@>!nlםvBh응OWY\Y#]BAĀ! _LԛڔbJ LR{5АyeJ=176Q{È hl l 5RVIJ-=qjyxyo?5S[YLm?VYga% ws{Y <"ݾ>y%@au; Bò9;[i ? ;(KWDpqX .Aט)OZ{5WUQ9 _ v=_I3H8qa<$+ЈS?_|H W>ㆷaU;Xզ":!X6DZ,Cڬ1KqajkpȲEhnֈ7 n[t* JlJ5nkA3o15v@<#)wA*$0*Uǭ@;gu;G‰<8hr:Fћؕ?Sb%SXtG`8JϾ.JL*u>PKBW"'0밁/j[C7-YtA!{SYFUZ$(۟B W)d`#s9Ʀ F̘FVI$!7IhҺ,E\c\'}]%!G%b^ 0+0>&7u -Іb0%y]ƌK᩵KY[BڔJ^} FH@4zB2SՀB!' y'twuY~Hpto xKq._,w@9~|4}t3 KP"wu%7٠'-**Ie.JQf&!F3S:1Ru}W;.o:ښI/xRz\3 !X63 `svuz4"qT(jҚ(%T[ffJbεeO) Ms! AV ;aKĠMS&kS*2<~xAA`e3 $.>CCp*M~+B?daMJY$O6hxAA{ޠ+aGU<$GP^=!OC/pUCC AW++ࠫ@xU?%%T b45dD*S UBf|`+_yPk  1 @M̬ʒJDLtFCRfϯqb0;  1+("A|yU쳗J &K/tx$唹 # 3oZ+&\i!æ2Bb4 uJf%RD~<;\c%KѤ-di8FI@Sy;MZ>b:ݽ0U@l΍,c5C7A p嗮*=ZM}X]@׏Y:g`ji Be ټ,'G(9*e2i[bȄ8XV^iP3vɋE0y< >8 | a68 2(X+Xe*M?h)L4,v6c{!3.K ؊`j2)"AW̃@tf,[;ÃT%t̠ƕjUƄ%)|Am[U +JR b0S(Zd hAAM 0=r>d ly$ĥH@1H;m[ C^; 2U0Ş_^eʒsJ֚w8LP>ܤYzB/7Lcr4Ho0nTXxA\{Ϛʴ0TSHj,\R,g_A-T.fZ(E"!@-j"{5 攅$I}MrraMP&S];)-kz̩&cP@eDqvj ǚuI_@NY*E "vB6/2<iӗOpS;mnepAg~;>{.M;) Hyj5 ;I9bX.&*0RR B~u;iIP4[i-:^ SL)M^[L; q0]:Ө $,/<)b_YM~ cF*Vo -}rЕqꌁ]cK4C7\^@&8CgLNEb\l/t"Utr_?5SJl Ul* iJ⣋ AWQD3y0S ]^̓h yXR)=Z~|sR+CkA2R9mF5C=v" /H}X%J+Y(eKAOMY.7q7^A)`Ļ߲x+-e45x7io |F֤eJDD}pVYIe>lj H!%A\% ~6 32OM r ,Y=ڦ[ n 2tE,uuЕqT3\{%*s^X!NseamJ1SFu{?^۠~D|f&-6 GBWauC<^, z,S!/K##!j GX+\KЫW_!BAN oj^?%SWsq͢A>UGXIJMd )\-9IiddaUe?.A񨒚*X"Z8$ Lt4E{ݔ5H.Nv: ZM>_8yo:2#3#ׇTEr_{[b)c8AbBmqg_ L0񊫫)*\k%z) Z L~oIj݌%TȦBE`!Ok^ʥ17oBTGg @ dPT;h0 JA|6`ovg= M4mXnH}C<2|U{ι'k[˃#dЕ[b],(Nk~S{;yX]L,tڵ$1 ~ “t#=2rKK*DS SShLndv(m5DtJ QoDYB]6}|b4 uJf]ÂgmX{su1QTasA@r2#b@Mt ŚI0ClBAmCAI)^\TȁO9$swDǢɹ[;kn/(P9p/7{@1O pzA$@қy}euGX=?M5n,GlC\!\:K z hk+YRˑz?ȭE7gezp7nof@[7>A0誯<9k V2) Ѳ y-W)L?Q@+7gx%$.RHt+97'A#B#bJOQr4,) XzA$W}rG A\AHFd|2WU{c0 C3tf`O^5;+!֢CY^4igF41W{۰4_u@S.>iY)-܄ Q;Ŵ#,@U{'UK2턂ګ*\^[7֢-ElnvV= U砱hr0vhA<2j>c!$ Ez 6 &MgѽwԂp8+6,8šҷ{&&,J :*;hlݺuuuu}t*KRKivT)B SBeJlܔNgTەHldau}X姀0Êa`nh94+؅)A-MA18 pЕypU /] T$  K0 +2 " R_F$lQe9mKu hPE!bNYHڴ,GS\IÚd)7:ı#Ig&kیB. HJLVRnS]F:9P6p_6S(OP.C)8ϺÞ_$Զ{`EAUvT>PQ@]׬", 䬢Y\D B,)b' TTSwCfdnjZ{\sS0w92*kmm$&!Xəa ,,JK1M(M^/̀i)[~0]:XYӐbZPIFoj+ujwsʮl[f ~j70NR|DH^? n`tUA3b!d:Bb?f_P+BQ&ĖW^;1$<[\&~tB|b⽀Yh0o [ X}@u KxD^-~Ds[@}=zH騻G? I>Z5mcl ޽&e?Pþhį<2([h<7o o~`¯[q OGG7gxnڈ??6s y7"H 6ifv=r ,Yփ 7z ~y]W"^a%?LZ,ˑ9;d_.KamJE'#nN76"~txԯv"ҫ$.HeUxX!A6yݟWҠB3ƞT//[G!)RBR^W"ާahH! 7(:aMJYf>x]e-awE/q^5!{Ρ$.ӓΧ!mb.gɢ[;9F{!QfqVH2ԇ[tT>0Ls n2*FY!fn2€Y[lդa .v珵v1;2#3SHMz5W黥;E:Ŗ_ae%Jv症)L L~ojquus"@{U*윐&ôpRBRt@i)'v4Sk u>Pf\`:5$.MoLzi, O=:|8c^=D-J_w7ϑ-}D W .Af)b5WK`@usĄ{l]7=_3 Gx[xm{u:1~/6OR^QcؽXc!6*y|+RN AsttQS{DS{DMAj̰QhAA$xŋlٲpPfX`'ӠMANmnn*WWjx7󒧶uյ7576RXtxKK˩'ϛ\7sBkd>Ԁ#sUo4_;|J99ԖSWevnPcPMѨo$%o3  6e5++Km)X?Ǡz~٤W<襔1OREQ|3'I(kίOTT=_},V&tسȿ.Ap*xi*zK2 ,l#JWIjSSyUs:9@ܥF'Nrrs0~!o3 )Ӭf*6Gi wD$}W|+7%Yth?{|σ|3WH"h:7kWk+EGʣ@Rr*ICfF!} *s[JJ3B4-T[4;?ogRKL}#~up[,oN.ú1(N>ŗ2+J޴xTfė7{"feK 4H'9!- m݌q^hpy\5֐mWm"UGG[ou 7q;o9ݣ1e8Pk[>uv<{ׄ.Y_r]t-ɺ{B@!3 󤞠dm{B lSv)l*syԙ SVd-yܠPyT)OUc+Js0a]@]'Qk(et ݇G1"AÒ>>ƛzȝKn{߶/ 5_r/|o}T?*@W2Gl /e_M$/"_Q7TSlf!t$K岀\R**tEZT#PO,XX2߀+]}?w#) J r7bd_4[2'KXml(N JR5jA֯kܧ7 %д,,踘h E}-ӶU[iA,X$AW=zHLDt}sgrXKSkKH$.&ӗ\JF_R>: )2 Iɂsru2wX(Lt4ӹĖ7奖ZE=Y?{٫JV% `oD/*|yXn1EB,}td2+޸KW[yJR"X`yakH^^8ixL͵:.j 9ږ1Vڇn<O L>⇵7p"jVv]mHnԃue(,/,$v!)X_!R#ed͓ 0 . UA(7e\[ѳ!SBАEauANA CҰH-. w #.)v)Iӊ;4irSV6!֜!2K/`/$iP^>Mkr^mÊ TZXuuc{#X,K[gꟾ<͖'F8GC7^˷%n5||0d'%?FL#r}:vx! l{!/%0)%Z )-}@4d!_}Ilb4ư6?U>5`U&6a7-cÊ ]|*X/;_ #&;ο>*<*,$k.H9oҘsW񤽅)"y8=DE={avqxڌQ{J4 *Sk ؛n\ ҷʶҁ\6ԸCm.䭺r!04:h|6akѶn[i">L0qg= Vb$tvYgN<}䳇IĿ߫^}*PqP{R& 0j*y//f.UgLLFehJwnf橢7kqػn~٥Ф!Oe%=.m赕 2k#H@O_<=6Ծ[" A7vut7wEsW!%dz;Hm0?S?]˰3-f P] 6r~go&!~i m ~|=K@xd簰ѝ#b;G%!:G xĤaa=w{fRfe5ӕO)*I^VjU-4V< ~Vuewk?i[@~e5l?z>=7C8%SJL"Pk -bs@Yﰍye-}XQ"j>!kʄO^O[/_>9v!c?zh^eGu0@$khhh{!-uzgkWk#KOT~vבU74XPZS0/~F5*N&ZmJǩ3NBǐ`Aܴ[M[dʅZ1Qoeړ< OP [JkscKF(t {K9YaQ9تmڒex!U Q(St*QFDY=\k8IV ұR1Sg1 SZ! ew2_>< ?} @ZaS|Ywp[cN|`x]zɔ]r3:;CBV2rAϨ?Z=g)`dkrlU hB=kް$ 6B̤TɯZl ^D;|q%N W~1yxC s|*67 )˅WxMnZ1jƍ{aI[E6=>w62r~@k1jF2u{K#% <]U5Ê+?u4on7mG7mU7,@5I3Ҥ75ՕBQ&Ki˫P A >mI~,О_?j}c&^td2s^{P3kWO|| {#QY g$bֽ#fȧŕϮ,K {K#0@X;Z[MD:vۙڪQ:δ8rzZK}hIaU?ݛ}ё,H ~]+^ f^#.eowkIǖfqY9!9ހ\W]4eY 6Q?1-%vaPyBߒLtkOHfv[EEIڭaӁ*ӌ}~ӡAjBcǤdžLJM=p~9tsI=?qY']PH.RџJR  a;>fTi֗l7)*T+kG>EqLJkm;fmnZK oyqfܢ l}}V 1Ƙ/1bPfauaPxs $>Oݣjsw۶Gta\kUÉA1QFOd}G ʏW1R4 7DYDs&cDt߄Y?Ug*hIyuz%VfL(~f=(aT-F-YTZDLDEK{Gqkժn*,jffv^Z|f+PT̰O?ӬӬ Xi^-tv !!!,,4jqwŞ|S_ /H~D\_j9RZC9GZ"J%oBAKQ8a7Z Jn*VS,g&K=/ V.hX:s Q ` N/GYY4&vJ<Vk1hFݚHaw:@`gZ` VA`5I 򿌎i ? _Zw17! V"RD&k¸@ V ;|#b@2Toc0#澥e \%C~ |A +!|8̈i`'> Ms)YAx!!X?jy痑/+~mo.)eW}ſ= @ r8*']j6FhK@%3)gG3pUCC ?S4J%sU qjfA|bp_Y/""FB| 1O(y[A.bilK ж*lQ@=Ml5h[W A$h`y*0 *42e4\tVcȭ"o 2UXܯIt%\ݑd;těЀJV!9rB&[AF!'.ly Wt$E獄|_jy^D|ߣkkXR<[zv{~&u[CUΈU9i+k Hׂ~LJ b^ё!m]6KChivY!1UvOJ* E)4Q6v[V3җ0ETQ~x.xH?M@z-yMޗR 6Sz)-7}%դѥٞۋ*YX$kVܫm\C5RmEnZ A$`N=iӦT-1lIFKaٍIpɂҝ HMN8oi%Cya!O鼽)"q`MA$ViZL"QS0/OnRR,zo$dDԄkY$@] :54Jޫ:hs̸5h[F:Z*9ZR#h'םvyX I =@n޼yժU]]]$% b/LTeٖdiF_1rnXJ.QX*еXYWޚ2{U{ M 2ף]*鴻L|+M6㦓mF-{ APQ"Xo_]C<%6o|jxccBb34NVM]K6)Jb~DsZvPR\,cb< !)_H+Gj7!sYt]e<=@ЊM pҬ)}˻pmmmbmoE0Ҏ4%D֭['O{RpMͼ\♎USbqA@]psYV~+A^;m?Q󈙟Wzgqw@$(}h]bjlGVP"@ > WcqǾ<{l|3Az qBHJP" ݢoG3W_uݵtƎ7C|vx2XFAĻ`eXL"EPQ" u+{H 5??_fFamhh؇AƸk`ϪZmke.ԘpeD@ DY#d~RyU\?P"(`Jo5mS[[::]9yvTlHОR| _ XqMnWۖ3G`E0}ЇuͫVHN<Υk]|6KIA\ tZ+BC+ F+  !}3+  +  נ`EAA  _AAkP"  ~ VAAįA  5(XAA+  נ`EAA  _AAk,z{=y AAAU9  AAA۷`.  _AAkP"  ~ VAAk$k+z VAAY;x   gT&=ZI&aEAAu iVؕ5!Xw_ϲI~lڒXAAH"ՕZ ՏxOȡz;duZ4'CAA;T r l*1HNniSYZfAAAWHLJ\iVC  M$ʢ՝`?Ѿ;Vm. e*  7UWaydf7   ?e   >xX6  Ng&AA}Q%AAkP"  ~ VAAįA  5(XAAƫ =G(Z  xF*$&|,H-! eZAA$֤Y’eL,["dͼ,|ro$ثRKiԼyjٓ  H S*ЫI =f"nSnLHFaa RX@FO"  N֤Ԋ*;JRܨIJʈ2YcZ@:qq_WMwp(vBi HP Wl@Kr#K 0 V# > آ?33:BRo#SܑٝܖZ_obn]w2ݢO).]5f6AŒ-Xʤ͍)ksS&*jKFӴo*˒ qU4EeܭWES\&yUV4rSq>US ./f%JlMƞM]%{OpVXf< "$EڒTlUQfCRM'NYa?%XT]P{{u[aݷKou5WVA0u^gp+/N).w_sÓ'O+~ kVxk1Zy.ٻ`u[ +CmRG0T0-hly@c]?U+ín,U4%gIVئm-+iQ4R[LljqeX%4Te7NG;Q+wb'HU9gy۲[l,Q8|Bn` &[B051~0=l>Y:^JZX8|f_}v8U|US'uUڔeRkr^5f녫RluNvjNJ)}}7T5> <6h4l]`Vʨަ~jTdXx'Db=ꩼZRfNfzNJL̄]_3K_mN`od|ָWR+[6ܐEGO6L5VGfT(ۉ#m#ڣW)(d0zqlZ;W.SLmmg;}A t%h%;=3AzO͛-Sl)xó]}wCwײ[9˻5>ihM,X,]]T/Gq1\Jl'--jt 8njW=S*MۇFDqmZf/e&> 6c&Ӥ;!w4|u*8KH\DX^X94⼚u۷Nڲ[VrđsYt(7KLRF^{VfZj~lwKec3|ЮJ\1[n˛mɰ~ ª4nՕk$ d aU|lRl4^\UN\"b2Yb"St,IL3jRU1So7۩`rT劮IНj-تTLI 9==6 TjT~O|D3؍"\16X߭ۅV}5-8tʉ:ECM%4/όA)Tؓs ouz^L01*GQ;-j~ TXk7(z:w_s`@*E's3CV}ʯUǓ'O G-f$d 3jeA+j +pΤ k_?]4VXnW]Q`UmyB wAj#}*yunqWP*ouZau'3@tSRsRy͂`X)kڦ ˟Znz&v#cr<>TXSzCOoKUsf[N;t96rVAZcsʫ#c'n``Ώ+UW$U_C2ujKNzԙ:bF} AVmzpUw[&Z34΋XzqAkUiMmK;[sEWmYV鵜vŘ$֍ |d>|5^9Gv[c3oѬ*Z` ;j~Wp N9 X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx X5+F`^#kVx =:o_I`}_\Xp>l_ X5+F`8^ڱ]׾ly{2 z)1v.xGK&T6K c_9㵕;ݙ(?}7äH`ro&ntȀTvppY^{vS֣MјNW e"9i8ԱDͰɟқ4V]ܙԃ 6#TgTQzY1FK֫C*4RQ")ߍBEZUҹGTq'U=[KpF?r}et]d%;+ ֢b睇˓lb+ #);l,T}%3QS:GJmB${+bʬRڕDR=37D*vH{!=Ǭ"l}2C9.Lۯ4d _^=ܖa2&>niF`Hcs6q;^[S債dzm :b)y:ꩃpT >/+nBRt :^6;@GY*epW.f]3w$>, p^a"ZnLb%d`RӇӡjs`)aWW:dK~*~%] X`Tw:_kqEPj.ףSy&سTd+nvfv6LjiG19)AvD'+|UdE;@ q'RNЕr&U1HQ'3 +#u+>Y۪PתU,?}xE=t?! (w8q9KTTKx5_)7|c _VΚJQɟKY+jߺu}!%Ei``PTX/*TXK7A?ZDIENDB`ViTables-3.0.0/doc/images/newFilteredTable.png000066400000000000000000000253001311223072700211610ustar00rootroot00000000000000PNG  IHDRAJl%sRGBgAMA a pHYsod*UIDATx^_lם. ྵEQM iqiz@[,-hpɃnYhu(l b>XwDf@41I'Qd%˲;sΜ9sfw/9sp=sܙ{yZog [AnäAVֽdRW_MB?~vmά,ˤfSWJ7^^EI ^9urGW_}ꩧ$Νo~näH /b>K`?/}>_nF|;O~Q[:DdZrF|}g>#t+5f">+O=?~됫X$C M$S]+?Enxf%.Rpe>Y~mؗ}UgzR_s{wkϼݴ`Y^S69س:N WnZ^m?%yD~lJ%us"K 5:`K^!\͖e =^}kh|u0HX?b|5V ?d) f,ɀ$ʪHɇ4d$7+-d1Fs ϕɾv1wh,҃цl5;j&</vJ<#/4+y=J%_I}_wsbYҖt|6IF-~HO@هY9~<-m^v1`:)2Ys`nXrU~wn9Y~5f ?W!d%+vmMFgQNsG*>C쓬=E&v`TOc賗- H" eVa/{ןu>sͧNn3d{r<@z>Q/ug"8po8F0;vm.9` m(r.gSS~,DSO=5{AYKG7r%ywzגJ22ciOIV|ֲOd=)k1;e;q{~st,f DYrx+P:4Y1W MkhdqqѭL<2(T\~wgk>N@?|UFzU>3E*)wI Fk;m-J#i$H΢U]@                       +yKn%P5eS󕔲R&qk@JJ4k/Uj/s@sbH7K-7^;Rv?Vx_ dM\K(e=%7;XLt;'7$r {Q v-S%2*5ZUq h/Q%7/fܲ)/'x W2w(L4_!5#Jw&ԩE+P ! 3GZD%'GV&@(ȿk)r#?#@Sc>`cC%'JTJRI*٥J^9u+nяVD%[Cޡc`pP2Ҡ^hyVɷH|kg%.>~N`e9{G%\C >diP~"UD?`qO@W;*9J^-6+i%]HMLiL RܞF*+iGܸk(ٙeuyh7De#A3S1X,f~65ؿT)k >|?}_}GKĽlk(HQjFҡ =9Eǯ6t0Trt˕.G$+-f% n=MvtY;x4'f, *9J&[8;-Ց3Vhl㭅{Qi2*9JswI {d"{q ~r ݜhDFǯ$*9Jh{i?mb*K%FLoV{r63W:%S<_T&5jUPVr\%4JRəoC;L`"$$ /8VUr/|llD;*ꓟ$ $RPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIS߿pD%BUJN T-$w'{Ǧӕ|7%Jp@ȏc'{Ǧӕ'S4*Tr앴'}Dn,*Tr:|?OnnnU*yPS7>?#wܱ#SءCxeSV0Tr |zO<֫+)vi|Z0z#hkj 2&z%MtřTrP URno9;nVr!'_I2{ } d$9Lc;[Gw, 23insa awO(?=[sgz0ݓf# KwH]?VRϘZ$Kg*m_ fS*9J[O}S+q'ܑ.v16sL/r#)ђGHUXf%7A١Mnm cE ١gLO[**黖%e4LSH2PƪQwI#ŧ?>ȍ&VI??#q`OBDsDՎU#ḐUwhKcj) v9A'MhZ9Ȥ &ùtiŧhւz7-#U>=Fvl̉ 3тYf1|hF [Vt,H)Y+)]pk038 OA0)TrRZIa>^7w[ᚯ"JV JDf98kjH p%* 1˲q&%36GBR?f_ɎsgK\ FxpVG% Wҵ&#E[<㪔px8)ːLLy)]uF\.{>(G-SdR@~EӢ#W=WH,=] Wrԟ)$}#OL%4Jd)%I & 33np,#;-7dȢ g=ni%e-.JHI*hKgeS?={0n&>.iNd05cdpVeiI$D#իWwvvvwwH]jhp9k0U"ɑ S WRu$I\jK%ם&LJ@%* * * * * * * * * * * * * * * * * * * * * * * * * W_ϯu-͕D>o_{][!<:x~kRW"W+)&y罇߷'[{sG銰_mr=+][GoWjy%xӞ.PI lVsKA%͢8pC*yç:@?[nhje[}h!*9d*io+r/أyz8XYr2zmA%H%%%QF&Ok_ۥH3AgUτ]Cq"i~$Z(!?2SRXqD(9\аB%𕔏M[4o (α˩l mŅ R{I%;lqD5dNL%a`Q!|%s|5AY 3&\J [53mV.e|#v9eKdZhrZG%*,X ?~$!%#Qf(=\:SAiGgSfO|is%v0<:~DWj@Wt\`0pE_=FW)TrɇMYt½"83{bNgM^fřkDu uχCy+gfOW5Trɷ}ܿ_#yzfQzu]C%g}mUש83{bNM^+P83{b.y|Gt+21ub3nV]]PY'ߦzײ+7)s,yb8PfNM}gy˭)fs=^xmN+P)q~_1XbzoYͫ*9T_߳<9?='Y+vAկ~}L6Qd[ݏN,}ג$KKK}K՞nN=ZC*9T_X3VzK̂T3/VBPU1^$&"M {Y:$'(3S)3}9ŭvy}u]C%g]?ɇ#p+HB!iF#'DQ.wG]M7n5pNM~b~ĺ|?҅W*Fً:KN%=Y:{vɜ[\:r+αQuu]C%g|-k|Nt@`ґ~N5Q䘗g_qNwo, SnsfaU]]PYg?o7O=}㒘;rĎ;8~5I%^<2b7'xbn~Yw֐pqnX:aM̞X#k䬓oSF+P83{bNME*yb4gfOUW5Trֽjȿدw\:W$0gfOu u~_Zt\Z`/̞X#*y\xQ.?t\Y3':JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJf+NDB4ܤNB$9raJomm)/LGtյ5Ɔ$\u`*$A"ɑ S WڄJJJJJJJJEu$\NLHrTC{]* `$D#RIu S"!PJJJJJJJJJJJJJJJJJJJJJJ6_p 8y{SKVpI% %"T.Wv7Խ@J%?+G;Z A%뢒-C%uQɖPɺdPIDd]Te$"ءsX?43 \Y>|[C%is%6^vza+yad*yQID]IF/f+6I-Ȫ앛U&3RRɃJ"J6K%)s'0fsÙTK$"mcci/%&V-C%@% {$2HPID\C\c?v%F%[J"JJRY߲,/,>F f^I)drHcy `K‣PɺdPIDd]Te$"T.ޖoEJ5H؋Ato- ϕ܀Oj8M$( /Z%JQɺ$nTP"B%{hyC[ $d]򓚽rT.*2T*Yl*J DJE%[J"J_U`*ŕewMrA%is%_|xz1Wi%[Xf|_- B<~/W.;+qTr_}pî<9If^:3Gn% GnyNnrc8X:MA.#r&Kgt]v]Er&ܒٖ!$:޷Z+qTr [wݸ=مN {gc{eVUR>?:+9'݊~bʲ,گ@ɈVEqd2*9+ ׸tY~b%{n]{#5K*.RoW߼woqQ:8w[=^]2L\2C.Uۚdw[uȑ24b-Y5[e91Cflv£pz2*9+pȼpg+1WhRpqk'dS ?3bӯVz:J!ٍ?~s71g&O{ 7Eo\T*y .wEyQ;rdn2Cv9%ڥnʜZx*k kO6'쎯[JCJ{lC.sܕq+yQRTr Oڽv̪Jb7:@.έ4۪^CH8v~sg!YUIp+&YUɎG%ݝx'[ ˔uxh\o5@^C<7ow[:bZOߕ ஻`0xS[J.P.o8*9ܩ]ɒF[ ,MC~k1@%]F%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@C%@$L#> !{IENDB`ViTables-3.0.0/doc/images/propertiesDlg.png000066400000000000000000000240331311223072700205660ustar00rootroot00000000000000PNG  IHDR#\&sRGBgAMA a pHYsod'IDATx^m]G/Ba+74 m$3ZVe2Vj./˗NrA h8G&!`h2c;;Nqx_u9u9uvS/ԩuIO՗/~)>#t M#$44BR@IM#$37~WgO"Աs?f^94B*д^zi2ܷ{<oG'!1vbLv䳫 _;c̅k׮}79&nݺT!AiBeL7A^Բts*-@[k`ü/>"س>+9s14B?lĴN ?gę~M1G__z4k3|ӆ/|AC%!W3j&l۴߻?:yy-}_7BNLr h4/} 1>:?n\?3_'ȷyBJ*m`ߗOe &7Cӝnp껸y_ԦgHl?S%- ?ĎPfʹB1kGUߥ4TjtYɎJZꌒ4M>2[ٝkuSJ2fg)eاߞ|vg@H6L1Gu9hɆ)BM#$44BR@IM#$44BR%t M#$44BR@IM#$44BR@IM#$4lô^xLK]__ǥ7mM$q?Kf\+mM#rٗ.]z~ur%xkqg*mMcHެ>w͛7!;Bn3g6b˗If&^yZ ȉ(xcOlôO3Mk)hдfkڕcwhдf1M,P~dM{{UTioQ) {n 9LܷӟvrlsV8 )Y; |Z޴c1['쿞>hZgS{|jϞLi 'O0y41MͰg??g-z+$7^6!tzڙ%BP jz %ET}Shy`v۟♢))Ꙥ7vz3*U.f,u7, aݢMӢNrs`0Mɤg ƣ6LHTubFze5=4H@k/'M ߫b\N:+LPEEل@gEM >=:+H>nX8mLr p&&ZQ>M9og"@GPY4vnZ^Ջ F9`{] "ߢ~ρ'bgb_]*oKTijB6i < t;r5DE7UVMHhMON-xɍv73o l{V3LGi7$Ղi\7+Mًl"l5eLSoT殭^{Uz?){rM$m[ԏiCřnſ]VaBLU 7ӵbBW@3I^!ShgwWGՋ2Ii:SAy)ZEi MS1 ߾<$(>Q,0-Mý+QC;?ӈi MSe˽ I1'qoo#2r%xcO5{7+^~e'qFn! i2f%iFH h!)iFH h!)iFH r3m;!d8$5:РM#y4' M#'댖`V50]e5uBRӟiiSN#Lr)V̧H{ڙ İAkT;,xvL3( lDBLDEm$2MiOBUUDW]E@鏴Oo+=zT^hb .`ԍ"$%IM#daiFH h!)i io߾zk!@YRZ)!iW\~;w'$s$%oܸ4u!)-49m.Q )-Ѓir 4ΡiFH h!)iM!-@Di$K6HBADi$K6HBADi$K6ȮY?tpHYk2uMTSw.4͙c"RC7_Y:xK=Hyi?4AF *m%UZ`[_HWEB.bH|?3֚Vnd&h"R?=*AeTX?R̪4 ^Ds*aU`ODf7ҢT`aO/vl gw*R%B%GI޿H K6})%Mn$! ]"дF%Mn$! ]"4BR@IM#$44BR@IM~KH#H4m:4t@ӦIH#H4m:4t@ӦIH#H4m:4t@Ӧ@~K,Mo[>`F6Ch49<IH#H0M=N5O}^ZWW# vѷQ`1G(VVsmZiKiŦ+%! "ǔy m(dD ]"4+(JLr8[ ֺF(,W>v %hL3كִW=N'3ADi*jTT25dF!SD 4BD>= [.FdY_~tܖi/ed sDF %BU٥pF%xLE4KiIH#H4m:4t@ӦIH#H44BR@IM#$44BR@IM#$5Ν;@BFLv.Q )-ڴ7nlnnʷ9s IcIׯ_r)!io߾z|Ӗ ,)-4BFH h!)iFH h!)iFH ϰW8` o۽[2Қdidtd`uLszҼ0V|>)LB?TO5PT0J:}iU]Mzc־!0Ӕ lU>FT&] [tFTۨS/T[ַ0 ) !$}TQR#dcib:}kB4qMB8ILPjVp9Ö́^7荚Ijg FH 27LiFH R'1'^r|Z8i7n@GHm|࿀AF 9m.Q )-Ѓir 4ΡiFH h!)i [$OhEiFr  _68o$7hEiFr!KvቧS:]a,\G _`"4T84(+D@[3}3д|E4_ APpU)Zm\oana 4-r7M@`9|IUtpDUi@)ӶhZ>`"i:= 6mCQ1Bjj4y&ad8d`"diڸEiFr  _68o$7hEiFH h!)i683cؿ4mp`Hn`"д}#@/M7ؿ4mp`Hn`"4пu=_>Q:4x@If<+i?XHFE4 G~8M+0)bf٘2R&^<25+cZFK70dMUžIg4".]0e$$^84 riaPH/!ӠQVE~SF*D‹/B#Qr"yZ7fr2!g\4!VDٶ!2R`"di.wT-DiZ Z/`$}L)eIVE!Kʟ ]͖F*C@zpLS^$JmHE+_,M 6j[lh)I6C4Uxbߺu /B9)Q~#4K27MxǓi.R)Z{=XmVzP~T[pO=p>C7MP>\䏥]t}LWH"*״"qBنe!nN:aDDw=>~OVuciZ0arX_M3(lԉ>vshU'jӚ"Agؿ&y;VRxg;ZN6PXjii%r߄Cj[ !mMǮL3XL܋(NJ6.LT,L_,MK.M}#@ъ4  _68o$7hEiFH h!)i683cؿ4mp`Hn`"д}#@/M7ؿ4mp`Hn`"д}:}j25=@葐~Ic򿢁 _,Mӏ(:ڣj3-4g:mShS ^܋=H;дRUU{w3 >uW^F73metn@`"diZ0iDU>KɥjKw3HE܌E?"Vd^}87y\ʧ _;$ؾh4=!ϟGeF۷Ro+y>ť ۺȖ̶H{_$ci[1.r[wB"ˇ.nAMc v\Ν;ΝCeF7r\PۋlɌkQw uu&m%Yd좛ズPј|h{]`lm02n',5v2#}GUbˇNȖg-riZ veƚ$cݴ1?yT4&&6׉ Wd*3RygıgZ%sm/%[f]%覽cKKGE3+3)8H5TEEB"7γgϢ2#u\+"[2ZܥK/b ,J2VD MӸIjktle4֟ʖm_ٟZ@_5tkǥbllk\[_(ԒњG>9s6ΔϩdE]K-/ c6 )ىʼ9 ?%+Okf6䞼kdΘbK*qܴ7o+dΘb]tdBF2vM{W1cp-Ĭ1;MAk&4 2LhM.4-Me46\hZ ?\0i4mд6_Q&;4ʯ_mhZ;\m,rO߇LVH+=gt`.soeMۦi'zf-rJKTLJzJʶMk<\piSa*t!b}k~[644x 5NԘ.x*ʧFX&0\hZ42mg0Tf0?'Lh2gL[*L3nhksfkj"}eeM({O1f?M0ӟ2#5ښ+z\nɴj:ho(Z |2ED M˃QE?"PKhZp-d[ki Fӆ MAk&4 2LhM.4-Me4FH k[3-aBhpi1hZp-ÄѴBbдZ MiÅŠiõ Fӆb \01kl|A6p-ęf14Q2j~|i36KlRSc]S`̟Ef6m0YR[3IL{hҗ|4:^Z>;7EvK˗,doϫ*V~0-iƒ>hLB fl)2Ntf"Eט^|5Ou'۫E"k\&"oHOӂK %M/aԚVy)IX+3k&4]kдv&}lD>4f@DGDLjB/=.dZI5uV 43mgH igZRK f-"ThZI0Fl[[3F@vF4BFH h!)iFH h!)iw2 $gڵk׶pIiIlxԦmllܸqcssS șKHHK2_~ʕ+HM}իWIfIiIlxԦ4BR@IM#$44BR@IM#$44BH xiS!u8mM#M#$44BR@IM#$4+~g#~܇Xp^xiױFhZ'{O}'uxo& (FٳgeXv O>xQ^X,C#Y,u|%Ų= ,ˎC:A{2c}0дސ,{2LIG MI޻2cI~8X.ٵeTfBIzCOp.5,oY^>rt8_N%ˌ&Yxw.<?P Y&M I?ܼslT۫e|]R:zѿ,S_I56$$ ɕc'8d1$ ?KO,/?q DqMt=4QbL12NeҴސ份wpxiRP/+.Md1$ oI7/_T8OnD44"W Y&M I޿uNW󇗖ϊi%>Y>IK3MΌ|xR_r0lad47$nm:{dߝ"ݷth|}okʉ,3fd֬ETC.(e):PPY&M Iz^gĥCgP=g2 S#G/Yf4͙ ZM@m޽'$|肮V){ReR q,?d6d47$yoƭ۝^=OCɞ:}K(wx2L=?^,s<#h]Zz){ `lд>QugGevmi}"wOѿd1{ ,$OvwK3Mߣ2jd47~|ֈ_@Y,~ _[Q# tmu7W-|滲G^wbkkk?%Q)@Y&O<{W'dΞ=+ՈLiFH h!)iFH h!)iFH `_|O|2ϢIENDB`ViTables-3.0.0/doc/images/settingsDlg.png000066400000000000000000000630741311223072700202420ustar00rootroot00000000000000PNG  IHDRO2l pHYs+ IDATxwXSg; K@{DMh[찎uQj۷GUۺցbU(*%3D$s]s<䐛$Ąx""""2'""""30<ቈ ODDDDf`x""""2DDDDd'""""38U1sLじ9 "" OE)6|ECf`"""|f$ĺL0d&'""""30<ቈ ODDDDf`x""""2DDDDd'PNDDdkn;~h+TBDDd} Od%""BSԩxW0~X̛;O?ϬYPvm ҐDFFls[TT@DDUV`z/ѯ?PPP 8:9" \v Ǝv(8=JR5O_~~zHO7>oZիg0oqr9FB@:| =lܸׯ;̞}zM?""z. W>\\\i!I<K,wx{{#99 4ܼl02d0>>꫍c[iVGҥK U_ƎŶrO ɓ A֠@@޽| WWWkh틏>HOOLJ~FU+W"##裏 Ge˖ƍh4r ϛgt]EϟkPB@Ֆ۾SÓVErM$%%4 P^2$xQ7Çӧltӧ cǠSN&L@ٳ'.\>=V7| z'|%K۾#IL’  bcCuYSJH}{&A&VENN.6mj2d{@ױ-*QWw~)!1~uEAZ-tB ?S^-Z_0P(T(Q2 ؀' ͛7݆]Y$jdȊS\\jyya/Ѡa0s{]yyyr*$ 222Ѫe+kLDDDVV-GP񁳋 ǣM8s kݻwkNDDDVVFvnܼV w7w1dPkNDDD6Zsn’%Kt9:u쀉Khߦ ']NCHxꩪ!DDDdjrrrpc8y$֯_ptt$G^QV-ԬYnnnB@"Xp""")U>< !pM~޾ 2 B,^ 4@K NDDD*ѧyVJNTZx׼yУ{whB,U6<)JebbbO?#773g6 G˖,U2>.ZС};c}oS(5u!88g̈́Bзx?@Fhݪ%VZMu8t~^VKEf_S&OBnNCխW:B\ND<;~6@=r}=z :o-[.VZȅ ѼYS4n?̠Җ->5[E?-=GTR/Oŏ%SX{=]WUvBB"//lۂv@zx驟Oaҍ,'qUu#pZ<<4fϞo[|ܹ'Oĉy3+V,7Xg< ĞǼ 0uKq.̛ [#Ĝp%%m_ַ>|jB֭q0u4\ФISDFotgx= ?6W'N?l}ݻw?aI&}Y῎S+4uxwrdggs88qܤ5eΜEG{ҥK8p Μ=[nly)]J1%jdX2ue1+mJLBBV %amr\|mXZDjjHNN7nׯ_ׯ_"))I$%%7ndq-q*rHOOݻ"''G剂T*JFt:kﲁ!!M-_̬yLJض i"##C?'۴n%^rhӦ Cվ][qetJJh٢6lBLm/6͚ۆ/X/oWo1G|z~z7ޘc2XIx׮]O_zUict]e9UsMkvZeܾuuj iF\rzJ[nzbHIzU_U'cǒ-/:_sےuy;{ٯazifw#OBxxx`jC^^QPPRT*jMiZNGo>k𘗗+Z~:55AAA頠 SS.tuݾ}=ztG?_uCk9?ӑcȑfoɓ4l_o4l~8xAhػgO}5}ظqqL]\j OMM1Ҝx 00P?ݠA0|)}TZ))w *mӲȣ(OƎ%S[sҞ7v9ONNN5jOՉN=z$?CƩj>|&/ׯQF 5huc=[fmFEAS4i",Y'x5kDnn;t숭lfh_5jm۵Î!@R0뤤$F*nܸ%./SĔ>*M:HLLD&ML^ѧܵȣ*O%KnW&!?? G9L݇FJR2 ptt# nE;::2 2 RRD} M45+ : ̇\.\.ǂ0l0? =khpL<ƍ-[6c-?~ETθ~:fϚeҔɈZ !4M?3^)ZȅHKKCZZ".>!dJ3l0v$ӑ4OS4cƌsqV2޽ ly)]\r1[xXͦWci})q-1gAww]UDsY/X__?t.CyMA*gkX0)kݻT*T*zm6?x5"#A`} 2]v5h hXK/ƚJtgg@.]ʵ5 z@Us3Ғ*yڢg Mݟ"Qi|-4k }zFP[}jsw+'0xה-|-3pqqA.]if@@@]aƌW?f-t㣟>zz5j .{Ȇ^^^HOO߽/)Cױ<"%}Ti%All,-="""c69ԭ[w)ǹʑ*O<-ݬw'XI1iĞ4'$="""l2\T8p#G%""" tP*juQrs H 4ݿ[?!.^Gv|"3vlRO: >>>岾7o>:dSZ.[#"""{RE“pu}8pmt5T """"S%>@+w۝?M6-58?"""mU$ t t''~]:u`9DDDT=UZt:bbbвeK`mIDDDJGyFHHHM3'""*Z'Bdԯ_j<ݻ[Q'""jJ'KAӲQTmӟ={ZቈZ˨[.,_ OUK.< !p1>ڊLH("""B]x믿ХK?RjuDDD*0~" PPPVTpl%VOEb9HJ$$$R)ΟU!ެZ *"vl݇'N!=g7A&U0B8I1"x&:7cن$R+EVl.=!"""{`)''wfSPj!N>}!]pS Ip)PN #_uV\c -"""QvhHp? F xy-Ľ$&%ChCh3DDDd><լY(v[rZp$u0c @"F.b\;Qubd+AaomH7 ڵkLZUUj\gᅬ3gzu܈P(0kBppfϚ Bar{q1!$ ֭[k],mXTVҥKТy3֯)'!7'v"""6V,_;wS8q$nLƊMn/w^= >Nft[;vĴSȵ\b`x\\j`&}?˖~~~Xb~g` xclDE} (q[31~Xdeeܹ͚Zkٺ.֭5_~/SV;zT駃 OM5|9F;5k>;ФiSt:r9r9̟aÆuî]XjeӘ={RRRp]"++ O?=M53 /NYF .`I&}Zx2v .Cѥs(0o2eΝwgt|!|}|У{7i ?NbѢVڟ_aa>l(ԗ`Mn'""" IL7AAly"k2  ؽ-* Ǝ5y͚co<;{ckʦN:'""""30<ቈ ODDDDf`x""""2DDDDd'""""30<ቈ ODDDDfpvd#rΝ=cRm4 j OT0OX"""kj]*s3.}$ng@"5 IDATYvz 5jXLf'+-kօh>¹+t:-bsw|{tvDDDd>NI2sA:Hʧ;R2UqrK%""";QeGOMD 9huZhjjt$Ajv%""";QG7 CFA.ASBUB+)pV~ _']* yU3(!:QLܻ}W7 eP:ŸΞPkRȏAJ$Ľn.;Xuv}xqٟ_N (us m:4Bmp.ثZG~A.)p]j:Cj|sl,Ri#"""}x̽ 7'/CU@#44PTP 5r5P4 54B NS8%(hJ7-  4B VDDDD<< !PVYVNq/i,vŸݿ7-:Q"""" 'Zg T:T:>i0xjqo Htq'$X e' OKg *MTÓB `ԩ(G+ K“@{ h@NDT\ы[oiRlb>-}JT<<w rPC P*i F4>pN[Ԇ{0@C GgkLQq xe dgg[c&гOfnU$ O:.@ۨ_TBHEkuFV5 S!d2@ ODF(S"`WIm+pux8"GShRѴ4{ R((H I H]dͽ&=BX7ұoȖUxǯŔ![[9 ! 5j:^XSхG4PCmaJP*Pꐞ.:89NhNm"Y7ӒoȖMxhAm, mj֨R߹t:!J(E yH$H2Oc p5- nq899Zwl:e,KGا%cx"[b7IVk\= م#K‘E OiJ(uP*P+2 ) !Axuk!͛B@*vMD/f%Scߐ-ThU'財֩oj(P  u %ɽuȤŧpMh%h^/..Ε_D2 ADm㱱GU|jyƝ۷p*.]ZFÆ ѫW/}__CO,d2z셬LLpԯ_@ iݺ!;.~w={wߢoxyyZ9Cd+ne2#1&NFVZV F Mܿi$Z 4E?5Rxف0x1류ջhu"TtnФIct ŷ}gx 6 \!@=p*:B|cǎšÇA{U&<-z;_|6oތ/`PT'#"̌tn /V-=x{׆JBR޵!Q B\v }fcǎt дISD9 ' u%l Z/^,'GvstxzTQTpҕx ?RI'Y ']g`v1J&gUz1BÆÆ_`Y 55#y桚ԩ#=be1d`QtB 33;wlGNvd2y&K$"#=ꊛ7:Qu!OMV+rssƍx'4xrssL!vVo$D~A]\z܄L{*v|v ;I]NAKPY ƍqb3 W_m_svvF`` {n5ѲEK| MGY'w]vaܸqpuuiQ궴ZBP !;;...dpvrB`` p7+ ]7o$\CYȖUxJ]5R;!ժ! Kh;H [P'b Ƌɓ&>5x|aXe=g˖/t ֮IеkWlr#MV[:(5+__$'BͰsth...}1貥M_;wFѨqchZt:4n:{yyyh4h̴DD" BA)ڢ!oíhuIpn/'22G _?|?ؼe3f̘44h/No }:w !:w՟FXn6b(5_I&ȑ#p9۷Y;v_)qƦ;ts11!@à99Bj2 ZFzBn׮ŗY=T\WVWtDB^꟨{:!T0<=2y:~CrF¿/<^x@?~\XӦM +Je^?ͺuиIcx*|bPxxւT*23!xhҦe2B;uS{w~"^HaÆaP0 ??@勤"[a @*qRcځ%YQj@Z"2/f%k^cyyddd ##äeKB %RRJ%1!` >ȖuxH$T[r8J GE/62 ODT5O=z(sGVUe]7ߔ6~xke OdK>%H$3ED*,,/d}Jd?*mdE@_'s.6ޔw?Q嫔vGL~8UxprzԶr_mq䉈ȓDbӧoa۶P*-8n#ODDDҮyTZZ>.=m따OF l4yyqxޟ6-3RE٩h_SMpP"8'w4k_8DDDdlv䩈+.)(KttAP*|=:xxz/w}%_?H߶y0,Zt5k.G_!,Yp䉈5Oq <m{̘6+ٳbРf%Cddo}[A5놤8@~F};{W3`&RqfODDD6y*F~ۻA{JJ.6 K:u G}oLaK#O-*eUmQQ>6;dFw|1xy`ժ~{~)Sv>ۊK H$02-<}1UU>6{͓Lم 27s{G0rd+}{d[7II@M,Νqh qqf_eK#OĄx_ !:6RT-|ѨV~y|:!ݻCEDDDd+W رUv?ѣkNY̙Y(@n|/V2z*J%]OXUrrSvDDDDUDDDDd'""""30<ቈ ODDDDf`xGj*M|8ٷڶÜ7@PP VtttpLhܹ-Z@d -cx"xyyaɸrvc?P(h"""i&4p 0n8ۏ=QF#,, ;cJDfƍѴiS_v rssk.D}-bΝ+uӧOc~?e˗-ZS_¡C/p|E5j5RDDDՂ p!cIMW8p F6!!ppq>}oW^Od""RIⅩ3 bcCuYaȐMHH]-^Ƕ(&(1!:veR ;|8T*zSZ$"""1z(F0 8۷зݼygB޽ѽ[7HOO7ΦM={ŋT*֣jɧo߾ѣϛ\}R;,FϞ=/"7o. y1h@aܸqӷX$ YGLLѶEaԗp! ?o5k6Ǝ}a}jV,DE};w"##֭3/.\֭[o^89`׮] ܹl©Saωӧˍؿ? Dzm<,DBNN6gg!++Էܥ \\\PfMY(((0|z /U.ǨQB! U~=U%e]驿_F hZ4E"0<ߏvmkݦ5>ZB=zK.Շa̙ޭݑ ONNF nBmooW_m_>>JNNh_"Di;2N\.w}cIF?>AVCa߮R˖?+ \gt;#F Dzeq h4\rӷЯ+==}#Qc2y"B*vо=֬Yf͚O>xͷpM4l%Kގʕ+[o>ڷǘ1_'xӦM3 &`ӦMxytаaCL,O˗cРApssų>GCocdX$$1!^=[AAlyaT9 لl5ul¸c˱*"""SwVzjժaÆcMe ;vC:x;w.4y=y`ԗ O\?7"ޯzwrdggs88q`;+W~s1.^XdJTL}῎S+m+/Ý;wp)8q7o&cŊ?K{ҥK8p Μ=[nf<$^O_ѦMxzz⯿;|jժ֭[[WD$&ċg+4h/=!UdMT!C6!!!w xۢ0nX5-ء=.]Pgly1XiILL!q*4sн{ >`XLxy|hҤ~[E}}qUxyyAT~ NJIw @||=  b`4$=Xi Bǎ{.!psڥP9 -eD ƉL5k`ʔ)e\I.X,#1`.*CٳY7$ Xaek l]:CT_ܹ.t#^doȦթSai.TƱf3xڎ OTaDDT1<]`#?FHh`8AuBBeĉK  >eݺ ǎڵ밲Ƣŋ 9?~ GD@TBRa,tfY]yHKKٳ"5/_ViΟCchW~_cǏx<|P36ݱcG8::ԩN] ...pqqKa{*g%K>3xɧ:_j5<<'OAbBf5ӑ͛#rz07$6l>>V9T*EQQlll999gJJuz9 ;v 8rfL+]s8MZ^_,Cx$aÆ ڰA3MW{vuu4=99...&wrr2|}}2M[vttD߷ƷwC&6LZ̏@(yxWCJ;v숍?Sc{iC n]\cM?AR.*/̚9˖'n޼uk˯6XP N.3igd`Ĉ}zW}t b^8G=M慇aȐ!:۷nuk>|8BC>j=lmjJͩ;]mzȑ;r*"2'nݺ׃PXX!44֮ČӰfjxxx`ڴط'аp̞= ;&NѣGS ѣ_ֈF3C FZZ|}}1kvSplz@?W JKᓅ =ϛАt8p$LA>QXX9sⓅ ѳGs4t=z = QH g{#123hv$%aO7]wc8Y''Nlيٕ~oJعs>pLӵKc=<1x8HOOǂ1`;]%""i;3<[x[.(--EjݨmSu<{Fҍm^Lh>M&NȤe>h2Ӿ}L1^MAzQQ ٷo!QQ5:tQő'2ڋ^y }=8]y"4Sӗ}z?>}cHKK/fֻ\ ѣ_ֈ.uC~?刨aDF5k6f͚]g*]-,,0cL̘1STCV9M_U%|bkDUy>"Q5AӧQQ3F2ct3Fi;-2cJDǘI~ :T7ƆP71gLljdi58ok8R2 kɃ^2v5Ŏq2nC^#!8?d'jX浫>EUgTs,7h'Rqn6&/6w촤Kpk@B5i[H?y(q{]II , >ɨ5<3 ʵ'6M]`((SYerZҬ Cr˭!Pd֯ wyѶSL3qȯްue>&m^X^GްssD"AAf&Νé^o…pwhu^t56T^^.jڣJ2gA֎.R#8@`# _IEg!YzhsN]Jp+! G( .O󷍍 V|=QR3AF}GZǏ@dd$RRE9sz쩙Νۘ9s6jv+b Arq>xkk|[["aCtɓZw &`$L_0"I]JZbb`$e rKQȡ ɴbgZcZRո},K@n !! АPť:'ǟg_31& sջ+zZ珏ǢE 4$ BCBh"\t 0m4|bt֭1eٸx1<G8më?>Dk(/\ťŋQ /b…1c&Μ9h\~;buU=!J1l,-KR.Ǐ½%KRTt\R!22={D.]0gW9?lނ^zk׮?>JJJjl6*\9PT9==OiԺeggѣFݻS2d(Я_?bG7kL~2e19,QG;7onNHOˀeZڼe3Nݺ]uɓyWb~<[LMieqqT*ӧP |ƏD&ECnm'CYK#$.]^[lkA.,LOIIԩSѽ{w?BVVVC~aÆڵkeeeXrz聠 l߶ݨ>1ё'A 3HL)  %K\ܠN__~%^oݍأGP(.2yqdggcM5cēC!)+a]6@T$- 3}8FouVi֠EDOD\\lقĄbG||YDT*ocoaАq#SeQO ݀W^}6H@kqADLx7*}#b|c{`md$@VLMcro܀̩ _:cBҬ,?[C_Grn\EFȽqCG|."(uӧM#Fhl,=-jJuض}N<7z|EGGoq<ߙ"5:J-*bl,d螮rXYagsy=[#B΅llm1uTVHF&MФIC5c{OCqQ!PZrKJ ή ֡Ccr%T=lx يOBffrss {sƔ'S%{-_oowMâ0zJ iHMyc"zmBkyyyyptt#*,^ Yf&s1yPʥ(΂!(1BcOW]9|"dG^ppp:}Ϟ=ҵ+ aʔ)̙JWWX[[c5ۏ!O{{{˨_ۉ誢bd2)l,+Mzc\c׊ace DJs=ϟgf {W2CY5vѢؘ*JxblP_BjUf S!L'.+ל0? 55K,Ƶ7~V~6/vvv==hRl쉈*hخ9N^HDV-`cg: qlƍܡT!(qi7x\rrrsrrPiy"M?O+lKuh @ŋpʲ2gOAJ+gr c24 (A^k푛&MT9ҥK7P\\,_P@VkgeeiӦUy<[XX@!fM(}1P@Ds=ڦU|삭[7Mr-Zk6|*:ջ^>} |vi  \&~Ѯ];l`>F$_D&B^|6h~ ld{yiC' ;UN Ō3ګM}ójyI#{hԸ1lWKWk$>P 6 Z[Zz< }w.](Jܼy aaU ֭Cvv6nZ׷ƆTŔx @PNv(>ٰ`-2rpsz\W]]йSg0ܹseee(/?Ccogg$Ɣ'c^KCǡM3ܺyrP4F.gs?F5j6n܄Eii)~?{6m¨Qr\;Y1eQwdcۦ ,嗡,H8^]$+ ;B`F{F7~3Aii)RRRE%%̆(pIDATPHMMҥK+կ>yVBZ#a5;-jtI. 6 f\f\VJ Uoi1i$deeeJ=wN0|p[1qDwRc\FRFFQQΞ=kыm~U$L{wNPP9vaXz߿OOOϯʾo߷!K1sL,_ ]v2'?=fM zP1*t9t[adiƖHS9ZpDBrr205G̋H< >76`Ĉcǎ5}$Iw ^j?nDd}T.|g$ھfPT?*$Ȧ  j=֭~7Rg^x}74i)ȸ|_EG()(A NV(QC@ iǢq| ~x0hՍClL~;nݽ[tcA09|5r%HKOMBMsST4y26Ac?3sg%g9s2h"-EN:q.[WWSr1}La"ʤ())L&*%)OkP1ӥFOAb)RrH-Gi"XS\d ;w'1UP _X l6M¦izګן1go}d>gWqzZv J=T \ڷٳhԨLɘ6k_.\Eqd<;w5.^ejZ7) ۉWɓ!1Heuj Q,$%YM-f)lC]mig KGGxI[_ Ƈ ! oy)zeq@ R R-Ѩyj{Q6yΎ<5$!clucczuvcLSϘ'6DT?aȑXlYmW GPPϘ>F}_ݤ$Q+iH|ѽ{wQ0S"l݊ڮFnj ݌cD'ODDDD g5dLD`DDDD$'""""<䉈H&ODDDD"0y""""LD NIENDB`ViTables-3.0.0/doc/images/title_page_plain.png000066400000000000000000001352551311223072700212540ustar00rootroot00000000000000PNG  IHDRgnesBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwxT?$@ !ZH W`O6lkNJ4CPABO8ٳ5쳻g&3wWH)pst@hY9M@A%cgiyifm 8kh'`03 hGFZ!5v{39`9ަvYC#4GJ!|ޘr#"{j<1I&q5n4q0rN?BmA5 EP-3 qFh!DG@*ʥ 9n44み7 ęcL+`i4?jwשӊt= F *?cOv9u}D1x 7IB G}rao &YL7̴v>"|%3 u-")eï?a68kϘmyYG]qf^z"Ϙ`΁#;:%ױR%0;*i#tM#>P mAPC9g>k] zGѳ]=ۆѣ]-(0'3ruvf1]uBЯ[$=ۅӳm=ۇѪ?Fɾc_g3:rޙנ2] Xb M<80U^~iͿ׽Cg Z ZA2x:?>cWtb^N/g0vZgL{V9;db(hËJ<6x3(Wj`hw9v}wuYC#$Qͪ6 lF)y-nu z -q> NmlRB!xt:[ڽ3n-/$G'(-E0 h@3ʹu!uPv/9u!˿! a΋f0b?~jZ2]YuU¼j*NOΆ wcPBHPˋ˟``l )Bp @"Ua~7*aZ\01Byy{mB00r8`@FqǸNnàŔ:dž=xꩧx'x y덗@A31gis˙kz@C}qm.~ovLJoem ns=}wTs]̋T6Cg `=|f?a1v.q͘1;|k1^菧Aǂ ̄ヒ5LEl`)"HA)|]y{9>އ/fſ-_c핖#/@+c!ǿu[N@zGQh⬡pбWwud;]`^NSMޖ JXW 6aՏ0#^G&["%9n~G:|Z̚?YFdJO_8LpAo]ww'`I}cO^>^_lܸ;v/O ]C$eɧ5KL9m8+ pm2k _罄~ޱMŞ78khݚ"̏6ʨ1z- M6~k_O9N2?Mts!UV ܞ ]h$BQ` 0WqhD'0eiVm۶vgPauRV\0悔PVDRoBڬ@wQ'sVx룪_4FC | Ut- XQ>z:Yu_l(PPT]n,b-oOb-G_UKaɆDM_>y}GC|XkV#D568k4) CT™.,jn,X߮W^quU9LSm7v-կ*Ϋ0_LoyU.,m; By`Y3kh45^&U  ??vYBSROؗo.%:^U< wUb੧b՜:ur#,تNods湪u5ʁztw]ױƄN>SleB4)uΜ1$w}+'=jZA Q}?x 2mm釒5~e']kҨ H(ZVK!~YQBt_|}*"s_vs`I:ٽC3gR[߮.;TŠX˷,- vsyM,#,üT}MfI =HKX I4rऋ/ᔧtuB+%ۡ"#­76AgFC\e|}'vfΕģ̠I) 0r/T,Т yo ߮d pۼ1?k{,Q\NEeM}Xstw1 vf X|,gΎ.e֜kPTVgA2GJ8k4 BPUj5Y*BARL?m8jl,%Q.&W;9v#U%F'|?TϮi$_b:؛;&8{F7*k+ww|*KcTEgG ,"+))ܹEoB~bvsbdHz6=:so,`A$!!tmt^U=ts0\~g M5u8HӬĨ{q5&E>|۴iâEvUrie f;M,{ϘV4nAP[|7X$ai\(c}v[tv w\hsMWR[qHD| fz}wv,ie1U.I/6shxptR-nj/|6 lBR"GoC. ǑxrൃIݴ}+)'A:J^Nkox`-a^BRr`^rj-BL5tj.} !*-}!e+"0~6i8Ss2Āi~&zS RW筞rNF xٳg3dXs 7]?X> [vCb-J.G5`^WOu+:C+?V (^8-bPLMNm=޿B89X W "bjijh6gzG1xvmVPP3k$V|=kmJD+ oܟN[f tf^~s V>%™ K-yV+nձ48k+B4`5\uUsηtҀ&_k3K??ʴY zݗNr}K]\B]';ǂ/^^9ߙNAfϓB0Ҋ[x8k!Z|gt`6PfΕTぷj=Upֳ!5CwzxֈƘ0/-rd)RmvJd6@+땰Xkl O, c- DznzWڔ\4܆BEIZ/̘1cjӪ[3(k€IpB}M*Oμ9[y>tiӌ^Hiy3:ҩXM`,7n[TK) !(GSNbGgt}`RKx[~u88k$a{{_qoetj''G|`5PoP\VKwҶeZT`!w1O+>11Fyex %oôDTc)\d4pz18k!C 5W_}եqvTO`V74]?S}zۈ߇X._gֲm>0DD]GKYuO8 H)Ϫ!DK>S<~-#=]ZyS1TGg:# 0s\NLL?Gw-q]gΕtJPMޓe _b>{b(߿v붟䍯wjq[!L]&$[F+:=/eLgj#<4$&uB1H.]J@QB*CBeP̌mFK {p)oWcPhovٚ[+Ew_Չ׫H0?~~.okp!(VaŴj`4v+ìQ.1,lshzZXRΔgq?QRZAV~_:̽GnIfuէ_>9_߿vlha.ER_1>MY%(mkcܹ$''׹}w5jһ,i4(f,8 :?~w_ٙ6 o;؝’r9d{R* 8`Ob#H؜A oO:%SFEg Bl21 1k,Q з,yn"7t~#8e =1Dd64htNaM]$<>m4f̘~m֨ɠ>h6xyV+?c= h0BJ2* o~***VйCoZ^{YָY~oAhXGg gxY@Yp! qFxxkXc@0i"j#ڬC!Ly,44e˖bNX3ifΕ\5 z=ƛ6{Y.ByˋEo=X[ 3uxn':hzCY7hha!5(jx۷o 0ynsP@pMM5BxL,[Gcg o'V4qRL\0 _~%;vlqFΜQ-UI}3iʅAͤqF%odI6㭷bС 6gRQa;6rCsR#tiG~ƴ= ѢBxQ@K[rgO y?pMy ~sh|#Rlk psTR8>xWǐmbS_7cȺЬa:?6 4C&Bd6ۭ|XnN1&%%1o5gҥDEEkhNY٠3Qs5rf(Ʌ* } ko~l7εjŅz)e3j4(8;n ffIdI@DŽ1QC7{>+?2 0ˣ֭[=118ds;ͅ/vV8b;7P~fſ0 !)ӳ㔔2?Fp:еC(%H;su1f̘:=43^g1r;;1wP >8 JUND6B"l7QJyιh&y |$h GO'3w]q&FyTnCkpV9.{{]qh٤ /Faɖd˒V&ճl eYc,'3;v{w? zSH lj0u; 7ωzNZzo}+xem{@DDCh-Z+ `RKhf R! ާ`7Ɇ7Ssj̴UD~+̱K/143w\fϞVR%Y!)`peU3* !D`;6 +Pɹ+ΠĿf6رcY&E LJ/0!uQ`bďTG9A_j]i0fҰGnn.\s0Vf0T%p xxHQ!Db9օ`~zFDg7"HBoo! v`eGq"534rssy衇\:_Jɔ)S8tE(L6 !…URW4F@"xnuaJ㡙5"ŅNSX R~/E?wy^8عTK;Ո)ѣؚ]~ory {%>"M}Y}ڇˁQRʪ^B(׫UX! Pfa+NىҪRb5"E'X|@JY\g?Ͻ#}T,d޼ytЁ?r|RuéUV\?V4]JZLb/ 0LdmHB4;f}H[|fZ Q}j5C[hYFbw!|)nG%4!h).ft}q:f@/7LW&))ɓ'iQ>o<:v&MhU`b.ng:V'"t !Mij=܂O t-N]b]4k!:MBIrQJn~O$ہʸ+TX )^>ZT.NƜNa%B;F˖-oPn`ΝKqs[a},X \oy¿žI nV.\XO#s\f̘AvOLVRc*M|ᇼ{jENW0qM񈶸CFBB≯L&!ˀV+=l7ߴCWN&&}OmBI],Q̉N!" CDD]])G55xf[\˾W֕mañ ?r5!ʢEfuXf _~%-ZPܹ3;8=0¦Ml!3eFм'-7df2pقd9RJidfr b\"S;v $ʏbgм;^oDx;hU4)7)Y1E[>8eɞO)ZWz&оrPT#^=fq>eߊ |9<.ܘ~۹s{kY~=ի… ,\k #.!CXz5̟?z~ͅf1Da[&a,<[Õ۾Pl7c}MJ)ksBL^mnWIprP~j3;߭yhJcPD^&(ڬ:GJY8T%BVdN PI]\,yygh ׂ^ͅ2c/L rMz6lе5kC9oBBw&Eo`xWn:/Ctѩ.K|Me5GN#@)@_-|=⯰yIE)?,7Rڼ !Qlk]}.{q6BFrj}` 0DB;7Y) ^JYm0WlwUw fχW>R\w`\(ERUBPU!u'WP֮Kߵ[[(-UYF'BPL V!77YfkQ\lԬY$^GZx{Yw ذq1>$oxZVMR^^fVhw?ݩV*Րg$$t'XڴIYS(++Zgq8o38ۺC@RDZ>n] >E94~UL䲬喝f"HNNr0BCuG~g+kSW)v]\Xt l^%{p"M~l?'Pӭkvm}Gc4V%yw>|(;?Ty(sBT8q&.I9E>-Yo ׫/<er} ;k OѤyxu|Kޱ5C`Æ Yl}?q^٪D|qfeY?R~YrHHz%9y-[X޳7g0 {AqZJ*.og悔KЂ8FG[uk]ЄgΦU{PbRJ+> uftΝ?U+=Q'q6D&SwX^qT w??@RRF7m7}0xe>W-Ȓ<\fci˳d?@zDJwK޹S*C(ޡVdĉ]\ >\^L˰{úOUN#e'Eq^"#Z:) _ŗ*n5غu+IIot#(0&ЯUڬ(%< \Zmog6)LdU]k;;>ۼ%>e^]|kc,ʡ"{gS.Br'5|*:YNxMJBWi2l}Y|IIɀ~84XxЎ+Cw?>)HOODsM[zK ༗%3dWˇCHKG86iVTԳuksUW_mQx^cл?aȶ_W!@|3-YoXF魔ѥYNCdӽ|nO^˅ g+g\+jӱC #GLm VwpKFg!D {K߀86Wh[\e>M}]`kړWn!$=m<ݻpˏG|+|~.#P`oxG !عs']tQ-W_ѩco H).Q^~ػELx7ï, w9㥓%:g.5CqiܵY352}X">I;ݦbح̎s~G:7#Bإ/#GL%}O\)%ϜԊK0) cl,qBlum]CBB8q1f>}1CT ] Z%K/Qvl5e8 !Sp^y !^o5.{aŷ%!NEZDFƺֈ /t;GTL8L8s`  Y]8{̺7jpYT\8t?Qq$FrU?6^o#RmAŅ}+̺:zfDG;iĵRʯ \Mdpp8}Ɠ>@,WСvb÷,t>CfvthLtMO;OKV.r ׌q"ֿx1G9-XRXKֺ.:ΝRI3.DE6M֠ W,6xa޽m۶G~~A{Lp]ĉ ml sl L%7'9I-sUQV\xo͊=PJ*."7xS}D7<çy8,f>uR).PBtAbm-dMڷKkֵC |g8K#e+89ƂS?%,(0>cIO,Ekp*OEFwh^rF[sI)dX=Cw~ Kޣ CLjARrKt:ANN/|9K||7vguSȬY}(g]UН'إFĜ-^U}Zpubj #[.ӑݛxmv )}I5Nc!QZj_O~b7ze^u`WPmFrJKYh'_dނذQ5-a,>ﲹ6^^>{CO$00{ΰ*$$sO_VR \fΦ"=7::!׈:-Urä4S )Ξ>$% 5Ɋʎ3~Pzx9mx nNZXRѬF,K%-SKN)lIJ=g)7*BEߍ-rꕏ\[w$-uISSNK?e`А|GDF&=u?mPO/S[ՂՅdruۚvaXX\Ɔ#|,2E7do\3n~tN{Ơ>^#֭"y`:EСc8cOvۼ[L"lB0n"7*6Ci6d7-UmWv=Ϡ2hfATy:OWk$% 嫅R^ptY1% g >1YKDd{v[qqKU"??O R—[72V>ΝR6N\*)Ct4kpُ|<$Fy%r1>?˥LJuxe,Zx˘ $FnӘѷe JJv{y/}E ֬\.q]7NBb-7J6d^`DpryvX"qݧ^`~R).3ɽsMOa#YuLSӺrf#X74)?>Ϙ͝4դ g)akEk8,zB'YB;$:]9g4J֬:ȄnS[:SL2t$-WweOQ\}tcNp) Lh+K F9`c+ 󼺰yI !u7Аƌf&^ ;ǞUe >!}{:˙30۶]NӹKaᖂXVV;Oۯ'))QLÆNv87gؐIMos}COl>$=|%DW\o'~"'.*f> O(kN^J cAp) rJO;n3O~ͨ7[xct^)8~3vVۻZgvu:=ݻ ow3b[ 3@@6e^WhK_u{El>˻?#/Rǹ_hh4c3O.ow=}\![6Wf C&l "k$QlhؐI2->f}C㪿EeńQ<2-څ۽# Ɖ/4:nb&6fˍlR~7Ϯ9=g`IeRӹs*~~V]\B?sLOB|t줓ǟ~}dM1d DFZ1^("6~& sXYe/sE%-=]HxxK}},,,aCn):cг봲]!%:mvC ?S%{βL> (*3һt1|WZ'I=p1h׶>> xt>-b 0^0rzNHGJVj^xyk+*ʫlz8Sȅ"ŞxR)bp|BaásUiUQA ot:-ٴyEYEE9FN{mhx\?xqykb0hס9zJ #{vaE~:oTmFTdI7y#H݌tsTP'`Yǜ#& )YrrTG)N##[Vd0x<8.]%x@+SHN7g<$`w9Y} y7zdF/ġ/⋯Aګ'm6*. !x$07n̚=uiM0X͝A[yߜ{mA"$j$"̙3#x;U2o|ЁI<$#2l(.#bdb* Ǣ:bGydstI>7_b=R%m6p:(o7ޜXŧZ\(N 0K1om&ךؙWFWY"5&CY q<.7ZF:& 9)) nZבSu|h&<T*Se@QPo̦-l702f|{X]ύMF;ɚ)fNS&|C՞m.F-0ì~<ʈթRQ} x0\]TY6 d7w5 A 7fcPNo ' /?- 6ܾ9;l:Px 1))9%\.5P 5kݛT-l8'0YW)= Y6PȍG9duzp07S I ƺؔZBO%XojjA3g%GBK{!EiHoLMMMl̙K;ҝ;kᕗ'O& YԔ* ̥J˃{߄Dav,-=qq?t:3zq汰`ĺɎd`N {vCzQ\7ԶlU!1`PgvζxJe8ZdT*(3vy bq.[vOŭ;377(~F >hVHIU" sP]T97N3zEjH,`" RfvZo6dyN'dI!-Cgv`qo8QEu޽M..Nr9:A={3!gYv:q͜ՉY af:֭42hބJ>kIv */;17ϗ.[X D%@TM 0;!oRnn?~CS _>ǞO@m6;Oի(.FH$Bkojk@XhHVn nݘDOuF= 11[ZQr۟1JZ$E\J n$1lqoɢm@[}!(JHW$&M$|@Z-BZh@*U`j+t)F$%2p`:?UJRE@Jd806s}s c+X]64FC*aBfF1|ŪfY 0laE|3'" qRlXnT<ڳP(\:ug4("6 r>uaW3lo '79I12 9zGcuUyf#h\Fݾ`yj 7&VD4=V8.OFCN2' >Iim.'ÖSX\'Qq̙MMMkIzU<7w!e!…מLoFV E<3GW7O` %s z# >k@C>_U ,T Ln/No؊WimshL=ÞX$!u#5,@tmǗq!5R⢩`P!`)obhP-3hm̴F MvD$meB>(=uT$ #RYd$E" 0fflv"EY )yg>t(-K=7f<ıh`lfssbi^Gavp }i!f0.Ӗ nL784Ep<qTJB 69|Db ]b{J:$vN `n2< 8?V)AuM*N{uYHI2uaMNM,/._1|p](tݶy͕1YmOx;5>kDge @U5lP4JK6 es_JյxxbH\1y }Ѝwgĭ,ֶk*GlN84VW5Hy럊(/Joo$܊pmqHx /'eoνE{Lx~, J=*]\鋤L(H`]^L8(+e*%ycP* wr8;qx? '|̬XƏ/Ůx j%v͠]YoG=uo]&gݙ NVRB$*e502"13j)N'vdԭU8"L##ࡡY4s[W^KTb Ƅ/_;o/ӭ |+㴴>BO`dx2q8P"'7@n\4c{ ƈIIY8re?\L4 &|Y?.~;Bᠽm|>5}pȫ]m M%p# ty?|kA']N$[@n|E2d*IhƷ(qA&`pɌM̊ՁlUhrR6nXY`Fw )YFy|w[f`l`I4'CZZ 桻&ƕbDUA!R}OcĂm?lo@*S:$b "Hِ/1WwSfsaoIuZRRATRޞŀ_5GcxhN *e"@oџ =(LNo$5TC"TLiN(ݻgM]p/1'xfGH>~kOvgrd*pSBK\Hbe'I-_N L6tkxmo@UuāC%ϟ*GyErפ.K[ bh=k0&hfK^ t-)=b6DQx2O`p>xp` ,ՠ` I/zOؑXk/C-wG KS=KE|4V,SJo=m;%ڏaR:`o}}ҋ_ۉ;jLNRB>v~ \.'#XΈp 111EN#LeH;G`u%U }toh|{(vV]rYgƃ{^ZY0$IL뱲=B]T^$~5ݳ/cSx'*ϖbC`ҽYF3z;1gն9CDclb"\}X_׃ c}c6A N*AIib$I|~7> A{ζ AuA%hӋyݜw>Fev`p1`2Bã}$Bl3lPJ] Y٪Y,^[X~AqB`Nbo]&W*Y;6w_db%y}M6U| )YnM519#m8$S%g?{U;p^MiYxY#mfiѳ& >aÉ1`T(.bӎA[Ip. n?X ~e;X$Ib~Hk_.4kr,:MbjbU7/EEe2(!^1'X߯&FX&iOݚ\eI 9#-Йx}?mg3+ IDATZ=$*h~z[V.ttl*׉C4dyE2JJ԰i=>VS'q;ǻ34[!Z0;#}krİΌ~stvY z 7$#_a4 tt^ e˾:,6IhdNXG}vID=צ+h%I6Cez 7ƹKKK'[ r̙%oz^ݻF~~<|f4 Ftwjp$Y02x|⡇ |әQZ}&$`).塦ˏCÁTT&#=#J &J I[,B$I5D]2xEܠ7O$|e4ٷ17bpi$>P}ЅB1=vi+ :rzx|t aٱ@Vդ2$!x0^ިF#V6p7N;4Cio7Vt x֞nLgb\,5(׬NxZ߫Ƴ;~11uX͂|FitIR\ X_D]}g2*J3/r=YiX%@s!at:Oޅbz0<16o/MƸfcFGi˭`Av p!xz6S+G<ͫOk :ˆ!igDG|l,q<캆5՚ 33zZ-?DKPryp՗ZV> /\GGIi"#bܞGt_t=#:min䪅 3.zvIܜX4f7vg0đ4n DWvV# P{9*r%cLZ-ZFi=7znNq.m/5Ο,{q qx@``U3~[7gs5 \ z|dv=~Q!yqC?rs+R c; 3Iv+ BtILw\J2MHN<~PhD:XƆA"u PZc]걇ܶUlѳ0<${3z7퐎q4.EFzMx ss# `+9ݳ' њ½Y.̠w['Z*|#P('ϏQdbZFҿh {p^-y[243=!/\zN'g4˯@AqE x"Ý8r49*=n/~k!N_e{2z^8~k#GؓğE AA`lO5hn̙3C~|M_tHpx{^߶V~}<$ sWch{MB]ϡbA]\2gGT86!6'lyIkco5&cF(7ST$F$BwM=ׇJͅ%?:ACkw:b\.4rq 2rs㨦J ɿԔ\݁#jSQtma NIyZG`o fUs 9lVHe͗ xugfcpKwϾL7f#'WXI@Y_ Xi9lɔntsUbAhs>]\>3\U&qMMM$I(xHH1aGR pAeU N,~s'y v#5M$ ݒ] AcQĘRA/3)> XY ac0:5ytق3;ň8ROɆ21XUuri{UvC0 /:U)oc prj߂Co׉wg:.S1 >sfsM+(A_.[oMᛁ%Vjܟe!9i de`>zҕ_n算Тڲ$'gJjx0i QZS#Sۛ l#n _1GgӍC:qܟ50JXQ ts?A!^sFp̙))4@H`D"̔A /?5h8 /MruՊՍEa2Yv7cBmI!9NHĂ)q(sDϳ |ԥFM[,P^<^NE:F7 %fblvvAg-{p!mg&"$ \$\0`bqGHl 񐀐O 7λ8YGK3BBTP65N-6;Dܜr;û86EQNn7 *}bbDTB&fh?[7&1>.{`Q3e;w ت=ӣC:>jƄ_ /؜dCy8ZO.N7~3;a6wVׯݕ9@G=ze &ShKG<͍=-]P_:N=# w\-;43i=v. nN`Op*JɒDQc6c%Gc ; h=E|rF&PDګ՝hcߞ/nõ+ ejGExc,rF*k-#z \Yfd1r1ܙePJR(l9¶693g0b7t:EXmÅl5'11l+!ҐB\\46OO۫E˝i?kV [w Lvj`nE} Ea~a9V8ջxw9C9y ~pjx6 )r Kʺ݅=A6(q4)hf6 薋%јprx$[rQ\@- LNe°\U hIiG,2uI6=ߙ|" йiqˎ^ec\y|ٳeIoHKWp Vml|&`48L$T#ry I+X篯QR6ܘXEuTYN%CSiG0B$cn~ KӾϜ9MMMA,^ZMس}Q+QQ\Ҁ}hm\ʲ;=mX4O;" sFJ nn7%ܺ1]_HxjSQ Ab 7@ƸOYI2|& 3dAdsQu I2Ȃ8ܽǜw ()M WV,qmmFm`dhܺ=L`'(eL{J?MN4RRY "Һ3b.4|M5kǟ )'@h= ?VW(.IL-_bp}f@5*+&!ds1zb(I )HG1\QB/ü@Ϋn755MrB_ 8CsƻXjtNGFgᅗʱ{OhҞN3mo҅-K޵;=ݥZN/w!6-ar2~r}, ,?i4a.x4,unQ& kh86\ .JZ 1LOZL/0.\> x/T$h'+'thL*Rsp~bO~yf=Z| M<\1$8Qx5+2f|?b1I|Z_ u?N7e8$LW ]PIL,fbq>'x4GH V0VB1;f|>#)a(= 4 F'P\d9fgBGfF1ZZ_3 qAOX?; $14&j_\c}a\-uww7I 14Ck4Z[f07kdL.lbbĘX jEII"UWK1з|>\n'Üwqi A(ah\]"^_Ԧ+]ȏuSkT6dsyºPA̠Ħ/B $Iks?mz<$tK=ZVr>E}/]i\ػIn^ vь QLjYԛ"9=o8wc'%Ug+' ֖ͅ|. m7^j)Ux0s{[A#ph^.H$1x3;|}ᗜ{ fӍ{ X,gc?x{]:0GE=\tungQQOn^g!ӳcWnů:;S>.OQYØ_pE. n&¹b s%0W008I'I~O:j42BXY`g65MAQ5SW{HӣYk«w7'E"n!V"dqc.M`dxÕ~PJBuMkZ ݇zˁR=AG<=]v|8++&Rct ">)y隻In5|q֮ISzӡJJP]kk.6<_Q4y yVᅗqxeGGP9vuY>~zج .z3,fsx ZK *6U\v6|q/Z[f0=<)G>νkϑ`Map{ t.0F">N$bWF,xWiw/Y,܇9jdal.>$u>,'=]Sx?%zVXnݺ $:'߅SuΎE^a v 7O`zJ>]ᢺ023؛E>H=grPx(U`PǧⱣS=1.@P[s}=nVT&i㜹U4~TLCfWj"cv$1aN)[Dje@HnBTJhit F[d$|P2Ac<Νgo/9n*17"RR8qu!1ؿى3ܟm{2pFDsm7kB(?TD' BH(Fϭw مJz7k4}ڤdCQa^&)ΩGdIbPH>A܈(z&‚$'1}>%:+5]RvՇP*% A))Z$naf$́gExp̪ {v3|q;<ތX"r R:^TZ))YFQŸpe-#n'ʐ3ivvQ$7b=`x '.E Eϭwᔒ8N_)ʃhl#Ap턽8$ρil adyaI~c>?Hbb#p%e )MXU)P'ʧGϷ&CO3">JX8k]v3|3tESJK(,Rǧ 6:`6YDž^Z 9%PB.ߙZ/;7WpqXyg齍:!'Ne47%Ohթ!(XdטTEϡKch6Ѩ,o=$. "gx ^We%}K"y;rصIw|1 zFQQ7z#E3zΏJ)r8c ܐ$ɪ :ș11"'7fCj]7sn /q:qA/1_+ʗO#Ps].JQpc`r IDATqix,..clZ08KU K(6E K>/܅aSB*@OVff(d*%(xٗxKVᢰ N- QMڧ+8ui Xk J.]<% YoP03AiB+?()8~c}Y0\Y@P'ȱ|z5Sc7e|a~5HsGK4W뽙t[k7KX:1ogZ8sy c%DQB[_Sj=Q{ނR)x 2)=>\T|tӽ=K"p x8|)fc&s#Y#jLazq;=`aHp1͍^ PDCa`202 N~x((*4 $StX|a d[A jBg/:ڶg-z&ose8=m6_ہYp%Ɖ8~{DnOgc(DC`SdC\}e ?>5x0k.!^*Bmz,HƟ_iQUށO 0ٳQ8r,/R:2;cga]ATդ2\ػbbmG51[?g,'ۃXܹYK! q̙3Mx| >v$RGTG'㏙i=Vn Aa\57M3.Y.FǼbhLvP24%cVoW]R@NC[eXA66de( aU\4Fi [(+K‘c(-Kbs^{s~usƀn* =WiV:ӑ- $hSe*pI7й`|ݿ)=Ft,a o#*P"GcnN%`^9Տ}%[{TE121eנ>UnրgXN4[SO3.]zj:+%BTl3b׬TtcpɌC:s4 .,ct~'/тx֞ ~}6N&bG*118MO`|>˯VH͸~;;@z{蹺&՛ A$x`ѳ{$.)~sAZIU)}a9q]S%&9pl]ؙX">ѐa?0>s%I1*XSlohgjX T$/kW*1]v{04!FШ vq =#ݟh&q(iíU7n[ⓥl֞ -P#/^R =2XX05rg …F_϶L&y F˱Fgw{n&;#cyFPe z' BfMί\ VC& 'x"9\1YHyC \V,N|֫E봞r6\4kvխ]( 9 xfYh|> Q^ *ml8ݥ[NT/3fqjMZ0aJ;tYT$g+q$%"EL(Al dY,..^cE:n\@9?"+Jw$Ql U\433CxWxNB"Č~ /T@[y#< yf7#H\Rb g[EQSSIA?=?>n PFeOH$Bdd&#2XQc2&3dwAaJnY: 43l`hC+C>ms*;Uh80|٭x~ uFᦢc ڪ==Z|ge .L ⫯?Z c/@]Y* URJIYQ!-- q'k }ىB_5;7u>$bbD0Z/.N칷XM^02ڎ%,9֞kӰ`eJuG Ԝ] |-lTXc ITMQ] OJ-wᙧ7蛌nթ-,J8 "=On©mC&C$h^eI2Vr.#BJE)lW3;wkqQ^DNgz5_tY|Ϳ΂|&\BiR 2,po9Gn-Rbb|5pAΚHĭ۟H;t{й`BƆMbhcRT`1ŹQQ-7!|#YI\ S=xo3tXa0=FYYJ44X,FD/0{lpր{3XXؓKXh|8/cjzY_Ѵo}-wa0 );@*Ƹ%"oS?8__x5G7ѽ—3\4 +ս铿X5kh3>^&ǾL%j]S$B>v$˰jubgzl 3 ܪNģ^7?8׌ʊFi^ޮ9 ǣݝ3ǻq+tu༘eH.>E~hZa-zjLS^e+Q,'\7wCLĚN} ř P^̩Dt)9+)\m6 ._}o|#2˩7 .)Gi=ƅauڽ# ++;Q*l\!]v{6gs~ /Y„R0!&d*R¾g㾋AHtpq&I L]ExŐBYgg pB"|ӂV:?;-_aqq<<OayOјpЇј:ǜTQBZwgY:UN?F{ W$s:߬Xۭ^~=WT&G֨u$p} \. Cd/rs#H_{ Í9#e}7[Æ޾;hkX.\|{w*Nn.XnJq R".4va ĩXn6r3<8t2bcc<# Ýu-Z_ŞOPvQC ] F̋aÉ{3ܟsvc%BTbWFlDu{O oӾ𖴞z;*Q\YO֣[KyN@wuYҲİ4Iz~ߜ{kFyhh֞w+pyt==J_ qys za'X!fir1eP*7\]_lz 30~`'?"66̸v_q o!--*]Y53Bu V̜$yRR$Qƞ@scs(v<^Fo/ިVz34<>3IwA\PQkUk[j@@Ծվ-nՊRZ[e# E%y}{g$vO>>s37>ؼrVULt<#3;oE4CΝY5E^pqϹtP.֦qRз,^֯#<+'*{Y8ppv;vlgٲe93Y Oeuy~ -c81h46 FƲm%{˷ qE^v:vcQ nڷMU$%O3 G>#FXv: k>?2 wl/"U xh VR-[sx5!6t&;gi~WW"eN.ٶT9;Хu3}:"Rvr9ٰ16l0ȑ#}wjpO7jt0!i4- N3b} zO:On}:TGn9v’3AG$gbrrSٿ϶Kc qGH $M0]9+1͈~ o&CH֯Whko8\{͝U ׆YUȧO32q޵{3i.C!rm?gSME'IymŧHש\ؙ [Oo<̬y^k%&&VpTNM]/l'J3Z K^LjKZ6^7ĪG#o/ q>uk~Kٻwo|Inq[6Y0MNAhӓ>7s(ۊX0W{ߘ8p`iIuf1ZǃvG޺>szQVvTV'Zzͺҡ<񋗽?S$g12wE-ꈳҲ3^̬O􀨬_~Ú\%+MQZzKf5(j6m:0l݌~3~:nƥڲ-N*/?˺|#bzZ2_GV8WlPP{*۶瑑ڼzb۶<;;tVr,XYPaqmv&0xHn:j#E!݀g>(co=j;՞*8+zcy9"zy 9vU̚GVޭ/Ft؍j[X1$PvlIN-.ٔ8 3+|rV/foL7P'cwGKw"ew8={Kf/{cqmqo"xr!B(1iI^gyថgU]*"@ ٹ~}jx۷d,k7N'Z*"=xz*+{W};c܎\߷Cp ׯ$#+MͬGj ri,N &,n#0ZB^NmkG*7?}quɔa޿;9"-hժ#᣼c\N!W:w5]2-â3} ~ycǮ=l+fF\A6֯#Czl_йuq.9S3t 0nBZz9Y~pe-yӁa5e^iعʩ/*Tulu99vjǘ}۱%1 %ܻ;2RYTGhъ_?;5$ fصk_'M 4,70UUW@uڼ-}?rasS{+F0ކS u$=c.~k}Ooq^V ב :7?&wO[Jb'egM%-=)@'-תz$Hs`7Рbcxdbv@!in?O}2I@z%@ ]}ç'<5Ϝ '7qT*07yz w3TN:Z۝',>ՑX7-Z7Rx]8!l RUVYBr [b11կiѪz.m3W;~rUeғ]Ī0R:GBrV2I&?VZv50̄U**Y[^oE$U]7>/";{a0Ϊ.6o%#3u-)y؃%ܥBoN(a{bX ;Nw?0ޘbP+ܱ:;%/lʶz]x*-=ͺ\=6l?H:sQ6k7l`n4nJAi&068W'z,[!E׶g҇gOIV˲)~o Ñ2hH8<$Vͷr_oՈePcCuyps~2R^ѣ-ĸ Dovn9W z Kbɷ_X]pMWUU= ";>[vtVRi9_i5B0CUȂM֪޽Mo_Gb4o_ge0>:b=ȝ¯4[WSe:YFfXOZz|c>j-`TՆs<r㬪DXρ;[D#\۪] JX0ƹyJmkzv >ܾ<(ufHsaq 9j5sje<>CU^_iZ04 /y(}s</üw6&'Ԯ'0=߅TVO'?Qڼe\=jOnO9AvB28pT6`٪jy:\8 }RT$2W>qk T:Yz =,19]Jԉ76RBW8/ylޒc[:))1U0T jiiWD*vmoKl߾mN%7wqkxXLiA";g!SP\yzWɪKbʯqٮhKtlrI lۖGZzk-6Y./||OqVu"hZQ5e*[i&UWw`eKnP+]74-[Wi^AM܊6y˸^0"-sc@Lǁc=x1gී3gNhL-cƷzÏhxkl~ӗv֐D^r*6aVUWHC dlo.+cIDATl%w|tV~%+ٲ57P?fYjK7DƆGW0&>6m VpY!c80I%]y3>273}& ΖOOZU6.+;˺+14-|`<t!"A*n~|gvٗ,^2_9@:{oD''O%3ks).yCF@[|TMs8r:vdJL o>Blŝ5>:5KƇ,S%8l5Y>Y!/[U=_gYڜ8y >1 WӀ*"3uyyKwE;"-P-a{x%VJUȜTBb˕ ғX3wO1"DU,!րr3ǂj<6o!-=+h}x3 , =WEV")18f` Q&itXѵ^|c(8O v\w .<]7w^ϷW7L݈@n{νx5FEYk0VPU[+׊ȵW1oseGJEvN*)?k1<!C;uΫ J2RHH6|ci68oqpf.9IUsl7 D=j "{7U2_j "_{:ǫ/ՠndi,X=LUي{c}L J ~V7sՠy7_}flO //B|yMFK}(ش$oHVvHpY,10V!U`KeD/y/1+++XUZG 96"r?xx0rW/fn _ԄY\"2cβ# "2"Qbc"_n`07<2!<;a+"#3d!rr(!@D 3fe$QW;}ۂj4>"uӼyK^kvIS|`?;3 2]p~zv}!"`w7%V, k.' 뢧c#s6*"ecd9Y(.yDdPӵKzQc` "2ðzcnR+0'24\8؀E2SUWwu~Ue~UWy7xGygG$#3+r&N`)5oA>g6t?p47NB $ rmpgҙ`5ap"C d}J1骚YyGDHOU U *$ND-}fZ2$7oI42|Cm6ƃSFF)/w)#5 V?Wg wkDz^c,F(Y5m:Ezn^j2 -#=@K.V۵;}NzEZ9#~i<9P!"k^K 9;@D`P%;Tu{'f3"2 8cD[qep#"b(Fmg( "fDw\0b1FAk1MP-YTEM\D}Qn4HPpY% jF&"ܩ_|O rmPa&? VY(QD;n0# $ETn'K;bVJ+xx}}GZnGpգXr;> L%W z!#vTXD÷h3\mSRӱ!OLQe 5)3wrSfEz.»Q7$,30Қ]e0FH5]F}ҶOyEC!흟@>g5 B!q rK,.lݸ qj6M =xW)if) v0Ua;cV8YJXwoD*V)Q"/J̓!p90eV8C-3!V-J$,ۣD=@j,22Q٫DyGe<\X 4W?9JqQ65-ye |ËB8Ig;F%+-k39ptB3v(cP1qG %Qs&0 &^r<L tbQKx(L^Ē[p2tQT: x~ QIU)F"^=/(w(M^KyǼ{LA)‘^X!fktrvw~6\RCh/ (ݬ'RU"+`Y,d8G&_YQW,!x%1_h^ WbhFi*8hLr ҃9&]M&˕fYUm(QX`./^mPȂJKZcqpSuDUs]ZN<X[N('^ݔ0a1CenB k$F+bGJ+#AkޑִeZKN!is"^W#Xy{bkLQf0S?+q4MGR y"l#&H$r>o#ldb)җdC4q% -sYjcFio>!Ad X tA*Sqޕ8GyLi݁0#&V)a,xRj:Q"L6M%A~'Ko+cưB[dhkX8kn/٧SBQm(a/-kH1tӷ7d=s(x<@U2 !%$$8_I?%5'xpC(i*Q#y*=fg&]_cmB3En :z>^9ZܩМ #A ^XjᰥK;p/<5ȗ~C0Czt{a=E|ng6{4 a`,^[@v'mlLT뒱*mz!<2b<gOZh} 2a7FK̐8B,Yr_ӾF^C%˘{-67Ώk) 3gA]~k%M;J#a2U&PR8[skSʽZZ? -k$HFXj3gZc?]uxx5fZf ـ0HGCl>Yyqj}\E3i3$׏̐)cԲ&sFtBL#0'^Q;=,bi$ eEs<%{ָcijZ 6$8/=f"E?s")<s C,6`"Q3E ~쥲r \&0xz2VG,,Y  YM]y'i̧TNba9C:rRP@g>>'"Դ<d(BwN2fH1N^ڙ[>Y9ƪ)YZ?YL4h8$KJue.WHưNW``u*Y@++-=@Yk4t(^.08x '4%[)nZ^JL8,c4x 2!EA{V40/x8\E 61Yg4M>#_ r*(@;,cs$\$QLVD:``h>eB\E? ׵XF~$H*p3~apM)|x]eiQߐj_72>Ÿڅ)rFlGfa`2Ryr>POh18=Q"q4f3'IQEumE2xy`"r?Xä7}ַsM#Gf#"bRA:Y{ɑ%\y)`v 2xc{q8#Kؔ^4М׀HO$Gg>ߦ# |S cx*dša"Oz3M#3VEd/TA%JROHO{ppߺ"> ϴf.n J?~gqp??.$ךt|Xxx;' x e` cj=Q+ק~4Ƭ/h`kWu71\eϣErhqCjxi0ATۍbk91\ 4 StjcK0ȯ@".n%^/dF?BxLEM!MӷV|MxS,LZ\9qz 3iiGz!"F8H)Z2TEs|$(c.P@lGB[xNh{yӀQXU(}6A 4+ aB!B!j7IENDB`ViTables-3.0.0/doc/images/title_page_plain.svg000066400000000000000000001130041311223072700212530ustar00rootroot00000000000000 ViTables-3.0.0/doc/images/treeSymbols.png000066400000000000000000000507151311223072700202610ustar00rootroot00000000000000PNG  IHDR 5TsRGBgAMA a pHYsodQbIDATx^ \]-!@b411Dj4k@є.IQ+TD u+_@ѺDh0Ny;wy@yw̹s瞹g<iiiv ========>8aI~M0JKN=J}~_B({?};ncɧ[YYS*rs+NLbX.=  %1CY^tS3*;9q![ۯTOouag`:/`rG~7u}e*"I$,1\}4S  4SUZ4tfipo{q 躇??ǟ>[+`oa@>~7Qa=eEͶs/'+*V?3E <&婿y24)EeK7`\.O2TfM#=UjPa! eC=<ny +^o뢟ou}mZNoOWf1Efԕ`#6q0 ‚,&SȘtRD3R5QL6Ve/½_V!+"'HJ)"#QnIΎd"ϔSģ עlwc U`ke5|E0 %¶9I#Ch^ҤY42]B% *8 !pWw=u=e槕Dmet*tԩT?o❎`\\8~U|<ɇ|Ѭ5ϱ'k^yw=pBrSdLcisJTV¶P2yiʯQM0"FsTأ6U\"爺HCժM!"xIlk57믫*D˵6 _> Eyܪa+'P\ +amUaL\wf%IhlWF&7lѺvwɹ(5!- Q{X{?ر 8QDtRԛ2|O:>y3*g6a"S- y5 V"#ͯɧIXAD'#5Ofy`@#sH]I3HƻVށw>XZF<6:⼢ŵf S{3WmEz%0u۟lO(|!cʵs`04=/suB&AX8kBtclaK_H- q"PQ6@`V?dN-@Td(iTxC)DPb tfS]¼Auqːh `*=r.$qbTboa{11{NxqPsR?SN*Fɖ,FWI{ix踱9K֊5EpeVZ"qEtlV3iW i (ƻ?T!6ι2,@I'p907F.2E$;1NsI01y%暧y`dϫm/z7>9sƙ8=;hâkN曩7~D -8~ Av2sN#@CI̦ʴOq@P R2|j>Ǻ_ɇIOJ?u8 a,`G8 {'ƧhOT0Z!c9UW=8_yFb_Y3GKy^s7\~Ӌ~]o޻;=ooїhA0XNM;ugIwq+YyGS/k;夔4Ga0x+v`7S|QVɶ:j:ѢC+Vmt׿~InK9۷'ʲof1{${w=>{ioiݻc;vQnnec3p[>uyE;w>w>zt{֮]ܼ0X $~q顇<3^NM>x;,…>6K[E.ܘj \VXS"x1ݖaF5:p80=4VO?v'> B1GLB@+yf%\{m_TDBmZh=!aO[EQiVu 5S*-WB :0!K^?lCIɃaaNrWt?]^쳖= bgǎAϮqѴvի+--|H覲lj۞'MÚRT4f|%gi*]3.G,LЁ Y_Q\RήER%I&l4̯ɧ[YWq}=, 0tC~gE0חrɾ^ow7Oooߟ>u_?Q'."ey95DX[B􍍥d%`*;RrU Y9AR=P[ywJr|v:faX wڥyY֫ZKZIcS* ?6cK%ޱrmr nzK!kIC))"8qһ??򮻾z {w`@̙SsM=͜IKXڜG4Uao^&$xkT#L[7$YՂTد6U\"爺HC w DP]h!{큔h+ P+"(zUTclF`] _o8;D~|PȑLNN?s39-tbw׿ܸ)2&[l΂c(Iu{-mA2[C{D}U Z) rHí*)DrW~9#IV^t"@n/yF,3~,LЁ ¼жkUnk%5N!Ӏ D()ny串QV:SbD,,_!>)Ͻ`__܄ ~o}{\ŋqb(ıE8'$d_uY秤 jG|2!3f7Z4ˉ23y{imn$<,LЁ {r%%y/:wKC]M%p8fĶ$s8X@=H$$<:`wpYmӛ6ooW|I8z荋;@ A 1ҍqҦM#|Ul3NѢW-"NB)FHBC鐳]PVR/3uXh`V tS_Cuq Ij/!*-({쓤,L{>&h(!kI`/7.q{< 'p:k:OG4E q4w@U71x%Q2צE&uq3,:n,jw ӪP>@f ~2~X0Fe4z=Q\Ip ,4`-إRxh!K/mWn/j&5?ַNn{Sih}8.?\q+<}ѢV|n&Zp@& LXCI&qjwLz%q=D,o]/\ڼؙNLHOڳǑǁN \x0u\`ٔށ9;owK@D?G)W<5X!$I8{8Sܙz晗<{ ==_xq{KKʤI,@bba-/p,W|d>xoz{Ng8pw[K qG8 Mgs53`&L@x /%=[~C`|nw(^FOpHp\{j? ӧ=Wx?,D=lݺnwvvm7.bpRs>;lṋ B{vu\ͪR'j:R̺WK0{8묳ؾ!!?'ڜ` `m6[0 \`w=Wޙ:`ж~/~l!0ꯦ{{{C[[[?ݺuO<\ÕzFP|q%߱#R6$kNҿ;cC3ydZ1fő競:W.;ӇFHYVkӗLa(`bßL~׋=}e0j;ws=-D{eHu3| tiǃCBJCҙMT^5c&LHt*޵G_sWӔ_33z&rze8; M zt_8aJyrӏE>VW 2!{p9X_}v!@(H7Ʒ;m ģ0VW$%RFqU@?}V%GBKgDmnxjDG:mm%ܱ[h*f(o\, 9SN<%>5u}҃(yڜS2.='nt9S]' N叫!N `#y! 6`j2&PUƆ'K*/H)WPs ' 4P2b 3TR6V6^JRq\B7Xr*oLںY%="A⃵)vSEDR@Vr*:~rnʯa?d6X*)Bt~0Fk.bSPxTY|"ҙM(X t:x6ۻ3'ov5q}|:>^]t~|0ﱓoޙS2Ƥj \m XC#Jɪ2tej. F:8b4#: -+;u*wL$ܚFFwhnܶ5hR}S!3+p8{n&$$#G\wuJ!ER2ZJ c XQat![q)g-X!YI`( s*Jlɵyz!zмn;v'l<Uvـ,h%/n8ar46 8#i, Cm[c Orzu{'V߹7========L~5}OMҋؙ\smT"-SW_3,4ar#_P]}i?@jEM!C܃.{ꓟ޺\6hx~ŧOM{jvsYJK5p la>uS>Xř"WPj"c"ll3.)Tg)'6A=$';I Q~p8\)RVW 0p }n0t̋0o^Vc~t( a0FfBưwhXS\z"abb\Ӗ?(ʏ řHH__G>\{a&3=DeT+Rҵ  DE[wElU8Hf gݲ @~DBV6-zJEsW,*mpl! 5-B,DF̲*Ae1cvK$1EI&3m!\YXd 86JhzQB`.4(UHF(+'4׋'+nDd .$KJ5P\wMFv?ɊKI}{LQB[^ωO)! ǎvx$KXFwf%M)X)$d5ۼL4אJ>>[Uj,m9\nT`(_ޯ.߳z}e}ݕ{zu{Z: 1-=糳+ٶnLK0UKBY,/j50BN0c=B JeLIaZv˔c3;[=ig$= =FFf$G5„Թ7DܬFe16{b-'ކ ?z`=wM#Y`\K3,BJ$47 hg-!0`/Gq5,)ŴnU}8& %w_85퍹'm۽[3&5#iodMg`*^*ӲbH)ENq!4c=B )"!OZzܖ H\Im h[ 'jQQˇQjѴ2Z< {S5kdcÎgGc81Upͯ'c3j)'ypE%;Y=6tfI_2޵jLk.6L;T=º[<%0C 7e,یqqr4{.FuN'J~ӆ3E p+Q:rLݷ .Z$WH󒨢yp+ AjV0*MҺr5BC)0޵zڦkZ|[pqdW62 CB5{=örE1 O2g)vnZw5$7RTT6#Bq&sM2!U5F@dfC &qGB-!E;.)>R_ 2AfAvd9 t/ˢ#,`XP5X.Y!tjEVH%4uS]>48a]SlUߴ8fq>^oˆR ݃r{̞kZ}I2# .VR񵭤E#m7Ђ]8^E\8#nZ;t9N {Anw4xzj,i1 EICIzm\W@Wb3!WcU&W\d`rTa@7{\6d31Ěk${< eaWWܗ 6֨efOp_mD`;=g:;{~4Lr?2e FFtsCMpppppppp_M?]|nOoL/b +n\53 #B?K:T/`ZB 2Z~ h.SSY<vnی]#Cg[WY>5+ue-aj82'S .3w{{%5vםeunD=&ta_ d A3_[wN>w"Y t*ӱK[E.XVdF7HU[^{e+s΋EC? h43XWfk{;=Pwaz+z3Kg'}pffYBJSY6XZ ^;Dy"-ԈR8˿_]gf+>$L*ܥjn\qbRl[7Tv|++@\ŲV3$+6N:^D t/+4V.]0!1~#lQ}p֣Dq(\vRrUȌ \aXCr}+qgH__.mu"w ) hXBK+#͒RE5h ifֻ/W6ޭW_/}v&a V)YZ(ϱx G8D G~]@2]a}N:9 *ᖕ0FWSh+8躇-&`3K]ky7PIjN91Z{b"j|O X|cNUje] _u'%(9%ţh>H%2E p+'Z~Ŏ JHčcȀ8 GHrLF{,v8DF(8Uզ0Ph ]!uȥӳնb|I໎ ը3;NUqL´ Hh-KY_CY$sb[ u.a|%ŅI}B6d99)RPׄǃLYI-5c瀇9AWly*^s,-K+#!gȗ%JȪd,,#ȪTզ Q7`8*\sxINW!xhR;(%=. |Lj;F3W@_> ZY?;=I2% w._}dL ?/a뒹I߽|ǏEroaEqj-;3Ү7`|) \UM0z))A-O&$# Lcz$4b:v݁ -d@ .p% zhjI˗Bo zS^Vo?gT-7\Ͼ<8nh2&=l߾}xi;p>00q~Xɋ=o.pppp0jW_3809/˃v󮾴 [7|~LIgcQ7 :L漩, ^=ݠ/{gdG }o]g![|Դg=E}ԸYS'6-+\sƝM~+#}?+n':vםeunD=^]pX_{j>R [7l;XNˑ<{:X}_{/+}Lo6o9ulG^!kNҿ;cC3ydZ1fb?2k3*oNyp'sJ*rU hS`%%քG'Vb5t ^R|Ֆ^Yʜb}yx7 d K_a8?XB=$LHt*޵G_"55!A Y^xx(C7̛嘧<,0[mkqƯ-vÚe@ NȎ-ۺ;l]ސ>#!w7hNy22d(,u|{\x_jO3.Ds6%_CCȥZ],؟Mq<*cؐѝYI Vy iʯ8;46 bՅULCy)KHfXEy3rC`[Y*F{D2F3lRfme"sUm g=&o]Wxaok['0AV9ME{ +Ӧ/_ٌԆ!l:DUtSJ)\h&En*PD#zDH,HteUBXD4z'p0س{eC#? 6օ};6k?ػSjz>4 (Bt* VK^a-N2ed3.͕4öIe)RԁoDr j6UJjj@g(to:}f1;eݏyuϯZs *fjNeT CrU\qճrR * D b:7V'GGDƦ @!J EC>;2lS7: q p-)w:@ݮG 6N WO?k<& 8C 5tNZ FYh0)'YyHŸ8ͦi6>"H )o-3 mE0e՚*QuBm<&$_A=ؐ#9SS\ק.=Y<%(~Is8u뺞p(TZ  Zš BI.44FF H +H+`V*`hpe`'VQB"{ܻ+Ɓ,;DFkRfSa8.Gxl'Glc zthjT,ט(z+у>;j͌kw5<ɜ@}t:x6ۻ3'ov5q}|:>^]t~|0[{rndueс[zQs\:ȣ 2fa= T #dT&Z1#eGb2؉"+3EbN4Zq=b2x (CvTcdM'C$G♨\K`(, jDZEkɑMtiYt"ѓ$gAK>x%7݅x(.Cx-zRZbCj7 7 pڼa=kUfՑ b1CܑPeL^}sbtcW-yq vQ@WOK.`Iq+'~-n ?eøSm !=Dhvcuv1r0Z[!=)F/3\˂ /\[q o09˃v󮾴 [q~UQVW6 ߾ͫrG }o]g![|Դg=z`[}_)xFc$  "sns{'`yeC`lB/;Nt; X=|U>dF' \%%1SA3 m۠Z83jV6*{xjkseys<}2rF囫)CuC:w$ Z_Abrll3*)' @rWTYR/ppff$LзUy}byy/e-qGpdơG.% N_qj|%a|.mN=GӸQ&A9&KK>&63,aԔѐ-j%LN9ʫ%%r¸8ͦ9t~x jLvY&&e" JG"#azۊK{y4q4fT(d!"&0؄da!k*,ax0Rw ETVRV•Q[[E -wPSq&sM$rUNcL2p`;@C)Pz^b R("ը3NUےmΆy/qtSbΎ҆V΅“a}4]FԭQNyuˑH&RԜ%\Dt0z$ML":}8E#m7\$ɯTLG%yM!buԹjͼ K  XAFc QJV{PeR@Cbf H4G7IkF6uʼn X9^ss!6VX]Dƃ%FZ`oRc;3]AJ6jfSI߹ovvO(1 {0vtO%J'F#ez|/F=`0O.pppppd޾}>@{;=-]} Ŗ5쵾?Qǫo=sF=}{l&47g2Q 1Y]`@8 bzmv[(ES_LLr65ᒳX1x;o0?)lwʿL;lxsRG; >W?llFGo ԎMxcɓ iḔ-s |y:i`,modGgbAMmwVw/K_Ntrm"z.;-d`T6*r]c"Z'X7;=ơCKJ|E RN}IOI<9)nj|0wތ>a凟i4Tc#@玤$]`~,g_ϟ29sOGl,%gq^RҴi SBqrC2 @j@CUA1r48B]ՠB&D;vo i% 웻,[I''NF҂ͫ|c2$*7X}8wc~4Mz\it5IY8nQi4R4%pԚ0 #l-rE,Xڜ!TVRBC YY)Hc#!g,!zJܦ2aqfwf%Ih*C^D ZQ2cr|\_$Blj{Kx3FϤl3xZ3-pΜTgrbUjdJې3 QvB KYd TSo\fR]nvvYS.4%8سإ5o` %.yn[8}a##3Zܨ) Q0P]aqQP-D$HfgS A50m$n?.`No/_zҍSL;S~w0wQq!f/Px9wcyJJq"6@99Ɔ**]m[Pk,bt5] G3>MͪdG1>;Ub<5F4q" 3j჈@U`_OEc+|hVfc *je] _$kV2#EgG(K7'~ͮ iNxy@x]I'ut G㘼Z+ M 6Z+[fia|v GK=qbh(\qDz i5k )۸VPYZ.H`0兏zL?TU)?2ܳU0b1\Q7`"Xz6yN9L% #*W,:K/j rʫlf6xL'Cy@_+j(Г$sbOd֎`z"PBS@hBIȧǶmOȇ=/_تdӨ,vY0ThX ͯѴVlÚ0y"@ of2/ MHA0Л%Ϗ_7:q-[fNbt~z6 zhώ_Qo[YHϜ'ٸjOWm/J0 =cۺ/v'Ƈ}oߓunF}~Q9W7 0>*z{8s {8{8{8{8 ͯ߶-<߷okJlӧvil}zӋe|m} A6o| /O |I!zK/`[%ۦF?׏G‘~lA={oo˗z}O=_zn 1rWy-tcV *6 />x~sϷ}mU/ z`X29 W6D!Pcz_t83w,ӟ.|m-@pu|҄c((zsrp< ]C1ئD!jPa!\fszu_YDʼyιrۄmly : V`MS{IkG V 5{УDH*i`yLLLWTT]bA'U |–e%]ҡZI!Ax,`ოG<3x-;uj[/(AvBt'L.9EZrd V&eE3k(*m&eIHRƒYrib5iuFz4=B[R-.U{(9 %dauMV)=ѝYTV!J04!Yhcis/w˄LOS~M"SܪʓQL^ KJJH K E`!f;{==%6}Գ},V,ڞ*aX*/$3sWeg5y<ŭX2'cr:׼E:z4-a+L!$lt[;ghP6#3[ b:E=8ET:âV,B:VNyyjW+ iTPLNH)J EC a)sOW^0yWW{ƪ_~uG_8<&ΚݣiJT=T*Krp,92mnPDTZUi?bŀ`Mc8] 6N€Ew˜rWKY5TZXDa]˲psÞI3e 7cw> Uh[c`MG iX4]Q-?/MPaUYlخp,riVQR!MFqT$s :C: *p0+Nu'$;]}=>ǭ}'Ϥ0U.YT#"ZK)W[T ,ŵm)PNۏ(F*h:ڟEL)cvtp?r*&ƃ6g)GӁ+I2Κ5+t%_~yۛU=(sVHd+O "g6Fle5Lk| P"z=]QQ(1=IVXIL+5aL_#6
O?s`Hj.΂{1tUDgS(ەY fZ+n|…:=J6gMf4?D=c OSL$gF^I(;ʬM/}*:ITQ)j,ݚJ|}56M%,TȐ* bCR f=y}"?Ȭ>?j\9OtRk4⦣JAO0v?e{p=hl-In(a|DgSxTM=DYUkYˬ*wsm=I%)qqU9H;,*]Vd%j 6ٌ}H<*PP`;`ٻ'YwH|% U ѱ*VZhբή^6 QV, I1 ud!?^O k=bg~49Ze@jbjgY TY[^mPVWHM=%<"4T~nJXe%j7FBe?e;iRGw'Il@'ji ZߺaV`}7kIH4}rv*BMS>a*ӣ2f"8ڋX$ nVb=6Rc{'e`][XED,Ϫ'Ι=";U(,lRBj'5 kE d(F*W,j!CaKC/"@x!@!@!@ܩ8cqk/šj1ӦolO~tg*p9 ߖ8>OZ z59$++v'O,LrC;/%~LGO+NP-*} '-C sPc>mv@ND.FN)dXJũ?~ϫO%tH *[M,q1?AL̥VnZ8;`c)hJ<{hp7ĜyYhjhY(G*L@9j!ѝQw=2-U 7YÕ5#D-&IGY7pQ`o>QN',C\Švɐ2a:Ï?޹FcYv g֖/O)z$*`䚐J h:'' V? Ƭ}pOjO>(^A>a} QI *X#JD CTdcisl`'-oqtm!YK'J58bR{fmYרPG*Bsʓ}sg,bb' ;IͨOp^(?$X_N˷8EDiU+v[zw@*:|Jf 9(qb83k˺FǎWkBʐb Uٷz|g~DZ ?dϑkHNYiǿ%`(;sbNM?mwgi=5[jl*uL3k˱GR_EBiO$v&hF7L>!>p=qnmRwo&+e[3yU:'=gDd7ѕ~z.))'ά\eѕ[K|>YtecVe^i\OiJNiq^|G@a\l"X\ޘ 2aJlH10dbsI{ҊXIL\l_8}=X kteo!V &zP[P4@(!@!@Z|SD|IQ'x+zV+[]u׏WM/ɣbsپ}֋/yܲ+\ 9J]v'Ou5.Z:Qƨcǎm۶m˖-7oްaEl++eggWtҹsΛ7ot֖/_bŊU]vӴiӲƌ3~抉sW=7gҼIL3e~k.șp͌Ekf,^qkJ X)R$n{}z}Ͽo}=7۳纞To}tbta:PO1֬Yvme]tkֳ管Cw豲ZQتVrmuYc&qc&L?q҄1kzҔ&Rgo) K\=r{X#sD Fy+6 >\dff>} JeqMlY{G%?WjڨL-b[ _;諨{TJu֭HJtԩ&L@;wܷoߡCz);~8=^UO8!6Ք)SڶmK-s,de9]dM>z)5S*~8~]t0J>Μ9rZ;O{,)iGO~zs~ں矜pC'S/|Q4_\L'#k:,`R&=rѣGyr(J9{7gEmuG?Шߒ7jt[V=<oF="o5}؉o)yT=zȆW2rxҥ~΢#QFͻ[La"ϑzj;HDH֭[' UWT.ڮ]A 2dذauuFQBرcv*~pm[{3+OǛ|,FiӦ%K 8YfX_{_ ([:t (ڊa?N`#w钠?_ӟ?~_hQǦ7oGoG.*pD 6MH$"J'C@+A(&]iyݰ~:]tC?0tG?~_~zȫD%wȂ}t`^V яćnLw|wP`-}׿{۹{|N '.ոONLmoR{ s&_ţf/eE_YFwy€<5 QOGxïs2#[~(;N>=??7RHFCAӼ ++ѣ)S{ԟ۵k|иq>?|7VZJ_|^x}5jԮ]"/L_ٟlb(z#*8`)^v,[7PȠoK(. > 7oLyEU)cu;vP@E՝;w&ʕ+)eǏiNYBU@Y/s=?M/zﴉ*[mesV+fG[/ڐeIUY՜ ]D`L4IM2Xyns##<ye(&F{oHqZ>6ٳgӞQeY,?2i,4"S_/)r^RZ՗X3Ʌg?{P`FY&M~w;sUmpˍOx6^vhĢr_p๎[+X[X!X[dBu] HXg̘A@-xэ\|6dU (?e)"fiȯGZL[FS֞"WZ j +EUV[{}ǎs#ErlD{[eּ-{"2ȗ+SU+W}oԏW W?[?X鑍SZ!z€9xU}L/_>qD:#W^dU6Nx`pJ3P`R>\1՚ STKSe˖b9nݢ.IѠUwk[ЬV-vj]|%;?tolx=Ck^x>a_L/#]*ˡ2ڵd^^14v)l@Q0==#][(Rg:[x毴iӦ?gX:oY ǞB]~xcDmO߶za1؀dSQ! G|)j6+,xQ`iU|*ʼnHV]"W(ku:w[i{,,'*)ZU}iL|l\XiEZe{/vCoqO#jUpn~~AGL7sϿ ww~f٨o^V/被+ ~{Q^!ELa@Yr Y~e̕u__m9oXˏ3#O^La.>}QLR#mQL3W tմ%qgG!Ao[oUn]z M)\BҥK >(z.袭-Z}wMU]_|7<{衼ܨuN({j!.׮]Ku.;vl۶)\R3JʿӀ5ٳ*͹`Sf;v,O>uT.nB@Ye˖^x_wRM~q~;q塧;PBe!/ ݡ{s'EVٍRHV$5Ҍf2edl$2:r0THő'E""Msy|̈́MGC+d:Qo+}P`5V흟9'?ȬD$n$HnF>2g?=|"ng}m/Yt:jbEڽ{?;o}|ւ[ 3 ))w]]am߈yfvM2J! Jbs"FIn ,`)A@k￧b _uԡok vj0[ے%K ιmMi{^}3l{-=噧܋/bX=zj:;tRϧ Ke)AK,0J):z4sAALR`իW.](R2&iVm۶/_Wwgx:v/85f}?q;V(6*|NzluD 6 n8V] }`(JL$kK -w@<:JE|TxX`mm5 5A3'/2E&&2?lذHLÍ7̓OcֽwGκUG<2?_Oh^ڨCHiu=>4M7) # }Ɓ^353~?b~./C#'_vmyb"c۷on׿| zdo,X7{˫/rOCF/w|-۵|C M7(0 O,xҚvo_EG/v k>agM/%bСVcǎ>hȐ!bCx`FM./~o)?V u?zDiULm'X Y^Zԣ?[JO>y}:Ц*N{ ={ENPABR@g|˖-ZCo+yݺut>͛7wYr X(1_uUW\qyw_tL:kgYWl=UϞ] *wM{"zH1&J}/Uf77;oj~x4o=0@y׬Clǣ]h?|1zu,FOۮ?tPS3fPy֬Y|]w'*=j39C/׵_a՟lnU*nq SɝѫGz8n]{Δ_?7劻4}AxwUbD,_"#eÇw҅ؐ W`Sϑy`VU5k֬Z*%Q rs]tQ#<;Tk8P^'Lb /CM6-]T4/LSŋ))Zv_?m?G??C_RK.nb@"L.+Wt(\tZ~</ZS`J{y7_s5ӟʿ֟B>IǰEGr=/RϽzc &Zm2:>]d'x^mJZ;(i5q;ń|P'|20=>:ΰC4"C'>kӪi 9ګ#hOmi_RZ}֟E~?\]w€<5UfʝǞh4-_Ld.e˖Q߿|C͉I'XSUsQTZ*%g}V9krJ=UJ{_w5zf-ٻE5zo"צ̩@x;MXM;mVbXkB?}Ѩmh78-> -&C>JCY{~N}X?H`byCkygzuޚ˖o^Hۯnk??=()䭁;j|'OAC3xщ'N6/?J SN>}ʕ+ZjM2w8|XnjC:E@Ig0>W[=O= ɩJspߛ$µk_tѲZIs6'~~Z}#/";; +Io`5׷o߻)ORӣWQGxH}}^ob7%*OW9| %>U&͞R,[lق ͛7a&>,cgGN8Ÿ}1tOZ:8F.37z҃Pj4r(6XY܎T텅k֬Y>o;w+/GڗWSzW^xa͚5/XB;s﹗W]y€9j6vo^8jꉄ4c{D͜9+_*nW_Mo-((KņH.?Io+ qHg{UP0rH1 VJ=Vu~>3)Y=sy[~Ǯ]q؋.w /x9dsκtwc/d{ /O.=E>8Kʬ&  OW`5{ 7\tE?XsoEYTeiV}+8qM+ 8]=ֿ>:iQ ^'NHJ[c}<|r^JhHfUﱭm'kuKAcٷg N =gߌWc?mڴi֭ێ;:}\}c5{ܮ?W?;wu=):u*q=y^{wwWb ;G}f{gy;(ҹƎk9"4QcNNj iG}gz)C[Ŋy`U'tϝ7/nLWÇ1L nϖsΚ˹1Ǩ}ūkӟsh+Mf(0 ϻ,$%^dhJ m۶*꩑/Pb0`]f7x%\Ra:O=VUžV}>qpVXeD>aV,z׳=gϞo-;wff²5{n5@(Q9)鑹AKuG9j!XvzK}sfoٲE 3z'6yǭ7^y߲|y_W?o~3j(ʩ( 2#krs21E_qV>xy.:Y)bx0'|??Æ UU=ެY3^3ḟ~>O mק?MtOULETPRJ?XtU۷o欙| JV޵kG]|{qᅳ~睷Wjv袥޺^ӟŀJuŢ)}誘0aLԋ ]*<7|eUxo)Gzk{*P^12)<Q'E)?RoSL… fΜ)[>ۺ,\"0`rl<{ۗ  k۪-q 7PXXwy'J^Y<)xِtiuzjYp… > EՊ+Rġ}V6lYr%5[;{,Qy3s6{3ʱ]4\W_=:\tQiA>^tРAtB˕+bOuW;M;P}/ta?=rׂ Ȥ <}`1ȂXNӦI&ϝ;g޼b@"?`Nk{zJLX)Ц 7M5;FtɄSwPk1dۗݻ{;wn߾}VnO뮺^võ/_,3lY [OޛЃg"r[s̩R]wu!c)Rڵk_|bYD_޽{sM(;列M[nXPPPjr3Oa_䣏>jԨ{fr='=r1KIB bڵkWUrEk 7p/w]vf(j2]~Mĕ6tw-t"yuf oSjz  %b5cnG5krrrDSy;:_>|-Tզ`YH+(Xz蚔oK322^y1KD%,Xгg իlA(JX\KÇ%/^pѢ-[Vѯ;x={nݺnݺ+V̘1cĉ[jU^^}Jݷo6mڼ[ 4xE:^ ێ~uV ~^1v߸ןҴfҟ ȈY @ ]w%j!swFFq (: D`=J"[BBgl!j!g@Ȱگ/+X!@H!@!@!@tWt&,gz@)'̐,q2 `)A֦MER+~u(-ˢ KH :,󢦃 VF2D ,D."%ڱcGQӡ-@jNf `@ P 29,4 (bBl0 (!R VOt(j|m`atkz,yݺubdɍ%b-.(ؽ}]TfJXbXymQӡq 5JץHqKWﴸf%GGj&sl k61 ՜VpQ1CCxDJȬ& 9y9M; y^ u=^/_E_%OeDo t;#Z[Z҆?Gyisrϙ@Ho`lhA_N_ot f],|y=lPFRN˷!6l+!.N3gn7U|Byۺ,}ZF[E?JX)~`4pP80f\5Vqg?6}#*6؞iC)*]Th_aޝEDa+-,]XgOсgZ-(ZO>-*fhe^PZ!6[NJ"J&Iyw[l:5/#-n~{1-l%6[NJ"Jk_patH9r"ӒJm6J vr-[ʧf5\i~- yvzOZ3súκp?:hEλKݸ NZ<1 8olݺV99VB`5]3335꼢O cۻ?5.ج,ѯdx)XӪnn]l.he]3!FDfQO|~owɱR1, -Vɲ(Y5EbkdYU-R63Kўkj>dw}9;)o`IV6)~vXK;^^0]~ܾ/7cslX1  V!:uJTАm۶:?QRc%&$6X Մw0akGu;nωOD7qD/(%д1Q}UFC<9-[8r+/-WN\kplrz!:ŸJ'giZ$)ZY:zF۔TxsVvuv8/+RLyq>y02g3?V|>g@iyM~:wi[7WvHZO<)*fhȎ;xAK()\r (&+!.h /*]4૿!(J Wcj+!.dǎcƌ͚0}A 7 .s6m6m,wz""Kf2OReʞ TNcZ|f9`wPg┡Y}[hfДxqz{k,aIlɱRVlJD>E7ŘMbkfLZ5;:^Y[TZxOPֽNMN՝_=n[_KZ_}+kQ_y׮%.?6aCDnl[Re(ո賛Dg ҂޽{m6^p%XN[X ՄwV^=}IW*tƍWPf/@z,Jc쬝Aid9` Sc*OAnZEv&ZSӆh{gz ()r*'JkxU No ~s߃ٷͱG-`Ix[cN;딇圿ozaC*ePQf1ҌJaX=f ٹs'/wX-rj» {?EQUlHm "[էY;v*6XNJI3NgR͟fXQx[X$5"6\Ŗ%DvNŎM~kowv sDr6hR#ah5|Dͬ0VV;ETАݻwBXMxƏ߬Y3fgi֥@ZhWv,ѝq=3œ9_h+6LܣjDTMe2Ҥ9tz2VJC`=Q[pdA+;[ز.;[.eQ+X.g.$s@%L2TZ嚪,&mK.$ݻJdj"JϟߵkWJ999)}ҹ([}:PwaVIuwg\dguQ=9Dͺ 2?aPRoTJO* YSu[Q*@ݨPF_TАBXMxACV߿ܹsEReEQ֊!TOHIS+!H7e >jn-Dr&RYEl4%pў4>M_,ule7jKmĕ?\ڧ_n9rCnv'O&(U|pZ Qg1RRc9VXKeM2Qz2 Q`=yduٛ8r䩓|kFjE'(Uk,M8bBl0 (b ,4 (bBl0 8Vi /Cպmݲ~ޯ} Zժ_'9k e ,.! V9ڵ?xo>mL#_l;έw-B Pw>&(DJaSǎ:#g9#m|o=ӇM_E{EooFQZ؟rS#/&(;zѢE  p]^bFDM.N:Ԯ][}c_|x?'W%{?ϽqԖSͮ|b\TWf ZB #HεReš5kD )-jڴi?OeZ7|sSN6LWZ|,I<ʯ2Qs[ͲkX^`Yk ed4B<9JDOj7y]Ye9U+%8&4W$Z;WUkp  +Z,vAth.JWz^{Qõ/ܱan۱KV<3fnJlg}Hҡ!Pga 2mWvLsRA^\)^Ԣ3wK뵢cuשq}t je~βC$%uCVXkԨQzuԕ*VpX]] ={ ]iJWmh+l5N>|d%U̵3Z-~!7ծ*=IM̡"k-S-gwQ'e}[$HεR*fcj"[s%K zm}֝UV ;L>$ݢܥU'Wbrv DWԯvVg0э.."?ߞxWAʕ>MENi8 'h9#5GjziU.Ì֝+W ;>ǀkFTBcedX5jDiV dT)oqZ~NUtE7YoP aX^b{nCswWZ:qhQ[W,_ AZ 7޴tW.Z~yErnxʪ΢zk_iD\VO/.:D7C͂5+s2\DRѺ|rQa/]yeYid%zP䰲qGoM7,FtF/0o Q0YBr\K/kڵkWQӡ i\+e7ͳE]L#3s$jVI3lWfQe>D oٲe^<(ʲKaeX9?&AߚnI2X*]\|Iq.Dpɱr- A^k>fV0ɫ͚e֛e6UtXG*h |cr^QjYtW_+QeWz.r+hz|+ʬuo|e8% :P!9VX`CswWɚw-oնu:o LRTb (;\-Vo뭽QVք] f2$}a  `!2cZ:xY {;|>%ڡ Z]+6BA>Q !PzҤ-D%.$*N:Ԯ][aԒm'tt?dGX5x~t*/^,*aŃ?/Ke0b!  6TX|بL-yyyG _-?W4k%>a-iu~EEEP=@h` Bɱ o`%4gJD\}*S+==*Ot&+*y:1LR?a}2_/J 6#Ȧ` 0J11e: *PZT=41;٘}|#I*/?%TG;K/*ѵ0F‡+7C..(ؽ}]Tf1u^n -X̅y! 0kbMWҚ5k222諨r}݁z!#-׋a򫫝}*)=z6}7'O\:i!OZntY+VP(NQ1CCx5 J_`PǶhF_yPc& \ClM t.S>iwS^:g=swǚӺ4KzԩSs̭FʟO:o[e{/^^8sl*F!6lր +}_W{Y'yP2+I~~ @bRX_% !Db e_AwZ\k8獷 7!Vʠ͛77l/wwk̮retڇhblڴZX!+}3g<}_i~@z'I~~: 7mG)*ġ&T$FV 6[G`cckqq}n/<6d6} ybF1VZJ`u}&|6xZJv|T"Έqs%{SU,lfYrE@ӄ ^k>sq{NgĽ'zW'~a1F\Qn&ѴEE:GRNrJҡQM#쟼`}m횹`Y֭Bape+3;Vj&7Zm76YmbSt%чUDֹcbjLEE;"*4P\}Qϼ6]BsblܸXjAe:ݺPN忍oyu{>5_<}vH/jd8q+Lf<%QqRsO ?KPc]挷? 'O2knǏӮr ?hJtzV;U;v3flքCgZiugiӶif/T"QF*P賊>i7 J<}XK!⫳+{&ptPv6*:YiyU6š$C1UTА|oU,j1 C`5WEM VUկWb3gl=t#Wۦ;أ|WqVmbBN2nF7DCjY氱Ωl,UxK;gqq}X Q7:'U$wUP'仪v7իWO>c)ݺuqU99YE7J ѱ*U[>ItXܴ}gOx:͢4FFѝ 19t(.:8 *{!6[hȶmx5 Ja`2Dtd` |H?whWG#?Z|6ELPDU6P*c} %?/a(B~G/ˣPVe*`Wu(FektMS쬝A;C'UߡxPXTD` D:+?Ƴdnޚ mSfsIzbk}S&}8bYE ?~|fͦϘUa>_,.&Q&{3k:d?e+Lfa-4ʫrRθ\ɜB & QvbGV0Q1CC;BǗ8*D#DFd}+ 4rƱ! *:tPQ)큕rqe& o?Cg&< #S e`?ş5ϴ_'E̟?k׮\srrDSailsSժ7EcUh:{Cռ'9tSQeޝqQFuԞ Rn"Jb\`ݻw//AtZ'f࠹\C٧YpbñB`RN3̘;2̝̗[<5,J'-gEWʁU#J뾤Zsu(nVe!2TuK&:gdBT 5JFU_G|ؙ?5mwF<{^[T "FhOgceʝ)C`5;jٗQsֿ"k?)UW6Zi`x`GRBrE ҄ ob;gKY!pEe~2Er-V!C`5.dѩK~;>+Khǟ?qİ(xO4 G˪)k*ߕkz^c^2[Ou/~ϒobq}LqQ`=#GP 5D0v\J^VdR$pb?VaÆN,"1Ls#uF̝}\ ʊZiIUksf1ēQ^KI{ш`l.-u틷 Q`= k)2"ˠ~XS2E'X)pXU<;:;]vk3XgBvEOne !D^.Oh@YsZ9 b2]hͻyYWi.C[Bc# *z+WYUM`N)lw]eRq5UߕJ )QMXlRRG lb.R]k a# *ڽ{wQ)S2+6NZQ㿒ӫnĥ`=X.MK,70HhD`5j^={%f-*J )W$d` ~xOh@Xc=qNzd͚5xk@X! ERT[V3i%HεRBV*G3f~c N9)&YV9&Me.:1n,&?g<o4ր Xy!VsXFQk@\q@%"KFI ߱jR9Fm]rnl]V;yɮW۽G}s3o!M(=VA`5Z <:L3]ם̠=gLgj}}Jr-ǮZ%#!5)sY4{ڱ1vTRG'K)p]o@:P=V -X!廪wZ\˒~Ϸ<釺=p/e>s惉Gx;"ْ ,q2,^e)ƜVGM-{cehZ6}V3ziH\W=VA`5.hA_N_ot~ňhwglz+G"M7}w捱_ )W$Z/~IP }1"^+*!-h$$E-uX͕ڭkWQӡĬ5f\꒫-EWYruݥW^aORV$o?4_q̫X!HεR% xzS/Q \VpZ,:nR*ek9Vs/v^th.1klڷoOQE ( kv#Z^aqLL@+sԻEïXَk]}wi/qj3cx؞3wsf3_n=԰-ɹVjc G8€Q v,TjDjdy5kJ[јUCnWX!*%gU +ҫJ[Ԗ=V -X̅v! 0+Xϼw?s>̏Յ v˱38ky34TX忱vKq5j>syEreRi G%zz/kjbmoW`f"E_=C{Xj5\^>GW=7;˾cik?Yxn˛\d?n]i&*~ + ,ZH29G-WaųYO\ޝ }_z;2oy6*-TȬqrl2Q)IS4NU9J cVsڀ637/"K;^o;GRKlr3}cf1,HM{wwyEr/p-tM37.16Ukr}tx7ޞ&,ބMvnvժ\-W3EnnE$Q[t(G.]TTJ;(q؇)*e9pysor:|WqۊZս[_zuϻvu/iv E sSbk1܀yErVoO&TFVl8l6Ill}x-.ε>M?RXy,; v#ժEed#X/z0,Q*9 k=x̾}MkRBUXe_DIMq26ޤEQ"Έp+ٛ_m,kPNh\כeÇS)˫Mjhk@X͕ڦukQӡĬS3YNw8˩?)jY.'?˙K ɹVj&UoҀ^"f`SqFc[m4DtdInm?n̮MKH ŋJu_!ꡤ=V -X͕Z3fT붢JU}ԁQg1 J^\ Vf=( oҀ^"ٱm!r 3F\Hy +ր +}OޢCsY%HεR[X;E܊."+OIT܃;Xb%;0H+yErd\8+2k/ӏlH;TƪuJp\k_§P/5 tQo]39ZTe W B^3g{`G vZmotx]6[첽}fM7f0H+yEr)5˵Z#Ee$wJlF?ڻ)<g=e҇#5 qyAepMrVk ݬ{#?f>iCc# Jڙ=^SoU.޲+_]tU%W]zeEKpe≦|?Vi0K W$ZOiir-sD dPޒCu_v.*stQeptHѢh.K `!sEef!±! Jڙo>CsYKg,Q { wSt 0lK^\rЊV/XBgU<:gdBTJڙ[o%f-v=17~iᬻ cY=\4K>Qw4؍;7 IړiLo,[ɹVcV(W*Q9V قN5X;(V9_Yu5*i+^-Iirk@ qy`,QfXͅ!a8V2/%f-jasWlGܮ>3n'Zh[;r;9̆xN9Ҁ HεR5֕rT-RCֿUz΢[O/~ϒ?h9>}{޸XBgU˛ |Y$XM&c%v \+}7n>ȼO~:瓟'[];|335w"gjMbd{/5j!yErVqb:cճLY.khRv^40e6[KK]s/%u3Ώ*M )lpa8V2ΜվlstSyC8ڱ;vԱN)ߓqp-['?s ~ 3":cDgB^k>b.77#Ɵ:9V E٠ rH/>@` q~T!.o2]3)f2ùX]zE\G3g{`}m@zxn7ݝ# e[F6 n1h& F yErV ky+윪 )QMS>}6~)C` q~T!.W2 V=K3g{`}sor:|WqۊZս[_zuϻvu/iv E 7~m>7G^k>XĒZ i}j3Ώ*M -,ͅ!a8V2Μ`k_sCK.X=X:}9ޠbSu.ƻoi$H(t J ~xOh@Y 8{5 tQ5 aaE3g{`m8q 5 tQ5 aaEig:k%f-i7ZUzԍ:aVصRLV>bRR1LsY*cM%? }4/$stQA\J0+hg־}f0W$W2[r%N+7Ř(bO~ mSfӵjqUG;XVZXx@;cX"BɹV"*O 8?ݑ2\h ñv&~`ӧ\bVd+sE"*O 8?ݑ2\h ñv&~`ݻ\b5uɦ5{!TɹV"*O 8?ݑ2\h ñv&~`ճ\b] D?xI{{Lg ?QpaK!dɹVjZF8?րбGc%-eк?vAth.JzbŊ4٨U:=zSm,U(i\+yBEa@ˍ( k@ qy˒|QekEMWT)77W4z>{ց:'-rZ&!mX!hɋ(CsYӇ *ZJB >Xou 4\q`NI@&Uj?Dػ-[e ,kNNЄ/5 XJ^~e۫vy#} 0Yuk~OD鸻w{ɵ' |zlg~Zu=Ӫ&f$뷯LP%uK4a&D` 9V-y=~}MlO}ԡأ'i_vQ*[`EqZ tzܱE:ţ.$*Z\dth7=8*KG` 9V-y7&=_?bS?M:bJܖ-toSp'kN?rZI#[Ia1/D\* oҀ^qKM!T-7Gn\DXj@K^ N3uySWG':N?*I6fMd,zZE+(釡*Al5Ziubuml+& ([rtJ*)+⌸+ٛ_mճQ ! 9V-yÇ%fM:u$sX\xcO XxJ ٩e*[}F~\˱k>,VEIz-UNNeqm9UU&T] 3#+kbo,sGߌ+~o$]2Fo۾] K{ 98H*b, p=!jR 6wNE`c"{] 9쏋lU1uxUP'仪vB` 9V-y֎W&+k9v',Ȭe"L?!휆Rke(qݒ>!A`5 %/~ڥKQӡĬr-5ʉ"Zml2yHޚ mSfsIz" xnS&}8bYX+kR +^صR01Fv)Re+![A`5 %/~:p@QӡĬ%jړMj6=:N9'>Ni~BU-ʕk*C"%ZUU~NiSb+^-4N08VsZi`M7]}6jky^T5>PO3av z?-\˱k>r-V.[{cU/ˇv4e 2E":߳;oɾLq!+X˗/_R\:oNGY^d#k9N6:*qe :o, %u|ǪD܋CbvY3'EHv02-åޒs/%uMډX!C`Вx *ZJB >XouT1ٌwOgHk9vGLd79rslQ4"ss!5(#Cżp yul>q +X/,Zc{w364x4y$oE7GXXVxt`wNgR8D$+˫ ]CX]^B~x)QMXlRRVsZ7 ?Xth.1k$ {#5w ?}Pc;bޘ-SI(:+wT6u-\˱k>XĒAϦ%XXj@K^Fw5K̚>~|f>rݿt'MֿG7]$Ƶ#&r )/Γ+a>}`1rlXj@K^mQӡĬC5iƱ3Ov{\h?DG0kRA,oTolXebk\q+u,q+?81U78:礫C6ɲ21qn*vѱYtcM6eW79QoAC` 9V-y^th.1kԩS'S=􀥧NwjSbJ,$kzL7X}FcmyEN:VvlĉɩARwzղvN.{G0G[9{kNy^UvoyK>ѹJXj@K^F5KZr2<. a7#?&,oZQ]o{4Ȃ7ɡހ~IiX&+lX,ǘ]5ڐ#ӎ˦-9&BA`5 %/~ZvmQӡĬ%gI35K 4\qVlB8?e)ƜVGM-{cehZ6VJ'>ր C`ВQ`}m4l߾cTG}df޶}!HHEbVsZ7 uV+"P,dPA`= C`ВQ`}DMoNܐ (rZw' "TX6<D^Fj*CsYSvɜ79pS'}^'NP+R-F8?v]T5 ѱGc%ec[XZZ,>\th.1k_vS.uYe_7ثUnOs2K^o .Y-$[rx ՜~L+Q`DMlڪ9W/͇{$u\=cG|Թ=EW([\1kzA`5xwX? ȋ?\uF //^sBG7Z[+eXsu9{2~O ic?2QI`cݦŰ~J)C(өbZ MݱxPe +$c_^3ZI2޷[7k@X!hɋ?JRJ">ElJm^~ӳwUwǍ3.zm6O=r:=rlƼ>yW x{E٨Q4J e]g3&lߔvz)= 6k%o~y5~R{2+& (Ϋw]ѪXj@` * *PZTFFu{7?7pS$V$*э߱X*;3kݜJ|>& {R:w)ئ6{>6g?A) H85BXe_D@ƛ4עPoz%RUٛ]v6~s2k`X9u)#yXɚ5k222諨:qĮ}^ʲ} hC[~F}?kܿY΍&WibVmٹDzw ^f-ݫKfZ7 阼@ܱS _kxm`mxtUnɽG9zܷC{cJ]bkZ床,ڪgV}W*9U)RK>"FsXh`fNK{Xb5 V&K.C+=\ yZs^>G7/'jܩ-?y苏Z|| :K.J#7Sw V0_51Op]EI8O5V0'9V-yn쌯FLlԭ{s?1^6Gh5Mڽ=뚃wVhGEQtN*(*Jt%N`eSFCqnEMo=']5IAtSE7dZvqu3,(UO)X1!C`5 %/2X~̴/>Gxz@{ڶ28ʀVnvO5ugO(esSW&cvщӤ 0亊 cgMQ c^"SXٽ#ݣKӍ ucØ_ _sj#766mjXOnĈ D! a#5KYrj^nuRẊ?)MTKaZbiurLO?zZe3i`ec\XZeΉoPx>'vZ%XHBV3&C"`W+ ޔ9ov~_?b64{Nm*|ϠA Dh}VfLuy˗\Ӽ )ȵRHVBLkVWO8X)V(gDZe4uϒ<ǻcb]/D^e$V~óeN6bc? e?| @oX,j:45etOXg[x(Yd ek9,jt`hbn~kV)pȚӺ4KXOVI+㼨(r;v޳,P`k&=Dݳ{ǻúpX]w)j:45eHVb صR,W`#~ ߐ+R[P%X>o=MX cV|lo.$9Dݐļ)q;+Q`>|\b֔Qj5//o'NăO&㜲HR;1U ൸8o};񛕨0ޙd 4 cխmо9ttLj:;W{E+YɵVB`Uě4עXTvFC@WAV-tw}2mۆJeVw)Ί j(+фXwKnW:2nID @7Zhޢ!VZK 6=}FOxZ VoC@WAVhk@ ,:XtDɑt3C .7 {5K̚2ZA?gˣTիWnnGvy?)}c8cqM%sѾ-M!g1rZO%ˑ-`3bOwIT܃Yvqu% y.~s,O2kn(yziX9UUŸE^ 2UJbH+]D^F5K̚2nR)҃yHeȑe˖n<{y[8Oc/❊MyYCDlZ +_9tvB7{fyY氱Ωl,UxK;gqqޒ8&ouOINwU υ@I# wT\l\ yֶmڈ%fMS333+.XQ&n$Űλ'qtL@r8[\CvVq-Ǯd\BxStsyi(}]-9a(}`V-yA%fMY؁[M e`Fm"ԢimI[vB֍rr-ǩ5#rXeOΉqHޚ6lF?ڻ)2<-zʤG,4ko'ր C`ВQ`DMw^3g^?~9׻ޔD^ صRlQg.[+{cܠX>({q(GNufgIwޒ}6yB` 9W`%D^ 8jUX@J* 5M5e "CIjldzK !+kVDM$˵' ܲ|sl1™c @WA/}kȫ3e (g5 XoXak9.ÁUߕJvNU(Ϧk}6~)C` 9V-yV|K͵V*MUmM,֧VsZG`Pp-I8O5Sg!+X!\q+u,q+Ud3G'd,+G馲hE7dZvqu3o4ր sVXX!\q@%"KFI ߱TQc,kT:w{wɱ{vY%^odq 5 \ y#B(cJ}0Y d }2&>cN5TvO;6.JjhDw)A`5 %/~kAs-X)%YdXR|S9bZ)TZO6l&1 V3"+k:uDM$˵VBZ\כ'{12j@K^F.+̵Vd![ +#j:4 YصRNE mX͹S,7 UV5K ,rZ)"$.qcˏ*EJ5+?_yY֊*%fHk9v% "T@` 9V-y'|Bth.1+@\1kzA`5 %/~:`QӡĬr-ǁV8%~ TwgEZo=MX Xj@K^ 8I6dBM?1$c_^l'G{A`5 %/~VrZI#[&J3|B@ƛ4עpܒ`gdXؕi oVTIW ̘(6P%OVsZG`Pp-AVZJ`u}&|6xZ-9:%yESϕMUYMVe )-k@X!hɋBVifFM_a nGj.n`5_j\$ureE5(VZUth.H+%VjjO*֭˯lQPVncz@`57/XyJp.iPLWۨ\k ]IsJMW >.nQPٳg $vƻ@j.n`5_j\$uҕL׳(\k5J ;w% [`Y \j b)¹HBС(9Q&Ç]IsJMWx!A;cg:&gVsq2T "v*kQ`DM.RkhV BX_X! O< BX!+ ~jڣGwQA`!B B` 9Vbuᢦ C`Vs&%+'j::V(A9Vs&% J+j+ ~j!Bq@` EX!C`0/Q-V(PXjDX8 B rB_X!+V(A9Vs&%aDMR %XB`5jDX`mԨ BX!+ ~jZV-QA`!B rݾX!C`0/Q-X322DMR %X |!C`5 `_Z,y C`Vs&%kEMR %X)9@ك /Q-XyaQA`!B rifƍ7G!C*~ƅ /Q-Xk׮-j::V(Ahӧab~"BKTÇ+J+~ofܹp2PX!%+'j::V(AN.]DF9@N { /Q-V(P\[FUZUTlD ,PJYTX!% J7~W^[~֣CN _tU BKT + W`i[5 & 3g,G5\Tk[4Y+DX8 B rVyU^M4YYk8.Tq5WL׶hPV?~j!Bq@` t>[.Pp<ѡ@` 'ׅ/fEF}X!% J+|@xQPٳg{{P B+gQQPV?~jڹsgQA`!B rVyeP,ԇrىk8.:A`㗨 o BX+ݼC}(C YrD+@P+ BhkT{LtX!uPXTZa} C`DfC $R Ç5VH+ 7x{H :, C`"% Bq@`"% Bq@`"% Bq@`"% Bq@`"% Bq@`"%Vԉ".LH :,6nXB֚5k@ȰZn]QXo)WNB֗k5a5azj2,>\BVOBB B  %SN=~x0  <&Tsjj,v]B@Ȱ+@Ȱ@ȰXJv׫Aͤ' <!Eʼn$jؓJ'+|szu>rДgSu+/Oj^-,6o֌WVH7rmouux+Dj#--(xЌ*2&X`xq֑b*+E[4n`yV!X{9V!X !$+ ! @`[oLꈘVe*}[#. JC3x 1PUɘ޸mQ%_kbFD䍝lR%V`UB VPC3RM|!ۚ!d?U4xZlR f`eNZT/V]iG(3 n~*"ƐV( D`ӧ;F% TZz$Eд uP%P:ڠAO`wk" ,L[*bVU+ʓ+SDW -l:G,>#Qhs#D@%s> ,b*)P@,b-hd&90ՎmeMbg <.0X9V!X}"+7F`u%X7H/_UL`| ?bSm{,jwV;xr|UrOKtT=b_k(,#m>U(pfOפ(v"V+Z9'sbԴ,mdq+Vb~?"{{Z'>Lt;Uy:$ 1Y%= @1:kD,+0j f'lb[}9G֣QN7l){{[i|g=M;eK@Vg `9k-AMd^T%L֫rV\oh#7 V ̺G-jȧ66F S{j^Ap9M$/F^23MrR3kfg(Q+G7DsIZPDt[{,mM4V`W9ma)>OF\c@˲k[9a\ kveWq!ubV/Tq:7oQ hn+bQRO!f8f> S(n7t;ȲO7*gUQ"ob122St,f 5(+]yC5iF8^5Ob4@uv6=lW:,{B Z2 6!X+UX +-&ىY|&XQI%XnD+^)]k|n|rٜnr4 4켟2ۦHd7u+'Rqvi{8{+("֯X!Kib('C7h7F?K<Y،eN&L> !$kǎ}V oGCJVaK{ݢ2 6i})qa7]&&~]M'aa7W_ǶOuWٿW~ ch=Zfe#vGggBŹ'PrD`zj%>Jm2YBbSk6^nF%S&ΩvMfQg-vh'a݁5(Y%0Vb+)*e}iQpbT[տk,X?W`u%:xs9oγmG-تfvpP݊ѿw+X"y149OI!L g8z[E⨱`Y(Mu2B "j&Tvz"+9{@Xi sSF&*, \C2uk޲xH!z:AI !Pb}š& VVUHIB B B B B B B B B B B B B B B B B B B B B BMÇ#@z]w"@:h V!X=Njjj"BH֊* @کS'V!X7BH֗^z BH!C @_ @ZZ5V!X  !$+ ! &k-X D`}7X D`_>+.+}+]vE`uȐ!B"Bjjjjjjjjjjjjjjjjjjjjjjjj B"%V5V5V5V5V5V5VhvsD 4ZHjW55)<ޥY|D_cTu<4"I\ bf{̐$vL?$ WFgIB`Hu޻V4kQ'~q݁xCOԾF*'ygFLj&&Wφ{:hܩ9ZyIbC5˹ϒ >Ӥ} ghvKLj&YtCb4ܩ;Z yIbCPߓQvgIB`H\489o4MuU6'zXjѧ`d=FOԬmkx elFM>k>jnpΝnbXCO`U7{ (ə78|"ʹ"g&ֆ1Cj )VcCy! 0V(X8V(1> o GR+@zg٣WϞݻv֭o߾m֬i]ӯo_xG~ң֨QMֲC׮]Zh1|p>#{=o4hPÆ zIV={˪VZH/Gy,_> :th˖-T裏M62dVFueW]_Q1f͚t!~m]tM_COv eԀ:u8x;nՊ:v|a?u!ߟ߈.;uԱqϾBĈ;g]IENDB`ViTables-3.0.0/doc/indices/000077500000000000000000000000001311223072700154045ustar00rootroot00000000000000ViTables-3.0.0/doc/indices/index_dev.rst000066400000000000000000000004741311223072700201100ustar00rootroot00000000000000.. include:: ../README.txt Contents: .. toctree:: :maxdepth: 4 usersguide-ch1 usersguide-ch2 usersguide-ch3 usersguide-ch4 usersguide-ch5 usersguide-app1 usersguide-app2 develop api/modules Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ViTables-3.0.0/doc/indices/index_html.rst000066400000000000000000000022601311223072700202710ustar00rootroot00000000000000.. ViTables Users' Guide documentation master file, created by sphinx-quickstart on Sat Dec 4 18:53:39 2010. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to ViTables Users' Guide! ================================= .. COMMENT: Page title .. image:: images/title_page_plain.png :width: 359 .. include:: Vicent Mas ViTables |version| Users' Guide version 1.0 |today| Copyright |copy| 2005-2007 Cárabos Coop. V. All rights reserved. Copyright |copy| 2008-2017 Vicent Mas. All rights reserved. **Copyright Notice and Statement for the ViTables User's Guide.** This manual is part of the Licensed Software included in the *ViTables* package. For detailed information see the LICENSE.txt file. **Copyright Notice and Statement for the Qt library.** *Qt* is registered trademark of Nokia Corporation. **Copyright Notice and Statement for the PyQt library.** *PyQt* library Copyright by Riverbank Computing Limited. .. toctree:: :maxdepth: 3 :numbered: usersguide-ch1 usersguide-ch2 usersguide-ch3 usersguide-ch4 usersguide-ch5 usersguide-app1 usersguide-app2 ViTables-3.0.0/doc/indices/index_pdf.rst000066400000000000000000000015211311223072700200750ustar00rootroot00000000000000.. include:: Vicent Mas ViTables |version| Users' Guide version 1.0 |today| Copyright |copy| 2005-2007 Cárabos Coop. V. All rights reserved. Copyright |copy| 2008-2017 Vicent Mas. All rights reserved. **Copyright Notice and Statement for the ViTables User's Guide.** This manual is part of the Licensed Software included in the *ViTables* package. For detailed information see the LICENSE.txt file. **Copyright Notice and Statement for the Qt library.** *Qt* is registered trademark of Nokia Corporation. **Copyright Notice and Statement for the PyQt library.** *PyQt* library Copyright by Riverbank Computing Limited. .. raw:: pdf PageBreak .. toctree:: :maxdepth: 3 :numbered: usersguide-ch1 usersguide-ch2 usersguide-ch3 usersguide-ch4 usersguide-ch5 usersguide-app1 usersguide-app2 ViTables-3.0.0/doc/make.bat000066400000000000000000000111641311223072700153760ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ViTablesUsersGuide.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ViTablesUsersGuide.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "pdf" ( %SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf if errorlevel 1 exit /b 1 echo. echo.Build finished, look at the results in %BUILDDIR%/pdf goto end ) :end ViTables-3.0.0/doc/posterIcons.py000066400000000000000000000062131311223072700166520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2005, 2006, 2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # posterIcons.py # import sys from qtpy import QtGui from qtpy import QtWidgets ICONSDIR = '../vitables/icons/' big_icons = [('file_rw', 'The root node (read-write)'), ('file_ro', 'The root node (read-only)'), ('dbfilters', 'The root node of the Query Results file '), ('folder', 'A collapsed group '), ('document-open-folder', 'An expanded group ')] small_icons = [('table', 'A table (heterogeneus dataset) '), ('array', 'A regular array (homogeneus dataset) '), ('earray', 'An enlargeable array'), ('carray', 'A compressed array'), ('vlarray', 'A variable length array'), ('vlstring', 'An array of VLStrings'), ('link_table', 'A soft link to a table (heterogeneus dataset) '), ('link_array', 'A soft link to a regular array (homogeneus dataset) '), ('link_earray', 'A soft link to an enlargeable array'), ('link_carray', 'A soft link to a compressed array'), ('link_vlarray', 'A soft link to a variable length array'), ('object', 'A serialized objects dataset'), ('image-missing', 'An unsupported dataset')] class Poster(QtWidgets.QMainWindow) : def __init__(self) : super(QtWidgets.QMainWindow, self).__init__() w = QtWidgets.QWidget(self) l = QtWidgets.QGridLayout(w) self.setCentralWidget(w) self.makePoster() def makePoster(self): widget = self.centralWidget() layout = widget.layout() r = 0 c = 0 iconsDict = {'22x22': big_icons, '16x16': small_icons} for key in iconsDict.keys(): for (name, caption) in iconsDict[key] : pixmap = QtGui.QPixmap() image_path = '{0}/{1}/{2}.png'.format(ICONSDIR, key, name) pixmap.load(image_path) imLabel = QtWidgets.QLabel(widget) imLabel.setPixmap(pixmap) layout.addWidget(imLabel, r, c, 1, 1) textLabel = QtWidgets.QLabel(caption,widget) layout.addWidget(textLabel, r, c + 1, 1, 1) r = r + 1 if r > 8: r = 0 c = 2 def main(args) : app = QtWidgets.QApplication(args) poster = Poster() poster.show() app.exec_() if __name__ == '__main__' : main(sys.argv) ViTables-3.0.0/doc/users_guide.style000066400000000000000000000210111311223072700173610ustar00rootroot00000000000000pageSetup: # firstTemplate: vitables_coverPage margin-bottom: 8mm margin-left: 12mm margin-right: 12mm margin-top: 8mm pageTemplates: vitables_coverPage: background: images/title_page_plain.pdf frames: [] [0cm, 0cm, 100%, 100%] showHeader: false showFooter: false cutePage: frames: [] [0%, 0%, 100%, 100%] showHeader : true showFooter : true defaultFooter : ###Page### defaultHeader : ###Section### appendixPage: frames: [] [0%, 0%, 100%, 100%] showHeader : true showFooter : true defaultFooter : ###Page### defaultHeader : Appendix ###Section### styles: admonition: backColor: #EEFFCC borderColor: #AACC99 borderPadding: 8 borderWidth: 0.5 commands: [] [VALIGN, [0, 0], [-1, -1], TOP] spaceAfter: 6 spaceBefore: 12 admonition-heading: backColor: null borderColor: null borderPadding: 0 borderWidth: 0 leftIndent: 0 parent: heading3 textColor: black admonition-title: backColor: null borderColor: null borderPadding: 0 borderWidth: 0 leftIndent: 0 parent: heading3 attribute: parent: bodytext author: alignment: TA_CENTER fontName: stdSansBold fontSize: 120% parent: bodytext centered: alignment: TA_CENTER fontName: stdBold parent: bodytext class: parent: bodytext code: allowOrphans: false allowWidows: false backColor: #EEFFCC borderColor: #AACC99 borderPadding: [6, 0, 0, 4] borderWidth: 0.3 spaceBefore: 0 confval: parent: bodytext data: parent: bodytext kbd: parent: bodytext file: parent: bodytext desc: {parent: bodytext, spaceBefore: 6} descclassname: {fontName: stdMono, parent: literal} descname: {fontName: stdMonoBold, parent: literal} descparameter: {fontName: stdMono, parent: literal} desctype: {fontName: stdMono, parent: literal} directive: parent: bodytext exception: parent: bodytext heading: backColor: #F2F2F2 borderColor: #CCCCCC borderPadding: [6, 0, 0, 10] borderWidth: 0.3 fontName: stdSansBold fontSize: 10 leading: 10 leftIndent: 0 spaceBefore: 16 textColor: #20435C heading1: fontSize: 200% heading2: fontSize: 160% heading3: fontSize: 140% heading4: fontSize: 120% heading5: fontSize: 110% heading6: fontSize: 100% hlist: alignment: TA_CENTER commands: [] [VALIGN, [0, 0], [-1, -1], TOP] parent: normal spaceAfter: 0 spaceBefore: 6 method: {fontName: stdSansBold, parent: bodytext} note: backColor: #EEEEEE borderColor: #CCCCCC parent: admonition optional: {fontName: stdMonoBold, parent: literal} pygments-bp: {parent: code, textColor: #007020} pygments-c: {parent: code, textColor: #808080} pygments-c1: {parent: code, textColor: #808080} pygments-cm: {parent: code, textColor: #808080} pygments-cp: {parent: code, textColor: #507090} pygments-cs: fontName: stdMonoBold parent: code textColor: #cc0000 pygments-err: backColor: #F0A0A0 parent: code textColor: #F00000 pygments-gd: {parent: code, textColor: #A00000} pygments-ge: {fontName: stdMonoItalic, parent: code} pygments-gh: fontName: stdMonoBold parent: code textColor: #000080 pygments-gi: {parent: code, textColor: #00A000} pygments-go: {parent: code, textColor: #808080} pygments-gp: fontName: stdMonoBold parent: code textColor: #c65d09 pygments-gr: {parent: code, textColor: #FF0000} pygments-gs: {fontName: stdMonoBold, parent: code} pygments-gt: {parent: code, textColor: #0040D0} pygments-gu: fontName: stdMonoBold parent: code textColor: #800080 pygments-hll: {backColor: #ffffcc, parent: code} pygments-il: fontName: stdMonoBold parent: code textColor: #0000D0 pygments-k: fontName: stdMonoBold parent: code textColor: #008000 pygments-kc: fontName: stdMonoBold parent: code textColor: #008000 pygments-kd: fontName: stdMonoBold parent: code textColor: #008000 pygments-kn: fontName: stdMonoBold parent: code textColor: #008000 pygments-kp: fontName: stdMonoBold parent: code textColor: #003080 pygments-kr: fontName: stdMonoBold parent: code textColor: #008000 pygments-kt: fontName: stdMonoBold parent: code textColor: #303090 pygments-m: fontName: stdMonoBold parent: code textColor: #6000E0 pygments-mf: fontName: stdMonoBold parent: code textColor: #6000E0 pygments-mh: fontName: stdMonoBold parent: code textColor: #005080 pygments-mi: fontName: stdMonoBold parent: code textColor: #0000D0 pygments-mo: fontName: stdMonoBold parent: code textColor: #4000E0 pygments-n-identifier: parent: code pygments-na: {parent: code, textColor: #0000C0} pygments-nb: {parent: code, textColor: #007020} pygments-nc: fontName: stdMonoBold parent: code textColor: #B00060 pygments-nd: fontName: stdMonoBold parent: code textColor: #505050 pygments-ne: fontName: stdMonoBold parent: code textColor: #F00000 pygments-nf: fontName: stdMonoBold parent: code textColor: #0060B0 pygments-ni: fontName: stdMonoBold parent: code textColor: #800000 pygments-nl: fontName: stdMonoBold parent: code textColor: #907000 pygments-nn: fontName: stdMonoBold parent: code textColor: #0e84b5 pygments-no: fontName: stdMonoBold parent: code textColor: #003060 pygments-nt: {parent: code, textColor: #007000} pygments-nv: {parent: code, textColor: #906030} pygments-o: {parent: code, textColor: #303030} pygments-ow: fontName: stdMonoBold parent: code textColor: #000000 pygments-s: {backColor: #fff0f0, parent: code} pygments-s1: {backColor: #fff0f0, parent: code} pygments-s2: {backColor: #fff0f0, parent: code} pygments-sb: {backColor: #fff0f0, parent: code} pygments-sc: {parent: code, textColor: #0040D0} pygments-sd: {parent: code, textColor: #D04020} pygments-se: backColor: #fff0f0 fontName: stdMonoBold parent: code textColor: #606060 pygments-sh: {backColor: #fff0f0, parent: code} pygments-si: {backColor: #e0e0e0, parent: code} pygments-sr: backColor: #fff0ff parent: code textColor: #000000 pygments-ss: {parent: code, textColor: #A06000} pygments-sx: backColor: #fff0f0 parent: code textColor: #D02000 pygments-vc: {parent: code, textColor: #306090} pygments-vg: fontName: stdMonoBold parent: code textColor: #d07000 pygments-vi: {parent: code, textColor: #3030B0} pygments-w: {parent: code, textColor: #bbbbbb} returns: parent: bodytext role: parent: bodytext seealso: backColor: #FFFFCC borderColor: #FFFF66 parent: admonition sidebar: backColor: #EEFFCC borderColor: #AACC99 borderPadding: 8 borderWidth: 0.5 spaceAfter: 6 spaceBefore: 12 sidebar-subtitle: backColor: null borderColor: null borderPadding: 0 borderWidth: 0 leftIndent: 0 parent: heading4 spaceBefore: 0 sidebar-title: backColor: null borderColor: null borderPadding: 0 borderWidth: 0 leftIndent: 0 parent: heading3 table-heading: {borderWidth: 0, parent: heading} todo-node: backColor: #FFFFFF borderColor: #CCCCCC parent: admonition versionmodified: {fontName: stdItalic, parent: bodytext} warning: backColor: #FFE4E4 borderColor: #FF6666 parent: admonition xref: {fontName: stdMonoBold, parent: code} ViTables-3.0.0/doc/usersguide-app1.rst000066400000000000000000000053431311223072700175430ustar00rootroot00000000000000.. raw:: pdf PageBreak appendixPage .. _appendix-a: About Plugins +++++++++++++ Since version 2.1 `ViTables` has a simple but powerful plugins framework. If you are interested in writing plugins the next paragraphs can be of utility. If not you can skip to the list of available plugins. Plugins live in the plugins subdirectory of the root directory where the source code is installed. A plugin can be a pure Python module or can have a package structure (i.e. a directory with a :mod:`__init__.py` file). Packages can have as many directories as you want but plugins must be located at top level of the package. The use of contracts is not enforced when writing plugins so you have nearly complete freedom for writing them. Nevertheless a plugin must declare the following variables. :const:`plugin_class` which is set to the name of the class invoqued when your plugin is executed by `ViTables`, :const:`plugin_name` which is set to the descriptive name of the plugin and will be used in the Plugins page of the Preferences dialog and, finally, :const:`comment` which is set to a short description of the plugin and will be used too in the Plugins page of the Preferences dialog. In some cases it can be useful to use convenience variables or methods. For instance, suppose than in the Preferences dialog you want to show a more complete description of your plugin that that provided by the :const:`comment` variable. Then you may be interested in define a method :meth:`helpAbout` in your plugin. Of course some knowledge (not necessarily a deep one) of the `ViTables` code is required in order to bind your plugin to the application core. This task is commonly achieved via the menu bar of the main window or via the signals/slots mechanism (convenience signals can be defined in the application if needed). If you need more help just send an email to developers or ask to the `ViTables` Users' Group. Five plugins are currently distributed along with the application: Time series formatter formats time series in a human friendly way. It supports PyTables time datatypes and PyTables time series created via `pandas `_ or the obsolete scikits.timeseries module. The format used for displaying times can be configured by user via the Preferences dialog or editing by hand the :file:`time_format.ini` configuration file. CSV Importer provides import capabilities from `CSV` files into PyTables datasets. CSV Exporter provides export capabilities of PyTables datasets to `CSV` files. Tree of DBs sorting sorts the display of the databases tree. Columnar organization of arrays rearranges several arrays with the same number of rows and displays them in a unique widget. ViTables-3.0.0/doc/usersguide-app2.rst000066400000000000000000000016251311223072700175430ustar00rootroot00000000000000The Help Browser ++++++++++++++++ `ViTables` comes with its own fully-integrated documentation browser. It allows the `ViTables` User's Guide to be browsed without leaving the current working session and without opening external applications. You can start the browser issuing the :menuselection:`Help --> User's Guide` command or from the toolbar. The help browser is a small HTML browser for *local* documents. Despite its small size it exhibits some nice features - bookmarks - session history - easy document navigation through navigation buttons A nice feature of bookmarks is that they can be navigated while they are being edited with the Bookmarks Editing dialog. Simply double click on a bookmark and it will be displayed in the browser. .. _help-browser: .. figure:: images/helpBrowser.png :width: 80% :align: center :figclass: align-center The Users' Guide browser ViTables-3.0.0/doc/usersguide-ch1.rst000066400000000000000000000132031311223072700173470ustar00rootroot00000000000000.. |geq| unicode:: U+02265 .. greater than or equal symbol Introduction ++++++++++++ Overview ******** `ViTables` is a member of the `PyTables` family. It's a graphical tool for browsing and editing files in both PyTables and `HDF5` formats. With `ViTables` you can easily navigate through data hierarchies, request metadata, view real data and much more. `ViTables` is being developed using `Python` and `PyQt`, the bindings of `Qt` libraries, so it can run on any platform that supports these components (which includes Windows, Mac OS X, Linux and many other Unices). The interface and features will remain the same on all platforms. Efficiency and low memory requirements are guaranteed by the fact that data is loaded only when the object that contains it is opened and by the use of data buffers for dealing with large datasets. Capabilities ************ The current release provides browsing, displaying, editing and querying capabilities. Some of them are listed below. Details are discussed in the related chapters. Browsing and displaying capabilities ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Display data hierarchy as a fully browsable object tree. - Open several files simultaneously. - Open files in write mode as well as in read-only mode, disabling all editing functions. - Display file information (path, size, number of nodes…). - Display node (group or leaf) properties, including metadata and attributes. - Display numerical arrays, i.e. homogeneous tables. - Display heterogeneous table entities, i.e. records. - Display multidimensional table cells. - Unlimited zoom into the inner dimensions of multidimensional table cells. Editing capabilities ^^^^^^^^^^^^^^^^^^^^ These editing features have been implemented for the object tree [#f1]_: - File creation and renaming. - Node creation (only for groups), renaming and deletion. - Ability to copy and move nodes from their location to a different one, even in different files. - Attribute creation, renaming and deletion. All these changes automatically update the database (i.e. the file) to which the nodes belong. Other ^^^^^ Other nice features include: - *Ability to smoothly navigate really large datasets*. - Support for doing complex table queries with a low memory footprint. - Flexible plugins framework. A bunch of useful plugins are already included, see the :ref:`Appendix A` for details. - Configurable look and feel. - A logger area, where errors and warnings (if any) are printed. - Several levels of help are available: users guide, context help, tooltips and status bar. We have paid special attention to usability issues so making use of these features is intuitive and pleasant. Nevertheless, and just in case, we are providing this guide :-). System Requirements ******************* To run `ViTables` you need to install recent versions of `Python` (2 or 3), `PyTables` (so you have to fulfil its own requirements) and `PyQt`. For instance, it runs smoothly with `Python` 3.6, `PyTables` 3.4 and `PyQt` 5.8. At the moment, `ViTables` has been fully tested on Linux and Windows 10 platforms. Other Unices should run just fine when using the Linux version because all the software that `ViTables` relies on (i.e. `Python`, `Qt`, `PyQt`, `HDF5` and `PyTables`) is known to run fine on many Unix platforms as well. Installation ************ Linux ^^^^^ The Python setuptools are used to build and install `ViTables`. You can install the package from PyPI issuing the command:: $ pip install vitables This should install the ViTables wheel. If you experience problems installing the binary package you can install from sources (provided your system fulfills the requirements listed in the above section). Just download the tarball from PyPI, uncompress it, change to the distribution directory and execute (as root):: $ python setup.py install If you are doing this on a MacOS X platform, please make sure that the DYLD_LIBRARY_PATH environment variable has been setup properly. By default `ViTables` will be installed in the system-protected area where your system installs third party Python packages so you will need superuser privileges. If you prefer to install the package in a different location (for instance, your home directory) so that the installation can be done by non privileged users, you can do it using the --prefix (or --home) tag:: $ python setup.py install --prefix=/home/myuser/mystuff Please, remember that installing Python modules in non-standard locations makes it necessary to setup properly the PYTHONPATH environment variable so that the Python interpreter can find the new modules. If you need further customizations, please have a look to the output of the command:: $python setup.py install --help to see all the available options. Complete information about them can be found in the Distutils documentation. Windows and Mac OS X ^^^^^^^^^^^^^^^^^^^^ Currently there are no graphical installers available for these platforms. You have to install `ViTables` from the command line, using one of the methods described in the Linux section. Further Reading *************** General information about `PyTables` can be found at `its project site `_. For more information on `HDF5`, please visit its web site `www.hdfgroup.org/HDF5 `_. Information about `ViTables` is available at `vitables.org `_. Questions and feedback can be mailed to the developers. .. rubric:: Footnotes .. [#f1] Dataset editing capabilities have not yet been implemented. ViTables-3.0.0/doc/usersguide-ch2.rst000066400000000000000000000256101311223072700173550ustar00rootroot00000000000000First Steps +++++++++++ In this chapter we are going to describe briefly the main elements that you will meet throughout your working sessions. How to Start ************ You can start `ViTables` from a desktop shortcut or from a terminal emulator. If you launch the program from the command line the following options are available:: $ vitables --help usage: vitables [option]... [h5file]... positional arguments: h5file optional arguments: -h, --help show this help message and exit --version show program's version number and exit h5files: -m MODE, --mode MODE mode access for a database. Can be r(ead) or a(ppend) -d DBLIST, --dblist DBLIST a file with the list of HDF5 filepaths to be open logging: -l LOG_FILE, --log-file LOG_FILE log file path -v, --verbose log verbosity level Basically you can specify a file to open or a file containing a list of files to open. For example: :: $ vitables myh5file will start `ViTables` and open the file myh5file in read-write mode. If you want to open it in read-only mode then execute the command: :: $ vitables -m r myh5file In order to open a set of files at once put them in a list file with the syntax :: mode path (one pair per line) and execute: :: $ vitables -d h5list Once the application is running the :ref:`main window` appears. It consists of a :ref:`menu bar`, a set of tool bars, a :ref:`viewing area` and a status bar. The viewing area of the window is divided into three parts. The :ref:`tree of databases viewer` is the narrow region placed at top left side. It will display a tree representation of the data hierarchies we want to access. The big panel next to the tree viewer is called the :ref:`workspace`, and will display the real data contained in a given node of the data hierarchy. Finally, the bottom region is the :ref:`logger`, a kind of text non interactive console where information about your requested operations will be shown. As usual, you can launch commands from the menu bar, from context menus or, if a shortcut button is available, from a toolbar. Also keyboard shortcuts are available for most commands. After starting your session, you are likely to open some files. Just drag the file(s) you want to open into the tree of databases viewer and they will be opened in read-write mode. Opening can be done from the file manager dialog too; simply issue an open command, :menuselection:`File --> Open File` (:kbd:`Ctrl-O`) and choose a file. .. _main-window: .. figure:: images/mainWindow.png :width: 90% :align: center :figclass: align-center The main window .. _menu-bar: The Menu Bar ************ The menu bar is placed at top of the main window. It is composed of six pulldown menus. **File menu** This menu contains commands to manipulate files in several ways: open, close, create, save and so on. It also gives to you quick access to the most recently opened files. **Node menu** The :guilabel:`Node` menu contains commands to manipulate the nodes displayed in the tree of databases viewer. From this menu you can edit nodes in a variety of ways as well as access their properties. **Dataset menu** With this menu you can make selects in any table (the result of your selects will be available under the Query Results node in the tree pane). The number of entries for this menu depends on the list of enabled plugins. **Settings menu** This is the menu from which the application can be customized. Customization includes startup behavior, look and feel and plugins management. You can add/remove paths for loading plugins, enable and disable plugins. Changes in the enabled/disabled status of a given plugin take effect after restarting `ViTables`. See :ref:`the ViTables Configuration chapter` for more information on this subject. Also from this menu you can show, hide and line up the application toolbars. At the moment four toolbars are available, :guilabel:`File`, :guilabel:`Node`, :guilabel:`Query` and :guilabel:`Help`. **Window menu** The :guilabel:`Window` menu can be used to change the arrangement of the workspace contents, sorting the open windows as a cascade or as a tile. By selecting a window name from this menu, you can raise (bring to the front) that window. Any open window can be closed from this menu. **Help menu** The :guilabel:`Help` menu displays this User's Guide in :`HTML4` format and a couple of *About* boxes, one for the `ViTables` itself and one for the underlying Qt libraries. The :guilabel:`Show Versions` entry shows the version numbers of the libraries being used by `ViTables` (Qt, PyQt, PyTables and PyTables related libraries, like Zlib or `LZO`). Finally, from this menu you can enter the *What's This* mode which will show context help for the components of the viewing area (the databases tree viewer, the workspace and the logger). .. _viewing-area: The Viewing Area **************** As mentioned before, the viewing area is divided into three regions: the databases tree viewer (also called tree pane), the workspace and the logger. Now we are going to describe these regions in more detail. .. _tree-pane: The Databases Tree Viewer ^^^^^^^^^^^^^^^^^^^^^^^^^ Due to the hierarchical model of the underlying `HDF5` library, PyTables files store their data on disk in a tree-like structure. Every time you open a PyTables file, its so-called object tree (a representation of the data hierarchy) is dynamically created and added to the tree of databases viewer, at the top left side of the viewing area (see :ref:`the main window Figure`). .. note:: since PyTables-1.2 the object tree of an opened file is made on demand: nodes are added to the tree when they are accessed. `ViTables` makes use of this feature, which results in stunningly fast opening times for files with a large number of nodes. Any object tree is made of nodes which can be classified as follows: Root node It is the node from which all other nodes hang. Groups Groups are nodes that can contain other nodes. Leaves Leaves are nodes that contain real data. They can be tables or arrays. Working with object trees is really easy. By double-clicking on it, a root node is opened, and the tree structure below it is displayed. Groups are presented as folders. They can be expanded with a double-click, giving you immediate access to their contents. A group can contain groups and/or leaves (or may be empty). A double click on a leaf will display its content on the workspace. You can access the available options for a given node just with a right mouse click on it. A context menu will appear from which commands can be launched. The contents of the menu depend on the kind of node being clicked (root nodes, groups, tables and arrays have all of them their own context menu). Alternatively you can select the node with a single mouse click and choose a command from the :guilabel:`Node` menu. There is also a context menu for the tree pane itself that will pop up by right-clicking any empty area of the tree viewer. Last but not least, the object tree can be navigated with the keyboard too. Pressing the Enter key the selected node will be expanded (if it is a group) or opened (if it is a leaf). The + and - keys expand an collapse groups. Every node in a given object tree has an associated icon that allows you to identify its type quickly. The following icons are available: .. _node-symbols: .. figure:: images/treeSymbols.png :align: center :figclass: align-center The node symbols .. _workspace: The Workspace ^^^^^^^^^^^^^ At this point you should have one or more files opened, and their object trees displayed in the databases tree viewer. Your next step will be to select a leaf and display its data. Remember that the object tree imitates the structure on disk, which makes it very easy to browse the hierarchy of the file and locate the leaf you want to open. A double-click on a leaf of your choice will open it and display its contents in a window (a *view* in the `ViTables` jargon) placed in the workspace, the big panel at the top right side of the viewing area (see :ref:`the main window Figure`). Note that the databases tree viewer and the workspace are always synchronized: if you select a node in the tree viewer and that node has a view, then that view becomes the active view on the workspace. The opposite is also true, click on a view on the workspace and its node will be automatically selected on the databases tree viewer. The :guilabel:`Window` pulldown menu provides some additional commands that will help you to manage your views. From this menu you can, for instance, rearrange views, see the list of views (which is particularly useful when the workspace is cluttered with so many views that it's difficult to find the one you want) or close all the views at once. There is also a context menu for the workspace. It can be used to change the workspace view mode: you can display views as regular windows (default behavior) or with tabs in a tab bar. In addition it give you access to the :guilabel:`Window` pulldown menu. .. _logger: The Logger ^^^^^^^^^^ The logger is a read-only (i.e. non interactive) console placed at the bottom of the viewing area (see :ref:`the main window Figure`). It is an info panel where `ViTables` reports the result of requested operations (namely if they were not successful). Also runtime errors are caught and reported to you through the logger (so you can mail the error to `ViTables` developers and help to improve the quality of the package :-). Errors and warning messages are highlighted in red and orange respectively. Of course there is also a context menu for the logger that provides you with some handy operations, like to copy selected text or to empty the logger. ViTables-3.0.0/doc/usersguide-ch3.rst000066400000000000000000000131701311223072700173540ustar00rootroot00000000000000Browsing and Querying Datasets ++++++++++++++++++++++++++++++ In this chapter we are going to describe how the information contained in a dataset can be navigated and filtered. Browsing Datasets ***************** A noticeable aspect of views is the visualization speed. Views show data nearly as quickly as PyTables accesses them. As a consequence, very large datasets (with up to 2^64 rows) can be browsed stunningly fast. .. _browse-large-dataset: .. figure:: images/browseDataset.png :width: 80% :align: center :figclass: align-center Browsing a large dataset As said in the previous chapter, datasets are displayed in views. They are spreadsheet-like windows so can be navigated as you would expect: via scrollbar, keyboard or wheel of mouse. .. note:: what makes `ViTables` views interesting is that *the navigation speed is independent of the view size*: a table with several thousand million rows is navigated as quickly as a table with just a few dozens rows. Another interesting feature of views is the ability to zoom in on cells that contain multidimensional data. When you double-click in a cell, it is displayed in its own view, reducing by two the number of dimensions of the displayed data. For instance, a cell containing a vector is displayed as a one column table of scalars. A cell that contains two-dimensional data will be shown as a bidimensional table of scalars. And so on. In general, a cell containing N-dimensional data will be displayed as a table of N-2 dimensions data. Zoom can be applied as many times as needed, so that multi-dimensional cells can be inspected until you get a table of scalars. Finally, if you try to zoom in on a cell that contains a scalar value, this value will be presented alone in a view; this can be useful to visualize large scalar values (for example, large strings) that doesn't fit on regular columns. .. _zoom-cell: .. figure:: images/zoomingCells.png :width: 80% :align: center :figclass: align-center Zooming a cell Getting Info ************ For a given node two kinds of information are available: metadata and data. From their metadata you can retrieve information about the objects on disk, such as table and column names, titles, number of rows, data types in columns or attributes, among others. The available metadata about a given node (group or leaf) can be accessed by right-clicking the mouse on the node and launching the :guilabel:`Properties` command from the context menu that appears. This can also be achieved from the :guilabel:`Node` menu. Then the :ref:`Properties dialog `, that contains the requested metadata, is displayed. The dialog is made of three tabs labelled as General, System attributes and User attributes. The General tab contains generic information about the selected node, i.e. name, path, etc. The System and User tabs contain tables that describe the attributes of the node. .. _properties_dialog: .. figure:: images/propertiesDlg.png :align: center :figclass: align-center The Properties dialog Aside from the Properties dialog, you can get information in several other ways. The full path of the node currently selected in the tree view is displayed in the status bar. This can be useful when the object tree is large and guessing a full path is not easy. The top left icon of views shows the kind of displayed data (array or table). Finally, some generic information can be obtained by launching the command :menuselection:`Help --> WhatIsThis` (or clicking the appropriate button on the corresponding toolbar). Querying Tables *************** An interesting feature of `ViTables` is its capability to make table selections. This means that we can select a set of table rows that fulfill a given condition. You can filter any table (even if it is closed) by issuing the command :menuselection:`Dataset --> Query…`. A dialog (see :ref:`this Figure`) will be displayed where you can create a query and select the range of rows to which the query will apply. Notice that, *you can make complex queries, i.e. queries that involve more than one table field. However the queried fields cannot be multidimensional or contain data with Complex data type*. `ViTables` always do its best for not being frozen due to out of memory problems when you do complex queries or the queried table is huge (or both) but it is not guarateed that it can achieve this goal. The selected rows are stored in a new table (but not removed from its original location) that we will call filtered table from here on. Filtered tables are stored in a temporary database [#f2]_ labeled as *Query results* in the databases tree viewer. The *Query results* node is always placed at the bottom of the databases tree. Filtered tables can be edited as any other leaf opened in read-write mode. By default an automatic title FilteredTable_X is given to the X-th filtered table created. In addition, those tables have three user attributes that are, in principle, only defined for filtered tables. These attributes are: query the applied query query_path the full path of the queried file query_table the full path of the queried table in the object tree hierarchy .. _query_dlg: .. figure:: images/newFilteredTable.png :align: center :figclass: align-center The New Query dialog .. rubric:: Footnotes .. [#f2] Every time a `ViTables` session starts, a new temporary database is created from scratch. This database has a flat structure and is stored with a unique name in a temporary directory so the operating system will remove it every time the directory is cleaned. ViTables-3.0.0/doc/usersguide-ch4.rst000066400000000000000000000062031311223072700173540ustar00rootroot00000000000000Editing Files +++++++++++++ In this chapter we are going to describe briefly the editing capabilities of `ViTables`. Creating Complex Hierarchies **************************** `ViTables` supports a complete set of editing operations on files and nodes. The result of these operations is made immediately visible on the databases tree viewer. To create a new file in write mode, just issue the command :menuselection:`File --> New…` (:kbd:`Ctrl-N`). By default, the file will be created with a ``.h5`` extension but you can provide your desired extension. You can add new empty groups to a writable file as easily as you create a new file. Simply select a group on the the tree pane and launch the command :menuselection:`Node --> New group…`. A new, empty group will be added to the previously selected group. By combining this operation with file creation, you can easily create complex hierarchies. Later on, you can populate the hierarchies with real data using your PyTables programs. .. _group-creation: .. figure:: images/groupCreation.png :width: 80% :align: center :figclass: align-center Creating a new group Editing Object Trees ******************** Files opened in write mode can be modified by moving their nodes (groups and leaves) around. From the :guilabel:`Node` menu you can copy, paste, cut, rename or delete any selected node (except root groups). Typical keyboard shortcuts are available for copy and paste operations. Of course, you can drag and drop nodes from one location to a different one using the mouse. Nodes can be moved to a different location in the object tree, but can also be reallocated in a different file. This way you can *merge* open files in a very flexible and comfortable way. As usual, while an operation is being performed on a given node, the shape of the mouse cursor will change into a clock, reminding you that a PyTables operation is being executed. Given a node opened in read-write mode you can edit its user attributes from the User attributes page (see :ref:`this Figure`) in the node Properties dialog. This page contains the user attributes table. You can add and remove attributes with the respective buttons or you can edit any existing attribute by clicking the table cell that you want to modify and introducing the new value. This way you can change name, value and type of any existing attribute. .. Note:: multidimensional attribute values are not supported by `ViTables`. Also be aware that scalar attributes will be saved as scalar Numpy objects instead of serialized using cPickle (which used to be the default PyTables behavior). This way you will be able to read them using generic `HDF5` tools, not just PyTables. Finally, the value of the TITLE system attribute can also be edited. Just click its cell in the System Attributes tab and enter the desired value. .. _editing_user_attributes: .. figure:: images/editingUserAttrs.png :align: center :figclass: align-center Editing user attributes Editing Leaves ************** At the moment of writing, editing the real data stored in leaves has not yet been implemented. ViTables-3.0.0/doc/usersguide-ch5.rst000066400000000000000000000067341311223072700173660ustar00rootroot00000000000000.. _configuration-chapter: Configuring ViTables ++++++++++++++++++++ As mentioned earlier, many aspects of the `ViTables` behaviour can be customized by you through the :menuselection:`Settings --> Preferences` command. It shows a dialog offering you several customization possibilities. The dialog is made of three stacked pages, :guilabel:`General`, :guilabel:`Look & Feel` and :guilabel:`Plugins`. The :guilabel:`General` page allows to change the `ViTables` behavior at startup. You can set the initial working directory to be that one from which `ViTables` is starting or to be the last used working directory. And you can recover your last working session. The :guilabel:`Look & Feel` page allows to change visual aspects of the application such as fonts, colors or even the general style, so you can adapt the global aspect of `ViTables` to what would be expected on your platform. From the :guilabel:`Plugins` page the plugins can be managed. You can enable or disable the available plugins. Changes in this page will take effect the next time you start `ViTables`. The :guilabel:`OK` button will apply the new settings and make them permanent by saving them in the Windows registry, in a configuration file (on Unix platforms) or in a plist file (on Mac OS X platforms). Even if settings are stored in a plain text file editing it by hand is not recommended. Some settings, like fonts or geometry settings [#f3]_, are stored in a way not really intended to be modified manually. Anyway it can be worth how settings are stored so let's do it. The configuration file is divided into sections, labeled as [section_name]. Every section is made of subsections written as key/value pairs and representing the item that is being customized. Currently the following sections/subsections are available: [Geometry] HSplitter the size of the horizontal splitter [Geometry] Layout the position and size of toolbars and dock widgets [Geometry] Position the position and size of the application window [Geometry] VSplitter the size of the vertical splitter [HelpBrowser] Bookmarks the list of current bookmarks of the help browser [HelpBrowser] History the navigation history of the help browser [Logger] Font the logger font [Logger] Paper the logger background color [Logger] Text the logger text color [Look] currentStyle the style that defines the application look & feel. Available styles fit the most common platforms, i.e., Windows, Unix (Motif and SGI flavors), and Macintosh [Plugins] Enabled the list of full paths of enabled plugins [Recent] Files the list of files recently opened [Session] Files the list of files and views that were open the last time `ViTables` was closed [Startup] lastWorkingDir the last directory accessed from within `ViTables` via Open File dialog [Startup] restoreLastSession the last working session is restored (if possible) which means that both files and leaves that were open in the last session will be reopen at application startup. [Startup] startupWorkingDir possible values are *current*, and *last*. These values indicate how the application will setup the startup working directory. [Workspace] Background the workspace background brush .. rubric:: Footnotes .. [#f3] Entries in the Geometry section allow for keeping the aspect, size and position of the application window between sessions. ViTables-3.0.0/doc/vitables_cover.tmpl000066400000000000000000000005631311223072700176770ustar00rootroot00000000000000.. role:: normal .. cssclass:: title #{title} .. cssclass:: subtitle #{subtitle} .. raw:: pdf Spacer 0 3cm .. cssclass:: author #{author} .. raw:: pdf Spacer 0 3cm .. cssclass:: author :normal:`#{date}` .. raw:: pdf PageBreak cutePage ViTables-3.0.0/environment.yml000066400000000000000000000006741311223072700163170ustar00rootroot00000000000000# Install conda: # http://conda.io/ # Create an environment for vitables # conda env create -n vitables -f environment.yml # Activate the environment # source activate vitables # Explore those old pesky hdf5s # vitables name: vitables channels: - conda-forge - defaults dependencies: - python=2 - pytables=3.2 - pyqt=4 - pip: - "--editable=./" # weird syntax until https://github.com/conda/conda/pull/3969 is merged ViTables-3.0.0/examples/000077500000000000000000000000001311223072700150375ustar00rootroot00000000000000ViTables-3.0.0/examples/arrays/000077500000000000000000000000001311223072700163405ustar00rootroot00000000000000ViTables-3.0.0/examples/arrays/array_samples.h5000066400000000000000000001507301311223072700214460ustar00rootroot00000000000000HDF  ` TREE0%HEAP8Hx (TITLE (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1  1R (CLASSARRAY (VERSION2.4`pSNODP08`( 8TITLESigned short array (FLAVORnumpy @ 1R (CLASSARRAY (VERSION2.4 @TITLEScalar signed short array (FLAVORnumpy?iW @z! @array_int16scalar_arrayarray_f3Darray_farray_int8array_bgroup1group2group3group4group5group6(?@@@@@@ @"@$@&@(@*@,@.@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@@@A@A@B@B@C@C@D@D@E@E@F@F@G@G@H@H@I@I@J@J@K@K@L@L@M@M@N@N@O@O@P@@P@P@P@Q@@Q@Q@Q@R@@R@R@R@S@@S@S@S@T@@T@T@T@U@@U@U@U@V@@V@V@V@W@@W@W@W@X@@X@X@X@Y@@Y@Y@Y@Z@@Z@Z@Z@[@@[@[@[@\@@\@\@\@]@@]@]@]@ 0TITLE Large array (FLAVORnumpy1TREE30% P ?@4 4  1R (CLASSARRAY (VERSION2.4 0TITLE3-D float array (FLAVORnumpy @ ?@4 4 1R (CLASSARRAY (VERSION2.4 0TITLE Float array (FLAVORnumpy pH 1R (CLASSARRAY (VERSION2.4 0TITLE Large array (FLAVORnumpy 81R (CLASSARRAY (VERSION2.4 0TITLE Large array (FLAVORnumpyTREE0%HEAPXarray_BHx (CLASSGROUP (VERSION1.0 1R (CLASSARRAY (VERSION2.4hSNOD 0TITLE Large array (FLAVORnumpyTREE 0%HEAPXarray_hHp (TITLE (CLASSGROUP (VERSION1.0   1R (CLASSARRAY (VERSION2.4"hSNOD 0TITLE Large array (FLAVORnumpyx&TREE0(0%HEAPX$array_lHSNOD@X`Hhp"pxx5h9"$ (TITLE (CLASSGROUP (VERSION1.0  (x)1R (CLASSARRAY (VERSION2.4HhSNOD 'HEAPX1array_fHx1 (TITLE (CLASSGROUP (VERSION1.0 4091R (CLASSARRAY (VERSION2.4SNOD2   0TITLE Large array (FLAVORnumpy88TREEJ0%HEAPX7array_dH57 (TITLE (CLASSGROUP (VERSION1.0 ?@4 4 0TITLE Large array (FLAVORnumpyHNx (TITLE???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 88Q1R (CLASSARRAY (VERSION2.4SNODITREEJ0%HEAPXpNP0LPN (CLASSGROUP (VERSION1.0????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ViTables-3.0.0/examples/arrays/carray_sample.h5000066400000000000000000000111251311223072700214200ustar00rootroot00000000000000HDF  U` TREEHEAPXcarrayH (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1 `x(,, 8shuffledeflate,1R (CLASSCARRAYSNOD (VERSION1.1 (TITLETREEE,x^б 0g3Brz>?:sUqW\UUg*3WwՙU]u:sUqW\UUg*3WwՙU]u:sUqW\UUg*3WwՙU]u:sUqW\UUg*3WwՙU]u:sUqW\UUg*3WwՙU]u:sUqW\UUg*3WwՙU]u:sU࿾ŋ ViTables-3.0.0/examples/arrays/earray_samples.h5000066400000000000000000004244751311223072700216250ustar00rootroot00000000000000HDF  =)` TREE HEAPX0array_carray_chararray_earray_b( (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1 `X 71R (CLASSEARRAY (VERSION1.1 (TITLECharsSNOD( h 0 EXTDIM TREE'  @871R (CLASSEARRAY (VERSION1.1 0TITLECharacter array 0 EXTDIM TREE=) x8 U71R (CLASSEARRAY (VERSION1.1 8TITLEUnsigned short array 0 EXTDIM  8 8shuffledeflate *71R (CLASSEARRAY (VERSION1.1 8TITLEUnsigned byte array 0 EXTDIM TREEE'*aabbbbaaaaaabbbbbbbbccccccccxA00`RM֩  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @{&@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @UabccbcdViTables-3.0.0/examples/arrays/vlarray_samples.h5000066400000000000000000246214321311223072700220200ustar00rootroot00000000000000HDF  #S` TREE8cxHEAP`n 0TITLEpickled object (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1 ` 8shuffledeflate@W1R (CLASSVLARRAYSNODpbm ((8X2 (VERSION1.4 8TITLEragged array of intsTREE`Q@GCOL  566567756988    1234563 4563 ']q(X123qX456qeX3qq. )]q(]q(X123qX456qeX3qe.asdaaanaaaana asd para@lel}?^˂=c?ۃ;˿MWؿI?B%EA ? e忚I䙄ݿ3᭼?ed?Cp?/_!ԿO5Kp?%vu?vecNЪܾ?D n?ۿ_)_rA8?=]@ӿ帚ÿ͹?Fu˝(tyw=U𿞗Ŀ><?ZN?o ?/?&svv>2і?j/iJ+C`z$ٿl2?+Zӷ?w SP &@#:iQ?^0L mѿFKeҿ+?w3(^Fw?ssWpa1Sțk?hpv߿)Vٌ!>ϡPؿK\ѿ ^.F2!#@?,V5?OUZ[@в>`T?x8!rп>?op92g?$NE{n?KUH8?Gv?RJ?0?U.T?41?hyE ?Ĕj8ſ`mcuXw@4/rԿyW8?ҿΜ_~?WCk4nd$ʿ|c3RB͡ozѿ_Xmٿ'|u?ć?\☾W?pC]ƥ-?p߿uqu!?եWԿV?{;?N࿇y?XBa?YeԑY%?b1˞?[Fٿ[*zkǿ&fM5Z?sa!?§̈ҿQԐտ>hS"ܿ'=?-2W#5|U?}@k?n>?qCM@^hmN?ޓLҿ U|DWc?x@,フԿzQXm?#d?]ݿC ݜ \ֿK?oVB?`n#?ΏIqV?fԂw?Py8T?(* *W-f,7=?n[1?b?_>?f,'K? |?ކ?<:tQ Rl?D2Y;?AοJ> ?YZ2ҿÿ?y?L-׵̿3 J+ 俸b}l o 3V?k5Q?"0?u?Z1j4?l J?u$]?v?`ʲ?!sv8y=?!?f?I@5hȱ9[?(ӱt?-?8a?(p?+8?ӫ/ȿ&ȝ࿤ê3ܿƫ#׿*AԿ'&pQ?ZYi?28Ys@g[_6]Nҿr7svb?ľ?9"Q?]^ ־?~?y'򿈀e@4n?SR'?B?ha@\tqRƿ!ԡ^?xڿm? ?q0(꿓1?b u?ܿI " ?AI-޿4BYhֿLޅ&꿪\?~?4hRKڿ*ٿarT5?Yټ? u:촎?ڨt[n?,7R꿡gy?c̡jm4"@K q?\tn?%-?NUп@QW/?ؿ>clB.@!?󩄪M?͖]㿧޿E\PɿPx? dLĥoL+cxΠԿ^f?Q[5迍iNk?|d?[i#?& r?r-">?D\ @f3)3?aep?I.? L=ڿr6?8O?;Xֿ?dދJ\?d?߅!7?F6пz?;?O,0??ZSr? :dA>?Q6a5?2gm?T>-@p]M?3T~Op)ELIСG ^wVNhZa?ݿ%.^^?o3X  8shuffledeflate W1R (CLASSVLARRAY (VERSION1.4 8TITLEragged array of strings (FLAVORpythonTREE S0()*@(* W1R (CLASSVLARRAY (VERSION1.4 8TITLERagged array of vectorsTREEQ  H3UUW1R (CLASSVLARRAY (VERSION1.4 8TITLERagged array of strings (FLAVORpythonTREEPU+UU=W1R (CLASSVLARRAY (VERSION1.4 0TITLE pickled bytesTREE`A FXPGW1R (CLASSVLARRAY (VERSION1.48d 8TITLEragged array of arrays 0 PSEUDOATOMobjectTREE`1PW1R (CLASSVLARRAY (VERSION1.4 0TITLE Boolean atomsTREE X@ZW1R (CLASSVLARRAY (VERSION1.4 8TITLEVariable Length String 0 PSEUDOATOMvlstringTREE   Pe@W1R (CLASSVLARRAY (VERSION1.4dSNODH;X8EhOxX @TITLEVariable Length Unicode String 8 PSEUDOATOM vlunicodeTREE@ 8)*H ?@4 4HF`o W1R (CLASSVLARRAY (VERSION1.4vlarray1vlarray2vlarray3vlarray5vlarray6vlarray7vlarray8vlarray9vlarray10vlarray11TREE GCOL@Hb m?8W迿¿?/°h?4>?Ĉ&:?J?&I pSG'ؑy%?ۑ?3?a3?qпP 9P?^G ?;͉?P $˕?Êy??捕?on֩?sG=?}l?^pFY?,!G9@@mopܿT?Ox6?>FnL?s|cF?Et?g?:Y?; @@,Np鿶#v'Lh;*/Y~Jkw?MG?qPϳֿN] u'2vYChOT[}t? YL?ȁnlxeD@=} ?y;?(gB]|7?s.XԿmݿ~TdU+J(JmU ;rA?+"`7ϻ ?ehIϿ9S?}tl~ ?+{xܿ$)?BhVH'";? F6?<k ?|C5g¿w.1(?h`߿|P|ѿ|G?Jakysi\ߜ@N"fn{?M>쿋fq*įpDUAnڿDD* *05M ?Wg ?>ABBٿ(+?L6AqOO bԬlǿz?ؕ?&& #J,~Q?;*n1?hZ:3? IDk鿃ihW ƿ`޶?$?A?F`^?31R {?BqM ο|B?( ˿umP?vGV0?|.#ٿY^i?` Rw ?GXJ?+| ?gr9,+vhIbd?;1 $`?.s\?^~]R?_^?hV8$ ދO-)?? ?m_j?jlP!kWmn?D"ڔҹa`ؿrmw@D\?'G?"!,F?OJ,׿.F0?#{ui?A?kE荊?&Ӻ? ?V6?ػ?T忄*?5E?\`ϥ?p<34nM?Ceߢٿ; ?2 g1R>?V.rտEElS޻ԿI/?d*ro?4?A?2n"Q?@?nw?W݌h?J]:+m?oxjٿo$X񆨿V? N濯 nN;Ŀ9)p?(YM?w~#?;a8?w0 "?xhf}NٿDO[:?NقvTMp(H?_7XF?TLce?J[s?h@i?hyrq{?G#A𿅥ySӿp??+}%]?؉ ?к?f\)f&bL?@?)?zTlVGG.-f?k+id:?OiL뿕$"洿ǽ9)Gꚮ>r?pſf߿S&C2(6~?t?'a'?0ԑj?Ag減? leeqxF ?TU,?j4)?|@B3?aOlS ˿T]^뿁tu$#XPS;]O%?@Y=Z6?(B9VDJa2ɿo?T???,6?- |?b_޿e?<=YB?#r n(ο-?;|N6?e|o߿b7wCg#•*~?0ah[ʿv]♗M ?!A[ӿ`ԟH*CO?%*"_'Gk?Ҿn?36C?W?@mB?F'?~hY6ٿEL?4K? pGǿ6?&A?ҕFb@#M?6 KPRݿŤB@KuiWd?DĿ Ahy࿕pʈ\3?kƟMI}x?}~qݿYkg/ ,D-|dWBvݿ0vg?9?A?0 ?M(ٿS‚qKٿ6Z?!&4t?n?2M+2}N@j R?5'?sh{↓|N?Wu4~e2G3J#~?䆶?}ӹsοac?/}-ܿ!"f?Orf¿.}V?! lM?~Ϧqlϩ!ٿe (ƿؠ!?3\? ,_?my?u?A6m?% ?*ۿ^Pn?s%ʩ꫋@k/( ꅵտ==?ˆ?1}m?i?A2꿑&lY?^q#Bsp%?6B _`}F?\cJ~ӿRƞaIh?qF뿖?|տ(%K?NtC0h -?6{D \{3?Z?*R?w$gp6zRҿRu?=~Wj}v п;udI!J4V ? EK? j.п9)ʿ-{ٿ.jUHA?Ng? N۲= g?`{1G?ZK S?7Z?UU\$ԿDr?h>6p"?t)0?Ʈp?a8E׿FYO&{j?fOM?<`ֿͪG?~#[?1Zzl#I鿺 Ʋ,Q?A_X7? J?R2 z}hпÈ4qѿ5(1ʿbü7;?\/ZlN8d?׳ ࿧Z?YPB|6ջ_<=?nWu?.Eտǿi?gS?G: ?Qȶ?6]Ϳ; ?r=?y+5翪-/? ~` ??CTE CRw4pʭ?1by3+A:B?3 ׿D;@ ? }lrT>D`nZQ#ۿMZOٿP[׿&j?> _?wݹ%*|<@ ?cڿP?y!̿ 9Ŀ0ȂSg?N?W!7Ma?wW<ۚ࿪V E?(L?ΰH{@+h-?G4LFп i?p[F?i6?/Tܿ[Hw?ˬʹۿ̒N4?4d `= 4*?I sV?\꿩9]p3?E?Z9a?eӉЁ?}!f?xo AF|jw`e??.,Ce?peh.+ſ_7S=?{FJ݈▂?#F㿢<*[?ɮb?F!lL?_//?*Z*? /ke`ّ4,k?60:9ԿL/t^VlᅧYyr?4h^8Bנ׿LH ? lb ?yI*]?yG?0i,п[ƾ￷cH?D3˵葍;r?J1ɿ]Ehڿ|%},kԿzEa۝'Wdx9X?Y?U&ɷӿKI8?1!?ӿVeByۡ?tȼC?xIBTS?BIO׼ n0@_9oh(&+Q?^ef?i_?=*APѢSտ(lܱ?`Ŀ,H:Lt<տN ?cAXTؿ?"ZG6?@&N7¿_Ag?J?B@ۿ?<@x?ߥq󿘈?`@7j?ct ?N3N?i11?WAh@sJ I?X s4Կ#X?:Q4?²jI̺_ǿ\03?_A~RCϻʿgdž/`?ٿV ?RY>\u˿OZH?/Ͽ\"=rrh0ݿ~՜t 8^!??[1?^U5l?m?"(w,l%W$#T?wkG[¢\l?;r4@Q߿T*?@M?LA?#?RBmҥ?n?F1zxrm8?n I?ە|^??^a4oP ӿH?z,Lg/?t?+/Ie׿ /wш@?F&?z^Iw? 俆`?tHcsD?*3F 9E?Mӿ)Vmd¿eI?I`?K ԥIR;G?7?^M][@ 5?}zh󿂗+ ٿZG-?$R ӿ]f? U}V?)2?Wm/GHPPS=?*f= z0&,.~?3#{#п(uIƿ%?hb&0?g;(?#C\ ?L#῭E|?\cL?#6?#,.޿GءPѿ:?"2n?h?lf?O֎anu?3J#');ٿDXbBt?tW%ؿyc!5?dfBd&?4P>?6> LK_ A/I^L"?qÒNp?=N%} ;?nf i/?ʿV# ?vk1]RNUӿ10b?9U ?l%L?r9׿MS?gy?#4H3? ]_违"GZ?-Mb"9*ῠT}$?BP|⿕3/EpU¯%-1e?bְ`/Ϳdm~ؿ. 5`→i'?(u?VBP?ZNWWnw>T02_ ?j?@uik5dL7fan~%MſEq)?Q8 㩿5o?(deq<vk+ Թވ8;2b&?\`ѿWO%?d}i@٦?߽u_fe?rGNS翞x?n?ԇ?@?p1?| $JX0YydO?xHz俓F?0 g_翟Dѿ޿8L&eʿ2dgZ𿠱*N?:q>3D[ ,DGܣU~ ۪ JֿWo5ҿPP3)e!KwP¿lQҿF6쿀?h@۞:?&22^7?j26(ࣿxkK%?>0c^[Ty]ExڿDr./,ɘ?vDé;}?1 ȿW7a?~0U?8!/?psm%Ý=ï? +sB>\0jQ3C?ۿ̡嬹?+y"%Uߊť?X}dB7ey?s;?ROc(@:3 &WL?kaPɰ?Bw+VeK'Y?`-?!X}` K? |Ǝ?[?_ rҫ:?Ʈs?9Ii濁&ZWgN?͇?*FM?Ž6?|:ÿd?le?@0@DžY ?ϻTa?t9i?ɂyP?2s?4{r?!)05ٿmHA2?-w)\?Z]e_<,3 @d)?бG ̿CRF kC?4}@f14dZ'㿅Dþ?~;ʿ2ʴ?_.yֿ.NS?6K?^?5*"81?,qxJ?Dٷ?Ti:r俷i?XF[DP?kZBk?Bg?zΤ?])Cx??GFMRJ#*?60v?򼿍#k8=?h?wj+mf@wV迼0.?F_6?<9?>t㿔r O?_ׅ?PP@>;Q)?'(?<޿"'@Np.Gœ4뿬c?aP?+gJO?KX2~?SGr*?ߎ?w;do]ZcfF?O-NпJ?^~p?m>/?VԒy?q?[$L ^PjPѿw?pZg̿\d/'A?`{n㿊9Jr@ڄ?ʰ6̹?< ܤ@Ggwʟ&% V׼FV1NMa=?$??^q;ԿP5=&b]?doI?S|nu,Z`Ŀn ׿C8*?]~?u?-]޼ֿvI?9V)z?z?3ry?ZR?ԡm ?h'He?**q񿌞 ?4H࿵Ѝ+?6׍¿g/?&HˍjCZb?[?7'?$ZfL?b%?hL?[nIc%I?)؃ ʿ*| ?Ȭ"aA0\]ew޿ ?wKOԿ'#XX̍<@ZۋyʿÝ$?< -cdo-?jlbh?2c6FdڛT O?h?]bgn&J@AQ?ZY|?D){K^?~_3G4.5?8-b ?Aw;i?~Dj?' HU6ٿ:">'`?e%޿́8?8a,?b! F?kA9D@rLt?/ZۿBz4!违5%zù?".@`)-w?Գ-_@JZ!]?!/?4%?-[@yh^FY?PǏ?갞?p }FK?p1?Q3]?{?xubʿ*?03 ?Uz6Y?}ʿiؿ:)l^ۿԃjofc7ej?iT*"6K'V: &?ˀ㿣Od? 2oUB&? ?|O1@Jnm?%*&+9d A?ț?4c7Rלu?yg:п-얤?g?ˊп.fVo?ɂ??U[P?w#׶8H_V?a EGJ?h=ąҒ3?4˯}1远_zX?[‹_??ܿ‘vsu?cbn<~޳?yϓ?E pNzV@P[!> P;*kaY?3j& п~fֿ?P:ȿ[?DW?Ռʕ?b7?9Xl}G?C/|kF$aZ!5]]/n? `fEW?Yd^~H޵ȿlHV`?Uۍe?b0οɝ.׾8׌FE9DYӿWe3Y?V]?i^@Ofſx?Nmz/?UFE?j?س?AӁ@cZW?kށ 1#?!RkĿt?,Zåz7 -?*.Ŀ~LuV8߿AV=𿍩 w?+/5 >?nnKdȿD j?T$տ63y5꒯?/kK?/od8;yјvqɿ@QKm}οQ=RELx?,Oӿ;;p\lewrdp Loο~C鼎ۿB??b7?% :+ ߿ECfvo?mUr?g q?ݫ }%¿W9әfH8?~?P?╌.?ʞJt#wsӔٿ&过LS(ο.e jſ"O1ȿ =&<?e.xێFH?q}R?A ƿ:VOH?ܿ,Kȿ\RJ@2G^L?A?`6<+N??xQ?JC-k7п$0w?a0^JM*@HU?˚|W߿p?ϡP@xQٿWcA@+?^D?z+q忦_Z?>c/?"?MCe?K΀ֿf6b1X@K?l|?)1?.+ Ϳu%i?Kp6n?Ƹ ?Ġw3Yyۿ`9Ƒ?>pة?c:|j?-;X8 `1p?ƘTpX՜WW-֐?(iv6 ?duJڮ׿gԫ b0hl~PAbQmͷp5ֿ-5cp? b?2\XBۿxF&?ӟ]R̿>!ſX3w!ɿU#?u_7KkA-p m$y{?J?Xȿ^῝ܪ5?!#鵷2@r?6T3f%?H9;?IȒ鿧ągҷse?6Cxֿ{_k%?mB^ؿ+kyTB?AA?ǤC!?ST*S*jCؿKWP} ßl?Ȉrƣx5U?Tu?EtF?sٹ?;M?y47n"G!`?8oEpms1,ǿ?]?H6?>\??ʨ%FT?Xر ?%0$̿V12?{DnW3YiPL!?0[f%&?`g?G -si?j*?RP]ׂmOG$榣Iz?&O7,&Pn? rY?+Z忙6Quw?fWʿcpE?CȟH1t?,0ҿXpv@~3̿QR;?L{?;Zxҿ 6Z?cvjy?/*F#@{T5X wL?Iz?Z95?'?D ¿vBLƿ5 MUƶ'U ۿI U.&߿Mr?d#Sn6S.VMB˼z5?̉SFH&ͿI#w?n?.%̿,'l?c4?kΌ?:ѨP1?܃O+%?1.i? 3ڿ'jҿBvǿ=#I_NcIS?$wZX 2!nV=?N4fԿ8^^?T݀?H+ie+}>?ʚ0?p$0I:?‡N[*s MDҹlOK50T.Ro?%gHx@9_\NJU߿Pf>{˿aܸyIǀ,H.M俛Y-V2h[Ȗֈo0?`=_YM?3r6m$a Cȧ!?ԿFF?IGI]ѿ}5N?`h?tet ?o#?R=?(Bho S v-?A>LYs?}J6A@&zJV5?X1]W ȭiK ԕ`eê?1뿤Ld ?k=|?9;r?~%?%LYB?4!_wuQҿqB0=?HW8Iyy?>Ͳh?Jؿ%o^`??!a?M@G"EڿbNܿ>u U{ %oK?h?v?!OT[@!aQ?ϨЙn=?Gl, [?R>1?h$C?_otr?8&'.?g+zw?^>\ҙHZ?ߤH?հӿ5W?h>??ޜ?b?3kG,gܿ2p{ ߿R5οP ? cma$ZI? ErQ70y[^@B+.9dLT?'@1ې?YP@Xv?]u?ύ?6HꮿOeˉA?}5μ2? aӾu \?&+pn꿭t0?J6 jӱ&)?\x?Bٻ?&y>\9?^FHm? ? b?. 瓿"W ?fa޿^WbO?>sik#4Q2?'?q߃E[?7S㵹ʡ޻?HvJ?|^7׵M\%E0?!e(F??a vп.[z?;X˿E4z?/[s:*Q(Q?^?#O? H?'`?H'axIi?# B9Y|?_ riƿ6\;>?gLN7d过2ӹ+I]$3ο㚢ij?]7?f: a`)!?Aȿ%O+? G?Kkݿ<Ƣ2i ?>1ap2?eY.2(ſ~&?|?s`ԿelWZ?G:V@p?>uӉ%?F,a.ֿ@-?过EY߿ ]?J~?njYJEgJ׿#|D?*?vߎ1}??Jn/GHg=H@?3L1~.?}np9%?eο/ùڿJ=WG?< DTջ?Cx[?UpDRW 43@Ӡ D?7Q?mJ-%[scħĢ;?E# ?%Et?s1V(:ӿl=3f?#-ʿin5?\8KҿD{2v???m5?@(c?M&?C&j?'}@ ^ۿP{gMt\ѿW!^Ϧ?׿̭0Vf@ƃ? X+/1ޕ?!{?)K4 JZz"ܿUbIĭ?aRRER@ۿ>y3EkN$ss߿c ۿюʳSY-?7۪ۢp=\E?X#3?y(1?V b)?1L^? 9sCq?z?\q?7VA?g3ڿ8?d#˪?TQ?Yv6ϿYˆ?e<n?X9OW2F󿻫PX1@Fc?"濋nԃJwh?DGKiPc?A9vuU?5I?rA sa? uA5`g1z)7@Q\V'?$? p+?T߈4 ٿ~!/?z%?wY?{?svT }?eK忭.#߿$v?ڛ@+g8Id@z<d٣ۿf9 ݿ$`?1^6RvշiM?pAuF?);"?\X?`U|PaE?A 4ʿD$-?moE?/bBϿg|jTIHZ?Vb.ȿk< r?է)ؿXr9f?aZz\GCVakR,?]a@e!?3ө??MsV-N}?$ /'"u6T'|lltпMu?z?9wՈB׿j9?&1iӿBze|l:?dX?ND/[$?VXuӿ /b1d?l:FxO?(OYA0?*(ij293?0UpĿS?$?߲ :?r09w/`ݿ ?D"E ð?L2?t.G˿ɔK`?P]?^>濦!g޿j ?&d? k?uZskR&[{?i@yzok?rZs?I}%Hz?Y~2?C?]/ Sݿ5KAӿ ޿0H _bƿcЧX?7F翸g_Ɣݿq +ܠ u?g?H?#WYu䢿~q3? ?ϿV?~Mz9=VĿNC Ͽ-b zbG{”?Z(?? ?VT?'>tvL#c?#[O:?r,X?8z^»'?C#Q?iy%+?7?t1Mrm?kT:?&_N UR|0H}6riԿko ?>?@R/ D!?iBmĿcm?_I`Qx?"=|g q?{CJ?,-?5Cr?:,K?~:l?p/؅?R&p ?p~i?ds) 6qZ?go6\޹?C p¿:`I?Hb?\ C˿@?i^0ܭ㿄R̕߿:¬-3?*J<˿ V\?Ž屿6#m?]’?t+>Vٌ'/?j/?4qg?Uc>2~Ŀq$8?,'??"F&D?;g忏~x?ȬG=࿷7Wҿd]ȿ_\ҫڿ ?KNG?.~xtܿ><2D?ϹOC?yR ?翙5"4m?8@>"? CS4!\mTKx?i/\okm?/zy?Qǿq i㿁Oi?ĝ? ܪ>?nĦ?spSap,m?̠N?Hl?E=*?&\ T#)?"v?zCo+? `Fh|?Cx?%&ĿKZ?mb#?E1Ì?`?3Sֿc5п'E%/аG}V|@Dw37ۿBf?3Ji?װTEB^_v@,Ƒe?uFz񿼨!?)SeBʿ> V?Ѕ?6SY3^W I?BٿX2I g򿚰?Ҝ/ ޿Q_ ?9 ?/>K?tczӿÇ2ye꿾GPr?feyĿ{=I _'P?4ʿ/0߅M޿0)⿹\-?42п>*V޷}?FWl0?(?_vg?? LUj?I_?0_[2?\ RO?Z?erS˼ ?OBia3?f`Վ?Т]̫⿺-{TEȃ[?ی&?Li?J B:bM3j@ ޥ?+k?:05?Wc ?~+?JVe>=c?}(? IJ?)꿿ls1`g,?* 郱? ??3k yj⌲ϿܿMq9 ?^0?>Rj}[?(տnVl?z]0 ?G9bh׿YuZ"L4Z=-?ii?j޿u?GU?sK?G?u?.jȜ#?k-ْx?MB`?:(x6gRڿGKڿobj?֖Sk0?Ooԓ5ѿB{$?q?Tn|V?"F_?oP?}a &?"f҃ma\-n)fdg?OU?XK ڿIbzWGf?X;a3־xȿ`m`Ῥ^P?X+Z?]`%|ϋ?t?hkA{ Wh{{?[ mD|QG տ3$w͌2?oB?DBϿJ Կ;?b?w#]пweE]?5Rn&A]?Z ?'G8Zӿ҇I8?d@Zwds×y?[ I Ra?>@la.-?߿(?C4'?6U)p@Ks@O p\Jט,>)U0?yVB?M}?Sx~?c-7(?x?͡D*]?}=I?FM%F࿏җ+A)a? .8e?La?InT?\Xz?wR?r-G?i?;ӡۿa؋IR!?n*?<<>?JX#u~s?OI3/[ؿBmy?P:?# \] 3yG}~#ܿ`e?%E`?2QFOjxf`翁vпD q"M99ʷ5T?ʙ@"?~QT?+dC?@%ޘ'v)o)ۿuJ6?Em?FIw #gNv}? .:~?4eoغ?ШJЙ@+;}߿O|῱"A_f/ͬǘ?z>VF7|r8?z 3Կƚٿ%rYտ¿,]?>9cX#?> ?̟&Ӭ?G ?aHo%&?/HfxޥM?|>uv?& |\[?-C2? J9?(某?m/eːi ?>^_/+NY{꿛 i9K?ȵ?>$,ڿjŔ?nCHl5? rԿmsX>?Q-u?MP6?4j?_Վ7@}DSտ/~I?Jb?vRֿKfEi'){4 Qv?h:{?Ih4޿ƬI?6,?g $? 7m[Nle-2?=F T5U1D;M%k4zǿ @5sz42"ҹ'8AD?h `Cy_@8@/mQp?#H;-?yQֿ{sv bttEQSآQu-޿J'?뼧οb'@tF;V-PPٿ$?FۯXz?鿓:=ԿCۣip?2*E,H ;?BGZ?߿7`?vsV#?#eO@D? S?ߦ4'?k/J!鼿7  uYk?Oeg?GNxZ^?Q2?SB&Ϯ?Ne+%ĿX2f?տ{'D W<??<Q?ْ="J $p?!?;_q&ؿ|X$<$jW? -.)̗Mvhֿ7Y?mY@ǿenɲ(#&T׿0j5ۿFꤖڿXʮATiǿ[ Յ?O֔? .¿/ytͿR'?n?Wx*,?Rhen>?#.;Kr(? ?g?yoMv+%ܿ6m?EX_7?)v&:CE`ٿFT)$kT2ֿ%%äU?q_5^4 AHjvc5J0?@K粹?l}?(W(j?p(y=}#ѿ7?Г^x pa'@?48bDhlfR?G:km(g?Wv?KC)$dž??jZ⿚P8^kiٸoyN;?;0a6j͍?b=D1?K s?a;`S?*AN??Ay#?D?^b#͝?Q7B?.\n'q?ݞ?EOG?nֿ'f9?'TS?(& VL1jAUɿi{OFѿP9տ_,YBɿӅ}mc\?h-7修~/SXX\?(ֻ?t+w?&j)n쿒XǿLÅvJ4?RaM:)=S7=Xg !`,?ڼS?FKԿ}1?*L?OR" ]ov[@# /;(of+?#juҿl?r QLƕ?=p?Fyif ?}fs?M1L?3qV8ΉPtP??vJ`?n:I=i*L?PiU0?gӿNiδ?yI ???`lJ?--#"???j? Ίϣ鿯~\?F?9ԿڝQ?THE&ſ>?;?z,‡^I?%9Җg;I濎<;?h࿙}6׿W7=Rif? }??賃/w@  X)jȹ(ٸ?7BB?>@gſP0Bj?(K\?'~4O?MiE0߄~?kIp~mo濂q&QI;sLῨ]Sepե^ @ wտDҐ%_?b}nտ47Ͽ'>?2z`.ٿ2Hu, 阌?<7%x)@@&mqYZ?#9?gܻ|?KJ2 XUܿNH?Bxx?)^пUΈY?{Nεɞ?`3=Iۺo7%yNҿߢ3bR-W࿐h=GԱR0 S?nLL?oYοTj9@ͥaI迣Kঋ@5@S?ۥw?3$nҿGkƎhΰ,f?)3@űo?6,orͿfcc.J?UD?`ɩ˿}dT7#?#"+ٿ ؠ?`DVUG?'mxw?. 1r$My-|@񿞟;AXݳb?ng($Ñ|W6D?Uk?dk~?} ^<-,DC 俗3rs(=ڿ[qFhп(p^P?%2D?ۃ騿n4-ܿ+\&п-լz{꿡Dܿ5Kӿdȿy@#7޿'~׿Vo_НʿJr@Wa-rn?g?CM? i¿B_LG|c%?k4'࿣+-ٿ:?ӽı?Ep1Oשҿ՜QTD?)U_o?3\?RcXF@j5?[ݿΑ?I`" sއNqc8{?о?"Wgg?3k/׿@"zsR?V ?{Li2?}pW ڿ` 2Y1rMÿ,?S\qDi?jŔ?1Qg#h꿳ݿe0Ͽ)MZ?>YF?ƞ50̿ DPd.?xq?1Fr?xƿv,>?9Y?м?;2H?<j?K9kOc9S6?[{?^m ӿ/}Կ {; s濘*?K(1e? ? ?C9^ L俌n5-ſM\0?]?4xϿ,J?Yaƿ 2J?.%,?%oҦOjg8d'Ϳhz4#Qc?5?|])*?dMڿʿ$1;J̀rͿA1pYb>X?%?-?i76NQ?*=ҿv.Y?nǿE7`?(S_&Hidƀ?oŝnͱۿt8?ۿ<%$?{ShſZV,?oWS? TſE`ٿ@X'?#mdL#տ_?Zu4?w1nRN "忞)%{fjW?7?A֪?4" 2?.0?eɿ*0_s??ꉅ=L-? '9?Q5?N&?#JO?B~FǙnp l\dۿu7 ,?VJO1?Ѧ,W?h?mDtv#? ~c*ʿX6q:|/KK'L\3׿T̈́?<di?z?@Pb?Ws3T3ֿtGO~?7l&?Wڂeʿ{!Q&w㿝Ю?~JE֬ט?bm)Z@[_쿭*Z?P⥉g?]yҿ%9ٿ“N8@tZ?c|qyM?>࿇ꛛKShK꿀;?%L@ܓ?Jqs?5o(?1 AٿR,𷯨?b?Q?I4ֿ0?]?Gk ?6yBDi?4?RXqT?p`$?#9y߇G .Yٿb?? >(uʤR)MZSݿXi k?;Rbb?O' \(LobV?'dÔI8U4׿6*\;-h?<PKp?ט/\ڿ"HN?W]&?dG[Mr ?b'5>,rrE?Ż[cObp|y?XwΞj ?_p6q?%ԿO=?~IJ&xC?RRӱٿ&Zj?F^'? =˄$?0Yaj{D?, ?yۅi뿂?O/׿ic"z6ٳVǥʢ)?Z?=? ̎aĿSͽ3T?X "t|΁SؿA&?uho?M_ي?!~o|?=phJ ?-?M ?a?F,+?_Ԭu)5$L?7%?9qW\F?#٨?Yb? PդA, wX7H?25#뿷=3$J?ǀ_^?.ߜdOYGU2ωƿj ?c+?" W 迻#@}!пBd'bd#?  ȿmw4y0H)hM8?qK&>ʛr9D17ҿ*$4?pl?햧%נ*ֿ=(ͪ?` 5?v?@x^hؿ+Y?/Dz/߿z ɚ2OW??m7?W'>?_[q׋?43?шa6K?iH翬r^{?1hL b_?*S;j?0OA?:Cf?jt9?tL ?9{7+)zIjjLT&]"?ox-^?˶U?l\?H@ÿ916?35IYPP7?J͒пeX1g1?U0F4FZ9~h?Sm6P}i?D&.?L 7?4}Y?aп=?؄翍ESfVkҿm^?| ڴq?}P+ҿ<_(9㿐yZ5%?s=@$-pv 哹?QW\-ѿg}iU'f'?^/ ,[?e˪L8?κl?xmɣ}!ѿkŴ??!S IJ3dd?WMH ?ݾ.?M迭LԿza0? zu?n+?/5.k@Ru; ? #눴YXntW?a~˿*`Eǿ?%{J?':tT?Xƫ4?0}?a'ݿ~ũ j߅?+3LU-J?پС]?U=W@a ?^#E !<?ɀӿw~6Kzla7Do|(6ٮ?/!CI?9Z>ܾGEI* TQx4C~ڿ?bd?Ώ?h{?iH?,`俯@Qs꿣=1?4>@?5iq?oPx?9z2ȅ3?Gr9 _?fBwILr!7?w~Up=k?^?Z?)(=Rտ?PI`tJr@PxL?B|¥AT? %V~Ɗ?`')&!S@&/?翥$NG)~2^ĸ? _w?۹?6Ӽ?01gG<ڿd>{ i)9εտ8!?S_?7|ڿU!$t7@?:ZK*!%U)<TI<~@?0bW? ? Z+K4m?V;Dl^?5~V%+=?zø?͢ϬIW#wJ?t?n?I6oݿn^?;PĿl:\d-2?9n? z'e?8u?{фs>Df2Zl޿[{?TonhFӿ5Rp?o @,"?n?t)@0`? (?࿜ƯԿ,-L˖ѿ:P㿉qp?.v_?>oL?h}͹4㿾s0rc5?- ]ݳ߿uz_ٳҷt/t"Կ,c ?o `̿Q+0UR?PǍN@ 5jJ?;go% ?D?~`C6ѿ)V?#N?d?.?vnJ;'?6e'HQp?'?x)Q'߿]й?)b6ЦI࿄8?l@?h4}Կ5̜l\Vl?"?s:+U?HT'׿ f8ú@?Oقo뿗cj\.?ؙ??!v#?)MžQh)Z׿*vf.ۿAf$7`_ؚ<4F;m?}SL?ЄiԿC(Sz3iep2?6mY׿H?;BM? u[?s$@?(y}?{Ox?hoL?O1}?yE޼c9⿽bP<0꿼A5?; V閉3$i5 Iҿi 3)?Ab0=!zP?"pMP=? iJ?Viˮ?PPd?5[ 3v%տ'>ʄdؿn6пJb|_?_!@Ԕ? @޿A?WQۿl#?)>??;?,Zem˿K,|RVnS?%Pv/#?(;?2&+mq?$o7)uYO?ap ? qƿڱc;濎ao2ނu?WsE߿b:b˿_ m#FA?W7vv?F9x;}p޿}++_ԑǔqƿDbg#Rn}?}zЅ$꿐WR6bzB:G|wIM?2f6S=c@ڦ'?TTf+<ȿTtO6ہq=m꿸Ț3?4w0?£Hԇd?>b ?K⿅ g0?-4{Ww\m?^&nўf῅Ji?YI8!?%Vp-?"?A{m @Sҿ?7I?-PP qӿ07~E?6f~QٿE^F?iK_ɿV3Z?o?ofVM^2q{+54濋؀?B|Ū-ٿCyϩ?iNO?@GCOLC뿑T?K㿺Y7n o!?>$Q?3!<+?@Sm˭?:L n#*=迬 @o9[?=CZ ? #?uc!?7_?3< wb?$h~?*2y켿aFr׹ Y;D ΅MTDؿtGi?x?~?xԊkk;"忖 ??zv7?r"ୀ+?K9P1t-?!(?GUi?8r?V9c?qN?ptW!׿GEɹtJ?w*v俧/?*)nN?O6yIRܿT }' 5?^H鿇W`g(?uˮq ~? rU濆x/0s7ET'd?^ @Hpub G¤?H6l&1^?sH ? ?Y?} G?ҿN trͿ ?V]?N̚ ̄bढ़wz}@敗J +3ٿrש??x̂u?aԩU?.>X?2.?p~YSa 5RTu?X,y?.E?x"nG?nKo}ī 2?8&?V'|5ῐS l@?/pÿ$v4?;z.&M{Y?6 ?rX)#?<5ڿ3~+?DM?1)?#}Ͽ gp?Dn6^?-e ]ʿs ^=+F6@SD?k=ۿ8K1ǹr n?6V߲?S O?IQ~!UZ P?gǿz):D;?K?3.u?%X?d&l?o36& `⿷1%?:i_ο?jB??]JGqDt?;C??;n? H?ӤB{ۿIv:>H'<|?Ask?`=hν?!SO?% sH?z|\ӿ؟ȿ5a俸BY Կ%Ǟ?8S?BI?2?3dusmdԿ#ض?I0?}&l߿\ \?c}앨qBzN?&j?zQ?I'e?X?68?a3!?rT!¿jDv?Ez?uؿ+G?(xf]x@J{= ӿ;ͼ0?iIF?S8|ӿݼ'k~Y쿐jf?m?=HRQp6H?>^ ?ŭ?;c3ӿ:[z3? ?z1?Q\?2؎ѿCx|~?`d#s?rcPa׿jqY(?JTڿqLɿ{Lױ0#?`ͬ?wJ?-_+R@B6Ow t?z53g+K ?WC?!W3?O%  ɁkXH?QV@ВJ{A?l?Bp߿x?׿3dԿݺ?Y5῁gTJ_! ?~+X?Jp)'%^mg)<?R`$?x?+忤1b͔?9&4b?'5(ZE?[zW̿ļ1_"? )E?(`:ŀ }#S@:v6@euUy?f`%п kRP?hW&@kaO?R? mп܍Gm?!]῿unƿ=J ᅱ* ?Cm$ʿ=P*?x:?/ G%&ԁe$}ῙL4ܿ*tF,1-;?~QٿX'8?oYZտ#;]}?-9^˿Ix?d0?"EǿJurssuJQyV@%?WgͿ?.rL?C=J?L?xnK5gq{ֿقU?<-z?& [Fo4Ŀ?3#*?: 7翿)?[ز1.qѺֿbR>&,? @@HZ>:J|¿e2qFȿ>8R^?ie忏/Mݹ FW*hߙ?(@ +iȟ?F ?ʖn?][?|J? %2\&ۿKƶ?[鄠?GBCW+ƿ~I(?MBMlis7)V ;[77f ܿzZ}d?a2?>@??ޭ3?bR 5۔?\SҿRiL?ڊV?mDd?YigZ^ C5?YVb(b?#4>-)?"Ǥ~4 9/W?%DZ?]?tJLݳ+?(Ȅ yk6?(⽿>TSk ę|Dÿv-Ű/}I?Dvo ~6 @?&LGD?V3?<n?Tq? -J? Kk簋©࿯b?G?HZe?\`?*%?k? jDT\T @ݡͼH2#:Jkx vSB?pb?\*BbO6j?]": --UQ{]:1nſ0h姞?ͽ|?Fҿ1I! ]@5GJ?c?\M'lu&?DDF&cM?jg$O࿼)yc_ǗDQkȿ%}P`忽o0̿O>?H L]?̿pc࿧8TLر$ʠӏ/v˿5͆Կl>пY迣qSf?h?ة?/H'QU*ɿxḄ?½UjDƽֿ#wخ P`ֿghإ|?(ōӿc?zп+b\$~Dn K?}n쿈Q;R?v+VOֿ?lS'뿗b%FT{8aI@yG2??ԕ4W??b?迩Kǿ}M/'?ѿ${࿫nn߷?Iο$Kվ?YlP9?y5@z?B:?Gb4GZ俧ïP?FGpAH?1G?-5jD?0\ῥ>?ȝ\e-,"?Kotan)Q?fW ?Q?+ܦ|_DӦ 7ző?uB.{-Ö?ߡ։YmdMJ?h?pa?PZл⿇l[5BAb?g/(?ҿ|8ΏJC{?SMyc"tտB4~=pp=z@{eѿ?>j @1ܘ!@,?Y[0 M ӿ^A;oJ?nDYI翷5?84' ?&?j>?n'?ͿC);??1#6?] ?'ԚgտXd?xJf?[@\H{?!q_?*sڿpuO4##6⿺ĿR7PȬ#:e?+ic?_y?C)'?c,@?>v@ΏſKhB? Bp\?0tI~c?նN9ֿb(Ͽ̸˿3!?;w_?}̿a?VnPDuտ?(Qnӿ~xZY;6ZJԿwԿ+z?hU?1"?k^{C?ΔT?p`wB?)1O?J ?9$@"EҾ?0 ?zh %ٿ#@ [-e޿d<?c޴WD??L3v?V $9翰H?~保 ?FDͿ-K-=@p$?G.t^j"пkk vŬ??T?_HCҿJx?"7םSտ <@?e/пY l?R ?]#&86:kJ?(e9!'.k?iL᩿>.LWÿKT*+[N@q:]ջY$?y* ^?g!-?*?nw-IIӽMſ{ ?w1zk N;J%ܿPc?g8ֿ3cW?%l"?Q{w7B4ǿa[ ?|W<,̿Bt ?{MtQp?G?55'Ŀ?}F?'&?8W}?t t?_eSƿS~?>[K?=D߿:aêq`Rr =/JӿUY/8t{ϝ??|a9i]W?gOs?xN?E?n֡k@ᒵ(?J?̢/Fݿ;& /p?ǯ?w+$Y?wV?ٿȔ|z?RMe{+?A4?m4Ow᩿p(? ԇ#? >X?%?(6dwWFo2L'm Gm.?W V{?Uek,[AB?t?[!OQG%C?[?տ3ó?r` ~Pjٿ]؅?p"?dV`6m`q9!c?>sĿ8^?^_B'F|迅 l ?^uFW?CO?,IO,6ki?cO?2^f8u?K_?7_ =q?G?r_^FHtGoeAse/?I#?6#?BW??.TV?3?JĿ5dÀ?pdk6Կ~jut[m?ov-T? ?{@J,2?g 2\пH{?b ?K׊8?\ t;a_տ]RK&?< |뿽>hX0il.J5쿟 WqUFoQN㿋$ʏ? IM$so b:FG Sgeqa_?=vI?F?9 G R?k N? V¿ g꿄 /?3 ? ȧ?jV?vt翐9?W9'V?`0 ῿?!>f?(~ϳM4*h?,,A뿌Zu^UB5ܿr4J-":̿0EGs?\4տW?G?%4WO?4Wj?Cտg)?39q?Z[b:?3@ pV(:?~Xmj?`TWς?@?O#? ?[b?gTm?*T? >XW$[կc[ɿMζV L?X|n`?] ju0 TeK忖Xѿ)JRI?{tjR9PlݿrP,?Wi?Łӻ?;(XCR}x;4U.B'?k?ΩNpX?|KTGRoQ#?a>?8ţEIeh) ,;ɿTcDgؿr?8̙7s?4g O?  ^?-؜޿ !RO/Zs3Ǟ?B .2w4yc?MJ+ &пf5I?G+vɡ?o8u%?-32?E߿~U0Z?מ?e#Z-+?{:Y=?P?<?;?"& Z1׿OH}iP$R?.K?UYc?.kV⿪ܯӿXe??7՟?^㸿DH?oB?<9?_x? ?z6?3a?Yz}?B4>8?"R6 maqcDY?Xǿ?Oᅪ )?ņ$5{W 1?Pf33V1} :?[Կڦ1ؿZ/?&m# ?]@2G?䃴?E.i?u3n >?D9v'G??+1C?z AHi[w* ȿd?'OsԿ_b7?pl~mֿ$gE$ ^/ <ݿhs&&U*W: ͤ?8Na=$?GSKc?Y$ ?Jv*ҿ|[ ޿ B??P߶ӿqu? ?w h?ҜyPt86\&`2?o.@?VHѿقRMZ?NB󿂸ʕ5$# $K/G >}\;X?^׿(} B߿2fLtkI2&?)=CֿNƧ ?>E?/d{ p?EQ ?$U @ue .6NT?u2?zr9??ͿPpa?Y?]P;]@?:H`QͿ8m|˙hMIH ]ҿו_|?pW5S߿ΘHC'?+ ?Ǹѿbӿ1;dGRx놱Ͼ?3Wn`?1#6-忻xy-3(&ߺ?yJ?h %,?~?u q^?t Ok?;(9?!]7?YЏ?qy?E:X<,"Կ#C?!φݺRXBĿEn?/}?vs?$(?w;?J~'p ?Z ?+b5ȥ8{m5{?FO`^?˱c ? 0$ഇl?ؐY9'?J7K.Կ"?Anbݿ镁Ɏ?R?}qt?]9?TU?un?Sz,Ozd쿂#!?UT?X‘ ?Qnʿ 9MV鿲5J?s YϠ6e?5s"??Ȉ@?u2pycOզ?VЫӧ"󿄹wo쿙 BIB?ZaK *iİg^񿂞q:Т? d_`?(!>?i]? ?|6u(X#sPq]7ſ H ֿj65NI;!?~i,U]?W?y>v?%h5?Bkw荾οN0$?ӚO$/G??E=$G?^NV?|eZ]M,g̲?)Y 9k?;io3՛[z[NET?u^F?ڿS@ݿ}A[*? ?!z$?}C\#ΆyٿS06?3v@j?h޸?¼Ltٿ\6?fP!0%?б~?Dq27?_*R0 w:/@i Z?Z߿?*`@POc"?R0 "I]*g?C-? }?{6[0Zտlv+ݿ@i=鿁>CU?PŒN=+ N9?Bjb-sN@cs6pe使.z?w#8?s 2E?m ,z3=?\"ntf x ? !ur߿iѴ?@-BԿIGBݼ9/PG?TU=?7kgPy?^OM?"?70 K ! 濅t? m?.H)?R}~q8kKJ ?jY-? KN~'?:;qͻZ`?Tn[^?2(?Wk?@#.:C5?u鿂~A:?"k0N_9?G]X"Y?տͿ;‘?4/8I?;迡@-;V㿣Ҫt+?Ɓ͐?Pq4U?z¥V:[^wo?Jm?xS$?uJxn}?L|2iʡTqwYܿ&KUcM/]w8@%E?eh]?GIAi? 'ZQ?Kku?Sx?왕y?[,P˴ TAI#=Uء7?.Wk?6Jgi*807gȕҿe-sQ{B.ڿ?9<;ؿypg`ȿ`-?v6@?+wQѿa*fOyc8_ ?w?( O7MI˳YÿԷ05/fz? k tĿto? ]v?Dt迈&ܿ.x?b?HY+6B^|?B(ZyO2x=ӔO￘E=IpI"8+?KJ.꿋!?H*/?f@쿘7P?뗆?vŦ? `)f#?1Di?8+nxr[ߏ8?I (/?ش!A+ٿ8WO!3ѿ0ii/v㿗Y(Kbпɒ+DdF?2@,@uOF!B{7y?UY3{?`(7 kw?uŜk?q? Oiۿ9} ?Ba?ƽA*ѭ DyXi"v?bA-鿔7Q?(#?b/P ?fݿgt|L?No/𹿆.q'~c?+&ܿh0 ?!_?zGҿTl?*#ٌFo* ? /Nɒ뿩?6VI5?ٿPˆ׿V;?eI7#ܿ:t3ݿ1xo1@ȐsA.tM^M (ǚ 迟̥d{e ǿK]? x2?36Cl{?.wVT*ckɧ?Ԑ?6°6w?\?ݿCw?2Wj"H?!&?T .~kU?@u >[/f?t?և׿erɣDᅱ* Z[?p?+! g&X=Z2A .<@w* ѿGr?;p'}tÿF﹦?A3;ϿAGC _?]@ڿin8%?j-rk[^Sֿ"QXOf?@Gex%0Q[?n׿pL ?o@sld?5Obܿ^'g"?9Pv? 0\߿6hп4dE4VEB?@?m?\%M?||K?r^ֿ+ 񿧇%j0:!? H?8]Xjˋ޹ U5ZGgljp?J`Z7 gb?B;?!i?W`ܿ x1ӿpALH?&AS?b*OV[7uX?%gؿX?3Im&e{?Yy?H =s?+KA<@?d~P3M\F]?Y8ćafz `ҿֹ-?>A^\|,4&?$t?cM?DiԿipcmoS?$v> ?o47?:?/*KH?U3. ThC?%@XI0 u|??E=?;{du?5YYF _?&,>,?k!¡2dY ?s,aL k?GT2ΌSRhܿ|!I3?I?Æ &q@&sle Ce??H$?z/J?ݿ*qѿv,O?ﴇ :?]LpS?z0^[?|p:?y}˲ۿ|yp߹0@3@!?Rȱ,$-a 刺?&X”s{FT ׿:?ى!p ]z?7S?C@K?1@F}W'?]\k=?~G;?V1ȿC2z?szo ?K.俁%U2%?Fb?W'i ݿT&dhgy?3;^ܿo?pZD?}Qn?I`9q?AwBj?TX֞3R.Gfܿ\ ࿂%Q>:Xοn J?ԘuOÌӿ}@li?YO:?sIAi_?g6Xr?#b?O?p~gޫ?P?__?t,CD?YDu?~7 ?H7?$C ?Kq ?͈d?==eq{1@n*`Vܿbg؂ῶR?mf(?Γ'?T]=?}Oڗ?Yct2|ؿq?rL?fCN$?ն?1?wڒ?|4s}|G? @`>V?գBﭓ \u?R?үsq4?ABf]})] _Fc@GnQ#iG?J0? (,`maԀ?:wR~K"?aXKTֿwD/.L sAc$-9Eb&|V&b SQ)8+@I'?HtK7~:0P?;tg}¿J{8S"-ͯ?[Ok?VW?@ܿn,=VewՁ}m?h›X?|:b>?ѣ%濊uI?k5^?xj?ĺ?9]~?|Yx?- 쿯{-?@~n?g"-?'u?ȣtC#?km^?ᴅjzY"^޳h迟qT?Nb /z9ӿtݿ￞4g<ͮ @s0?ݡUӭ?I|5U SߐB7?ߎ۬?E.?(UEVPv׿x!Q&W(T-ܿB `&r׹?w"<ؿ ]% 6v?O=K<%Sd=?aT?-lOm?^?t2^؅I$[$9-F\P?NЙo?.R Sؿ<?7SG?j_?dq@"A)C?!Ǐ꿆EAjWX?a?W?St? ?-C@^? })&?8s9nÿ*b}^lF~?Mۿd~\A?M+ڿj @Ez߿%˿h(׿ʳ?v*ٗ*eh??ƗiXϿn N+P?XQ?5L? (l?u퉷?C9?dju߿0?t,\Bg"n@' 3H?Ն h?q6?$9?h{]?}%|mᔣ?FX$7a?ىx?l#o. ?!(Oܿ ݅ `a?籍90鿌MY)aP?J"?koCCmOv?8_?<?֚47?KGbU?4 ?VIQFx?s]A?>uh ?ݢYY-%ſn? G+ſ?o?l?y׿Z)?5py VT? @;??ڜ?76|3¿;сk?kfpEʿXr_?[4!?R!{vq~M?{Ǣ࿙d#˃ֿl?FQ,տ|!\1?uA?k*uSgrkᑁ5~q?/b̻ ?4?Htg_]@6aQ ?ZBu?qR`n?U7ֿ{wrg?eAa}a9ÿ P?th?;⳿q\`?(*տA޿ݿHR*FG?)嬺/i?! X1"_??S?FP-7+ ?S~wK?/t\?$^?iuoeO>8?E=.(Ag? ":⿘wq.QO?4y+jXÿһ?tX g6yyV ??{?Ax/?N?eg:俣UGlJMM鿍*L?jc3?h۟Կb@b#n?o Q?&.??bilj?~4PܿZ'q@me?;C??qaw4㿼29p?"6!?=Ͽ1m*}c?Zi .Rcsӽ)>E?+yE`?@м%?o?LHJ=`koE9=?EYk?qb?##(,J-~Y_?*?2 G~U2V q#*o?Luu?wxhW?D?Ps;?NXj@ ?C<?V?ǩmʥ?5?2 #Ͽ0:?yF42Y}G?)U~?ܠ?[&Iqҿ M~?a5ܷX?.? hQ!?D'w ?VG?=V?.k49>If迋዇SVu`N9;? ?w4 ۿ%?{Z;~l-׿vlg;?"V@xy?}(UTFy%']"i?_ZVϛ޿vQ.mD?R#U?Y:ii?0tĄܞYɟe?7wK0ט?߂jJ?8xatNx$ NBhz )?'"Կ{JT?ćf&Sܿ$8?V,ߎ)aZT?tHց_U@_㧁t̿Is?[x{ ?4O$͝=?u_ZY俇fRc?1%DŽG?(Sժ%Jnȿ<?>Uio?^eP_2?ZK߿8D?V?>)?3v?BdNW}L? [ z0hb>&ɿBzLR ?T(gM?5"*ӛgaz翉Y7ĉ鿬#꿅4m?l"?Wl߿_ akѿ,Fp\?$Yl?Ey獘?%*>27gE+m)?o]Pΐuܧ濐4¿tWN.<ҙ?(?tҭ?&ħ?DǀY?1='`ԥÙ޿g?hQ*(?el}y?vK>K!x`?kjM]?UWRk& ?eu#ӿG-Õ~jgmpпTD[)kծ?mĉ?a؏&?%6h?)}o/ޘL*]இiQ?7}Jl?I?9X?48i? οϽ?:.b?a?XSIp? J\?yHY?TQZ<= B?WۿPH;?XkGz?)24׿)t `@)ׄ?MN ?8']_?[/ ׿ːd(ܩG?3{F? `?WFZ-?Yο[%GX? u?{o?Mk Fb濘Ú?Blz1?Q%jǿθsʿϮV?';) ?nHg?^"2? TYb?QA?MdRmȿm{BY788?u^CU6sTyWԿ+1ӛ?͒G?V^MMI?O_c?I*U*Pֿ氝"v7׿cdp?9fH?UYYÿU?>Yo׿%ghyÿ}_i?ȧШ2߿8J/N ۿ]fy0J"|7ۿS H\N M/:,^*?o?4ɡɿw?Vl?Ntg?tע࿅j|?R-7?h^ 3Sj?D|?^Z 3L*?eYпcsl?RطJ?!}+῏C?|( G?˂i? *%Cֿ>X?B _L60?~@(?&SVk-?7E׿Nו?q?Tʿ&vc?tS|?S=?En,) ڿx/]?Ph8CɿJ ?&yjFb.9yZKe͖忦dPl?kYG I+!MaH?Dr͵?Q鿐C?e;`:tBM?⊞Կ wM]? ?<?Ux1ݽV[QY俍f?gΕIٿENxm/4| U+~w?O3?6Qq.?-?fb9r!oj=ؿXkfɿ12OR?GŸ.Z$A?ZNBF;?\?5;_?Dc"%]�|}̿Մ5?usMhݿU??DDA}⿂|x/#?Yn %?(hd?Zk?BA鿛Eo忙7C0'9?P_ 5Fڈ*?Ya<s {2US?CY!Jo+꿙 $ÿ3~̹ᅪ%i??t3g?cZR[I?'];c?9Mg;ou4'?N:=;{Ǭ-?:>$LP-8?B8g?W3=N?;6? u?#ɱ ?`'MAW?ádſz=eg?_ iw+_a_?~EЯ?o%?:-|W?7?fytv@ [?տFP}ӿ3hţX¿vNhI?>c?+$Ϳ:M|6?E1??r?mP?#E?WۿP.0\?EJ Z࿰{S¿q?AΆ'?Jz?5x;O?%di 6ut;S b?^=5ڿXW9QҼ?|^?k=5Kjl×?EQ?,P)r迮?ǃTʹC|?oް(򿓍 1?"CSʿpyv}gj?$d1꿊WS?n]3ɿd?te-]Z忦o`CB?o* x࿕@#t?ͻ꿖P??Pw\οIGgoh/½Dޟ8*S?˕ wT@?B3eп7?L 샶?wNh?8To?y>R?!a@a?@Hu2W5(aBҿCDe?Zd?t66!^z?p Y8M?}y?' ÿ/C HS_U=?N(H?A:k޿݊(k?@Ó10_Qhbr{\M?5>y! lwm?hx(`+?dqӿh:e?`ޭDM8~1KAA迗4A?q!Wxӗ25M忰NVP?M?tp?-r#Q?MգJ?ry?C?ΰ}D!?A[ቈ(ySR?Rڿ~\֑?kp`?2{fѿs?*O¿r#@hF%x԰?#ȶ߿ .|T-QȦ? =?>9п;?vwtLjS2:Ŀ9*c?4?k|$?&?nq9?,ܳE?A?&/ ?:dž |sR`џWRHҿywٿ[?(-ÿ7{ Ϊh?,hsY ʿbvj֩?"{%FkwԿR}QS73Z]"ֿ7AU-ֿCm??dwJD?a}gb?6뗑F2~uɿAEDK?kLT?8ל*ο@;?cd9U?V\. ??Y޿Los̢-俇m[q;?Χ_H%u?Ÿ@|׿*x>4hG?q0 |e?ep2 ""?Xe M? .4hn|޿fTk?›i=\ӿz%пl/a6зXҿo L\鿠/.?I?nhܥ?E?nrο;ə?/.ʶ?Fӑ?&β_? -6Aڿw?O|]^p?;^?y@Կ3DC+r/򿼿Vg77a?@ /G?cV>~׿ 3 ,hc?&?@a?T⿸޾.?=E\忬aaf?'׫/?e ->!?os4?bX]?"p{B?Fu(|)?i"Ʉ?<-"밿q("ԒWþ`]? z4'$"?}@ /kS 13? 9#?}7e񔞉3oHrpQJhH?KN'?` ? a?>Ž?.I忻yѿʠzi@A?4Lɼ O?/=I7g"?m?w% ?STw)7x?,xߕ6Sѿ6ߋs?ֿ.Aݿ01-Xÿtq@K߿Ojb:ؿX!sƁ?BտqC?A)?r?"V?i>r?(K?EZ9aD$=`̱?b ?ik 5翦چ?͉MBg9u?CW?A eF;Q9XzHpnDҿ͠\*.xտLsč?L>→dvk?5 n?-I?DP19p&W#?1c8T? /1?Ѓ ?@ KQοce?ٝ?,J?)+x\,忈r'E?5=_q?*'7?+FE?ՙÈ?ܖ vd^;?()ܿK!c˨?_] пX~y wp? 4;S@i?H.񿦏?*?W???os_ֿrxO? =%4B?!Լ-?\.ݿ?,h꿈<N+߿ &=VT?n]B|ԩ?{?-ɗ(@WoZű޿ճ9?_:kמP]?(4󿰖biĿGNS9mF?&LF ?mݾ6T#0L?H|?mȿ( /M?Jпm+@n#`4VП7 vXVghX?^\ҿn@wW?u?Ws@k?B^ڜZƞ~o& ˿e49ɿb"?<%^SK?x1EտV_?"f2?_?N?=$%gq9;_@֑N!&鿏7(V0ƿ]V;%?tL`1UƲw9?C@?4Ţ?e7@6?Y :C?#Ӗ@z?f.0??걣?` ڿ=fï?ϰU࿳F0L?%+hG?R,vH?q?SBo zkXܿ3|[Q,_Z_'G?;󿞍ih@HW?6B?VJYM_NۿpfC?! @.7 Yo;^{ `u՚8?fm?@?ݜV:˿쩳?8^3? ! ?~2i?"5gctN?N6zF?6O#˿jUI8#%dEJt?)'n ":N?dQǷ۔O_?:3 @ڿNܞ@~$ ݥ'׿%?ҩKO?%ud?dzz+ؿ9<`뿏[x$?&I({bI?)1P'׿mx1"翢kr?)払 KAoһ?t% '򿋯=h?"y⿬̃ t?WWJ?ExVL ?XEzXy?í!)u?6o<?LAjnsiM?sgh@ S?˾?>?s?`:&׿kC'h?ki?;ދ^DK&=?*UۿUb[?0]?:&4\NM?δ?U7!$ۿ (?g>:m?⿒գgfSX?h-o0;} d?o7h࿒UJҿ1Ǖ5Yӿ1q?pƮؿRd&D?R7 K?E0?ĩ1h?tw&%俑 b2.=ҿlЩQ'[ڎ[m8J?qj?JE?|o?ZdM濠»eC$[?dRkժ"?r%t?Wr?aԇvܨڿ#4呵?5'=f?f?t?Ĉ+.x~?yCZTw?(sc3[Q̿Ԑ+}?2v>7??[MvK 1^?17fKm߿. Tjn?ֈK?H;xHLfԿ5ċY?*ͿUl$Vu\oĿjj=Tʿor%R࿖UQx?/.8E?HۂGPNkZˍ?tak-俦Z ?S9߿0j^ٿ7j/?`>*6?v@jQ?E8ҿsX%gJݿz(Y$\?*ez,QY?!nh,nWпI͹I8_h~?+ajTI<ҿC?鿟ؿJ* ?s+վ?EHv?"ݽ?ܝ+0Q?|Z?0e?)q7Y?x?eHz66# rVs¿ /?s?.E.ݕ<+}z? %^?7v -Mut?e̺@%?g7h Ȋ'f".fwX? 9g%-;HnA?;ڦ P0w?W3(J/?W пӿ;>?(Zg8z(% z@/%D?ĕ{Կd˙TR2?L5ٿ"U`俷P7m?x=ɒ1I^ϻп?}ȿm^Ew?o6:Xz?"?A] Ϳ^2nNӆ??sa?,lc޿!5~,=C;0v࿅+jI@B/4Pÿ&??SvTU+?0T2ῐơP2̱@?#?Ve?0o'z=q?3)~ְ?Sgh ͿnaY "?Wމk'Pʹ?o?eZ?o??nlXnr%yf?7?sە?y,q4 c(; ? ?'!?L:Zu-?!a!%\ 9p?OZ&DD!?" /Rݨ n׿ T<l̿vDh?Ǫ)NI?V?Lu"?qF}Zht?ݓg:'ew2?ÿeN?~D@ٔ?S deR/"<=?1Ҁ/¿p,nh;ۿf>=^1טݬ?CJ:X@|ܿN9I?s=KQO)տ"(UO%X?$eH~;?2ǧ[1wf?Kiڏ¿$sp|ɿZ?!$?Zj?d?R+0?N+)?A ?XF?A??2Ps^GU}z4j*~?ܡ]ޓ~noAi `r?ҽ?XwY¾wnw$΍$=Qj~o^?1d>?Pg w?rQp?彶?4ǚ*?ѽm}?!l<*:H?'d1|?,?M?+eѤlտi>h?8L%AZL8hcVb?eUaU&z%*bT`}筱h=?v%?7N? W*AHpƿJ:@c/#ruT?|ESz? 7i߿5ؙۿ k7дܿ4zƿbXֿvE޿Oڽ˿d?ӭG>7.LF^Xt?VYMA2|ĽڿQ?)U@俩B?:醠xt鿴> Wس2ؿ C?DN?8?F?u?X:AKG"W +'?6@YK?UI̻?ֈB?f@?'@NP%S?ە?ޙVg;jGAkt?Ykǿeo ?yM-?hmj?Lh}ӿRV?p?&IRHv?&Rr?dhE[?$bq?Zgп*S) 21?u'W;!GCOL[?2Zſf2Cۿp~/y`?G4?¿1ٿz?uſ+Stڢ?f?WѸ?-޿a!5?me6?V_\$?D #俴wPAw0Ǝӿ3DL@:2I?>z>@N@?.>ݿ'?Ҍ?te?S?Uݼԏ?pI?@?:Xۓ?Tx0ܿ%'Pc῭yǃR?/糾 i?dN?ʙ@*҈r9uE]!|?Ak|?x ?,EXQ? ?NMaܿt2!?K ѤHm?D$Adÿڿi*R1ڋmq????{;?b_xĿmp}@.?Jij z׿%mnjn0w?,pcm܇?)?p/3^dQ? @cM?-?ǯ=6e?!;B?1a:?W H2=ѿ "¿?D?i?}c3鿙 *)ʿZȍ?5<,dyكUePYq&z]1(Iک?qݿ\忴2P|sۮux ܅Zڿmm?Sj@W?@$1쿐x?lJ&2?il*y< zȿ]3Lǖ0_<ȽZ?waR?y0,y? -'?Rȏ?x"ۿG?[1?=-?I/?ob?wBQ?M{3N??,@z?æh?tG.+GʟNpĿ'?zX$u? ~s¿Hпs 7i&ib&l?Ui?Z2$?ZŦL?Qς?g%Կ}j' G?j!?AuW^ sq{"#x?%{%0?@DSj?@H?yW@ňp1F$9?0<ܿ. l冏*?h+\f/d? 58?sƺg|w(v ?{,?m+=t=ݿooS?gZyp??t{?ɳ?vLܷ? 9b?D3p޿C??~ڿD2'1:P k㿰,?]V?&n RAbE(.?$S@+pm??(,[ٰ5Z» Z?c¿Se?.[y!ֿuDn,K?m$@ε?cqM&m濖2)9?򏨒?Bon?1|n6ae{Ŀ'"uCf ?俧fŚd?W=tW? ?[+1?*?ƐGt,8rۿu_r? J &&K?;а[by,dw+ ɿۚl?%܃J?kUl/o?FthF]5?C)C?s@ L?[?>4@p砷Ȏ?{`@3W<*M5et$?{4{,̤:>/ +?gU?Dɿ";5e7Hz?™X#v?pe? ?Hd b#D,6?z_wL<ݿ?i "R;Lj?A&?G {~^}?D1Cn?os@H\?bԝ?5͚?tvOڌd&?"Btǿ7ȬuϘn ÿ 놠?>`^ϿD0_m!:Y.2忺ߪ[+?02󿀫R_ϿF ?]?x6ɿ4Ԑ?d>|ú?QЃe*P?9{z?1G˿ğ?:Df_UUz+Hc<07@K\?r9?l`I?v 9>;b} P?HƿXAd?Sbk' 7@n`@¿0I߿q,˦M]JO?dLۿ@?]+- k'&ׁHXUa#?R=w(?rۿFQ8?G+/EsD?BnݿuxSпxg8+1|=?뺫?cvQѿJS?l'k?0D?N?Ju/}g̿,Hpe`? Z2տ[);?EoLZM?Sr~'fᣐ?z&?`SοT?Q9{9ӿ퓱fZ-KڿD٫̷?0c$?=ᅤK*9C?4 U#{PJ7|U̿^69#BJ?⭞?I?Wc??sE..gп.?7[L߿f?Ír;?.8TZ~_?hh?x7tAۿ}.?BpXcK[< 3,?J >D??T]%?0U$]ֿaVO)?%= '?h'?E'n\?N?|8fD;8?*49A?x _?*w?XLG?}wNʐ$x/ q?߿R?veǸ?b"Ko lj;?\,?Gn?QKV?&:@ؿ7zt ÿn{3/P?3O\d?WXR뿑3^W?ݲS?v#xi¿zh|O?Nb8ʑտE B$?Ū׃6?_'Hz 9*?&LBTKDw3?#1U"bh ϹlvDֿ9.zTĿN%o&_U?o緮 trc]4?|2B?>@ ?Dq?VUuK??B򿅆4F?}U7vp*?vJ?L,?ķ@?@>OHM0@ʿ'?H?5^?e7?Szou󿻙XW ;?Gk釴?i+f=.? \b?'?M0J6>[?"V {1ﻥE>l)(ƿ_3ѿV\п%4M,?B ? <\1L(?qf?C&???[Pu>$}z?E?HEk?TKϿP 4e?%+'տῐU`@/ T|!ڤs;Wۿ{zg?ʽ*;0 s{?b&G8M]se~ iW?W9? ,x&?ni32?P?aRۦ??TbN?~U{𿶊[w?ecc⿥?8Jpr)e?+?27m k?!?8=ٿ89 %LK쿢X:ٗ?Wb;޿JD?5%?j+O?]v ?`>5:ƿ lmٿ G?8vu?oe!?Y *ݿ"?*;8T?ӕ>4?Rhտ"?M9M `za?k;*?4cԿ\MiT?1F)JV!?ZK忁:/{ m?(ͬlF}*R9qj?ILS~?cI?2C?wӫM忲 ?3Ux?౤"8?YAG?3 ?NVx96@.g|??G?p??w?m;ӓw^$@a/ {?hsYq?w`$տتK5п/3o?"0?Bz߿ \=?斷?9T?rƿa^?RlG?ֿٹ?8P('dd5gdZ:MV9yۿ e'(dW?Ƞ1?-|f`?6!f`5I?^?&?G>7?};*3p9D?0Ze?ߕ#?\% ?w؇k?E[AX@;I}?20s/:!?wl?R+޿d?b! _ǿRUlɈֿxY?\QfWۿ1C?/p0޿1?Ҩm?M*+ؿt| k?ުH=N4޿KQ @>?L@ۂS?Hcȿ^RUѿ}X7%1>?&p>3#*ݷDDsZQϿIZXBCHW+=#?odBH1 k.DKh׿"5y1??Խi?f0B02?z $?"WN?G4?ȳ2濆.  4mn`?|H1?~?L1P(=?8v5H? sGXPj)Կ})zT[?eaՇ?>fTۀE?%?rsD@ Xy3}T 7Ͽz?C?<&_!?NEtp>oOؿ@fV~0:"b?p Q㿑irؿ-UdNOfЦxTG?[,?<?jR|OZBƿPF}?e!@(-sp@$ ?|-Z? ?J&/R`Рxɿɔ?vXҿRE4? 9wg?\b?fپvcpJFA*vJ=? 7?^ ?\<ֿ,*?i/j?~y 뿵TH?O .m?I&?s Ŀ i D-?yO8?6$q>|2?3? [~n?ku?Äe?c]X4x?$'?yW?e;SQg?_0/5ʰ?fp?Α6\? E?2??et=?6Lz?<A!翤cQN!-ݒ^?زA?a-SȿLV?(đ?Q\kڿʄ99>ӿwŷ){p)?#8?[??N??̿UY?@ MؿɔJ?|kr[}?nBPp9؍!e=mw?Ŗ??ĿSdG-f׭>?͕aP? !H@hy-?Lj?ynQN: ?~  )MrA,i?Y`Se蠼F9?CSac} ɛ?'IV?8U?_J$%??hI?HeKĕ@h? Tk2,v?>n?I|%?w? xΩ?ۯtߨ?<`U? >+ٿKR?&;ڿ̞詗?MfC?L^?lfI(A? _翀iE?)Ϳ%)?7?,Lx? w+XQS?sW?~Lx%տ|wJ`@~?ѩ4[v4~+?rw&D9BpMw$O`ЎC?[Ŀ"X#)?>!TϿI:Q]? e#Hأ6*<ӿl.-޿|G?5Q\c@3ؿV1b?7SDM#/ )?4҄46ؿJwd -?'iv^ ܵ0n*9>l=?ɹ /2@??_=S1?4X_?Vtl޿Sf-?2ZEe念J^˿g-?z翊/M\?^k(٪?`?+$8֝տ{ǿ1q.c? =Ʈ1nكK>赿<\?z]d?m@:@eզ;՛x1޿*L#̚ؠֿ-Ywo?0R=OS⿗C8? E,? A,B a3*4?aSç?Ps?qm?phC2*ղC!?58n`Aٿ9i?|S- -?+܇?gI +пHt?a\8gۿgI7)?3?Zf0l?l}?aM*#!t??J&cG e$?3"pnTL ? g?0y;Q:nȞ/?u&FN ӺC- qWȿYF GdH&(?Tza?NyM?)s sjdKa,К? ?751|ұ@c??':b!ܿŮG? 鿼o읷z`翴ei&G.u!nD 3rJ ?NKl?[)?h)pɿRH?qͿ~?|JQ?屙vf¦-Ge?"-@ҿzFϿ慛5?Lf2鹿q~L\?3jF~"`Y@`ڸt՘)cU?M6rP?M>:?(jn?Ԉ_VŘgMſ>-j?~g_ϺL7H>) 3P7?v׿ZM?Γn]7jG@o?dh -?z1t??@D?&Uۃ? TزP&\bʌ'@ }?O}?-!߻;пE醻?c-?7?bk!? bgҵ+?rM"@'࿶?C}">C8 z/?OgԠCۿj@ pb/?JGu?*V-r?W&^L1 #%ڿcֿΤmj⿮>lH`2A?sN?lTA*2.p4$$UN?¹ۆ D Į|迠!sȶ?|z~^?`ֿ5 |cS? 2?T L@{{xɿߤ? _׿? ?T. ",-KRq ?j|ɿOOb?aѿiQ%+8п!y|h8m#? '?P0?Qe ??"s,?E ?uͿI.eÿ0$?ʷ?JfGY%=?NRd忿Ȫ]⿮G?ƹV?2Y\?}ǐݹM{7?*>?UWI?^y͈]?YSb߿g ?׺5ѿ`^v Y翀Yy ?] c?>?? D `[hm#?|?4Eo?SI҂}?~T?J*rɿAV+?ABo˿dVѿ? gHu?khs)?Eϵ2҅֞? ſQZ ^?z5X?)=av %?IOLɿ7g`M?pj%??l4?YڿQo[g̿s?Q?#XD?".? i?[Ҟ1ۿ H?`ig?jKI?r1oFze\ڰ[MSǿ0Y7q? ~/C?oV?lD$'濲Eп!*?a49lr?E?FKD?N0.X?/)J?8y?P?.Aȿ%uN?M\u?V8~?ntfg6ҡX?xQӛ)Ϳf3K?;ebY? ؿdL; ǙzL?Q`U?;ztܠ:?yiR뿺:!?[ae#}?K(ڿڵ>{@hW!?>[ٝ(@߿`#oI3??=Y%i8?q"?AlW??_*CZ@t>SC??.Xjnl]2N?ǿ ]ٿ4P~A?QeK#bkK|ǿj1&Կc]?OwL.Q?7iH`yf??P15AS[l@TM?,mDoGֿn(?⏞k~?ikBؿP&ޡ-?KM]U?[@P*3Կlmt?g"rֿײ)?/)BԿcvɞ`?*^ҿf? _4P?W >S?BÍ(ʿ@N?zbnw?]?{?3l1 1N_Wخ3?6Itb?]CGxݵJ[?*p8FK9?1f " yc.GEi?dxۿ 9P?!o&ֿD￁!*?k AW&?w'j?|\ Yγ?5܃#9?Uy?!? :M |? ,ŧr?ٚb Xj}LnH?lti習(K?dýпf'w?{-V%q?LbrhϿ&K濡@Fc?hRԐ?%ho#?*Կ˟\?/z / ?yU[[&?'P ϿkP%?󭔴2bc&`?9)7qܿ^9M&~ye?dJux?9.u?Gaw[n['?R8P?ldv?0g[1hq?W?⚍ӿÿ"ֱԿSe1?./NC??wv+i?M?ޡmr忱bW\׿s;F?&6ӿ߄s~ :U5jD;?V9?feA?rh?^|BQ?ex6?PR`9mmؿ!F?o&mg{˿TL= ?ih S￐ Le i?= /֤? :0sW?Yi5鿣T?$&wgi@7@dN?-o}^en?ȃI.lY?^pNUV!j I ?+?G9?4|տk? .E?=7I:?|N¿֛8?:m???_ !. Zÿ-ۼdU?~A?!"a?_2CYs? Jr?,պ?ľ?;M)?c?162ݩq?9U Rܿg:ѿPB? W}?hԤοEs'p?#|rNu3?;?RSalh࿙{r *x[$ǭΗt+d.Ymh~?7=n.?",C?ݖ,/o _xBӒ꿯[ B?1A*oa ?Lax ?󮅭?v?GGO?9A[ɦQ'V)Cſo>^ZK'?y_enhK>L?`l?qۏg@& 5?TE?:_׿hd2`Z?qQhW&l @=R iձڵ*I~6fEG?E?i)Ii 㿴5*M ?Y0ڿc` W[?sy\+;2VTP?5r?y@RzL߿?Z(P?\ &?=0?ƚ9?Lǥ?z NK?fj?kɼ0꿜1?\&*z jsG޿%j?][=[I?oEY]?I7Dewl? ȯFd{q!?K86? wcJ?ѿK%?@UY?~A?7/W?K_C?-eT8<3-88,?;R?K`Ԥؿj?:>?G%\[դi?Ǖ!c򿶩z$ccӿp&G@U^R?e?7 6vᗳ"ҿ忌qא~E˿ێ%m?(-k w?̶16ە(}6!+yg?#j?^:쿋?VW|Zgh?{y<ڇ4!@?sT?4?kzU?wFo/NN?PT@I ޿ܼ_k@Г{ %?w3jFHMk?!d.r2-VL\$3?D\[?t.QG?cWwOH?+#f?"E?l;j,V?I,a!∿ZT1ܿ@? 4ܦO-(?_8;?3??ݙ'ςbNTP$? bBq?tھ1ui'?ῧgȚȿ8d+ʒà׿H ?T? ?Źk?>>a?^(d ?/ ͭSRE?#t?ݝX$?Dg ҅#0?:쿌ͣ@>H??ax{?th=?8q,% ?x ?h쨗FϿ Ix?,NA?7ܽ|?GY V\?w!3b֘ 9 ]?ߖ9Vrܿzxۑݿ.Uעl?% {-x?X2@:eL1;,F7ο;??FcxO?uqF? 5?ބ&ѿΆHi?teؿh7%߿<8_?iEH*ϿOϬ?ѡf?lO?p%SҮ@?_k:ֿc;Ax DpQ?sN(lQ??鈄?i:GL ?͌??Ъh??H? pgZz ?Za[??>@z*V?#˦x(xnfZǐǿX2;-v? LI޿>*~d{?H)Z?*ŕRc?ӓlY-ҿR!?Q?ƩBt!{.Rz?\1 M&_l*@Lѿ֐ a?V[?"6:N?/E?z PX_Fſq/-R1Ar4N\࿿($$?i? Ԏ ?8l)?bI/N)~eG?KM?M?",j?`!3s?1+@U}WO~̇Ǝ,lؿH{?AH1_C 꿊L3;?T+l?.sr?ǜ- @#^:6FEHI?^@yv7 ?r/?ǵ%m.E}bsUԿU"'z鿱D?|Y#^?H,?Kn?%U߿PE {$!r-?7q ?Nz?ִ?ߏG?ݿ?$9:? ک?(?k'jUZ?Vd<?k{5?Mmf԰޿o24^?a>KM"U?^NB?X貔??,'+ÿ6+P=Dك8m?2|r?.&?S9?eZ`?ۜbuU| ڿn?,A?to i?`fz?HX) 槂jxS**yz}N?Oq@}@ivm@$p(?97x ?L(?U;wQ#|򿐅G?cZ?~B3A?V{-E?/:O04Ce4I??}_?sLO?Cx pqLc?Q.%?]cx'?ڄ,ҭ?~p?v"\ϸ`sf*V}@I(c?i84{8j? Rl!~ތL*I?d.a?9sm?vؤ2?Vp%]C?BIO }l𿆵ņ.!濙q5濼&}?P9|Q7d?5K&i¿Tq_j6.aӿ)/=?w|?BA?`1V?ʑ?t %?5r ٿ%:]#EÿVT!ր%ݶv¿tʴPBHG?Zl?Mj?p0 A ?7?iDV%׵濜k ?c8?`!?w[l??g.^ T?M?]?-)#?@=>/%P?݅|^j?IQθѧ?>b؊ѿE{΢e:X6;, 5I?iK #࿯S  puz#sPܽh?y?up ? OfO@?ˊ@n ?`*p:? Mn޿* j?Qi$@}Nɶ@׎?2D迁؛?QTdok?,dzaӿWbrsӿ+N?޹TbPֿfuc%?ds)rB91u?e`fI'?j;ʒ )?ka?rK?J@?wڿa|~?#3@ Dvǿc}ڿ'E?N|ο,X?k@Կa#亿ݵό=?94<㿉~o ѿ0si?R ?˿&TD@;f%ٿZ\Өig}~ȅr͔?j6 L@{?N/ֿPq\)q?A{d? !(Zkj)@Rk/-?_ۿP)jy^翃iO?ѽ,Z?NMqv @3Ql ?]㿧[Ѧ\e?X?U nDQWh?5q_M Ӣ?|?zF@??;ܞ׿)W㿞ڸ?k`% @qiHM}%?\2PǿH`?C?<7?ۗ ſ ]7?ʾuѿ 6ǯ뿳Ϥ]?$wz ?xNFG|ɿ۔LC)9?|t?ZBU!AXy  |^$ҿ9п&UVC<1MSN ed0 lF3Oq+0aXd׿{%?zkRo㿬Y2?Z[҉w0ؿnhUY@N4Bkʿs.]1?ԊX75&.".?&zdc"?$9ѹ ~@ ?j4Ŀjr?2ŬS?З4K?±t%? 翎/z??LADzf?=V?1~,q? d?K4D?@՞[?37\E_s*es)ῥ\G}?,v?S+ cCmy }?PB?N |}?t{KGN?oe?C^nzWm?mK¿6QeZ?8z?tUݿ,tW2l?ζC_?䤆Ŀʦ=Ŀy I0ⅾlo?\T@(?ڌ]F.Thy79?)X?bDnտ|mIR?D?)r?VgKu]Q9ܿ_m[jI1 O2q ?`BS?/qTP6{k-W ,?F%(տĈfG?K/;?ip.?p'ٿ4_$'xʿ>$ͿT:2տ8Bp?H?j)G/ܿ@d%n5cJ\Q ?h?5eFQٿ=<ݿh&[οU x?,Sۿ Ne?/Կ+oۿV{M?pVc?ӏ?.!&㿇^Rѿ%ǿNC?/n??#@k]bo?YBnĝvAqt?C#?0?_W? .Uƒ?& ?@M߿}Jq?p%uʿz_H %/,}߿@?/'hп'.߿NYAZΤ Gy):31?Oy?n@V?'AfB ڿ~?JO?Zh?'?)Fra?f?X[­?`O|ÿ%[X?Ih ?En:TAvii?d7H?5v?p?LJ2I^?'rSۿ]ߴʳ̩s?v 33dZӿ|~\翲hGߕ ?l\5g꿺>D6࿣ADC?ɷ@F-Rп.JY9." ?.d4?^|Q?@BKT?aMZ?q^O{o@f9ZTtbqVSr?x#A۲꿗r ?g>^j?QZy 2ؿ:TGX<[翋಺e$5_̖?)>@ж/5+ܿq۠b}I?VIaPK?aN]5[\?ÎO?5cg,? Zg?=A Ǻ?7DN_HٿSJÖ?g$ ;bc'?׷< ?}fs I D濳Y(n??B?TURj;ps%aS?́"]HqkbPKHȫC?>jokq?<6C?]?3c?-6?Rq?ֻ_?R'i~3ӿz0O?W=?念4:agc8b?K"ֿ[d⿕*WEM:TҿC>iͿMx?iKh'ҿhּJ?[?=\?>d⿀9?2T-l2?_ݺ/?;ÿ"P(޿.?#Q*z '?ayѿG?RQ\߿=JO?]np3?"?bHwlJ/¿nV?g*k| t){~46W8?Hv?qX?3X3 I4Jc?^ y7$??CEl?ʦ 7?<슘wDD䖝8 zjQN?GA|= 翞;￉]+?^3qԿڢWlU?7?Rw࿑>;?6H3P?L?i cqῴ;F٪_?(6?@#v*տ0̆X1,v ݿBmѿR56?8 ?7 FMj2y?6?C$0U*?֯E+Dž4?WٰX?C8N?;̮ſDލA̗]e~&???'-Y?_(?/7~@?cs #M?F) IPR+e?VyE˿!u;R+?F ٿz/E?iu( 8?$2?v'@%?詉I迎J@?]uhl?"uc{ ?q?<1p?"{?ـIK3x?F?"Y?a3.ٿZAd𿪠ck?nUD ?Bߖ9SI?M؈&2?T`ٿ45y?])smp޿m?ϯB? B4SaX?+Vg9F"v?FVb⥗? 7*g2?GKam?n?\ ˿i^GoO8@|@/9?k}?4չ%?ؾoο1 SsC?R%/?PP7?/]?gY @څUM?]$ޱ?g?#cł図 {!i򿿰`?|ba\ƿ#"aڙ~0ByLݿ%+y?kJUj?Fء0}пqӳ?RSTֿ@PX¿2YDȬtz6f@>ڿ{@? >5?l?G_*?ne$i-ٿMW} '8xn?0?+Sm?Er?ݻ? f0N?ءC7?4L3R?yO?Μ?pɊ?i$ ؿFק+MG,?.B Q?rUg)E{Ny?ik S0ÿ~\? $ @.KmQp?->2. ?YE}? }\??9{*?TY@^& dbF_?k |(?Xq ֶ?tVEԲ? /ݿӒB2?Xv,-T?(h?b\=T+l?4Ͽ?yٿ7*d?j}zuDK* ⿪ r?U? ^f??k?Hr~Z ^B }?b׿װ?uʿ{[z?[ԳuQ?_kbA?l)4[Oݿv EH?pce?slE Ojr~?^hV?%瑟=?'m?SAXE7s?qˁ?s?"LurU?w?#1v?f֦?f &j?yd5?' i?C?j]|5?$_,ue5a@IXxݿǫ.]@IVyf!@PHh?f/"\g!F<5?? v尹*п{忛l1V?|ٿy8]P?$5@ܿyǔ0߿,+K?f϶L|Kp?g~ʿiGJѿ ){Rhm?ܿHmi+mamM|N1?R?4ſSݱB@?z@9KTFMѿo`Q?6Ux(?hl錧 7? |Z|;Q\$fO9:p,?Q/J?޿p?`?0翭ճ}ӿaQX&n'?hdp뿉ZffIoA@ 9tL4?R*>)vb-俕$مi.=aX?Cٳ?֦bϿ[*?'TQ&/ /?Ϥ [?:30Ͽ2KڤMW?,AZro#-| o9Im]{wѿ6g?2ݾS?`j? { L(*S?IpпrR ?`|Hп͋?z`$O'?b9>e?sы fIn-?GfF?@ҿ4ÿ1R{?WCYοǿ,O&?Ʌ_(?f,@{^Wꀬ՘? Rt?I}2'?MxEԿ;?*d ?J«_?\?\ƀ;?Ո%;G;o俵 )῜F7}dy+OuCM? 8F?r%X *VpH[#տ'5Y?aH?^Q)"ڏؿZt?ZF҂Cs( H? r u{N/"?M*F俖髶4;?,,)ſՇB俼7 Pl5"́3? PW^?O^8@T#Yc?fP͕cǀ?qYl?cy|῭"׿hr;h?$Gҿ5ޢ(5'z?&_asnd@[8zg 꿌,%Yd$? so?+?Lܔt ?~"Pſ^ 77?=8aeׂ?B"?_KO? '\# u2Si?)]!uE@?R??<0?w?MjHT?"B4?j{H?O"/&ڿgҿpaO?~tdALF@5KѪ@YfVg65?î[\?"DZ+{D?#u ?zQ述OiݿcH,?3 ߿MU?3F?L*% ?gbMm _&?t<(׿$lT,{d,?fOy,4@(b7?#W7go$#?MdW@Mn7?ᅼ|c3_̉?#.uɿmpر?Gva˔fu'ASJN?S忭?}"x?~JDXm?kv CD?—IL??/H4_!?rUfpJts벉?2=ܿmp?^?꿾Z?)ؿ"b? #?cE󿄐3I?9eR? B*B?Ѣ:h?p?z6 ήvGZ翷s`? ~ֿD>*ʿbdp?t?s:])$En?@W c?w xտ-mvTǿ֊?q?(zn5=ÿ\:X̿ '?X}?-c@ܿ:6i(~3?`?9)?tg?۠ҟ?q-?ݘiE ? gĿ:ܗD ĭ; ?^19p"fՀ9?Vbf{?"b޿60?jD ǃݿ҇BeDҿw߿k??.?y`*?Ps?7q\q3U?]nY0?c9S:4󿟸A?LV:)#-Ya?F?(x ÿkR+?N釷?q/_6<ۿ-ͿiPGsR0쿀b3{޿C<? }?=?-+i,uM X:?RнPT?A-?\bIa?>$?_FKu s?Hkx?cBE?H\ 0?@ۿ.*%ȿd?ʝbb?@y ȿ>'?K?Pկ?Tb~O<^?}{ڿ(o2?]o(Y6Fan?(V? )7bC-5?no5ز ?3b?<_^k?ܔh?jl?XA?b<2޿ $Oq.6i\)S.gn)XſBF@@?2Y ?bTckN6BT꿔wqؿ&׿KfAm¿sGuAn;ؿveQN?j?I(ʿ1H˷h?Xθ?|؍Y&TMUģ?A:3! m\?;M'9)QQ]Բ& z?A}A#ե?z45'2yIHq#?-7%ͿU>֊ru!->--aWO?eͿm?SU? ܺ?4 (\\?e\?ZXX?hGC?ELS?SȞjY j?v*I;3R ? p*OP9!jp)+[?6sO5ٰ!? ;J? u,\A?]%Js@Gؿꉈ/? !IOPXWbM濱 ĀڿI!?{?R- [F?&ۢ+ ſe4z㿙N,?1?;.|?K@bſ0d:?\x m\E_*ά *9׿B֖?v͉ڿLY?|y?|(?76z֐g߿; ?O9?AV?T%?Mx7뿣?B8l:9Eu?8Vʈ?I!5BRo@f {:?IaG7&?Zo2^c?R? *Kuf>EUvɭ?Ca6?kh?Xտ9АXץYI-?JW'ifqi?tݿX&\M?}5psxa-CVNMڻ찐?H|1a, ?sFw ?#PmX?d2_%?I7bb2hؿ[²?XB׿SݝY^O??A*ǐ?v~ K?X>'п^p2?LqȈ3?8g?翧ܰ@dy7C??9_[RٿV?ǩM?g絿9'|A?dYx?m=0Nuh? !b"!/׿V#Z«?ÇQy By?$uBj?H$)oJnhRHH'Ԃƿ%$CÃ,1Ky#)8?%7?KuOK??ͬ?TGY7Qzѵ?~fmaݿJ5tP2&`?Qtm%?iAmw? +D$?dTj,`nc? d_Z?,n&PZ }?w"i,qC!??k+ oտ.;6%ҿ=N,*翙PZ?eof Y翆gBx,;!ѿe8_ۿ\b??]?{0W俬2(9^??v|?dUM;?it?ϡ?Gӫ)9?Q @XCGտP*t ?wPu0s9#ӌW|kR ?¿*6'_R 3?? y?Ğz0.geWֿ`?#?lp b?$-? ArE1t&M?Dj8?ۚyY>[7οlÿ?ſ^Z;h:%3 I1APԿcFU~?/J?mҿUƐL˪r?$4?W1{@?O;|n p?O}LJ?R?4]e?;~qi9 ?Ǖc40$]oH?/ٿ+S;.+5޿2 g2?`X3D?x.BOV?cc*?'{;?|B?av2?m=ӿUv?DB,>yy ؿq F٦RPR*,tիdeՎ_̿"]Ӻ? CB?!Ŀ.R??zO8?3CJ:Ŀi?P\ٿfMP Q?ض ]"2:hR?rυ쿁T?Tp[@`Qh5_tNg1|?ŕ3?&? @٤?P^`.?+-фt@5pZʿ@Y?pD܆NWĿ\x510=?W޿/?=d7?A?5?*J?g{?=HϿQG?2sh ?hL{u?F7J?r#ڻֿCx-|忪`Y?_h5P?tRѿ\dOF(4c1/Tֹ_? Le?]fj"]҅??𶪁H?\?Y?Rq-Rj$?zYrL 7h?'GʿQV ?XB+x?4~DPK7ӿR-0̿~,&?jERPic\?Ymy翛q<i?܍XhH >v6ֿwr!LEP?[qog?mq[?{2DyO?$ SEE?7U8%ϿLe@9nCݶ?HaPz#?}4m?m @Hٞ,@#? '?)!k?e/ihpt?FU u޿{?Ǽ&ͿF?֌`?0B Y+IJd4 ʇ߿ qYmF?k?9nV%?+>=h?ȕ-K濽qh?haJ Id"??Y]*EV?0;?ݕ?x\0W?ۨ٠G?ȗj#y(Q#~?i&*ڿvX{.SxZN?V^z?&i~ӿᅠ;H.l?I/G'~Կ ~?VRlyTg?¹?1ӿm$4ܐ?$}) 1?&NƝ_?@S? K>+_Ү? hp!|?o+4V># g?mnWoR2#?0 {v]e/?n"(÷ɩ5ķ?6ZL?*6ޓ?-=?svpYi?eq&?X?S ?pgn?ҞG7,g,N?>$}¿x$?e[w? K_?P%?M:nr?d]?f.lZ?/HR?/C^&DQn޿t1CM?=D? urE??G{n!q?"3*-ed?=BP??Kb?3jAjO-T\ϻ˿aEEEd 7o?%$#VR-x5? u֏Oѿ);3?xZ`u.:ȿ~0I?%?ynN?FߣA>4;?I??ҍ;hݿuUOͿRg?!!$NV?]_@t/G?۪(Cg⿽̷?v{ ?[;J?hE?G{?;5]|)Q*D߯rԷ@[C?P3Ov1?#e?V4OOr?:%c?`ˮ_?U򿕗/??gyP? 5+? xWHÿݿ;dҿA4Eo?N ޿5/?bC 7YԿcw4´8! @j?-oA?[-x?[ŔԿbHѰb?}-?Uz+nM?\琀?L꿽?o|󿲚).@Q:>?@GI?jkݿYS ^i?'awǬ? 6BݿN ?ł.࿽i׿]*V&dſ:?m TNTcT?Ķޏ8g}?*3?Aq?əcGi?K*'?OS?wH OmHe+!?cP ;w=տ /?l)ԿC>⿅C/$̞ѿedʾ?7ϵ¿2U1?n@*?#ҡۿSR3?`K'^ѿ4PCS?S**o?Tfٿ4xc)j? ο?-@gS?=w?A(ӿ&60?䃅y ?S U?[>s_H뿉PE5AҿʆoV]ztǿ12|?@[a~?LWu?~eϦ*?tY}S^ ܿ"?Z42 (|ɈI3?鿋bK"?*T`?$ڵ }>@cr?iO?엶ѿo^m?ـ[|㿈?T(ToݝϬWQxܿ?.!>3k0+p|3H6Q+? ,UȻɿЫ*鿙ٵz?DkW:?_ֱ)X(SFJ١sLG%?v!2?.RQ[?qN꿣^%2?\a1 !MWm5l?ys?\^b?t=ZL),;wAjͿ gM5 LDKȰJ?ٽh|@*e*?Ģ ? Ќ%?vɧ濪J׮:?&K¿ Y ?3٥ȿ xǗ&tA{kp?m#S?N 845?US? .*xA(?&Eyݿ8D?\T?W +߿?n*=o j:ݺR@v7?I?*"fQbfE_;4+G7HzXb?ʣ@n 6=`ܝ¿UFߥſ`=Gݿ/d\+0?kP{h?# տTWJ~?n?0KA?ɝV><qϿrJ?Wb8`@^+A?@q/?`ww|}?y :,i#?YZ?64\o?x?ى?kѸ?l܊&?m"So"9p?8eH?aCtK?Ϊ d޿Iv}Z @I,+-zc{' 򿔾?,xѿ>B?Tj뚌?ezO}?[&|? ſYw? 3Hf\UG?"]?V#?/}>Ƈ^=?7Kq,"9JϿ;~)_ǴÿNt*?k,:ʽ6W Z⿌_?8s>/[T \T-?D͝W?# ܣgnv?Js?\FتᅴVQ]wt~[ܿ~rz?2) !?ml i ?hĎa?jM?9dW{Ujp 1iۿP7?P6t?"zb?1$o??4uS|]69I К^ ?c ?&?RY%r5c%pi? ^K?8@Y,?Wey<οk=4H{9?KXw/;)쿍/ iy_,9Ė?U0#?Cu >!?V=NҿE 6`Ͽ_?G[?Z?My8ҿtuGJQGʿO | ]?P9ޒ,]?1?V?`X?.cZ?Z5?qؿ/?m~tůxwk5,ܺ=wW?JGiR?:oK'z?:hw@f}& ??:7 ܿ Itk?E3|Ŀ׫e~Wi?WY$?i1E#횳Ϳ4*m˿4Ã+\I?{x?8*? *sb?>pgaL ݿVt MK?C~{{?]3?2&*f. 4?Ok?(GnNLOkz$鿋5hyz?lU?/F? _ 6?̘w]?$??dC?Hgc:1)WQؿ9}ֿLR@X.O+?uWSͿ;oak?7?-Qθ?#?NF?+:O?7J7:?Od8cM?XL]G?- : ?j  v?>4^>?Zu=(&?|?m HV?ZVm?4,"nئ᷽s\P?1tĖ??ى|GN0ݡ?n/?ܞ޲<."4:e"sy?Tȱ SuK|!4ԏ3?@ȿ*?RF?0 apf?ݢL,#?սa-X?@򨨺?t}Yӿ1X2u?pёyQH]T?uyݿFf?]]? &뿟̶Mj<陲aWʘ\=?:(俧/١\Y?";K?W, x? !)Ϳ1X? N0 ?Rw$򿑛W?^e)@vR1q?M@?$1`s")ǿ迍a?[L@A?ކ4aF"ݿ؟׿_?VbwYR59?,OHƶ?2T`?$gc[۰ɦ-?뿡}]?AV2?Nb??loXL4]?O??=&Կ|/?L}?oi)\7 ,& ˫?>oKlUH?dϿ CϿ?0@څ0ܿ/tj)?D ?l{5߼?=iܿ,OP?7.D?~`˿f@66zN O?OAW%? "; @'0tD kC$?1҄ݿٿ5r`p?,m?+N3?*7Lٿy(̐.Jwr@C`rt @-qi󿤖8x{y?Awq+ҽy?y٧S?ƄF3^ ؿ[Ք/&ܞW'$Bt3Ŀ1Aʂ鿙x}u񿻻??z ? BAc?sn=z?}܀?hʶkq [?&Ts?M=(!m-q?'4f=>?ᓑ?!a1RoR?U,qtU? ?,uyP?ᶯ1k!ȃEp[9пtBCĿ 6n ?a[Gq,ٿmW ?@N%C?Iz|02?,Ŀq1![y?8t.d-?K_?*Zh̿>+ˊ?*m? 㿵+[뉮?"B=1eʼ4?|Jd̿??Zy- :nщl? lE?[w?]wӞi b?_yE?5)E`ؿ ?3%Lx?s#^N?Оv?7"2$?_+?O)֪{,"9翀̤ ?\kQֿc$,2?{*}@B?տ<ԌO?!6䗬e/?4 ?zڿ 2?U|`ÿ+?^?WJWk ?D?LnƩ?u%xֿkcnJTAh?2\|Z?/*?2#_޿ua?#H+i<:"'?:t2)?̺]?YW'U{zQUetHx׿x~/Y,@?:?1(ǿն OPʿX$|<@CT?QM2jSٿU?vXڢðٿ5<տj/?{?wk!Sp ӿ54g?UXB [#NF?/{ +,$->?qZm?ŕPKȿYտ>Grt=?Bcx? \h꿶ZQfN׿%[p?c¿Y6zǻrh:?$5 ]? V"AewL?,?齹Vw \ $?H.}z?A/>п_"SտY;Կj{?IC(2O)?0?v*u?*0;y?fD. ?ϗ}'8?r#| +?h~Qz) =?{U%# >+$ȿp$T?7٫O?tԴ?Wn?ID&);׿̀b͕ _DPwN?|%?Z^'R?:# (?KМqz?W_̿ jpMgE?)p?jbI?8|߿B-cӿj/T0?7b?wп?1 Ȋx?譡 ? XeۿQgf@d=㟩@z5b,?'&)b`TĿ,Af5?|翑' xӿ} u₩+$׿?4?8MN?!1iQ? xLQT[b?:TgE?ac4? j7?7W4^7B'C⿕f]D鵷6yؿ `τ?_ i@|?&y)?@H JeC켼?C٬?N0ء?/b[ѿw77^۬˯G? :?]qI?u!9#(J鿎8?q~?Yj6n%tո?JeFE4XnQ^տ3#?/)ٿl9?JJw ?"5?RJ"]S;6SW+ܿDQ@,vt?@ӱcֿ1-(?$[q?xCދqv:忉s¿x=ނ TiC%N/?˥1AUMo|?OYtn?)?X^ֿ]$E?Og&ԿC2˿c{C ᅣWֿwv?~-mӿv)2?ʄ?<ʠ?qH?Y6VL?ҠGǿq3?g,P^?ؿOE l,?I>Fÿ\puq*'_ȿo,ֿL6❹x`j?R?C`?( {ܿE3z%8sϿhzC?m\?qAɿֿ^{D?t]t>ѿm`>m O@/ʟ?;擟-@HD_?#WKj8i`[43U? BXf?pn^?Km-c?O5@D5?>?c@L!п#o?H3Կz@[oWPd \?gy?h?V|;fhEDЄhaύ鿘ׅ?q?ʿ78cd A?/pB?|{a*@_?ޢ@?c֥7/Oӿ \#?2ɿmC|dO?)ӛ_bh?ݺ\A¯ }.H>"<鿂j|%!K?Ae߿?> +Ϳj ?AD28k=?M,^l4?g;r8?XT?4R^DؿG[ֿu;.?g? bk^ܦMs?J}4ܛ?,D?>翏J ۿ$S?J +`wmk6n򿤱o+Կz0?Q?^\.q8=?9g?Uyܿ?]s ~jRq?$caKa(^?eV-?rk.ǿdwMۿUoh&?&0vԿ13`Ќ?$s?i`B?#Mz?] !VG?A鈿/m@K?Dp_ "@7gLYu$6in0E kXf?aiz?t[?]݁ڿ Y;?V+͟s?H˽?l4??+@连G$J?kYV?[@&G RͿ'C ?2 /+cfwLٿӱg?{/[7셀T2D!8X^ʺؿa@ߕg?r^Et}N[?;J[٦?kJĿ?{ި/?~q>m?}N:q? z$_?f4^cP׀άz8W1tiDCx? ]i|~&<ڿi 俚\̿\s?;{?>#?㹱?"\@ǬdW鿯yZv]p?)(Ye;HO< ?0W'?w3ea@so?"e?oCl6HS3?l x?MvԿ[[O'࿊{pK↑MQ&ۿn@ۛ?-?ʜ_Bܿ|?w{·r?/o O߿>ҿjN.?=?n-?$^?a|ҰOLJؿ1( ?ZVj? 8?M^m Y?\ZM?c]_9j?hYIdG%_@ODd(ٷSᅫr&AP?L>l?0lզ*h ?#!~ 3ῗ7bւS?8 ??+\ƿx,?,?bO?ֿX*#8߿/7N?޿25?f[M?sÎ D-]H?J?D.G?Mt`%/SmL1)*ƒĿ*S)?ga%?jW{>UnMN߿(?x{,,?[<ʴ]>bgp>@d ?u-f?Iݤ{½?5ο<&?,?kqEGA꿊P?.ϯ^K@Κաkp衠ſ1?-N?&&:n?@QY&<գflP/p?=}RR}3˿*?o.u&1mCacW{?"75C?s1׿SJȆ7׿YE|?$zʑ?tm;ӿR?9:.7O*a?WN?6ҿM"38ķ"~. t??T)Wѿ$J?X~?.ދ?V9_?ez?JKyԿ9->C?4P-#?:12L ?H^3?`YiC?aq9¿&Y@d ?)Mh5GDu~K]e?k?)ҿ ?? .0Hok?JߍĿ,r?տ$ȿZ,3'?a==ÿwf &*֧?60li?rT!?>ؿ]22% \|KYES?`unLKMs c?_`{5?}E3y*?qk_trH ?e[M?Hkȿq6?@NA)~mlȈ?FtZKg:ƿ%-?A?U`OH*!Z&i@&? 4u߿nnۿh7se 7ӿO_>@4σ?~嘣3?@?!5D??ߓT㿤Uɿ2[XO=?N"k.?3?a.P򢾪ƭxf?iD?D؝7,῾f/O}r?I FNm?Z?k^v4?wJ9_# ? Lu?|IuA# r7+x-뿻 c̿[ӿTWҿP%]b>Ke̅Y3ʿ%\Ϫذ?qˌ8?bg@?8My'?O[/v6?\(?=N?Gul?޻O?mܺ YkLsu%ӠO$;ML+V^!r*Z)Q@?JWfW?"UJv[8Ͽ?j"s{BP@LJ?QD5ZYȿmn?ט6!@lײg]EМ+?[?c["??Lv.:7?#KJ Q<"$?rncFI?! j27J\&Ϳr\qC?Τ^?e?mhn0Bu\3" ÿ MbJ<pXhY?{\`?ߊ?oL{z}'k_ֿL.?o? 3 :?>P$?3hΨؿv%[Nkz?tR߿T/^[?73Fs?`Dp?z`e?[e?3QN?3aoؿ޽`"oN޿ASܙ׿NQ;?E??jW??suAA?RI`?sWmo?3Px?n~?e-Bbi?@ d}쿴 U\Qpo??c;̉e쿮U?O*?.?5}?Ooy7, ?scy95B?>=hw*u%#)?*G뿧EozP*;𿁊?!4^|wXn?xU~}ʷ?-PLW \l%?Yrc?1,\ٿ8G=@Ń-Yݿ̡iXj?ƳR #zC¿˅]? ?##R^$п6ڿű"K»ҿ h3E.?rװדb ?9hȿJCLb.*P5/Y.׿|X฿OA?I3?U/`'lZG?]B?JlKK?y׼٬\^}tHzͿP-8uQn*<ɿ7i?ake|BH{+?b2ֿM+?Y~Ÿ?tkM胱cyE%.8,ԿUݯԭZ?_t? k[ῡ~3s{?3Z:?aNK?wۿI~?WMspz?DӖx-X;:V~?{{&?A&ᬔD9 ?|c.G~?xX:?|у(?_?WopZwJ0?p M%t?bK?C$"?\YL+ n?|? *WkA?h~*Įsd$%fe?@ӿ8 %*%?C=35?Q2?i￁LhտxD?{,zܹ"qy~-R?2aRѿ#{Ǜhs?6[ν?&?P<}S?q٣߿٦)mo:?L2ֿq>?l#-1?}(d?ٿn mzp:?6L?Emv?ږ6?Zm?[O?]@X6/P?V?8J#̿v"ſC2E?UqEH˿W8H_?6? &8sw8ke?* ޿l`̊M1ؿ`DKMy=|?z@?Ǔ?pd9޹85b%WUܙ俧NY?_- ?7vuN?1 j@Ck~̠߿ڞZn%ֿ>=?PH?T@࿺bQ?q>Jο2mο=Dp?T1I@6*/ZO-2kMl %2[y?u?+23%cտ2Oտbi@ 0?|Q4ֿj̟.-hn?lj"4?7<;?M",?j?OuȽ'?tDdY?:؄PdVdq?d.?I폟?7J]?Ym\`?&<鿧p^ڃ¥ MB[ok0?1JIqοqBXOk(%u8ĉ[ȩ?Тvο>֥h࿮b 0W ?vvg$K?2xPB։j?TD_M|?0?;{fѿ2= ٿCŐgyk? +R?:+=Sj/hYRum5?%g]Eڿ?pujٿ(Le7?iLzv@&θ?@Q?+kH?'z)?$?iF@+?CUI?Y?H8R36UW#ڿF$.Tgup?pt(?Du7l?V7BGI/q࿃q׿{Č?1_?lZ?M.Xÿ%ԙon?vS] ?2~(8'?Ix?}%t_ՒMROIfcp?Z3?2?Tcs?*?f?C-?e/;ۿaI?o|i?Mpg?Ŗ?66,?b!(@DZz?e?LY\ Ԕj]}S4~efVz?ޥTP?=5n?wbL?gɦ< ?ar?~!? I?Hbݑo?q#0K?? n?*?w}˯J$gS?Qa)xԏMT[?0п )H|LT;Č .t"zЪ;4?:7b?>?`Y/?Ի94ycPqmh~{??9y?F?H=~?wC6K*Y|eQ'f]z7?Y?4IUܿKC:?RVJ otj~5?g3?<޺ ?,wĿa~qsh6qX+>>J_? O`?S/qe%d-y`ZF?}v$?=kR쿓<.?5 ?*ϓ@s᭝ֿ,̌vP?Lߠ?Tu?!_tNF?݀ r\_?p5n?Γ]?c]υ?2?X3?ْwK?4 "-?iO󿅷gY??wk|?;k:?\ǖ?'q>kpFc4^D`gdI\?^oKտn??{Y5pӿܜ\I?C|??sѿC]hNpMq=-H?=Z/?r9?C:s?Q 󿉍J[׿46?c`E?V+. ?<ƿϿAhb@̈́TԈ??HyC?tH^Nw?M@ᡏ(%A?'R?ѹې6$)?hNG翟)\j?S ?h4a-#'? HdvȄ!-?KD  _&?P ia񼻀J3r{y?ݭ ZW? 2 [)໿}"?GH}?nyQVD3oA뿇@?X g?9Ö΍@ҿ:H{^s?;')? SU?xZVfQ7/"}Ӟ#?];%?D*%(Rw(2@sbSÿO>B?>/.޿"}y ZX?`?,@-`￘=}ӄYܿ!\@lxaiG+{?ʞCV?,_?;q?W]#v܃K? "O;?2!?SD4#dNy>?2LC?*$6?Y,gI?!~ڶ!?qv+?2em'пpGο!Ͽ䥈s(/?я`Ҥ*0ƿ"֧sn˿/#;?ΐm?HB@r'B?V?)#g˓|j!܃8W ?nQ D?frHSy?3TCLOk΅Flom?$pcN?_2xI= ݿ@=P?(o߿7Q?[+%͍@J!mwѿVty]߿n @ ΂;"?Fx`?QK?QU׿i1rʼ?gg?'D#~)?X!?f;Ͽ<*8?7s\GnJgVEe?k?[vs?9B8忂Y'??P+J4dȇ42?֌[ֿUЌ?R󿬍?)ҭJP?uR꿺_ Xο5w0>1mU#Xґ 1k?aZ?#V^?`F8rF-q?7տt * տExu@D(ZҿP"W?.w.|?6jS?aER翄y2$?nD?2x^?NH@etQ?hW?8̤rSǿL qῥ ?qW)i?Ѱ??W/o ?? 7V?֬vlnJ?a3ba*@(x?8#?y%ו!wYyp?*Fݫ/v?>ރ"ŌN5ƿw:T˿ ΐ7ҿon-@?ȇ71>wCx.T%п5Wɿu0لZ~؋ qWLdԃO]?3*: ڿ:Կ"i},|̿&ֿ|1?tƂ׿KU}o? G?)F֯2?ѹ '?8s?P ¿W~ɿF]?>&l00VD?1x|濙rz˿Wy) [?鳿?*i?d?On+?y9RռJ~h_k*i(?13iWY#߼?GdsPY%!?aHQ.?sW?^+r?d P@YO<>㐳qm?xUR?'?_j࿁KEi?~$?E؃sP$e?=(ƚ?ƿƺ@$H!Yu?TgU(:/ۿM'[? '?jPƿwԞ:Ig|l| (} ?д j]?(V?~ ?%Lo.?DxڿǢ8?W?JׄY?=r?G0N?nǤNIcA` ?rK[ֿZ~|ֿ _8J&#=ڿQOҿHqˣ?;i?m*?ϼ? ?J,Rm?#%TY_rҫݿSsN*Y_l?3YRx.i?.ʫ?iϿu1 @%K?p)% >翙4?aj:?\3&4L?h?i)p?0|NQ?*ȿ=? kؿqSb\"俘fpЌS%f#T?N.&$ =?k?^MIyZ0C)J#b:?)Xa?d>?U$ >?+i濯sؠR0#_ͥ͘Pg?;? |x?`v`>ſh<\T俧>nK&?7?kjA?&2 Lݿ‴ ]@"D?SADQrpĿN?R ?\_ boҿ\? r;U`ÿO~o?9bIC?LZ󿆜K"㿶,(?&i߿9.s`ؖ?6/?2y/?h)?2e|?,],?G*C P.?{lܸ?|[?tC@?&y ?2Nqdx(}q6;Z使"~ 0?xsR{H,ljYFW ?ŀeX?cDxQt@W?%Ȑj?^#@Qu?ET8ؿoܓԿ|㿚2 A'?{/ ߿=s(!¿iNJĿJ?7"Z谿Pf/G?+ȿqQ?؝ @ǡ ?t?Qֿf-&a WF=ֿqvB̞ۤ?C.J]es?v)ef?x$_?W<*?Z?;n@'Q ¿Z~⿁ {O?g1?.:Q?he"h?G?;?k5 ޿M߈?6 Pd?#\%K?ur?,Fmܿ+P?^,Xu?.S\ ׿9vo19̿m]?yh?!8Gә'?*&<@vis#VcA޿~s@"? ӿ aT}?q?NK? uJ뵹?cnQ+ʿƠS,?$5@ ]uԿ<"?1*A? J?LP ?17]1%ѿoƿʅX z] R8?@Ea&?{Em?V¿C}&?rdzA ?E 7?VHdݿ?PXnu)8F⿇w7?tYX俖9jmk?COB?`TJ#ӿ[C ?m)@?.;M?f}?`~;?5#k>?uwːQt&?e/Ў+PVf?q"n3i&?~z"?X ?.´pAXW~kF؞/?LI #Y-?]ȼNz@?iF+$o?8 MevDտYzδ3.Q?ˎ)'?`>?JQٿZEȿ5}+?Mbܰ:C?O<׿B4?*upgܿjIͿ=Jj?1E?z,$2?'lCGXH??/`ggx.?9s)ֿ)r ־ۿVA$,=hT_@?B!guX?x8)'{l;Esx*qĭ?J"<Jp;2^̭y¬?d1`ܾ榗Un(Z)?_Zop`ेB ?)Ll{V ӿG Sm?AܿK{ {Rb??9Fѿt8>?d?[.bFU?YJf0ӿw}BF?L]&g>?+9z?+?޷] [?5? o?ª&?ikb?`5239׿sÚB( XE?7P<A@2B ?_\Ϳwjmo?KvYfi?y>Կ~Dz\D}d?v?"|<) ?ZEp^a 𼹪?G;f*[LJڿd? HԘ࿇<4/* aI?m tS&?$a8?+eҿn!?ೲ?`9?bL/y??-Qؿrsq?^'ſK`'RB;߿-近/ƿ>{տKk|?gPBqwѿaaPYWs?ͽտm $ k?$q^п7(&?13dvQɿQRoۿGԿ ]ʥ?@ۅ[ҿ}A#ި?DZ?:9c?)w ?fBIɿ<?`ʒE? ￾5E?q-i? [WB?䂸?0(h`g?@ =i@DLy翮5~A?RzD ٿ` P?c!K: 濠Z9e?Je0?w<4',_1Ͽb~Ɨ򿪦Ed҆ǿNw??L1ZܿKMMeWݿB!cǏ?`;$?8f3?vm?eWu'OcZ?Auҿ2?& :CԿ˺{g+t'|,?2a6?EaԂy?@?.xW'J?5&G@ǹ1jпx d]?wKӿ3,dIҿuk:&?z"´Ʈ?'?h)P$Y?q[a?{ ?!#?]͖̿ZX9K}m?9Vǒ}ڿ@5?4en?PR*??g׿s)oOi˿(X?fпu<?Mc\7߿lf6ﵿyck`迏h7[X蟓°H 0]sp 2Sb?{n?࿂{9N+Ѭ>G?ԝ"H࿧\ ?J\r?q-t?shۿofʛ? ZG&;?Ԗ<ۿY̥?Y?uw{? ܿXH?_?k}v/vܔ-2ݿG& W?2N 'eR/?˰FǿVݿtۥAt?˧?$ z?c'?>$P?> ⿈)Q?\L?zmO?4T?Sm깿ʢȿ|iOJ?W>U?T5?L_?7OwM?/ۿc#eT?U֮?%L|13j?d%hk?2^!?̿%Ĉ?k-?Hqylؿ֖?OǍ+ϿЍ9 ;Zm?$i̇?g`?2Nex:]?B?W*sA¿,CFd/E'IK%2L?Jhÿ ?{&KI?ŏr?–UQc.ֿ7 U?3t?9iWqPB?/2\?ꌋ-J?"0< J?n#&?GBO>آ`RL::ǿ;8Q?z؁EyMtv"?f?[3V?/(b4')MسJ?K%5?7|Ŀ}&"? ?7? %nZ?}ʽ>߿H??bK?SS0E39+ּ<;X=?= nq?Ek?O[hп{q$?n@-Bf ,? 8N;?9 V?wg 3׿4$r,cE*@pJY?jdzP: @4Ik)y?@Hg!ݿJ>F[;?GбU?H?|[?og0 c?tsM˿E^Ͽ›b^,G7¬џ#4׿آ8&?Y?pq2?˛z nfҿpivr?i?[gtmq$Y9?PL?4Qye?ܖ.?}?Avv? F1߿񱔋[?\?ܑ_\?A`?xǥ?IDv?v\+nlب?2kDR?/g?usRG?Yq;E / H?ﴢ|?i;?w_Xy*??C]GF)ZvCPs@? k #!꿐k5Ɋ?ʫ*s>?gC?w ܃?4 +#ޅv%c#?zd?0'P>9?FKZ߿c~?= ?,xCTܿTs?Ek`+?'"%qk ,?0ڿ_1Z@BK?s_z꿲N;iͤ)X- <?O9+ .1GλJD󿡷E?nd e?TyL@TG鿓 n?&G@ubƿq^Z?"V?~?,#{,xڀ?Rh;n?[{SΆ{7X?WZ?!rv?C- bVп[UI~\EADDz?( ?,HٿmS"P`Q?Xs뿒8t?2/K?V8 KM?dJJ٢?9;3v?[?5 I?T@a MR?K @b_?u(?LgVf'?tjr@Q|5UmN1b?䩈\F+LJ?Pmk?`܀?ݰD?F??mM̿0ql׿ N9?wKU?'2^O?Da??0??RE܏޿ŻeNʿV ?X ߿ ѧ*ݿ#Ÿ$,W!;8R'KƱ?63Sئ;?? wz2M?;1?LD堙ĿDq^rJ?wXLݿe?:>O!&ݿb,"?5-7Rvϡ L? dA=. O>AdMOX@/?<~$?[54 0 ? =?X{Iޠ,?fS?z,JP?q0濘58Yo .İ?r^NTۜRh%IaϿT C? P(jʿ/H?...G 4l?vG?֬ٿ8 4`?јK?iy @"sǿ@ֿ0r]d?9?W???Gmw?4L 㿎^Wc+?nCȿ?S?a&z&? , v/O׿9&2y?8cf̿ś'?B~ QG|Ug?? G|w俭E?hcWwZb?6~?]R߿KoMɿ,վ忤2ܿH(^?2U)?M ?uf$X7?ؾh? ǿL?$RU-K;ĿGhOtWț?֥x[?h&?-\*?)[)sO ?5l0? >F޿gf! fV?J$?Cy6|0ClVPտ.9Y}k#R? DOAznQſۺEp?[迤 ?9? *=nK?Mi?b տ?,.%?N[ڿ(:W+?Wfo!S?^? & v?dUoҿ{7?bxo?9'8⿞g?#[1?6z@?ătn|?¿?́a?z$?aH+?0k@]F9sZM_忛qU*:E0| ??#S& HU{?ݻ[2R8?Ԫ20`5JȿFpuIGӿ.,rI^2VGE_o? >z ?Ȟ3@vg׿3#X aؒ$?Eݨ3?e ]xC^?)SW?o*GĿ^?i?5ۿ2p<@{=2'=?`r ?%hk:K? J ר۰T;?UfioҴ-f̦]^9u?C?*ˌ¿q Gz񿜱^>s*ٿފU2ߞ? z?q4@$iB?1V욿vl@U.?c?>u\#  IGl?=u?#U!?&^TC_?h{:`:CZ?">3;Y?`\8?_?6GXT9|ЫCӿp ڿ?޶P ?r*=?|<俾e?1@uw,ErP4vYVOտ\s?=Rk޿ _ʮAd*/w@+rw?*.ӿ2 ??}mNWoD]Do?t0`?V?A8ۿay`Aڿos(FrJJp9S@98~D0M ?4?@9ag?\L?63Mտqnqn51@@?Π @<"?d?y?epcK?_5_?=B87忨^ڿX1B+?jiIW,/Uo? av?f,r Mv4Nėؿ*!gG`pUNP K~?kg/8ӿv ӻ?爊{??vƳ?'Rn4k2/8و?!!jD^?)|?2?Wm²00'?&{?D XO? NgzXShr@!!BC?ǒ?M˛#?QVd IwG ̿tT[Ly?Yq۬@WDXvaj?q ?o}=T'zܿH \VAhϿ?ZLpR?*1"̰ԟ ?rO?[F@wG'U Qe? ?Yq>pϿ'?"*?vϡ-]̺{a?[`? ~3?*qԿ P?mQb7v~$¿&1g?B-Y96#?B?1ߴ jix?ڭ뿾?w/ 8o"(g?$-h-i#?3즘ɿ:hL j?krݍJkFzGοUj`8v8?͌5~[I;/=?צㄈ?3>?d ?8 H l}&2?/QA:*?.'gKb=?6#3ՠ ?vȶ? jjƯUcl)}R?Y;Ǩ2Ϝ? @7޿{ϱ&LFCw_L?Vֿ>_ҿ1?ؾOV?]]T?% Fuѿt=e"ݿaix?Uit :䤿) q?tzirE-?K~,?%!|ƿe3a@?l:[ ?t $-lgү?ie"#?-3ӕ?ap I?:%ӿܨSrh,?fA?t5W?Koj?}$)Ы)\?@Ͳ{տHr@OE?J`s?wF+[2ſDM?w" ?NV~@t77Lv*dـ?Wпuwпꂟ?]o迃g^%c?\;yεfyտ&MɮSNlE&eMԎM ݿf7>kezRS婩?,0r?8bejFZ?Deq_? p!hD?Qc; H'*D?a ? ׿O<[ *:A?#_ә?2E?pJ!2r?GeW?2- ??pB]?8տ b{i*au_WcxJ}Eѿ2 Un7X˿^l؟XME࿙?*?q~9?/;H?XAPA?Txӿf9?,8I?gZ6ӿBl0&?w'v*Ϳ(ӱ?/!L?bZ쿹L#E? E+g02y?=Q2iT7?zs|QٿLge?ӽƿ? kֿ:Z?Vп؍|e[E?@~y!\4'ҿl6¯俹(ų?NڿHԹhb =ȿg~lP g (2?C?]@eETBXKA?`o"\?TZ>ڿ'Q`?<6$"Wħ?eT?B; 3Anc?lzc_ ҿ@ hD濞^܁y?-}.%hZ4忡o?@k?:.yۿ<܋܎࿚_?q9[?1 goa-^;?Wh-X?p L?!ֹƿǖ?+X͵?%e,*:?T#U©Zkl?:=?˷ވN??PɤU}ܲo4?m&t?ѳH?Vӄk?4?3nv7 ?Ca6F(?{EտRL'ΙsꪲQ]7ᅨ>n ͔|ch?R?S?tS'VܪF࿼mO$ڿ G.?Sѓ?#Jt鿦Y?b?\ſdC@Dƕߧ?=mO&*Xjq?}31]I ?T0ҍQ?\ Q)?;JvlVC?K]);&^[?5,Sֿ*;e?KM?D7٩?,kln/ )*+sA?lAhпfז?vbS?y}hGVv|?s?V ӿӃ;l ?o?Z?I?`+lML!zz?+j7jСYMo}ڍN?ǴQ*?N G?ù?8ꊑ? 9w ?<vtSV!a8ǿ-8l? ܾ8?v?U ڿ<X`迚T< l? 㿺Psm?|8ҿYv~?TyQ?/?Ȓp?:U'~'V_?H,?0^쉿?&;zڿ(- "6υ,9?uB?mu>?CJ*F?Ox/?a~9BA]"?Mn.^Ŏ!z?8׿bZ?~:u5 ۿ?Z1jD?"J?ZJF?;?Յ?\s?2?G]?3< ƿw?{R?r俛k/-?Yi*C"iֿJH鏿wŗ俹H'ˎ? 3Q׿d$P?L~?F|]FGB?ˊM;?HW?~pٿmeտcuῌC @M߿Ie0o]y?օ+}~Ew*LVпm?Fm~?Ϊ1g[ڿ  @+Ϳvg?c,#? W`3??Y*?q6?>iB뿟u?&;&=~?uXпo &L<` I@L?-#? xua$ YSKſfS ?hxui;F/ d޿㐴rٿ_w%Kֿv|+ ?y^?J2?q;ۿQX?&\N`%?gf ?:?ܯ1?k`Iſl濩ƕQ?|~ ?}Q`:ƿ;?opo"ofV  RxSp?DQce??Y)?Z>?>ʪXcտgZgG $K83]^^zEĿig? o++̿~9TQ_d?P 4L4v$pkiS?o2 \?6ܮ?w"R;\@d࿋9vʽ?L? ĵ$ۧ&Jx*?QxG'k#?l[Qfo?(qs1?z9ݿ dLfk?NE#EGMtU^EJ7֪)r$ÿR3?S*@Ea<޿j8L=bQ*L޿2yBlf?q[?ޢ տŕEƛ@EKSy$_>\܃»ɏlN꿈R?h' M!&ٿQS104?'k(jo?qG@;? h??$]I\?-"8?^lS?E?,RvXZJĊ?8?h !k I(c?o?ʆ%חRHٸ?S)>?5k?Vb?uHd=?8* {u?P_(0d8?~Р~xgfrؿR1#@/U?/ۿ=-AO{33?š鿪-"4῅3i~ڲȿ :q_[;ܿIKÿ?~".?Չ 6?Nӿ͔k?zi? l?8G'?Vש[?YgcԿDI?m`[Zx?`ӄ?@w/sS?AA>jJ?]@?#d߿:F?]΍KA^?fVW?f]Ŀ-?ةܿM~ԘAI%fqa޿׾ܯc?/mz3߿"忖YQcп?Z k?ۥNW]16=?hg]?k 1ؿ=IOΞۊ ޿;?Ia16.z춴*?*=OO?W4bm5ؿ1hxH \{?vs^sUlU.DC(￾;%?ӯ?KǿRoFGNo9S(%}?Gk|CFX??WVR nU!xq.?5r2Y@97iF?H @9s?yeS1?I?`[?)B{E8y&,To?*N?2L?J|J??xM*=5qHwCƿU˗ؿd/t⿐42տȧ ?$.]]?TxJ"xGuahĩDorm1俨OL?me?;3[?vCe"?L6Yb?$ͧl{{?6?P>|n꿉4?u{Ou?c ?IDB5u3-ڿW2?sdl,5D3Ῥk꿑,;?L)3?eʿ^࿬>k$K?&ko}$Ŗ?T ҩeWo_?!?%?aտ*%P#zT̿ܮM,n?$տLcֿIM?Dп+q et?o ?~3|?,h @)09?@?Eԉ@o95ٿGi??Ϳ6}v. Hn?C?jک~?*8n?opЩ?:< a])Z<ij$?y?vʴkRd ԿMd=Ŋ?9Xlrnd'?~ĴCt?d#JB)cB?8+?]k@!?p$,P޿Wd&;?H p(?-? ? Ȃ?VΒc]]??ǫ15 VՄPس?Rm?)ܰ? 7?ͱ03?Xȳو֍?B 3ʁ%%t?eTva?^iտAJ?6. 7QU?=տ`{`n¾깵c?M Ͽ8>?"KY? _Vd!nl?4z?I^F@ƻ{ܿ#} ?KH?v}~\?WB?XnX迪XG?yeUi0w#"ڿp ?#Wg?'?|?C?=?LL?S{X9% ?s :*Uũ[X1^ۿmP> ?OI?si#b< ]\?D>Dk?YfPf࿻ ` F?bt?vjd9ҿx?7 Y^vӿ,ǐ?W +?ҟ?k>\F(?RAo? 7 K5?S~g? :߿|ǖ2?GȃÍN z?#yp? FC?FZ׿SΡM濄 NxYT?At?r/?dbؿ0%?&,?:M!S d?GL߭?qanr?mf^?ATJ?~O?`8mY?Ym?·}{?3˿\r/s]u?xj>q?/)^?r0a?4?=]?3)?lUz1CK)nҋ=w?\0xտe1c?-:ԽNʉ?9h/?@ U?d?Q߿_ZLw?'"p?bTs:q?NFus?_>?(ᶌ?? 1plBAZQ$N?ԿE@ef~fK g`G"&s(I"?BϿYX?QDw2ȋ??詄syu?yE׿Š<_ t?]PoT$÷?cuŲ?9Yz(y?ً8#?߁?D[?|K:< ʞ, ?&C?f!adZ?W~Up?#/%?և?͕ڿF$ǿHE< ?{e~Rx?2YѿDNأƤ E[?{?!?q<,4俻 "?hNq?_h !a?DWCY?8>?u*1͕`ubS=YͿ8?xJ@뵙꿁ǁ8@ڿ_SÒeth*A?riM@{n s&]^q@9՜ek?ۿBG/;Zu?VxֿȘ$o鿂}޿FzͲ?3?e_ q?r?%yhbٿ7MӿЈ-";?7b4o?DewGV?-?Xa}?ـ16?k=-ȶ񿋞sZ6񿱂w$8w,9>:?&i5|?\f%U!?\ÀCJqTm?vF|i? V˗ꈻ}xzҚsY?(qӅyW?prv?FA ȿ:kUD[?þ?TzHXi?ҿD+Jxr _?Eܿ \?ʥ#?%?A?L?pqެ忖(B3ڈ?-~?YZ?C|j$?T߅4hK1m?:C v <5?,j ʿcN?"Giʿ㮁e.?@kQ{?<ƨ[?+0?!LjH῰ao?40?g2j6?~bLI [ݿ6ʿU}BJ]G) *?%q?]e,?ǦMԥ? eޓ?im?Ki4A=?{8ӯ3j(yCB?#/ ?O>%j#Yԃ?Bܦ,!NNfELl/ڿ6ȿo1vB:?!b\'Зf?'}x f\+翃_>y@TE|̿NppgGu_0Z"zl?j?ݥb̈́Y@N*Ruv?8?(w?Eĸ@ ؿRb|?3sgݿ0S̊?Q )tMXf?2"Կޢ;?o@?*?Z#? i+? @t28?I?`RU?ɔC/@4_-ɑѯPͿ ?VۃfS0?N0ǿЎ?gEGSS?|?:O]?[Km LNIhݿ(?NIOe#;{ZBk4?|zܤD"߿M{OzJj ?GbH|% ?Bu~KJ*.⿞Wt {;?|H4bVɿTU?`>?r^#lF,BJ?5R~׿aH9w?Q?$ƢӿdYR("6T??} TRHa??z4?\z"?5=YͿ"?>% ? 朥?RP? XF? g?z9p*շq濇;iQNx?n΢ؿÅ*aٿ%n@7Q?acN=cdh$ƿB u.?e~k?Z⌥i}K濔?NA?8թj7?>uҪ?Nm? tտO'䜩??*w?MCo?w'?Zx쿰A%ٿң:B:2D,r?kCkE L#u?Yn&.X&]fnMܿXe?,=@- _oG㿐TnmC|r]*?oL˿W}/\?s?|7i;Ha{R? >Vy[@??}!%?`ؿ> ?]X+¿ش%c?5W?6#?2yx%?+X翫4)E?ǀrN2uaz¿#Syw"BCiqzbg㝯d:n_? ?#Ό@?KZ?L?zh`GݿllZ!P ?3]ѿ:ܿJ2)}?Pt쿆 sJ&s?H:?Y?Iƿ&~K1V?*o?Lv;J ?J9a?u~E<˿,iǻ?Dɱmȑ?W 3~*T@Kќ)SԿ3kTrLҿo"1D߿HܿSCR?W4?}?MBEӠ/;6ݿ(5?`gX?6? p\޿[v2阣߁ۿ剋ܷ?{&PY^?@6o^z ?Fq6?eqҿ-u04ΗMпaGw`D@mUxeW>s)?@b]c~ҿ3۞)wRڿH??f#OE70"翴70Z˿L mIyGdI~ٿ~?Q_5??'?cq{?ʪTF-?ƣGoſC԰?x1?P=C1}s\?3'? eE찼?b^gCDU?]'wӹOŶ^M]>F^ܿ.hJAJT?|3cF@D1:/r5?Ll#?֏?N?=]FW?SXQto?i!$?*Vԧi;1;њ+'?0̨Wa:yɿ?|h޿}#DֿT vO4UG|Բ?p@ĢXұܿНxp?Tܿi.$pCqa?[t߬-țݿ΢'?c?SG41Ì ??A$* juN cE@bFwb?>,-Үu8N}B$?ZfРX4??"PS\IF}Z? gN+?]Dlb? ẖ,948Uf?@? տQ~lx]t>5.B:?d\"Nܿz^ţB 2f)f?y?@Ӹ?\Gl@W?!-99K?|#пI^Dѿ6n7?NV_yoο [|y:c 忊sh?tz5¿+R?afտh°AFH|T?y-u꿴ƫ?FW>/6 nʿP@Pn3?I#@2+ѿ|28n:4f`lƷD] Eܿ%6??K,G뿌"'!Ὺ1ኩe7 ֋?{??3z=]*ῖOp/nRݗdS#e cX{>:CJU?LfG;wM?tfHI?RF+qҿǾHO)Zο ޳?oE;??"pI H?&S?B9?m?G\?m=@aT=,'W?{忀}۟?ZMmz?1,iK$Vs-޻&|Xγ?qw?Rל8K?wH:kPI?~cQ?2dm| @AV.}?;! Jҿ@_D V ?ح<}A׭= d2 i`ٱ?i?*?-J~?f[ݿTY-G?:\?/LceGY?F\ "-?=ѥ?a RVx!?.7 ѿ3a??u؃7H?[rl.vyp?}w)տfr@w}K?8?2i1ʿGȢN?4^F`T? ;$9 nd??h-tm!Ǽ?q՟ ?A'p?\OVk"# 'Ηɕ?5 6,Կc mGdv?EoN?U\?΃?b9=5?'f<[Іٿҭ?Π׆ ?mP8FV+ C׍;?|t(RCt#?t?f8HS/zf>[Bȍ[KySۿ?C̥):\wm(᾿7k8x?T{8/SSg/?04\? Qƿ&rN/n=ay @@B?Z/!v:m?]HaT# ?.F?9 S?΁Q?:?Aޕ~ɿUT8#?Reѿto?[ou׿EnO?.ʼۿy ?&<i'R?A"L7$ 1@1%*8?0? ǗTDϿ;V??Dm?6Pں?8W3Տ?i[?rU)M?17?_Z?SL.? CF`?cj0?6dt?Z^Z?Éuݿ].y¿}&?[uπPF ?}y55yP@NrD?*xit׿n" '?h:»ܰEӿN?(=7 3 m﹐?2I9t?֢?ܗ??p?7&_ʱin<ν#֓ 8Eڿ#]R? ɿK#+I ? 2>?EIؚB^?P*0̙<n"?*i5?-f?k NJٿsԧ*?|ĖX?Z?vcČ[L=?XճRY?c H? `E,3}Q տ0c}?XOtd@,}ǿ+F>V c+]C߿HŗuֿX^?$@rvտDdȯ#u?`'Ӭ?X#p?ۈ?Kz^ײ]M\_?I.?9 5 ġE꿓/?8kؾ?Y7ӯܿfbnbE?Q,i? ƨnO?A?t??+y\IpNᅱC8<ؿڕ$?@ $!mu?eh{8%?2?J Y@r\俐~cOݿ>M?<H#Gꑵ6?r'?Z?@P?m|f3̿H\?6P^ur?fA?jp7D?L(hƿuпr-vHe?)VytptBvݿ׶h~퐨Gm?D#W\qKAôG2?\xڅ?Uݙ1ut4/G?`-ٿC5<-nWF't?%0F\S(?6ƿn&볂st]-Pe0ǣѿM)L?n_пxn6#:?)PAN%!Y*=?Bj1?_TLA?>>VѤ@]?^?rV?7ev??݊8tuɿ7zM%@e:f9?n迧|ο~ONI-N?[?59?0Q$k0Öct¢P?Y|տXI۱?C#?>@,:3}c;쿲t\-]QV*@?+?&!K?R,W?w2?ZF?*7S̿l|࿸p1_V?O_d?;.raAk?&x?y=?VvNk26>c? ա?N'h xLE?2kg?JX1/ix?On"R?܅.?J/꿨AN?!Q=rcӷ?o@(E鿗Rw:R4LRWu2HR@\;ؿ5q?|D5C߽?_5d i?uS@?>~zkhu?w75?,?_ 񿐹-D`U2b?f"62 N REo3ڿ P%so2?Ls|? 39$X¿aR ?k/@kriڿ!B"?ۤ4ݿΰV?VF0%—ÁسX>V?3Om+ {N?3տSO԰ ?R?M/Z?>j F ݿD1?P⤿͇P׿0f?Le@ٿ)%+a?B~ɪ;Yۿ O٢˿-tD&?EB&:!r ۿ94V!п*-zտb ɕ?cR?w޿i <Q?Y\U3?>ߪH?P%?!sȿA'M濫 ,_?+*$Db[~HIY?U<\ &U{8eݿ^"sԿtgַ9+@? \O?E5-!4uXnc5U~c?oErNn9@L׳ٿŻŽjF?h[_Mk̿`P⿕>JBh;Xp;%$ Fd?a?nQ?T/4?NQn>ZݿB)c?ĸbr0Zx44p1M?͎*b?9+*)?n?D%&.cph?G)rBA?"ʐP˿8,?#Q/?; ?b?~ܿՑc?WՎ,濃4ͧ֠?~8cdzֿtYf?\?z%6`Dy?KIƸTSWNj?BY%?TM !)mta?m5c6/:vy%?>ӯٿkU`kJ?? cGcV6Sɜ)?YeU?K|x o~п×yѿaῩ1EJ?mN?NZW3,{(?|=dIUF=u'aſ:xɏ?D1U?ٞ0Ed٬p8c?0>s?[֚?IPۿP3hcп$%?Yd4.䇶ձ@ShcQܿf<4?R ?., ?ޥr?|u?翤 G=-J?%Z;`R?g)[$0J?H/?cyE9^ K,?w;¿|(@>v#ÿ'W?&D$qtX?N q.ɿ VSkm3?;@?H@wKݼ쿜NbAK"fPK?CQ&Ϳht_XnjKԿ?o&ܜ!Ϧ꿈FK"c?y;?cХE$(d@ВEY.՚͇俷e?sJG?B?g"?BG?OV9 ?X?F;IZ˿ݟtɿ_#?kx˗x;ο?"Կ .9˿+?N3ܿFh,f?l=ߥܿf'H׋HcܿH@Cw@fϟ?j2LXqc?}ȿI23ܿuq]Ϳ䭩?:R_fؿE? p}V_ۿj\?P #"׿4&ݿ&@ t?|};?KU?&?Eg+ ԿbiSӿ .R7CڿB \$@?z)?@{2Rԏ{\Z@%8Fʯ?kypV?¨X*>a]⿥*?9zu?On]-)O=(οs0ٿ2 Q9?N,tP?qW7fyؿ,Wk'ѿѵ/nN2h?Jg?e)k畱?Mc?s+Lt'2-(ؿf$kBPngXտbZ ?@YGf&ſqhӿYu3lp?{%\BտK簿Ppݿ=Xa$޿}(o?7̦ȭL4o?YڿE|PfRHV+?ffP?+Գ]ECS㿏d 4&?@>Z{`"Z ODA?_e6,1? + N?6b_"3:gODBſ,F?׎MbGp=R?j Aؿi&ýdD.(i}?|2?%X??QB%!V]?Ls@쯤?Ϳu׿t﫝 (׹&I?eJ4lWcP?zO ٿпľb Ypx'/K{K?$eDgڿD룰4yLqcRIud8No.qy?*LĿ%('?%a2? ? ?^ ?[Bֿ JZ?R8 ?0bο)õ?6)nk?!k?( Q?f3F?6 s!8%?q1Ĵ?2E ?Q? IrпjMp?ZeNۿJ]2S1m?Nvÿfپ<9?=.?m_S~4R?^@[@M^:d?AiJ"пFLZe;?z@ mE~?0HΊBZM? }?^<+6ٿ ơvѿ!0?~?3ؐG@镌=?y]?NT?(???y8ݿa:U|ᚽ:?X{ &?6ҿ"Ƣпc9%z$ޜd?~ a?3?a~zLO ?g@-?1dK?\\/gc?5R}k? 4?W0'?A 2?U$OwU%?m"\߿Gn@\q"M+?Ε`k޿u@ @5$񿜆DN??I,8R0B?C3쿏{o{S?Ѕ#+L"Ăӫ V/2֤Km?΋>@@#=^ W 忰7ZK⿒aeo?27Ȱ RY)ӿwqo

@?&"z&ԿN,yc~,w?פ7e?::/蝨J\dM'?_'[gbȿɜ@^*q|0SRIῄ;)l?Z?$m?,!+1oBLȿ.z%?^D?j~ߑn ?LM/M?cP*."4?2xg?f{俵#?+? $W1}7?? H?{|?HT?@It?jz rOx]㿹w??Va+߿M䒦?C?(?XZ[ɿil?Cпu 4忀ve?#Vs𿔰'@ w:?[!ֶtϿ^h9ԣ`书?t^R?(GPr󿻈jcXU u4k?hqLX+?Pk?S?z/ƙ?9?ڨvb?Dz?UM??)`?;›?c㍒ֿ]'?$`e?&Lp?lc?]?qg? Xb$&8yٿTư?c~?$LZ?>O?V߿v Q?RtE?_SI,z{M-z?_la}d?L?d_m ?2& 竷i@ ٿҦ?~]m;Z?Dw"?p+ F@|Mě12kBI𿿟>%P{o?:)n߿Xf% Hǿ$:F}3.?K;1%1py?6-+?vkr](W?dĤȿ`?9??qt*g<z%=?*S1*`@K'㿦2ɤĿﮕ ֿ0п?Ei?|y]ҿiO7e? /ZC#ۿ4Ć ׿堼6DA?ԐJ?onGЎKe =?S*Z?ay:*?@"տ/C7ς>,;?1 4?$V% OO'l_?\C2fs忾Yi迫D? ?kE?hlŨq\UL?x?eig?l7!V9NL?=?s-?b=k?FOg ?{mڿ-&?2BտAq?m9ja]?,`8y? M@gCa?JE|ҳ$v44?Z?OK*@"TJ?aY&)?nߑ?{hŖPDX=:?]e-gfs?*?iU?ib?N0x @6"'ٿijy?'?\ U2?l'ex߿0@?o ?S M?.q[,ݴ_Iÿ>U'??orOy?/*?Ww*w/uu0O-?ٯ3tx gcf?8Ur2Ft0?" ȿd/D>߿ßO ?0$?Eɩɸ 6?i*aFq3ѿWt,q?lN?I2p?[w>ÿؓ8u?wQ?XGL?YL9?}y)L?yK8ƿ6Z^?h us1٭/r+G%zi?hN@`Ҕ+tڿv ?Dj񿸈nǔL2뿡!7v|ܿ5]?^Aޤ/.ȿ4'=㿤X8F t?&:??2H[CΌER?e$?BiKڿlߟ@?+ĥ?9?/U俦`r?K?sVZP?gtZtB/#M5\5;x政:r^]?>KTryLyeοWPrRA?yh ?b?0iN?7u޿%~%S?=A?ϙѬÿt^M?ڟR?N^s~?2_ĿSl^?# ?@?nT???oWXXo쵿MoxhB6#?}=:@ v8Rq˿)p2这`N?Ou ەV5U7ܯ?T>x(Qv:?\P?˷d?E@ڿ8h~?:c+A??5zO_4])?.ܴt%֒2?rCa-?؜S?}cz?>c -뿃 8?IB>:10w?&H?^Wdg?U(ۤ#?U+0m?buz俏irt?`%w&P(29? 1xC۰?Eb?p&Oӿ"g@MdLRMLM SX?G:ޠyޤ4ҿ f?7?A_r?9^%d1?Gz!xU?Ryo?0Ћ{]?!?W?̴X?kJM?&YU迤ⴢ9?P(o?W}W:ntjSI?mXN? ͻ%ᚠ?R?h>X?Gq ܿrk(V}7 U0K?ҍjJ ij?)UV3o'뭯?b`B?/NN?85!N? ?ij[ʿ?KпՋ(_-!?xC-VN?.|?ƥ!8'?zE ?|zU?DxoL?}x??15?MB?li?+?>c?gS?]l-?'(@P ?/nh*?u0m?GԿt\bƂ?x?+}=? P;ON] 4@={տ`6~F0{?t{F?ydw?ѳK:^?\FI?H݂@U4Md[{?(%Տv޿U0c9ֿ U?48FKc9Ϳt])Hց)=ߗV?sБ?Upg8ȿt*N+&@rs"yxR?3Dwa*qjo?D1'ſgus?i"?ypWZ?@?LK޿kz?;Y㤿s`?B'?LUQ?U?:'Z?Mٹ,CW?V²͇ ?Y ?kN`ȿ?%?WԿ&!?',?_5?^?ŀ/agؙ5M?h$ S)?Ud%?Ogsr?j ׻vXqܿvkMga?@f6I?wV&?W{A? !1߿^zH\D5aϿ23,U? jx?8FȚ8 6DuӿzwP?Q?^ɷ? :/Βb?W?G!Т㿾@!J{kZ迚d5|40?f]81z?pX-f?HMj˰Z dnܿ#Ͽ('Ycqݿ.B E?nuٿ9B'?.տ[~(l]?Sf 4pd߿+h?|Y?!A?o+?5Is,?2Z?׿!v@Uӌ?ƿmjG'󿩾Zu\lcʿſ20X6?fiʏ?\ z?he_^bŚ)A-^ӿ_Brl5ۿuuޓ? .7`c2Yu?f`^Z?0㿟$2_.?OHJ?$ ?T?6俐% 4??wֿEϳ?uq߬jY@}?isC8c ?g:צ>n ++tB*0Ys9E'?q?06?Qwviҿ>> .'Ϳ71?6$Wɩb??W|7rYAWӿ#Lc7kο=Kп紭vm?;Ԗ?vQE{?„ j\⿈2 i?DL@"򿜶v ?;'D?řwK?${'W׿7*PK-Ͷ?>i^VO)`쟿^^qNbG?uX?L>LZsN+6࿳yz㿆X[b?zIp:d/LܿF{9 l߿>a ϸ }uqEu5TM Is%IX!J ?S@+?+/oX?ȭ1)gc!zN}?w1;ء뿏 ?7+t?{-?u1xsu?P?Y͗t? Ig4;pc.?||{&x?PRlݿTI@ؿa?^*5Mfs*c]ԭп*4(?{8lC쿖yv).?P,ѻ?Xa$T`-O?? 0֧?AhW?aK?)ь"T T?7ﰺz@†VI׿)w0ῒ\tEO~??sAY]0p?Sp,/ ?rmݥ?p]k>¦D?e[@Kh? U?xP?{D@?vTg]?>4?h}a%v'6&Y@Dlh ?rjH'g??iC2x͜F_P2TˣKL`6$?nqQ3i~ ?A?p2̿HgN?en?}]FϿkA8?j+ ?Z=-D?:j@yj1fc"Tq(X)'e`ƿXM?p3_C Jп6t2ٿ\d9࿹$ a@cw ? cg*?oZ7@gu?@kD x(ݿ?0!ۿ M|?J-.?Ed?9pN%`t?|A?XCbDGhVXI?_6*aBp?ؿvطcd%34^ ?ڟd&?ER޿Գ?1ȿ8x ueڿ8BVĿJ {՝Ti :-'?_sP?? 7)?3>J$pw?ʹ?Q:?jVҿ`?+9}ֿjҺ?sy?O^z?#lv?RRo[ .[?{9d?fѿtխѿWbx?Ve?RZ@c>+?⿤OK?Fd?;J?lGҿ<: ?6:ܥ?6Am?Ӈǀ3?үwqAѿᄁv^* ? uC?&rġڿ)4ѿ8zN @ \s!Ì mw{oԷ9EL#HGTѳҿ?ܩ ӿqb?2wp鿎u a?@<,?1 w&?š"?ԷGʿfK91ntNzrŮ?*ܱq? 2<+t:?X#?nLOo? ͌VOL,:oH'a6?P<7?8PFsSZ;*t?) dKv?Zu_Cx?yn??XF"jHM?b Hſ?? ?dW !qI!;DӷĿC/?B h?Hk:p[?=W?II?|O? ?x?cG@(4_ ??ccS?^w;$?y\ϸ?:x?H̿U _bпj)01]f?ad@ 񿏪?'ٶ)'٬5ȿw{R?',6?Y@PӿWa?O\߿Qn ҳ0Z?DK ?H:?p7? 8nc?i?3 5??.3%꿮Fwd?ݿ@Ya̿:g|c=?w&[E@9z*?bK?ilQ? #K?'pWǖYF\տ5]? `04?-nb@A'|:y1뿭N*DM]?[ŹCϿ4ۿſRl?S{|73?I]'B?nd;tL?o=H -?eq?!Xg)H?:?5w;nҿt:չ?5.k4׿( {@?;_*?OܪZ迨>@ jrڿf@h ?z{i쿼2IgF?mmۿK{#N?v]֢l?@ۃh?#e u?Eyt?^쎕?ݔQcJa?ܿ߿smI/k@-8?ܹ?bf? D,?}7tM?VqQZyÿYI?&Q?/A<@?*0y?UoCW?'ָBTwZd?Ȼ9:Iez`?gdǿ^`{9"?"Kڿ!UC c)I)qؽۿ _?<5޿Ca)?4:ڿ5ҭt ?f+?7'E3?˙?t\lV @5#B?o ^Ë{ο9mb׶SÿR-CɌ?nsfQ?߾ȕo 2~FMC?飯^?aձ ?MsHv3?hDK?JYk[;O?=I^`ԁ@}>C?L/u?sm迸~C?丮mԿV.<5^.?'uu*?w?qXFp? ,'D?,eIO(?OnI$VL?Ru?G~rԿ!ع8?ϺgU?V8W?F,s?l(ݿK-Ɖ@^ZiWǿ>]˞oٿZbia?.P3 ݗs?`?8Q?~_?_ͿTX`Ԗj?VD?Ŭ80?.u)c ?+M4Q?=wڿm"I{8?6]޿hW?2޿^$N >?⿕u?&џ?j^B_ݧgfo?SJ˴/ԛF?Heߙ-{.ٿ:UesUӌK [,=ٿF?R-@?8U4eb L?_哄O& G?uCi?1*Q`[㿟*}{?L?xB?>oq Qt?xo,L¿j6b'?, ?7u{z?AbMI9?Aݿv`V4 0? X`&3?+R߿w8r t?!8?أLe?C׿ Wf?8⿈ܦX?xD4b?矒e?dn Xj)?KI?c-[ (ٿg~׹E /?۔?zH?ˀw, w𿸟Q?eʪC8?2,?~`?2ϣ?2C@Do3J"?U:^鿋[QNI?\h{?ZQ)yG5-?(?C-vy?ĨQ,rV?} h[򿪵EP@V)-ItOb*?pC޿WͱݿOO~椿N?:[u?& 4le?qo7qJC?{3 ,H?A K?V??5e$οT?NVٿIaG ?&[п_L? X?a=L?p)M-I⿈f? ah.?2Z3Q߿hƂi_Ep6UJ p+|"M ?ti9RQ?LVuֿt0)% bHf+NZ 4?? CUv?+ߘAԃ?~y[?  V-?ѱ8ο= Ǜ~=t? %?g8ڿXqj~?[zs  ٥޿hW?9/(?:6? 5;1_?X?dI5T?Mˢ4?D ?7uWh?翏s?a?uĎ ?NWL=wU°?9C?ֿ*\J?5Z_BKi-e߷EՃ???I>Req?,lQ6J` ^?1l鹿Qt2y?Ѷg ?p-C?T? {ޜ{ۿ=X?dL*?VO?x^? “53Ŀ"4?WSȿ%፫5?ϱ'C'gUu@.'^?*HC`?F)?B&s@5$d s?h 迴LcQwl̨2@.?D=帿F'b? E? ?i=0]? oh?ۋѩC?>83~ٶ*dmĐ?]RΖ=՘?MĐw?0?<<Ὴric?F=m+пn>?6? ?&˕?(kl56{VRQ?p<@WA@?nݧ?$ ]%qg?+ C?{Yֿi @(? ? '-Ͽo#m3{i^:fؿL5?e3e"gw`1%)?oIV/K?Ĭ٧d?K-9&?q(smn`?WcAC˓bAݿÏh@c1?`u :J$忻T;?sƔ`73-?.&م׿/b`}_A?j'F']&ɖ9/v?y’eK$e#?'*^:??uL{U&qŨ?,r'j?(0ʏ21i׸9#?_(: ߿w俸W(?keC?'2~}?kVK &_&?L5 5ƿ?sV6{迭U%࿹𸺓ɿQ)3K/um=?Uh?ޡ\8HF>?(T;1j?!IP?znD@?D~ݿ+$CӿY%׿Voɔqm!ӿ @*g?~f/㿋ρOzߕ(;>?dkbq?HOR>Tܿ^Z:?ǵ[~!?~َf֥ *˞ۿFTak?> ?XΫ׿Bq?pΪg 俘Q?`:xZ翱@^꿃E#d?(ȁ?l׻y3ٟο6wJb?]R??" XmpQvU?KM?#E`࿝OѿUJHCWH?Hl:0Gi=[}ĥ?L7i?#Nދ?mV$i?V?l)CV? ?h}B?؀ðп+b\@!vE # Ͽ0rÿr}?KĹ? :9Yjʛ'i? J?% YPÿ0}_@LnOM3?][e47RKs X?>#N?2FW?Q ehë©?[Կ+?s-Y"?%xU!޿>=Ӄ?(r\J?`1?E?pѳ?/xh%?DK=-𿳤 *#q>?g0Sk6?8(uٿ[zyFH7=w?p.@Lz0}4F΃f+?Gi&:;ؿw{֛O%?k??_(4ԿYJ'?%_?cOs?V_?'& 5?T?ZѿJB}`տ]?,w m?U" ??V.0?7?[?;Gg?_9;׿HU袹:?'}XVʯ,F!l?X(?3#8?5eh7?0ѿw@vo˿r>Կ!8?8ʄxV(?À?Z4?pZ?E9IqO80࿰ڨN}Β ?WsG?0Y]1 ࿟& ?8ͨ[?[6⿐1u?;&8ܿ6?gIW8I?ǭX69ɿiB?{G&\+> \)?#Y?Xܾa2qI+Jr=w$e?vC2?g&T%?~H?uNY}ǡ>=??ӆNF?)=ؼ8?5?`g݋i?V@k?o6b$؂y O,G:ֿ"p? H݉?l[d@j5?(ՇCӿwRXo.?h/@:?y^5ҿ<:広}-vp\?p#k?ЬBL? gXѿW?n֑Oп>&SN?gk|w?h?U3@?nTk ??1u1)? f'Op!?I|?uT?vh?6W?*0S\s +\ӿ6p?U4ž\^/.?D'CؿƱ? }R?&I?'\T0Z Aڝ:?ou=?\tUпznͶ?βB?}k6?Y2?,n?T['s?Up?X/?l-m?;7qݿmܪ~տ9O'?'N1P?x?k?8t? B-p ˿r4?n&U?ZDo?j|Կʲ&{]t+@V?=|4&?dА–"ua?)B&@˛??0C|?Ӏh"a:?<"忀1au[rR? \8`CdпFu??^SVs->ſ7za? G`3`/J? KL;# v?YZh?˻??>Zj? -w0B?5C ?u+ű?LbR?{ 2K?Ξp:UŢ?ߴn2?)w?;E&?DՒp*V&(Ftu|oe?ެyҿ;k?A"Y:h?(?6C7T?yk 5ӿtWY?s?#;9?2n⿦^8?]m߃!5?gkD?(d5󿴂 +<+Mhd￱D ##z,<쮋}?P.LUi $ϛZRb]T_*E俘|?@)W"?Or ? P ?J+kJ?hx+<忏'Vl`R]pTXֿxz@N*lA这CpRG1v笋?Xl,rVz]?Cm'?)T?)h?'/Mac?Ƒ TG9?!W vGO.? @?lvfedx M.?` ?,2;?* ?Od?{~+Z?TYO`e?|nuG?+8\?1>ڿHcT{?y?nu?e7#?M93ԿJEҿ?n~%?.>=7?L4^:쿱\ÿQEڅ?h$]ˋ0࿡_ʿg o?]I˹?0jYR@cɲ+/?+õ?[쿿!?#-f&KYڿ(s9-o4W?_?j9 UڿJ?]\p|°쿠ݙ:1"AOٽ?ozn /? y=nEW(sA}?L2ezaci ?ޓ~?ݿ<6?G?H=Z`qz^?ۜѿ r?LU*ӿ?k.iaz@ xy?b)J(?L{p=PӿK}(ɱ~E޿ה܉?iB?DʿG'ńT<ÿ1ԿE2$;?w$迒;)1?g^?/w?J˾Be E?s{-{E?Tr3?i%G?EՐg?\d?(+hlJ+MD?`ɿ׀nT? uT?psOaoi?UeK?iۿ?BA?0yH?"! 俇H qc@,X?OZjNk?vQܡ?8PZӿg?ͫ򿋯9e( ;k?uԿ,gU?3gX\@yJ(/?*W?ױ׏n?kbV?~UacĿ&?^M۽@+l?~:?@ss?'i?^*GͿO?b?&;NJŽ?:m1?ix?ѡWu1@ ]ݿ@E|D~?x\ɲ?X彁[?rb! ?ZU˜?\fR?_Htl/'?]h??LCa͍P|fBֿU1?B{?:V*M޿ÅrҿHZө꿡O񿋰1 ?Mj¿,$?'^ƿI)|ܿZ?-Bܿ% 4 pG?Y?FY5DR޿!?l==ؿxa07-?ϸ?lKOQ??+j?bJRH@:YyQ?o8~ޖ[hŕhٿ>ZAP?0Pj*gxW*?+%=?Zr ?~V?WYþ?4@#?T&z[濉˵н?1LܿWiڿ2~yPd7Zt H?>pt&?V~ ? b=ۻ?2? :֋޿]5[?!t?*5LbrT?z^`?@Ȯ^;m|O@TB_L`?0_Y?G?6BZtHڴZ?FYLP?Q3?0)6=ʗFpǪrj?m޿E?y{nr*xzRٿ- r?Ί?DMHʿ(ĽS!d/?9ik?)w:aU$\aT?Z ?X/EͿYvX,+?iڎt?cS?Z#8vg_\N?yZIV(?8l:Ϳ`?K6nῤ毦KĿ`g>dV*տU?KX4ЕJ? 9۟;F?48?)_p&?hAj|hsJf̮a?;֪;WԿ|_޿{~% ɿi a'ʿP?t6 M?b d⿓ :qEɃ?nn'G??߿f*8@]A!远` ?`ǿPқ~acHC2쿖/?ȍx2rE?Z# ? 2 J=T?̘t`Dţ8?/X?=tQ?7ii6RӷW@.̒?(!?{??U؝k_H@K?\ߕ'3fv?nB2"Sqݿ3ӽ9-k B߿30*j?J.ʿNY':?(_+{0h?V%} %#-0ց) ? h=?U2%4¿yJ,bC,Z?C*ʞVrҥ?[{N7?p `ͦ?qk?:'l?3ؿDTsu?Kw0?P+6x%@QjO?ջ0{hAA?/?荹?B}?˯Ĝ?M{|@u?㝶%?BX?QQ? k5ؿcnĿw&VGd\?pq9V> ~֝?yZG|D?`_qIܿ=,WfH? ?1A>~?t?LzKQ?*u[@ *uG?SNǿy⿬/Jg޿F*kC@+B&/X.^t ?Tʄ˧?mIl> 3?'q '޿1I·鿢Pp 󿲯6?vԿLhuV?\+$ r%] L?T套?ѿ7XWsWϤ?ڇWw?{d9?۠ݑOA0L?>Mw-gw?>B?ynij?lCAHY? 9S?^ ?l5ſtne|?d0?paнp?0Ts'4_ 4@q#u?uB?ZOU?i̚?R=c?nN?)C}?F?|P p@ -P=)m?N?^3%?U#p>S|]@~ſb:J???Cpeޗٿa"-򿁥)?; M46})h;?\B;m $f`?-YF^P࿒m⿄C))o*^?_|B~YԿ޿6JGtn![?(Կ|FQҿ4?x $|޲R+ۛd?ږMj꿡|t?_Q?(R ]L}B!ĿPtg?Rkr5?ZE ӱ޿B.Ü?QRdѢtD6f?) i2?տ< DŽc@пwyAZPc|Ŀ_ S\l;?F`׿.-V~AM?\3?vC5lwM?U2?]T?WY#?7EsdʿλﵿH'ɷ=1@6!Cqӿd{?2󿓧{c#']ۿ?1ep?0?Zʀg?|ZYDǿa о?`yݷ1<:@%H|𿟮Nc׿qOv%M҅x?KkʿC ?@f; 澰?CTSU?k?Nˮ?"΁6?5@,x?k6ı _beқCLR!?ƎEmΈI?O[?׿>zo?-NUàq?f)?%\zm?\vaiAJ??dL?oY?і񿧅l<ܿ8buٿ%F?!ڐrX?u4ֿrT+j>Rr?WW+?)gP;zǀ 0ѐ}RHV?B]4?r[')Qٿq_kL3?C:"Ud,ƽ?eҼE?úӿ sEd4ܹ?&c&?FZD?H ?m?z2}`򿸭)?&Q:bji?&H?F] F@j02뵿3aݕ(X`n:THa@4@@?jv| ܿYȣ?pK"?b"*gݿzDi ?:EJп>bZ?g0t?SV,?F I?Ȏ?P@?j?5 {F?V0?r3qm={g?Z?KtdǿNBy6?W?c x? L'0?'?4^3?Ӓ`S׿K ;?#'{ѿ^4p?,+?Oj?bP:fEy?l^q_ ?lh!P,ĿQ?gu?` *T뿓 WG`|n?.,?v ?&Q˄?{ڡKӿ{R?NΥg}[ %%пE?Clm;%ݿY|3 Ss=?o.˨7?lߦ?'B??TZ:mlͲuT?>ٜՍ01 ?I/?8,$|?h?<2pY5𹶿+ﱿ7ή??nXi?kAf@(}?s?1u%bwS{p'?5x/_?ۘǿ"K?`?qs*ÿ Pv?xYNj)Td4f?_*G?Ta9?0v3E?|ԡ?h~]?&`?O㓢T?6 l?,.r+ͨV?=?L<ܝehqte'q+ej?3pA9޿X=#$W?+Z0?!BoTbw~nN~vm?0?1xgۿkl&A2|!X㿫#?s#BWd?4˾)׿!f+}?SsTp?jc?DEym7G?3,B"2Ŀ Rf/0˨?iʟH ݿu }a?9Mf?ȿ+GܿsI׿'߿U?*w0ͿQ'?#ph&^޿cKM?bBB^?$bkk|˃\A!5q?˞L{Sl տ^8G??g'2T߿܀>?$㕋?p/G;XPԿ~8߿KlT4?:љpvq?Km ^~_iP`*QbH$ށ۽?;ٕtl̿~NLi1?F.SɮYwj:n_j?M_:*gaտ4??p]@O>i?xSm?#}qۿ@^? Gx?!`?SR?éza?Ah?>*?sL$@?ZR|œ?#tѸ ҿCM?j;ҝ/y,_j+R>4m?7J?jMl?U&q?mxUÕ(FC?dzg}Xʿ, ϿwNEq?vUk?$?"j*.) \\@=aZqu?9cۦ?Ծ4~?t.?FhRX?L0俯R?+]࿆9^?Kl騿9uQ<@|i|?JD-1㿚>MQ?m"8FE{6?Xp?!y'Ȁ?;&zӷ$3S߿qݴ"!?m0IY?C|W߿HEԱj߻?,?mҢǿq;?Ɇګ?2,?ĶtʒN@k@|y?DE?W\?$*l@b6$͞D<*?GpgVnYdZaH?3X?-|g?]-.׿ᖵ?>z?2fn|Jd㿻iJ++u>g6}GZC?^kNPF}e7l?li+?q;߿п]6?{ KпP Жf? @ [ ɿm$:? "mc??tF?: "=bqUӿؿ=u?2hH\ۿ 3T?@ ؛}1hq?G4K/!?A?%(*?YI(dn eK tпa -?r?uVyrĻF鿪?9b￞3K?2^k?j%?Iʣ_U87׿Y?ӈhsj??,X׸G >ܼ뿍;;?@+fu3g,7|RPȿ-?wٯs)Uy {b@ c|/*Bsi=J5H?=<ʊ\#1?jh߳?e(r? $<,ӿ?77 9C 9܍述ĺboEWg޿ꇏ?S5?V(v? f99""? |նDb_ϣo?_?n)?P|0Fk?Xyٿ!A?`|3ɒ^N^`@?_!'x&?j2俪4!A }~?Yl>ݿ"=qF'k"q? ?AoѿCcPҿM[Pf M\-?[u~Ϛ?p 8Կ3G?d=m?\Á:׿wsdu迲ѽ2"Xe?έ^?kk??wn?dX翩‡?xT>\:? I+7zUAϓ?Lɑn 6 }^?t @*8&?DbRտ^&X?}^2m?ײ.%@>Gg286m񿸯+v)濤.ؿYDQҨ?j8?ɿݛi2tvkѿQ6cZHLvH?N|?ҿ~^y?|~C?LQ?$U+?DJ;a?oe?c<ᅭvlo6-?4 ??6z޿eSῶ->3޿TA?e;?ڑ-v??`H迕8"q+,i@w}1) ?}bӨ?U?Tt+?-vt濞S?sYmkM?!Gq?2C?]h?u`?!jx?^{C):k@= [%?=+ ^{9ʿ۪j??Jlܿ5ԏn/j=+m]ŨaK<#ſ-C?a?K.~{B<྿iв?ت?\3ҿ큡WFx-⿊2wͱ( ?Dy,ʿ!gj?[ s!e+RпUV5? e%0'XL+Egǿ]`HIR:Ýz崿,X)r?8ӊI;h'.&߿+F ݑ=1#3?u_r0y?I^>>?2f?)_ȖӿI`"|WH\c*g?<[0 ;n7BD $lz@-GT'пx ?ycԡ?Fn?}0Wm?.6;>;Xc@lmY?"?v~N_ ۿ]ɿhj?Y@R?§ ?+Dt࿟Amw?XDVi1[۝5_Y0ǿ-jZnmS"ֿD)⿧I=@/#kN:ݿu忠ܶ-ӿX^gzw?J!?Jl?/ӡͿN-?]7f<.??&8?} )??%d vݿU0?ㅸ?7m sͿs ?b_s*?Bs-+.K?ܣy}??^M?G=t?ʡֈLWk^q +mjEտu*DbS?<7]N?t޿pQI?[W>ɿ~%?&gпbY\?C>~y >)?P04?}x>?i7˭? u0hir+tRoi]˿F3ƻ?п Zugy?Sؖ?? a?;cٿW?&@J?ಟ?U\q3b?K0sw+uIly+)e?Q?WGN?2,pٿڰ^׋? .^) ۿr?W#6wan4ܿVl?e:y7?K:F8ҿ8?.ǩ?&,j?#[?;? 赤s[G_T?;, K?.;O|4D$˿A?6\V?<F?e!G\?} aG?ƜX⿯`?~9?:˨S? :+@ܗ"Fs?Q?z"?7˺pґLͿGpIT?(a\w?z[?%?#S%Ϳ a?|p?P7@z3Կ5<7,ȿJK? S )ۿR?3@d@?d6uX?곀7?dE?h \׿jI1ƿ%^ ?qۖпshZ[iM^?mVAx ?|'?=y{?V8m J?1|QcY@D/a9wiEҿLٱ{6?{?hRѿ)ۃ?Z7 1?Ť2?Z٫Fk?;`?a1` ϿOKٿٞX(R俒IΑg?g5?GȿJB ܿ^\2?X >?ڨ[VN-?eo8Yv""׿*1OF0"žX3ٿ8bL?3m6L[E+$ˮ3@gNh?gQ 8?ss7L?9j+?%g8W׿g?<&?ʟ?c?㬗?[@}ܿK3yFO˿AiB`sv(E&#GO?6lҿ:5c׿^(ѿSA?Ϙ?_X?F򋿅Z ?BX?#% ? )?V]A?_!?H:b?*އ~j?(8? ? |iP%/ؿd,)-ؿФ俘ez?|-Jݿi GB쿷ݫ ?DR@}g،$E?ν"i?]?va޿ӯY6|eƿ>ƃ?/t͏?96^M/ҿh6?<`P% 忏)g?@Y?n?>Y7T:.,g? m19?x3n7?.tzPٿi|uOJz"w?sn1ܻ?'<)i?{R?8Y?Et!?K m?=iX\`?MkXLѿh]Y/?v,z>ɿZ߿_&3|W?bV{?'?hq[?u(5?m:{?( 0?-?K*;V?oS~?fGۿ~*ɘA?P$?뫮2a^!?l?g?yÈ޵ɱN_?3`???뿓ܿ3!<ܿ&NKf?l_Uz?[0%?$r?òq?/N?^Y?.wNB??!e9шҬ~g?c` ?y6X ?H1#翱^Կk٪?{+KJ(Ŵ?B'x?5Sy?8ggT?md >ٿ~vfAn /#?Ub:?<2B=?]'#Ŀm ۺܿpgg&?ļ?§c쿪]xRnP2?bj?5Q*eAѸ?QA?ձnI?ƉjXۿI?*xF?25|4)?Nտ0i60?!4#? ;tпk0?*a>?r}12*@g ?ϩ?j\?+?VjqݱCt~ul3X)NG3DT?41Ϳ,[ d2`ѿj9O5%׿'?+"2Oੇ甿`Uo:?Sr0?z?K& s?`D]?,N?|C𿴺g5A?^Q ~?N8&ƿ\W1xW?9#W}8??wؼE^@ZfC}? 5W?M<\8?Cf3 8<֏/?u<*ؾ?- ]7bJ쇫 [?K?GԿ/t?lèZxNz5iPݣX#?v'k'쿉LI?Ot?2GZ?I ǿ qC'?zIx(տ:@d[O׋]!?ܔ.WM ?"ǬA<9/|?㕎j翰4;뿊:?L$."y+H ??'m??%z?r쎭?hI$ֿQE8ٿaO#?X84|kDo8?u_j{?Ӻݿ ?d?I\\G?s!ݟ?o'? aC =ٹ?N =Zҿ&?xYZ5?  뷿 1$8X?V^?ֿA?Q4?&W濳{ ^ؐP:? 5p?@5?o ~ht -FDM}Oo @?h;P!ӼN뿵K5eiܿk`?ITf?NR5׋??%y̤2Ϳ;:q P?L?H(BDǥ@d]7blBJ9Sſ`&{E2H?K\-,8WPwٿ&򢫏ǿ&lӿظ3?qY.h 5޹E!'B?X$~ qxN_RӿIO?d>\6OGCj_ѿzcܖ1d'ѿ|He! #(.x?ءD?1u.ei{,!?7SdݿʩZ?h@`I)[&?!б7E쿗c𿚾Ѥ"1?txF?'?VοAϿʱ@r8%_?v"\L@~{o@!rS?UF:@Iy+t:>}?k+ ?ː6?<1}?@'㿛xh(Ϳxst ա}i?7բBj?k&sؿg&ɑؿ\P!XWks? NTB/?O)G?￘Pyΰ(|HNT?X?]ˎ۸{7)Zn1wyxܓm?v?0PF?zNk̿TfpP..ֿ ˩&I?;S0B]ߘG٣X LW;?9Z'?\o۷?tĺſ| k^?T{ҀL[Rl \{=\?7n˂L-f[?"u|ܿ}ǿ3?(^rz?hi}vyS?f?͓75mDz?i(?QiPn%F,??C, @ǑRW?æNѿḼ?m $ߙ\?yN_Z?&??>jsz?ϫJD.Dt@b?x('?o?X]3\&?58M̸9-?#<ܿiPxb?HqbQ4?ܕ=x^?xC?+;`PC>|G*?KV'?,6BԵ?+N(wͿ&#??_XtƻiPovl? YX?]eXk㿕yuֿә|?̑ny%ٿKU)쩊 WvU#Ɔ?y]%?$*? ?fCӴ俯]C6ο4!ҿF9r?A0jR?]B.~?S;Y?>,B?"C?!s?2E_?P迚;Sw@Ͽz^Q?~>?O.@޿]z蘫sklH?@eb?/?>Y迩p} /?êyѿBiV̺?b%7)69H mGn?RxE?n_E@0»omT|?G 俺uh?GQ%@Ԏu?pFB?wc?=~b羿A;*?nyo– ?l?zk''h?CBc7Z?׆h?8\(e?y&~t ?F7\=ͿF͈cǿXBH"?D4Z?wx/ۿ cG?(H%ؿwpiԿn@;A8IJB?5n%?P7ojhp?G<_?B?A 7(p׿to[&ǿ1}?Sިӿݣkv7Qy?UCXumMUj6ƿg?g.@&xԿsThnL:F6տBP(?GٿX*| ;ϣj𿲰w*/ϋ@?,w7?S*l0?֓> @>OU;޿H<+?Y566Hܿ8@W @yfW#XIXpܿ]Jm}칿 TPo^ӿI ?PP?LSV_DHu?H;K[V bM?s7<?o<Ͽrd@'O(\1=ؿ<1?8:R?J.P{{n?xWP뿱 ??:IPWpYA8P?\p?1!?|]?wyU ˿;bEbP7տ7$МIG? ?tcBlCK?uNؽ?n[Wؿ^l @J?IqM?%@?8JLiݽ@7(Ԃ ?֏2<Fja՝r?PTvI?Vt?w?ثdz]#cܿS?ISrZ?w2@?R=ry8{͈?u?W m,2?#1\?@A7.K ?I_\.E)Hhпޱ,?֐vyvl<3UͿ}:ww9kA?Ű8K¼?[1 o-?[]@kTpxv?ʡhAka￵ 6п8ƿpVN?HՕ 24O?$T?B]Wh<6?ܧ?˳ B޿>+ !?)ʒE?+t꿽G'?1sɿã3 ܿg?Pvy?7G?-ݼ[{?-OӴ??{rc.JF2lwѿiS?:?v_}Oۿt?=3uɿֿ(?4REп:~宿qblAd8)?у6HBhPɿFO|~aЭ p?X?}?9-8?yImF?jsƀ?D\JٿN8'?koDPq(w?^T"%Q??91{?DCBt ( ]De1俲N䪸?*~6?m S0Ë?_?hiM?c?jB?{4?ԯ>ɨ?î!q/?f?8Ft?{wfY-?Jy~wkN9ܿH2쌚?C]q?S$C?;n?hf`[?%EV˷뿳>zmG?v7 g??óEҿj? )?X @M!Kӿ?X?F[_M_jB% ?!?s{tA1tBQ?=o_Jp+2F?WGĚN i _~?.y ?j?j{ 8׿Pׁ`?%/[Uο/~V̿'& ?phL~e?✥_?lŔa[ޤW7e,ؿ'O?gCbO9|H(=ʗֲ?餅O1a.? w ڿwEB?=6;?U&j%¾?<@?࿛&\ꏑͮlV???vژ 簿Qп#a2⿸,y'3ٞ?Å뿽c jϿ疁P0OҿN809C@Z?tT?%qBǠ0}?zC\?MY.%?#?BԶ?Y.?kh?{L U@ҌO&)57?ȷP쿥 |>ӊ(PD6,:J_L <&%ٿ#,T?q]?l"k(?X+ jj$kOk&?rlxf?;oK:??T`i2¿?ԑD3?@Xܓj8?Ff?&6aZ?u}տk%;ZдþP? a?~厔?ߕ5amy/@NG?}Rtf?W16ݿ@]޿o0EF^I~!a`u?cߪԿeP"A?6(YI?cĵ!տ`NYF$t;#Ōƀq|=!?g?67(῱O2+?Cg\?fs?FKu?TZj.Jۿ}:?n,+O_6):?98M]jc?Q?lev)ˮ{?M ؇o?S пm?=!'cVڷ0$$ۣ$?>m?4Z޿w?Kk ?cۡ?{$_?~e٭z?\!*jupqN2?V8LgG ໋\s?=k@I DB?;yY? ?pIX)? q4cl࿍AH,nnMG ?<4<9_A?xJ}%?v4 p-e?|BuTֿܚ???20? ?56?e5?7=̛_?2Ce6?Ƿ%k\?` ? Ms?,O7%?%2gnؿ?.?I@>* {a?ݹ:?SK5;2w?1n@6?me? s{rj?pR"vTQB!8?EIg w￞ײۿ0`??`spҝ/ֿH\?Z!\?v?TOҿ50G>?%PŊ?JK 5܁?a2[T? x~IJ&m6 aI#1^MEN?=?[w`?|ͳ?ʀ-B@78?]65m[0ѿ6Jt$]M4u?EWx5?$N?"G ?lo{|ٯqZ?_k(޿a L?5{jr?*H*!?ٱ, mEB?7Cܿ P\<-g3?ȝG#ҿùN.2,F?(^׿=Ucʿc^?kB|?9HKd6?],Z蹔s쭇ݿe ݿٱU?? ?>U.c:*?|t͡?Xx?EQ$RT"hS?FDp?/ <(?Ӝ~?ʆu?D]+F(#?|-hF?ugs?Š?.3ڱ? ?jʓ?)#?`x^?ˬH?MhA?D{^?Z ;A2 ?5SܿSM1z?ʼn'¼{x>?HA?Vf<Ȱ߱3x8YPX?w濻>&!;?qCN%@qOG?U0@? Mr3Hܭ?Qd#Ϳ!{z2?/ c?_?%?j?M(4b?@'V~{y?Qz@ SA#?/9ɿ%z߿L@?l\ [L)9⿦Y XH=?-v ?CR^9GQVf@Ħ?,@aO?t!4?.M<@)6?$7;@?H%&?1?2=_q?Q,n?` ^@zYr? ~?voKXVSFT.p?Q/0߿_o?>r>&H=/fT 4GB?0G ?=q?U-?SKH?cƿvI=&!ǽ8Kտ ܒ͗rD?R˸?VҿVg@SggϿ ܿ/@V?<+%u?u&6ǿCZ. 1濄&B?K䠘q㑆 $?|M?3u尿TZ Ͽ>?)2fԲ%*?vLJBsi*}F'X%?/})$ L6j?j%aӿܱON?Y$P5z?iU%G>n?zF?B< Կec?|NƵj쿄OŪuy翑}?a?kP^ տdȼq2ӿn=2RgU4wEzr"L?Ej$z? v O,bQ?ů?OTG߿P0qz@VR.&޿Cзڿ4 ?ާ?nJ\cVݿ8pm?.Exڿ"iitc??"E(zDP+°[Kc?K\R<Ŀ_0%׿?kJȏݿg,|?Cvʆ)bſK?GS!? ?*6?[s\-^]׿x1LcVb?4@^ƿțŚ?iy9?  п?2|/VI+z?)-?khd~?rü?[?J+X;!!|??7<@m?y~?◿GN6^YDտCn@#Q?5Iտ FAQu?UnOP?XuއHx?.edקT˿b;?c*^p%5v,?=w (pW_?C/gX?MYT|o.R?{#ʹw̿(̕h?9ӿG?1ͦ@ ŮúR@¿:*h[?ݘJ?H>әL?L?exIb?W1o=@R6࿥)?^BogK鿥?04?̣ @֍$7C~?`?{K=fڿt?2@8zٿ>?%^Ԭz!ZA.3ӿTA?8fCI]?f{z7Z߿ S?0)Z?g`?Lفp{I/Q? Z>Ste?t{?.ˋ:?3KGƵ޿:tP_ѿLR"0?T//?722fG?ۦ@e?ib[ ┭?$?~8e P?ͯ|l7{ ?Ս?[P;ݺ;zM?Bat@M(?̀俠3s<AB](&?GD"r? a?-󙕣8V=j8'zkvr-;~@uG2?}+v.>+^9l?2$=[ۿ/l騛@xj?1=ſk?5ѿvV*?% NR?d1-٩?a??Ɨ׿I/迆?dٿH׿6Dῇ!?6lQ?/?7Z ?%;Uj??'W<(? *? ?w_#dm'?)5?*㿃?RͿ&p?Ŭ2 Fl?R)I?So%!dtNW] ?U?neP#Ḭ^2~T⿊ldyWu㿭5J?Uxi?L%@?PJ8?ߝWA߭?t`G@Z"* ?=?BG?Vk $f2?*" 3Ǹ?:P?Y`㿍8®T$?׆п~7Z@lBFծ^@; ǿ1ӲHῶ`Ł?쾉Mݿɋi?Uӌ쿋tgV8?=h?b= ?DI?H\Cp( f*-Q?k{{○ǿɝ[j[6u,пR04Q[SrFgW-׷?AЁ|?x) ,h5_?g?oM+ ?KEѿѫ Sląt3O?r޿s%Z?:k Աqp6$Q?U*dו꿾09??9bY?Ħ 5{?lCͿK#qƿzhaoд^@م,? <ѿb3?(;lb?yLh"eV%R*0 ΧE?X,A? /,2\mʿ J؀?XQx*ʿm{4?@(ϰ9?:UL*?-8ۿRƿH0 e}mc_ʿ ?L[:r?B ?wPf_;6_ܿGw?I?;ao?4cNB&?ә¾-? @V>Rv?\߿Sip?-s#]m?A׿C?tf?XtA-(꿁^*?q2c޿HBZՉ5G9!?}ȣ?wRT! !3P?|.@!ЗOo@#Ɵ?G5?#=:?6?ofѿōF?qꤨQ?W7#XX@Z6;/RJ?.p_?ỗ?IhοB@@]KvР?SlqpU3ڿLԲĿP'1mv?8e@w菴?a#t򿬊]'3rr?RpF͹ۿz5EA3U?T?@Nf?$Xcը?1Pm?Y'6yj=?WHt?J-mm?I/?KP!%&&J?nBN?Žο(41 D?(¿*w{n5ꬤY";?5[$"U5?-\tƘ?1{@C"PT޿gb}ؿpR5?)a?fU^b6ʾS?J?Q@[q- mko\+)?qO%ÿMT_?4K?dB@0r%y:rɰ?==X TՀ)I?)߿*RiѿzF7?@.v?ϒ.?LҖ?3MZ?X&?Rr\?ó$W9?(J4Ә?F'4jāe?|dn?@b*IS:g?t?'п?IR'i:ڿ0?=DqoqQav(}[dk?-?h`C?7)E?ۉCuN,?28?-c?=1$?2}?ܴNkVpb@*RlL\]?Cu͠qS?|^yL?e٭Ϳ)s?RyL fM?4c?$ă?9L#ÿkt E?-?6Ft?K[oT|?4! Aֶ ?a$ 8?AM]kΖ~c?[5?swVb9E?+ed? bY?kxTa?Qb%CbH !RNolg?Sr?( l3WZ%r?z.E~?t`' ¿ =?Ś@I?ZxSl.LYa߸ĸ;H7ÿBl^?Ҁ& wCOqĵ8c?+ſĜ^?EbWAg?tt ?eY?(J,XX٩?@?#?޽?KPm?ԕ!?;t?X7F t?/A76҅XȿZJq?ښ}޿n V-?IoS9}y?Ι?Asǿj W}X ,jۿˤVjܿ1ΌDߚ`I?5*?кfǿL `x,ǧ?SoG2e?fs$oR?Te=?^(˿X;wNP"5?oѧ!?#9YS/Bwv ſq ΘOG3+yeC[?Lu1%\G? ֿCNῼ,￰ԲᅰՆ"|~D?7d_TO cX@[%wA?=` ?˗Q޿'z￵c??$V>ڿJZ;俛13?#~Cwr\Aβ?WOM :>oҿ,{?ŘE?~W?w,3y?Cl?+^?a#?\Meg쿯2 @ ?^w5 ?>hlɿ۾?w|f6\T?27uHXԿcg )@D֏ῠ? ?;&?y?WhI?_2<o%+?Bl@0S3ʿ2Կ`l a9Kӿ%?'/TSڿ sӿW=eY+]?>y\ETpG?K'A?L-'?}G?KlZ,)??ԯ7??2 ^?)\}8$?Ќx> +⿦0r>?Aݳ?*7 _?f;ֿӁG?]U2㿭Uȁ߿=Tz3?S\;@{^{?Hz?ʿl5S?n^п^wQ?7?}vLy?@_?wAh|? ε?DS7_}?Bxtܾ%ܩ⿄7? h;"ϹB_ڿ`Rwd JD}-0?9)a`@?L}S?/ľ? ? }!]?cK9Ŀd?1[?!rῪcL? ʍ/ my^`@-B?5jaN)C?6R?1V3ÇvqBRƿuNKHh?=PM??/R?JkU\RYxA?f cp?,B?V)?g8Şx@,`?K ?DsYٿn0k?&еZ# (8Z]-{?d"rSĿYu2?9䔶Yo-?b ?P?qqҿ8C䕿Z;B?HwK |;?Ô? oi?kj?+f?c*`?st[{JמXMpּoQ?n?OeròʗIB?G~oW?Ɔ ?(! q)0ebl8?5d+?9D [D!a?8aͧj?RzOmIt3^K?X;@ |?87?8^2UKdGr?sUc׿Yk Bee?!'IֿaoֽRYVۿeΈ?$hG??K]c?5o"@?c$z}M]-_9?v ny<0J?U пPͅ cp?F?xtNAaG% ?yTZ?x?}*g?Au%?U>^ע8{ӿKaE-?-f`0fH@_g+ei#O ȿomqY'?C?ߊ@i\E|?vʿ3A,pUB/hSގ?&Xb?l;?7?H?J? ?]!.?{ !,zg?{ _9?Z GпHڋ?`?&= ?M@3rX?*j?WPUCY?"š?.?wI S5_6?fQ6aܿʺKOAΖ?$ 2cgJsQ9?Ὼ$) ?α?&ʌӿOMS?>QKlov?)?W!?G?l࿋WGUYc߄}ÿu 2?@v>?"9N?q?F7"6?[@ ajݿV7r#?lSjP? p?:î⿣=u@(mM?kͨ@<% IkW/ϼ(?HXV]п-!׿hiٕ?h S? 1 ?~:y{-?S59I?Ta @!35?Cʿ"061Nj?"g)jFa?^J)A,e$b pLk9?!P|~m? ѿYxefwҚ!/NR?d$Kҿ; "ֿB"8?&:U?$-cN?5&m?: 7?H b#?-}pW?F_e S{[@L+%@qlI?bѨX9s?=s?5r+\C>.Hnngҿu{1=7? ?w{gVsV$n?Zo@`?|}翼Qts?9>y@t.9WtԿAw78޿eB,tqmsM?؏6"?/3?Ӗ[?_Nqo9WYq?8@`?w{迎G*O~5? ~9n~ɿ~8QVɿlK!? ؿW:j}e vE?umE`8?rأŪ7g?>4g>׿C?P5e?~W70ڿp?.'?chτ?<Ѐ ʿba?#p?Ry?[lpqr1c?,Bǥ?9E %ݿ쏜B?ݔ?cFz?T]?W@G_{?ìay?vH!z?'u?Hk ?K? TUI OֿK^q\c^`?̖?x?L8K?y9?V ?pKuN8)yۿW'?uH5 H߿sY?f9Qa?@8E?$A+?SiWnPC"@^q3ڿtA浘?_Sh?ugfa)Ohz ?_uuZM`?\F?)9Po?T@1wڿGks?G;dzEY?ddn2y> i7VKrĿp 5ch!Som T/,/L˿ȉ)?0?G '?BF,Fgi?>#\?ںt@>򒒞?߲$?*?iF?D?]\^9&?ZcU?Q1.#}Q?r18olJ9I?ޝoߏ?Z8s濇z9$6A=gMO?,ecbwPct`?v]޿dV(0?t h/wB¿eK@5[Ǿ?!'Կ8Y?w!Σ?. Tݿm ?ژ_:d91;ld!ҿ!_?-ݡ(m?t:ʞck?%YYBk:M? ?g?5?8%j?\hK/?g1 {保}Aw?JP;+'߿"Lԩ?e?ە: ?*ښ(a`͒?W8x>?1G6?djῄ>lY?;{?Q1U'X8!$@翧UBIrIL?\?Ȃ?$?B?_b,x?f~< {"h{?SeǓsRR ?M2@-?vWտ5?P;,_Կax? ?90?Y+ gRg?lrȿBRvſXYW=te81EnƿGLrz ?.ԏk̿d"gR?SFǯ ?᭎ʎ?[x'c%VeOԒ{ۿԿ|5ɲⱆ6?NVX׬trD?ٿ'K?3տڿ\dc ?.ӵ cz.οZпH+ ?V|?(i޸fhv;?䚫? $CW?t"~?ÏQ7꿯ֹ?`x$`?Ck?k Vֿ}l'?&eoeտj5G?%MX\ Ʉ҃%?7 ?΢:֐?̑^߽?Gϰvϧ@E?: w3@ſ,}5?oU?9fտV^¿/Eܺ?Üayÿןm?_7=D?MH'?v=knοL喚aBϿ>v?*?*jb࿘Vګ8?َL?I1Q6r| {?"F?w]G?!?Ue?\Wupj}`?Ks¿d뿘=?%忰h꿺—{?MM?ؙp?Vf Dl?1\,鿑dH?lY?iźhl\ H6EJg?:[ l㿖 \$r~?C Q?h;?8Xj??`?louۿMh:Zi?AFi?6?wb?mm=O`?%s?&J9߿=B?<*#|ƋMᅩ]:P۲?R1A?l>ӿi?hGCOL@ˏ ?ǽe??vT8I!?خ n%2[K1׿29J|Ի?Ffx@*0'N?:Xa̿sr?N{?ak7Y?P?1\1?UБ{Cp3 2>%?mX?шXψ34=Yξ_kvOUa2ۿ~<jxe?Qz/ix?RADS? 1]?S[fտr1aƚVſI}` _ńnd`C?7 _6a[=? ^#?`K"w>2P⿦2ſE+1?553ۿA2=(zzМUa@0i?=?C2d _?L* '?řYY`99?y Dƕo!*2 пS접Y}Lm ?/ zU'Zg6BAἿ $ݿbpWѿ6R^]U 0/5;?A;U,^|@)b+`ǫZP#vϿ]32X?q2< ?Es}ӿȋ?w> <ޕfT?9ϧ?:iz ln`?Kñ?A"?-}Q?}ݿ:$>/罿ָ߯sI%mn?w|"οlEGs?e ?!i꿨59r?oid?JSXu?U)LW]N,\7|8k`bP~R? ?>ܿm,ü?W?dd7'>NvUT&?dM11?&@Q'f:V0V? B:@?5?/t(??p?`{@o=C?O@E*ǿ ?9*l?S2~Zkտ5;m? T?dwW j鿗Թ"?J ?yc~5G5?RHc?_?Px0?EUZ?ԅ?R2^ݿ@8DPkZ(k5r?}Ձ\?1蛗 sh?LjZ?} ޿i4;MORÿV!pVc>?+,)?X03 ?0Cy{?ScN?m?;i=c?&e"F4?``ӿ>g|?z~?}'տjxo?)w=L1V[gC5H󰿥rAI83ƿm6?"l/@M]:5=NZ=ۿs/RO&2Dd?-?cFo%I<_c/Y*?Ωy)]?8A =?iT?Ss9?qLD^ؿUؿ~ȿ?-ٿ_LۿD`~Y?`)Iw?߳(X?K?Ӄ?)"?7bH?]H iwOjfIe?(u L?gҿ ӆ@ RJa??mp +t%%k?!JU?߿XP 𿏞CkbCfSB?.`?%>'ӿ?R LZ?N?+?6{S? ?[qĭ?#6RM?*p?ňi?%zy؆pZ?Ę?HATnؿa ڿ{?&4?j?ۿ5[?@r7GDVr?Ws?+S+4?*[@ߋ?h+"b?ʆ$2?$'ڿN@-xw6?ca,xN\̈́z#'qK ?dC( ?ޓ?p]$v?zt:Q\? kؿZ*%?30vsпjIlm7"mB/?x8@H6W`V?.z?L_?`Dr?*`HU ?ۅ6?sbL?HMv8Jۿ} c2@127r;(te?:fmv?[%2iZPGz?3}?s.?0|տ_$G+r^?`պ?C!ҿ. wFZ Iۿ9j̔6߿kJFb22@m^*>⿁4?UL4?q?s? !6ҿ#HBVq?nS?Vɴ@$VF?9J jn?lӽ?<꿴܎EX͋sѿ2DhA?zv?OI?4gΪ?Z?2$+Qtk+?C 5v????IrW3OĿR?Bt?xy?,jZ?6O{?@x?vXDjmnv?gJr}?ili }Htb?Ph Ҷ dֿw^ڿMYE?mBP2Bsχ?$JBśտurҿs/$J? +oX4?;D3Tڎ?N\XV9x.ڢ$?I(߿51 b?7MNٿ0Ə=Ȇ?Gvi?4[2.%SD`,?P|w*?W?Q*5?3 e6?CY,b?t?Ցb<& =.?j ?2"b U@Efx?_ŭmEss?48ܿVDe 3Z? p`9{2?-נ^?`o)EJ?b$|&Nu6B?H?0%is?(e?:!Ͽ{"&#ŜYyg@){Y ѿ+ Co?I0 [V?Yw?~cf0[s???RX ??f?, T?\Lg K+?O0ҿ S?:?Ti/?MC(a?%~B鿭ҷN?݉ Ms_\?o 1nmǿ#y-$KYG(h.?R?}0XkD̻5?&/-?4?džŽ"/z󿊞?D? h?J,Z޿" )@ D42.H?F??Y- **b#E?v.?ko?ǼfV8޶=b #}>x$㿎w}U?@;jҿri?Ma?9?QU>y˜??~*(B?rZ5?1ƄWa(aE3K^? `c7?֨@k?i>n??MO ɘrxRn#k-E߳?f\z#/Vee-!b]]ؿpRݿ_XlhѿzM G ?:w?*a? ?252*[J0?8ܭ?o<'A?@3j/x?2=u^[?Wny?yn5˿h?^p=?1NDrx^8:鿠Ơ,b]6ݎL⿹DD;!J\S=ҿ:AQ#Cݿ38? ?S˭ӿ]j?k>?ϓv.@#7?UU_6|?6=K/|Т?٠ "ҿ@FAe?WݶVM?5࿊n?h.0ʿڙ9Ϳ"<%n?xWemW4. H_s0ka?<㿕cؿ |+ƿLÿ?sIGB=E?vLL@_Z ?kӿi{-ͿFBS??N?T8տ6Oj54?G2+?wO濎3O=?+h? 8:?4?CCMmQ;[:?+g!?>iG??2@]4 aKY.>3eAE`Ŀ" pMЁUTU\JhvjDԿmG[{P࿻ρǿs?vԿjv 6z)Zc?ҍmU|?~N2?tz?c =?KÿinS׿w-P?&#O?U X?oϔO?X?6L>?DܿZ|$?NNg]%0 ҿ@Uc?"#* ?P}|?n] ?vT9?:쾆?Sr俆R\꿧 RO?s|DPw1v`KA@E u?Hp￧W=PTֿlÿ $ۖ8?VF⿴`M?!?TYG$?k RڿRҳ?kQ<ܿ e-~?__?ZWҿc}?RGr*}.Q?{ӟc?5<ȞAa7@U9Ã@S燺(XqJjg7?aBī -?.?DfUxd?ҴD.j?@|? [?TAӿp?q4? >?->G<]_?^?~MpxUD)' ߿o?U7?0##Tҿ) ??M?3wR?οXk ?~b p޿/~?mɧ?M_Kئ?8Brr ÿ >޿Q%+?K~j?'}ѿgc?g?4yH?rDxٙf?D?? t-V?Mؿ&B?J6-h꿮7퀼?#g޿v?tد0Cz@RSdjlDODn?&?M[?4gu-RJ٥0 !~f?CLֿJ?77摳?x'B*? 3/Vؿl?8N{i?ޒ?I?g+@{F\?G<Ƹ?ɭX$W ՜?\S'?b&ө߿^-q>?[43?c1?rm4!`3c?fb?liw걺,߿r?e\?,M(v"I?d+X}˿Q3Uz?YBʿfCP/p|a䏱X?nr?=;6?`)?tF?q3ڿnL4"k^?1Qܑ?Tx2N@ !ݿß%߿iOI?\+쿕G|?zA CxJ*?x[? )}BV,ɽ Ý A?:>:,n?"|ؿ\H?Ul?(h'?ζ0A?k|4׿-?YO&T ϿFvRB? g^Q? IWB ? !sy.ۿvJ’? +?C;R?bC|rq-?t=&([?xZ?Տ!пQ5?xd=?*'?d g߿@^|PB:?X@|c?a?e:ӿHe3X8?+j4YO?a};T[? gKi3? ECR?'a 0'm?~Ϣpaɲc?Qų;迦qſd0$΢1t߿.W?B}f?x^zoڬlտ?|om;?)pA?L&Ŀ K?0$?Vʩ9?+\9U翠v??wx6楷ǿb2ZO9 bEw??:D9;\h? X1\W?e?r&ۿT)in\c,mW?f0h u<_cAݿ]"hݿ}wvԚ忚&IwஊJ?}?pAphmʿbb?5wŊ1SC陨- >9ؿA73d|Z:3U?Q?zف(?д迗 _=?#?T$;8gGQ r￝&Wʿ̈́?Ϸ?C[voW?`ln?;}ſG y𿘀`# fO?5?Q?Ͽ!L+$? 1?+% s?3zf??L6v̮F,Mmԗ2:\IW ?nICp'@c?`>׈"b4Mu?z67@ZW;?+?GI?,?OyaVh?gј{q?^?[C}x'G?Al ݕN!Y;뿁s`X?N*b翮_tZ@q(zja=|ֿ.0P? #?;w??ۿK|:?YX[{3 vdۿIMѿM{`2A?p;?7qdʿx"eѿ4Ѕyؒ?,MGG]ݩț꿱n>aV?Jr}?]޿e@eMxdh\?JOֿsHĻ?|l?XV2¿q뿍XDVoRɿJXIu2jʿz5'3eǢel)?j?S@?JqwLN?6w ?|6oE ?a?Z\?e? ??ޖ@rt?-|%ѿ[R=o ʀa @Rcԯ^/?f?9(ξ?{H返q~o?T=S@|96}ܓo?!?L " ?ςQ?؆"޿T<;?LdQ>T?\ELP.?ʵ)#LPܾ&\Q.S⿺acѳ8/۷%A(2.ȿ :ѿV.iC?fo?z"kp-2?P͗?cTCDxLfDsxptyM?gϬB?;iR?t5^?&X?I n}Vӿǿ ?DߘC?U03?2cNB?z9|T%??6d|?5h@VSϽ?PH=F? `qG?XDޥLIԿHCe?8i?HWF? Mɿ\o~9B?פOg?@&@?KOӿr&Ss+vDԿ#bV?_ S𿨒u݃?Mi?Xmw-ATZ뿭58?7Ҏ&ӿK0g$e YOj? ?q"ScQ.]&տciT1)O쿧D?M?bz?%(õ?+|? Y9ȿ'5,ѿVX&9̃E)ݿ?YSʿ4t[?crc?zֻcCo s#ѿX^?%ȿZ#?tAly ?  )#SМ[?-?@?1!75@-s?=H_7ݿ0oPA?tΨ5r>oN\ѿhtN?riQ? ߭MPM?*mgdtg n/ڿVnSܿ?8@'kI5?vEB/^t?Z@/?]IOm?ZW2F^?:*.?Tg[Pֿ6Q?CZg)Cn?UѪ?Rzt#? ?Bʧ?2BD?m+\P?iCҶ ⿱9Ni忽b ?Oӵ_;h{?17isG?ȉjE&V{8x#&^aο7 V3ɂH??wھ_?i[?Zirz1?HD.շ?N8ѽ0迃|/m忍G9[k@n,m|=x!q'ul[2u@?z umRV?TJYй?8fUt?rS݃?ץC ^? 㿫D;!!qGe?T"?1kPW?ҀNbhD??Zml?ɿSTMn?6 +{Iڗ}?4@Y?Xx#翧]?Mƻ1F,{F5?ǐ?s A?(Z6P+E)WY!@j*M6+T?U}?MUWl0qK?mK?$?CY(1?$Ѡ!ͿwЃſ0H 2?6  !?1oT?W`?dIۿBA ?4z?]-ܿf%w?"46P Iﵥ_쿳Vܖt"ʿmj7[Z?}i(㥳F?TgQ޿a \֟ד a? ՠ?7Z\(}?JW/T`sΌJ*sӿ|~H?G"2p?ᅈP?S?Ah%C?w 'z=߿u?kdkݱ'T\ܖ@=1P᷏O1̿"οߌct,么mP ;ֱq?.ɯ?t?WZ??E@ùң?8i/տyլ`I5e7mr?lGFWA&?po*K)_r-)俶 "?!s?5bᅬt_Y6>6!Q?N7@cLgdWX?*R,ۿ g_ĿHy?ƺ.iP^?񿭖b?_?_tۿ/ @i!j¿TbUſCDy7pH8?y!|?o?jHΰ1v?2/:UοBQ^7-LOp"? q?KOͿA)"|?ss=?:!bC? .pY! ?&7o/k?%bu?ǎsf+G? C | Xv?.k;w_3?6Ms<ڿ?9?eHӿ!5$u*ٿG?M6?.Q?Vv!?cc?XMm4?0x=8%OU pN>?Y?:ۿTaS?F@gGr 2ex0Rzvxt~?q}K뿞b?ȝo?i;A俽qq5?|kh?޹д1?ZO?LALND&>$h?{+έDԿn5?x,Wr?}cu? R?rZjZQ?@?sy1WB29X޿eh?^꿗`g**~?߹%?s?Gvv?4M9ϵ?.:d U?1?Ԋ???L#~!޿"ܵWo(?;8ŝ]? [:1uػ?6Ij;Bm?/h0ɑB܆ gQ~S?МF?/牍(׿wf?c+:M@Yݕ?guLnAnujBZS? ~˿ LZ?q0Icd>ӿÃ)?V6`?'j5f2:{ٿO%3?12C?:? ?_sԁԿ?0ſ[OJ1?K~?#{`?xp@?#.陆&2^!n?׾%XԤ?s.~A?)f^`hLf?heT?9*?NkME?Ɣ#濘CVqb%{߿sD: ?bꌃؿ9cЪ?qN(bnN~\?8#N?n?i]̖\RR~kb?'RE=xɿPܬ\?$e@k?#doӿXKTB?CQؿa \%/2VN6 ?OYe?dUep[?@v?9WۿȦ2~ F?)+R?Ǝy?@[4n?:Hh4ĿAA@*2%\뿾I ? w:߿%TV?x޿H 6?j,% + zkؿe*c?}z!? ܿ@trXh0?t?ŘyܦLٿg?#?ycZ>??XX?- _?[6G`¿M#7@jF?+8\?eLY&Q a-_@y~?Y?w?ΰ"?:y࿫'?Кw:㿧U?W?ke+)?~ݿ!῍4w~?‡c$ɿ ۉ?@BLտk H?7& ?(ӿxֿjȿܿ%S*?^JL;?p+5w?C?$?"SZ@߾9?ʽ~9\c? fY? ټ @?޿U9 ?S2RWkO?3|@@uk1?-0m濬@)w?܌Ω?<~8?m&/ ?c$\\hn?GL?h ȿ8Y[?|j?4ӯE@p"׿~b7A:ÿ.T7U{9ٰ?MҿV(꿢V?@Tt+ ?2۱瘲ſqǿT!BHAF?^\Mz3m2?9Ie?5 g߿ U?O!g\{> ܞ'mW_!{FPA? D(&տEӮu?lh+ n?!H?ry?W G<:O @MտQ?]כVzտ6Ti?"Uݚu,M?Y}?YS2U?ԿY??R?C%\?rIE?ӿf%_￴?NOJ-qڿLؿV"3F}7 (?d= GM̿/z8}e¿;AMܿlS?j= >տ[8"x1b?oBDPT?I hv?u62c࿟?||c?y`c]߿!p? _ؿ!z?j rhd??x㿆 ePg@֭oP?Z Kt?=V/῱Łͽw?BݾzeWh+*-忊F?֖.+?H?gcSɿ/?l)Lw? ?8'c?`"?Yy,~?mXп#`S뿑0|ǭR ?!bh?+t8:4?G ;?.-B#iῶ[n>y?j A+?şEn@;(rKͿ͑㣲?%/hG?g?ՅF\ ؿ߿ bv[N&c8?G}UUR? ?ل7?O[ZYLbῑxɅ׈?A븓~NT&-5?csO/WL?,n}?|Ws?DLw;C?@%1׿'$]?}x i#̓8r4[|v''j?ƚte9@7?д#?ч'?aؼlt'♽?` 2ӿ52)Ϳ^?0/0,9= ?`1j5?VF^ ?C ? ݿGO?>VCIE^#?c?x~HHzt? w!?ɵ g 6jw㿢w+&οZYBT4$؛na? s$ n-c?}Xss`wvפ?zMḽ0[?:FftQ ?ӝ(nd×?ExIE?(ѐ }? }꿭qxk83f?z?̓oiR`*? }?*\Ņ\?` Doɟ?dn2?U3?l !>)N3?.vӓsCPhܿk1tN?owߚBhoNLZؿÕh&Y\ ?gh?[4M/忡r񿐴yqf:mԁ-~E+?KſY,ο]/xњEz?1v]s:,?1K?ceMۿзؿtA5̓Ú?K.7E5?&Y??%^+&2,z?߉;0𿂙1}-eg?w?ړSz??A??6ۿf;{E]W~)T<R^?VH:?SgHzο" 5ڿ+D?(7پ#r?hϬ(˞=sRK?Ͼ? VB"F?KS)vChݿD1}꿻"0;'S?++ ҿ T{j^e^?K*fQ)?9 hH?0=gϿ 8c` ?|(-b?G?} ?G`Oa?*n=Ŀ +T?G'?/p@SBbGո?:*o?!@^-5? 面}?,)m9 @5+2*wkۿڭ>#?ycFu`?*Ebh↓p̶}q?g_2?-:|??6E\a?f ?hS ?LJc+g迦y?9W?%PK߿" 6P$nUU6MH>I@asE3?KXX,K7? R?%Y31BS?z/b7п4 s?;%5T5ݿGXVgcL#Equ<ۿ{?t?V+@?yF?8Z{8?:lnORB[W:v[>?YZ2$ؿPFf€տg?9>Ĭ?݌?d63N0?翵/47u~{"Sۿy?#4E ?.Z<J?h i{!Cu?R8atޓD?N%v%? B ? Cu?3?a?3K9*@61?D@⿍yB鿐'Ђ·mٟ?L#Iƒ?49]տյS*?G7ڿq??qI{K?pyG?s𿝚tJDgb?fT"?xs?kR,(k¿ܚ%+A?п63t ??Dg[u?> J?6h1ᅬL/J?t1?Jz?gh?r?:~3?K3?pN?OD'zڿЮ进Gغ4?&J࿬Щ?X_%=`A?~m?^U?Ý> D=cM]e(?}FIZۜ迱1?hRw$QV?4g[?WQ,"?BqX {DU%?S: #?wǏ@.ÿqAf(? .zzݗ?tJ.Ia?=zi_ؿHsF*_,g??Vn$dCLIj?z?+O?o6G8@½{`-??2h?ٛ ? m 4?Js `ԹB}^2A?3ar)-({?D#?;k/?` y?$ʻ?ŲG?/ N ?ʲ ?|eW|8g#y?cMHfbοq ?QY񿙞"jǿř? 6?a +@$H?* 9? ;gFY<+ֿq|F&55[H?sQi:?YCZ7?M^S>U#_?0&Sj?&by.xr ?| El ?MB1_?CJ(ֿb+ѿ"?b+{Կv?fYc5&xOs/ ZyS?O?mzA|?X ST~ݿ%ɨhd?,`?q`{¿xX%Y?;M3ؿ9\_?|h?Tژ?t e?nu7 ?9;x?9@щ>?: ?ԫ Ap?T?;/ ?i-?Z))uK֔F/uEۿ5LдC' q?oDe?O/ %ɋYͰ %EVY?9;?M с? Sd#??B^F]?IǛhc?3϶\9&?l3?:=Z{6?)7E?P)1?6EMؿK5U?'ҿ*˶Ѷ`G1˫?BK&ֿH?5Nu"I򿿁\'⿝q/o??{o#ÿq*?4@Rl@fn00o7?/ö?Sv*?ZB5鄦?-m俥*?3?%޿7hc?xyH61o޿懫ῢ{l|qտ]?g?/m<?ZG?pDl?e-z?s+= E?CM4J?2L:]¿{.{~?)BJGͪ 远’B? {ę?µͿb @?S-wI? d{K? z2?ȢWp!ݿGqI믊O?O+~"E0n?{;Wp?19ơ ˿vjF~e%&?B9r~,? ZS!,~Ԁ`}%?0A?{D01?"(l>ur?7cicGx?gޓ/}O?Zr[.P7?Mn5u5U?L_?jnَ9e$ƿ8Կ WY<?1Ԥ^pdNJ9?l8?y ?,Z9?ဠ 9CȐ@SEJտ?VB%>myT򿼬~?I~f? S :esqK?j^l(PRֿ|V}ۿO'@='?j D@.8?B+@?0/˞:giڏ?.L5?{ЂS0?rZ?CAWލx4?!>҄?])]2?2>?ՓӿOi׿"}n('(?<|{뿑/1??xؿ7?K@y ?G>59?S${?%25ID?]+l?L5?; hV?;ڿQwu)t虫Gy?Q\?kA:@/!L?8띬?uOn?ܽѿf?6}YE.?Bҡ/B?ʔT?)+?OQ?Bt-?O?%ħ?t^?[Hgݿ?kܿ6ITRTuB0˅O@-͈?GG+?QЪr˿L,{F <;?UW2?k1t?&k@H?(Bz?WxXg忾NF g濤=+?r-k?ωT+?!ŋ"xJL?z`G}?vm@^ %ݿ/[s@ u?%A98ؿv]e?4?=cG(ݿT*0H?((9οB?T'b;Yp῎(HFk['3? 3P 93c7?/H9]忹$`׿ LXTqvvrI?[}?(%OBD@+Hf;䊈@߭Rqܿۜ13տ& ۿ6$n9^ۇ.?*%[?$p@1I.¿sPj"?Z*y ?qg~ߪ@/?USPrI]-n??JdпWs:nkRU=?Ha@u4 _?wL8ڋ?ꎀݿjRd ?mj$'M?.n?w4J!5gx?| +?ZX?{?Aa5 t~ ѿ?? 6u~ܿW&)鿶:vo濥?W翄 ȿ)'~3C]%ĿuVI9%[ F2nojӿ59nu?sa܎Ez~i"#f|qzbҶ}8?u(?CT^.]@ݿ)Q ?Ɔ\=?pA?D#N?O\4u7 @KLTؿLNF?g?kSi? ӿ?1Gq&l^ /?G7E*?ܿ?Է('c?**N)]?^Ub,l?͎9 ?鿈]VU?9Y#-(b6Ty 5Zɿzg?-r|"߿5#į(ݿ xɿû  B翕o׌. W>Z+%?w?[ۢfV?>j={(0 >ƲlϿ^ Ӏ"_:-f߿CzF"?^Uܿ9woMf`?{1E?Y%cٿd09lh!ݿ5';Ϧo`3"LP ?(J뿰6ؿZ鿃x+Ҁؿ<vQ?(:4?@S/N? _?&F y凈οgZ9?=&9ҞGL?'FoI? @ jʄ?g]V-j?!ÖRV>Zp~Km)s ?9?9`Rֿ$?u?^鿈rm?aҺ? ~dI?@C@؀ƈ?» TQ?fj}$$'7 N =?3\'ʿ/уs_bg?8ޯ=SY?Z œ-?`SXs@  ?E'?ש K˿u`P?P?]jKUv?/sըhؿ5%w?Rzk?ǿK?X/'qƜbt.7&HH信xX~ڿ\?`j?i^(ɿ>~?tl ?d~?~Ÿ?OTvX&տt>'5ZQ^ 4ćH?eDO<仿k|2?݆/#l?Wx?aYO?麹"ܿYOC?B!?TB?(TؿT?[ /,迤sI9"3/ ?Rφ?6 俒PyN?24-?ʓDZl! *],ZvєFԿ63=?F#d rfd4\4ЕտDG?ݽ^ę?پh?6d-)?L7?)4Zm?ڃ_CHܿ?D'/O?a}?j+?\?À? 6l?:ؿZơ}JbakQ\EܿNkֿ%hD|y志 QsR?tIo鿔B)5 VnRBٿx$ ׿ziHi6q?ؑgο|рbD@*tu?\R_Q f>$+l4q3?C}Pep?'#?6ř?﬌|?H9 =?H?tRW?}~?;57,ʾ?ҋaY3? @s?q?Z?3?o J(ȿSxO?*1%C?C%W?}vv0~?r뻮M?O"Tc[aο횞?en?O?6a ?^?tPfy?:o? ;s?N8ý>ƑI?Jޫп߿[?0>Eҿ|YO?(0[d4?;}YfXtC??QQ ?TI?sAwC\?F??e% Կ(MQҨ?CWN?潒VY?1?Q-dyEjQ?nGw4(A/?LP?ěH=zr?{ժC`̜?s0? fj͞z?x6^/ؿ˰zM?.p?BJ0@1_ae_f{ ᫯AῩF)>迚+?S";?WG%[?] m;w:ѿiԋV쿧,WZ:Ozjn?vQÃT?NV?bZٿϖз׿O/i؟&޿  ? ܿhٺe?Q+5{~Cޗ??;zj?ۀ?ˡn N?kGs6߿WIdYoֿ@G?j?..U 'f7z 0 /7vƿtjS;@?54>?Nj?jݟ@? -?*KՂ?pr?$ ?gZbDk~\>?X"yx?+ B?q 4?=KRr#~?<ξգ6w̙?_K|Uv|<|p&I?>#jq~j6JWo+U1ɀw1nܿ??Mʎb꿡S?@?^o;m?P,N9Ti?dr?1J?ق ?wF??)?w?O>tM+@ޥ ? m Ϳ q6r|޿$YNܽM]C%@?hAG?-1C}?YU?OF ?/?J+}B\mD մ?`߿:pD-Y-?gf罏?Oȉ?5Y~Xif#|@~ڿ2@b؞+ܱs5 tm㿮p޻?+j? c㗏ѥ:%?eOd???qۺN| +?GAE#?*\F.ȿoq[Ī??Jw?տ#zg?w}ƅD?[KH ?EֶiJkU5Q^?}i)u?W J@h dۿ?v %???tcj?Oѿَ?KR04iª?4j0ԿXs@rpo?3ɦ\-n? -+}ӿLg]U?+&=2?뿣vǥ^?k?Nw?H2Z!8󿠧K4?^ҵ?YA远vG: ݿA쫞?ȗ翆~aÉvMVP@}[/?{60^In|쿺 y r?kw翳HXӱ ;|EhFl.HZ@YW~G?:] M?Nr?ǀ?}z|? M[rh?-|.n?z?i?T4޿&!SB?p1?궥˿`+!?1?:3?,q>?,f?~㿒?o5"?sfܿ?ڿjI?: ?d2H\οt׳:?ܱ?y\Q͔οh\ῈCrM?'w? Ϻ୫M=Ϳ1>WU?\];|/ Tf?JY?oXڿnm;@Xƿ Z翨ʿk?OEnz?Ke* ?M:8ʬ??F?>3?6F) }?o:L>?!yp;濗*RfYߜ㿤4Ccq-Q E+^#ٿ&<̦׿G7vi?3_y.k?ښk?&ͿVu?*M%?[\'?qu?v3z쿴W?A0?W+?Nxa ڿ]@D~4T?(ps!  ?!8?+W].޿m_ lj?IKg;vKga]75?8|?siߐPпX(¿n Ț?8ܛ?."~?9q!οtwgP޿DͰi?6E?]ƪ?ZUu?E[4[ ̿rxb?f?8wῆ*=Yb0 ~DuĿ䢺?h 7#FRw#?_n^Ͽ2w$BR?V2쿏H]%?1xs?x{g?갽%z ؿ䞺6?UͣI?-??6ֿqZ,)?,?7a?i~?[KMm?-)?ٯ_ſ?i' ?jc6>%ͯy7qz@aҿˀ* HU4?\"\"ۿi=:οv?6Uv?7[2ٿ5PRoiS3?ޮ@?!8.܍tH6𿟱ə}`e`?[g6D?6u?$P l˴,пAG"Q?,?L{!?)񿅲O Ks?_տ&|@?Y6=dڿ}ҿ^?J&?F¿۷meܦsǿ{@?^ ?slχ#$ŒL߿A7i?ƿ."n?뿽^?%z?:KYrxƇ'Lv/6V?ڷO/7h R??~\{?k#[@mC_CĢ?`)?NGu @a| ⶿3?LaH'T?be?(S?uxo׿a5u3ۿF+C?JlE8ѿR#5] )@}?Y؝9"QKRޓ?/?V`ޮa5 0^4,?ΰl0?#cU!L,;XxK?:*@@?1y5֒ǿmv?>.4?@F1^ }?_iѿI.s??$4?:4?S^D0??s Ej}NF?Lr޿Xֳa?Y콣u>E3?_|CeS??@?0q1N?JAb?eŋڿd7ǣ[T!Fӵſ0|?u6~ݥ׿xXz+ۿz b=Zņ?"(g?0O !Pa鿃-娩?o߁Gҿʖr?=r:@l?6RxOQ?CFg?4Ce?t?Q#?^b뿀CS3MZǿFVyXS^?DF?ŏ۰Ͽ@k>?|3@\У? ˺64;.w? 92L濗삆{Ҿ-ο2"?V)!?~Ɗ'V?!Q?4DG?51_?.Q&H?}?q^?H 0`a?7$P5`?~;`?I?0Wd0?(H\ݿ 5)? Ț?j!"l?WkUſd߿1[5.V7?; >~p뿏0p?vkܿ+Y߲?]n?6|n4?Iء?ϛI4?]^ة?h뿛f²FNf@ߏ]O sP7?eU~0?|p8}-ɿ abݿ; /?op?_xп|13z?Qoٲ8 xԿ{s'?# jtc?/K)?3|?.B/п!v);@{ #(\ˬJ@`dŝ?k.l/? mA? 0_ڿn}FP?18ܮ "쿻Lm"؎?F?Y *y}ut'?x1c(e+?p'?4?wVK`gqͿuU?We?MomGꜧ? ^*;`Med*CD?ym??;˗͛4Adr?D#d?ѻ8bYпvL6|?95։QB6?$?5ac?#3>.?tBi9?F}kѿf፳@IdPEhd??Z翵Zuf?Mwr? \bz?im?0 `[wqИ@8?Q ?0e!?1 ?[T࿿Ƴ?#3oͮؿ/g? x?J]{"٠$i++8D?s@(пB;Aۿg h^󿘼JͽԿ+Ge?LۡTzxm?"/2IVſZ4?ɿ!߿6~+ֿNF?9ZGb?h\?5?u磿ܽIܿVB:𪼈?4RbO[?wZY?rS٢(+/BҿojJC&?YzWI;?[[?2m ɳ?*%^?j?kx?_Q8?. դ?IM{XSLj?ٖs1? =HL0?K!vݿcW? r?z-Hأ?|OT:Y4@пj ?qGܿ6,O^Ss ?>*߿㊷˿/cy,??&e(vW!F?T ?5yŦjtoWfRuϭ?\VqĿ6[mx>kؘe ?qMcSֿw?J\,?~4) zSԩ뿕ȇSq?*@ vc?\B?wln{Ęӿۈ@HO v?Uo|?XR޿{>6?4d̿wW <?߱U9ܿ^mPٓ^v?'XR|-?KL3?l-տr~&+?J}Cƿz?pbY?/2c?Vp?FNUj@kˣƴřK?K:A?R!p?$]yY@UBU?k6n?nCAԿ4#i\Ήh?,>Ilk?t~d?_s?-Eӿ"-I?s~?oӑ? ?DNJb<U{?L{ [??]e?x`a?'}b?Ҵ齸Qq?uj ?j<:?&?!Uwגz'6ؿڿMz.7Fʿokc@?U?>./?6d?@6⿮36B?l ?8?ʒ,Կ.u?ֿr^V6?2Ek ?Czh>,Jo?QZ@NH0|uUտ+>ҿ;?c^׾"XKF?|/2V]?B?y{Ͽtlr@&O?)٭UGCOLC_?oJ@W?7?ޱ:3ֿF' UM ]z; O-?&S?=z@m{_ !տ?ma >?J H?)iEY5пUz?Q?δ 2k?M0_𿉹ɣؾW?׉v3#T?Ҥ@TE6?P?q+Aɷ\:?Ul J_߿ 󿒷}ɠ?1>m ?.o//?! }? ,οDy?AV/ؿ)1?|27 ?Fag`?/T2@q3V݁%}pW?ȿ>y&y0?~e(@t~}?> k@Un?\7/6ņD>dr5?V?v1ĿL.|dN?^Vq?)Mϻ]Vt F#S%z翄Z񜀊˿ͬ<u^EֿLGozUl @y#5=˿*?ϿuW?RHտK?lj;w?\ M CjJӿM=?w?i;2?[U W?34?jb?.̢ "~K`hu?QkR?T)?Ǜ$?v #y9?qɇ鿷>` ?T*?Tàm?!3}%B?q:bU0鿝7}DԿ2~ h?kb!xki?,"JʥHR?`ۊE ã9rohZu1fп固$?&lL za15bG?`. 쿗kWcϿWK9C͓?0Wb=/vտZ_tGA?*Џݰc [B˜ ?:uڿFB_׊?ܧZְ?ROuBAWT<^?|?b@J70ֿ;E?IWh6;?RA|u@Rb i'א?zu?$凲РYFZ&?;>B}i@(/ @ ?K ?ku? N??σZ?qկƿ=@?}d?Hlf?=׿d⿡jԿ`vtQ ?tcgoH?g{He -? SkH㿓#[(U?l?xūpX0@?c^?+ˈ?C?9c~?Y[r\gd?|zO>kp䠸? ?m a?&?;0՞NX?0 rݿЏ?M?#`[9ʿfۛfv㿔.w?[AĿΟ?um׿Hܿ2 ɿs~ )?>@j?Hh mf61ʿqNj>0?o3O)ȿT+oiۿo?tˢ,A?[p?|"?McG+I?9:$]׿`bGۿGjӿ*)?M?C%sO?P}^&kq?+QM?f-n?PGOjp?Z=/ P`4cVe?Dzp?N׿> 8ؿ#o1︄"naZhy?^?ŷ̥?{ޚ?ŵz?I}pb?:+?]@?Eu@{8G㿼Cu?*ⷿ[R?tݛ˖?mSpFҿAQ'f?^}g?3ÿְ,[Y_cZq3˝%?s? ULᅫ~=?i9$!?g]Ű"?b/.?B|@Y#A˿p Nn?y)|?h@P{Psς׿ƌa*"޿H! ls}cti?cBÿ`M`?F 1~?Rnl?̱R׿.?u, ?~/@~f ,_;?6VV[ ]t??I,⿄!To?hZ刺䢆 F;?c>%le? mѿm łi?qb@ WؿοO!/ 8q?J5B0 "ؿd̑iPL?Dӿ?pS޿+sh? PF1Mq= ]?yTY?T "8me?\02?_a' ?jlT˿RnZi:?}*?Ue?P #M?b<=?n|G?fWSM?GQѿ>l?r//?Q׳bC}?!i-k&|JدD? ?T Z 0]gL}?#z?b㿻hX?J ֿ"K?qXzSXnٸ1>M?q,5鿯tR=jM]8j7ڿ0sԿvNg?6 ϿXZŋ?1%?ª6?[ܿQ3bmOMo?{.?ouo|(?@#o?{jl:[?X}?Ĺ[JU@cUܿFZCUBs v?6/cnοn![@?M"?,;Q-?e뿈g>ӿEFʹJtd3?:|A?C]?Zk[?;ĿN?uyI˅MY޿@[>o?f4lڿ7?Kseci*?)_?`F"?˧+]q@ـ?ïw>JF?⥻ܿ&2?B_xbxٿ'W*lӿp=@:@X?'@Joc߿.f6A? !?ۉ?6?!l7 ͿumyHп?\ҿv󿕻zy>?\`9M@n""*?HNOӿ1-!V;ؿlf<4VT?9̊?%0~#ɿJkTv&#+Nܿ4r%𿘛#5ѿ4EWBUޛa޿T A"??S9m?ԂA!,?( (?ΰ?x~i?u[X?B?ֲLe7{%֨"YѿjכlKu.53@'G'ц?9/?G 9?q=Ě ZƿFeps#`?>|[?!?xM>?u?%sȿ+10+⿧ajZ0@Ou ?* uA?8h e!>?A??;CM_?( (:޽,_噺4 9 øi?åV I Kwu뀇kOG;?'fP?7~L?Qjo0͙ĸ?mU$e?Yǡ9>?LtE+ڿny; %?hՐF?OFw%;?P#? lae;ĞRjg?=2))1D8.[ż`ŭ{?wȿ2@bւ?W?-lܿZ! M_x#*߿C) ?pd1pZ(?J\~?LD_?|( e?& ?:Xz?8ύu?qaO4? j<-?*P~SԿ-8zeG:u?/&?ٸ5ݿZ]忂ƫSGǿځ(?yFw&?Dk?O"n㿉IJk??HVe?NZ?2߈h)߮8?d) ?oyVDŽ0p?GE f޺R?՟(}oAֿi䎾Yr9?A{ v S?2dsݿ.7? <_G1qBI?ҥ?N&hXOJ?f6r>⿆1ڿK%??BZaؿ\!bp <ƪ?j?X` ;?z ̦a?l'Idݿ*Cǜ7?!ZP?*I&У).?nN'޿r?R'\êcjqЁ"Y?$q%.տV?qVlzG—?$b)dRPyS29Oۿ,w.@zܠn,4?dKc?*| [eG,ۿVIw9俋H"8s<?R/{?}/4? | ڿS ?u|Jv@oz|򿷿o'*R U?ݷlqZi+h׿j?0 ߿v-8῔k6HV࿲m<ѿ@aw r?~,bP?%zٿUum?y"\?RnG`?bL`?O῝11Yɿ?Y ?Ay'а? o־~L?U-H?ؤEUN_:?:VV>I׿?Ck?h?v!p?I!&?qG?3>oPQ?ydueR{8 J O6WQ ;$;ۿA?r? &Q@ŵ?z䓸?LH IOXֿJ4-ÿڿOW迹MuowU?n:7B?G3oU̯*[kEʻ?őS5܌H~l?n&?hfZ?)юX?Ib?xġ"8߿wqN(;lO{?Fmۿ$!쿰śSpS?4pc?.@d33?ҋat1l!שpC?FC?I91we~h5ut?Wi志ߎ9߆?5g5È 1?OK?`SxGB@DtͰYnQOck̿yi_ڿ#_S?`9?yֳ|9KNgy_CF4ֿD՟?of?7V?ep/?r51B{-R?XM oӔ?u\m?as׿ }Pt?uHkӿ">crRпP6 ց?(/UB@8mH4?!?@&XֿhsiHF*p&?:J?Ǒ.pտ@T?;LC-鿯{$⺿?l()Xr%>r?B}/ڿ{9ɤ?h@̿G?9jHX:d.*?w?!J0?qO&B?(ҿHd?*e$U7ӿ`#!?icf )P?_֐?`G?tFM+@xu8A<:2?cЇۿi, 싿6(@soJ2c}3@^ @ǡ?i3̞Կĩ+fx??yi gӿ?Iؿ}2 I?@7?nBO?KͿ?%f?XE?xtF)tBv?c_/aC5A2? "ruWҿU@cN?aMkt"K$??3ǿRe,]ӓ?= 7Ϳ]:?M?&/鿻Y BӿFRҿ5<юaC/@Mzat?zzlWp|9RPqACLǿV;%?frd6?oT*4?c_=׿D=?+U?DmЉю1?}Gm@G9nC?]N?広⿌F?^tE㿕{D"p rv??`?:rjʦ\HBDauֿٕ?wĊ?MfW?^Ꝯ㿉ÚR?cе9u?u<4GR/?Nr ?Fs4?؃ ?H#!?r^I?9l[? ?TFA9翌E[?>`U?9^?eܦS)x?z ]4пVt2=[bv[?on,տKh@Kt ?Fݎ]&\(͗Q;2{9?%5M}5g~()[׿Y? z5?%#?k0QRv.󿮡a??j.(?ҿbSUԿN?S%?K6Jz>O?~g׿"knwg z^?aaun3Ŀ+[@S9?^?gαb?k$#t쿜,< ?N?*A0׿Sg޿!?׋S?JQпc CXǿ1ӿ(߀VҿP|?ʿv~$?ל@X7|?g<ÿ, #/[@7OxҿM$?1If0"_?TLKkAg9J*Be*.?ȥנJ2~l~cl׿=r13њ?{l;?Basuus=O?)5Sa?+b?Pп%%޿O)S?ds?b;'sv۹?ΘvY?/RQ?($?wbɿ,L};*p7O!*?Qi~?4Jӿ3=?hdk5l3Ésһ?qa?>.|X0XM>!!?&Щ^??+g{?n\?{q3?٬o?BIyGR-?Aq''Կz?[ֿn6 GAbd߃F?T(@T<__ޫ応Y?.)uaݱ?Z˿:s5#󿑗 tn(??ǭZQ?  ?ΦUGsR?u?3QfY?u`4/D\?9?,٪fS?VH??dž<@vط??WLy?٘r.&Jؿ;ws?f=z?$L?.+WA9??nX?۰?x1H?W}Ῑ/@ș?]%!9WP?0(nq]ݿϯm#Mԫ'p?rʥObP3[TH^!?xUW%?Sf?5K߿TWؿ?]?O[G|#ۿ `p?P>wI3?gÿAͩy j濎OT?"~"Cؿok?V;ٿAӨ)pLWWX`o޿/?b(^h?9$:?$kK?؈5_70?Lrn?QꅽpZ?e xN ޿^w?UFN?/M;?5&?֨F?[.hпfFA?-Y?_˹?/.o?$oZIMM9?H?#?];wؿL;*MfÿJ5$oW|D%crRI? Do=ѕ?@kX?qo?*@J ?,khK?ž޿Iy]4?pKK@D ?sf) ?`?濢HS߿|7?vo ?!??9?O'ҿ6eϿBWw(A 9bQ&?|UP??)?9RU@2I?? ,?qп"G 0@'( hԿ$:N&nO?Dn?` mFZIz1?d'¿ Dp?sq п~tu俶Qyz-RZ\?Y]Ŀu0nDt܉a?b`,[[a?<"ge5q?2?Q2yr!V¿k9wFH޿b?vWտ?㮄Ov1q?迼v.a/&Y?}[?-q?4ο:FN5| Nk d?&EII*?mKӛ?zn% HW?F]q¼ ?H\Xk?h?*,X?)j#YQ|E¿Kǿi4Np[ӿن? Y{?]'6&?ER5@CQ}@M??3mMCÍH?D3?o1?{m@\:V|ohUa_yB+6"9K ?!}{q+FCOD?9@x@흌w?B{%ܝW[&AW?^7%?'o?,_+8>T=L󿒜 >3?h6Q?)y9D@#y h?~GU\ ҿ,>Y?-)?Ǹ-*?D$?ֿli‰?ϙͿ7?#:}Lٿ'X?C}s*Ϳs"?9Sj?b7j 4,ؿ bVI9U?j?O$?b[, b?z`d{r迴1 ?2?E6la?z@t߿aW&4⿮gڿ8c?K;?xf@򿈱Yٱs?O_)?4$/"py?w?\H)_?{6Mҿ%L9Rkt ?fUP)/GR?aS?&?T?FWB<&GR-?*.-g ϚVlWڿ,1G@PM?(ʿC[J&(d'SO޿x^Oo?FH}f"?'8+tlϿ0˜@ZJEz i:RoaL,H?NiT'?*#DP1zſͳX?M-N?'o4-?C͝bV@J !C 翹~?p&?š1?~Or?S@k`=Nx)=TE/Կo@2[ ?l?Z>#y3s?~94tw*"ǿ-9gǿ_3a04? n82kJ3#UiN?>^PWؿ }(?QJB?w?J S)W{Կ{{hxۿe?_3"M?lRz@^EüڿX#\ǿD?۾_E&?5+?gm߿h'@cDZ%y&\CY?D?؁~,w}2nRm?Y$k7ס c?WN Q߿% ⿲Uc?BϟI濯sͿ?qML?ۿ%z?+wj?9B"L@-Fێ37?NW濻˿Ϭ? @?v| ׿#ڈQ<>>Q?y>^?ir? X5ݿI|Wf ?!컿?׾\(*'|ג$.<9?Fl` r&zb6r?@sG`|p?=?-TmxD@8]e3xARGNakܿރ"kѿN ]?w?35տa$#? yܠ%K*H90?ٓՅſ^]?o9Ԋ\@%@l3?WS?dF<z? :K?UJ}?_ }?r-?˵fy~N꿾4d?@PH?}җ=vjj󿿓F'PϒDݿNذ?oW?vT6?u.?~-?#Մi?o?ʂSvD?H̀09?ꁠ*S?vA|Ir(M;$ѱpoA鿀3!۟?5qPf>?o=?2w4x?_#R?b[ l0?B:F?|KFde쿄C7GkǀOd|@kdy8CGlX\\?p`}?V޳G ?f&Gwx_ɿ۳"Ȉ濱 .:`?TY\?ٞ3?ma?֕eu@JQ\U!k?enn?Aթ ?=򿖁uٿlLl?5np? C%M!8vD?e#[FHοh-ǿXl$FMg^?N#V[seU?X7dJ?sjRnA/h?Y*WB?G6[aӿ7# "qUſ"WmԿDFlU?zm??"5?y12j?،,兯[(?`࿔0Zݜ?ԇS8ڞӿ0q?PA$?MؿOٶ~S?AzA?QA}@îR"?7?1%^F,:dٿ5?8 I? 8qeī?I.Z?Ǡ?1]? b]q?gKt?0H?uMݿA9.?4eg ?%*?[Q5?~2J?pk?: e~/?VH%ѿ}SA߸ kV7*~?4cnI0?a/B >?Pfy?な1[L9?{b=?us`t6CqNܿGʾS}?طO鿳߫?>;J\?-~^ܘ1\?;0?Ipr?:C-?znCʆn8?OK%U?-tR?*R wgƺ迼H?t9k?ɿMu{-*l+?e?v!S pݿ+&fq"ُO@M󿤙c?`?z?սϿ0g>P ?.J\]}@kIA@dX?%%@ܿ?$ M?K F^Y0%?,?1ϒ4(?@i,w?7Z?̲uSlѿ&tK޿D\GVP7?5>Kҹv?byӯ9ƀQly?={?Ti?5RQ׉ʱ =5?s<%S}\{#2d?ӭ!j5'JοQZy↓6?Y% d5#4g?ӧ&_Կ:ȋj߿KF?` ?%TS)esK?I ^:?hN|mSh?a{s?d eQ'ݿV2Jw?>7F?;?YEv8.2?Pj[?ŘplLY{ͿF+W D?e ȿGį?F,>GAh?)UE޿ $.{S?P(,?Gӿ*.? ?UտD?$?[YT>ο' u?ѿxC#-@L[K)&gȿ$V?@m軴J,oaX_?:QLZ?`޿{%D^IAv&?︻So?PQ|\Z濲Q-N@?V-࿺.?IA?o}ʿC? C?oW](fտ Vh?7>T"p 4_㿗lIR}?XFTS?W7]?9X<ɿJ22AJz?+:>UJ Aq7ſwY1wU|?ajPM?h?sf:d1|? +֗?Amz?Ј'N?p7p?h`ǿҀ?>3Ě?q|)q?jڿ[+Be@n@M?Wͯ{xt 񿦊i>C!Z?kα?Hh? *?2?)EϠ?dԷsQ#܄ӿ R?1`c? ?%?'m6pؤ?n4 d?<18Э ?L)-?*PKӾ?Suт??N?C?%ܿ%{+hQ$ͿoTl 5K-?~YəVB?M? ?ϝ &\x)?塼v)@9~T@O0m?_@(ͺѵ{?,+?v?w?ܷ%~?g?m?_v?NrY׿'Y?E&?l<=?[9K3uI@X? [Qĥ-ԅM-JrV|r M?= ךLǿKZѹk@j.ҟ?,1?Wi?a72 ?evۿVe&My?093?M?ux?(?0S ?)PyM!&P&ZGȪnq꿩;z+U_jN?k7f?P"g?~6?UT>K꿍"?" &Riٿb[!?X6y}?XͧRٿn7ٿ^hĈKL?/E9_cL~?Ʋ?&?\[DQ?.ؠYCh߿G&?d򿠵d5It꿥 '3dQjm_3+~/Mr?M<? &x:2ގп 4'_Qÿ xh׿hJ(* w3Qʓ?5@?Y1Y" ڿ6$P?K0\?}T8?"˾@΍M]qU۪ؿ<*fc??\!a?m</?4tL|^MxWӒa˿? )?Jm[h]R|?R-"e?us>(ؿ<h?h/O8?b?nF? ?Wu?l7?w{?<3P?.z9?I#?KBҿQgU})Q Ow/81߿v/fP?f4? ?I!l?@c?KM%пa-?J?#[/?[2?9_R?ݾiZ>?0|пDʵӿ%ֈ?0^ \?Rx@!F?=_ܿ$W킠ʬ@ݿFcw~D?8 ݺ{=wn?H|?Q'пTeWFp@Zܮ%o迣kQ ,˿U!*?'A?O')Ȟ0OַE?}L?ek1?\H>W4?g3~`D?0H?43VCIWӿ+כ1?㴋8`\?'A?LXuؿl"W$M?Lv_e ֿew?H}?Vҿmk?sm? ?fR~pPV0Ú?>0?\T&?^C?p%D?d(Tңxs˿-X\?4& 7 ?EFv'u?sxj?#8ӿ2|0x'?/ A?De=V?%-ܿoj@Aň,vGi12(l?(rY?,%?bH9#g?<6E?S&}7ΨؗܿaF¿iꐬ?7x'ͪM(m߇??tտa@F)Pu?A#?-gؿb5@,&30쭢P6[ ͛?8V8:`2U?U"N+zҿ Es gܿ L8v1j쿟UPĿ.L){KkoῶǿʙBtM?OX¿6_&]}x*r$?Ň?W?Mq?C?*]CB.@qdy9#Ĺ[wؿ5?|Boٿ̺]࿥տ 3տQ${%@>#?q*z 1Tt^ ?x*`S?xLm?lj? ]׿Kf?\.?tj?{_n?iψ x:wp?[\P?k) ??=n5ބrkÿ"i!?/h?%(󶿡«?9Rx??Bÿ.tM{?^eY]9?܇3Y꿻qnTܿX!y?EEIR8̿Nz!?dcG?ĶAnA9\b?B\ya忽M ?O|y`Xk`)?0?|!?U.}*ylC0g{ſ9Y\*Ŀp?uEڿ?? 1ex K-??@ڸ[ؿ@翯({?+u⿹,?rOW?' a3:h⿖\7 戮?kU?0,?BWe?S+D¿|E?6\dݿA}?}zgح{X?3q;?` o t?Zؿ?(-Ջ&?`1/Ro?\I?BH}?lD?6~ڿ#``GݿjiZ?;Ep?_M!Uӿ7ݏ?.?Fxd@g?gЕѿHcS#?MFҿ,C#Vq?tLZUſ{`oпLZ~f¿pg;п6slډt?([ZMݿs"dhP@I7}o ';2Wp?{6?k_DԿTZ,+?-Ss?KA?&9/y? w7Pڿdÿ? *Tݻ,û"˄.ߗ뿥k^?elS¶?hbgVT?ÛD-nZ4?@?UrdI1?oP?e"ߖ?f0~n?miλƿme?A47W?QS\?cBq?y?u~޲?vaMevq?oKu%\'?yҭQ?߮׿Cݿ ~A࿵):6`?0OW\ܰ搻x?@?FhJ?ʗ"翋9=w?#pLeo}+ÿ&G ȯ53f?&%E?,or濙g??7ٿ$Zh|<$?P8ErS?j\*1|]o;U`,cnx[?G ?-|!QR?&X?uy?@(l?fN? !ӿqGVDA" B%?wU? ,?rԞ? ƯB# mI WakDC ~/UL,ܿmZ#clW?j;vӿރ cL?AT?̺y7?&no?w$#?Q_ϛvǓG^?[U^.n@s5O뤿 5;UBh' ?DŻ?ܴf?,(ݿק.',ֿ4ig? ` +/?uCwM?V(t?G9HT߿I~lpIVL?r?yuy ?6/뿯%j?,-$Ӧ0b;?8叵-h㿳m?Uֈ3/?$yO?xwU ݿ'شq?uj^/yU鿟V_ڿ˿'А? X˿TAXQ 'z}`o[9M:ʘK?`?e0F񿷱H!qDc{OG&qĿ=GfN-¿6"#?1Fc.M?Qc?0kJ?y>'sdsܿ\Oqտ ꁧtT?w'tM翴?S6"#?]MlA?: -?!P3h!jmb,?L/qa=7x!6k?nQ85?,x?K?=ؿϪ7??N?]?:LTF_?DƲj2VˏuQ3z\?lMծ^g"??ۓK3<y?HB?R}?M{@ #L?#p*% ᅬ c[пtWuWl]?/H￸@"%:ؿ?I?c~?H2{IϿe΀򶬼aɰ@^?Ft [[Kr֎?rc1?-$i@?J?(D ?*? f .?"D?n Q ?Y-,?&{S%Z?# ?B%aq1xCttQ/V]meQXsX~( @)buv?]zտke?W=?bTgE?!T?s2#3翎zK翙.s]dɿ(mj?:8=?gS?5D)?i%V<>ϚϿh 3ٿ:ˬ?RY̿q &?r^<;ЮQ?ǭJ)@/vMït,xމ~?N`Z Ib?b? ǰKaNo??b?3*f?ǠX?*h=޿D{?]Oܿ^d@?r`_3Z*R4 S5G-KzV?Sl?]^?Gslg,J}YOLԇ?oW&v2X>U%t濈(0hEVW?m_a*ͨÒ;d1տyi?N4?9>?7G96n+$ )?%Y5x?>@BZ?}KX@(k,$?=X6c?8T ?RD﬛!4ڿ N迱tgZu?"?nAk9? Aܿǣ< Vya?CyXaR4%, `?!}5Q?|3MP@? j?RF?H(Q"?L?)?ΞX;?sE[ٿ M*⾴^dZ1 `:? U*]0]o?h? ?wv3?xG?]/ud@1N @06ȋ￷h?eX?Ga}H?[{Uÿ#Ì@ Q߰׿h͉?Lڿk׿ص%?̲?AU?cP-?·\C+ 1@ c?)w<㿹6u7?K3b] VC]ԏ kyk㿂cRhl?/d(?+N+WE?t ?Zl׮?_ ~z?n$sSʿ^ ?c 6C&?b2T?٫?n,E?nhm9?1?y? Kr8?X?/}?HfE'="ֿklK?_%п#Pccδ?G?eP=?!is?GiC^@Q&gT? ?UH%?*j &vߦ?3k?i@Gɿ!fo?#$=dpyN?#0,?BɷA܄L?+䴔?-kl? #_?eE+Z2v{I?? ѬX?, 0ٳ^> H꾵i%ը;)@=Ŏ"_?㿑'^v+?Jtx}N̡(޿屈@W?):?JH?x-F|riK翙ֻ忱U,d|/;0ns Tؿ@5inGg:ex\W¿RR[81d?Ǝ`ҿk3ۿ׮m??g/{|?ɻ?/rgoL?dR?ɂ ۿ)To_w~sELbÿ@xqNBӿL9\?v- ?\}?k?1L:←?7|kf?w#pr?sCHxbB12 ?{+ψԿ:t[C?*0?Ƽ ?o)%?ouпT? 1è?'i?A?j5j+?>"/Ϡ!Kftnπ??⿙ʿ ?/u_;c6x?R]ƿ1bxC|gy? + zcz?̃*?45?NAOG"?ᇚt?k1AC"?p)j,x?#/p7Y?̿< ?PGnԿr5Mzv?2܌*12/٣"<쿋H?zѿ=տݿҹi]2? FSE?be@?@;SL[Sn?Z0VbIcҿK@,LR$ݱ%?}4DqT@XH?a!+忉IQ? ӂ=)?PAU5㬿u-c|?4\u,7 5?(?/?w ?TmpE}j-_;2?[=?VJȖ ʴ?S4ȿMɪӿM ֝?aK?2#v?Q ~?\ ֿYKS?nUw\@ڿd26?b?-?n??5ۿ[9*A3?Qʂ?PX NW?'%na 2?vLs/?wQ7'n,H Z)\3?XsA?? ,?ҶT2?u" ʿ ]??t(p?^چ¿hsi?Ǹ?BT?UT?j B1򢮆?iKHX?:ϼ!ęΌ?Y,?e; N?m!6=0]88@]k6?Nտulu%CW25̿ eݏ?:#c?RJп&,? hNU}@cVݿTBX0?$?6כYҼ?JԄ9 o?|}?̎!߿?#2H?2SY~t?lQ?Yȿ2[?OIi?? GD c?Bm;?W R?l?g?<߿H_6|?_l?'@ &?*,L?"Ԩ?byo]h1a?M2ؿz1-vSވ.rǣ? ?=/{n£')b??5k1?ptw?2š}??mЯ?Q祪?Js? 6%mt2Ha . UZ+$ѿG]b7?8,֭ |?WKF~޿}&?cߓk?;o I%?w͎K[ֵm?\tϿ\p&EA @V&C&}?t69?bN_l-@ &?r%?Nx?KaϿ3qЈ@U}!}b9C|f?K,d3?.|?a[?3-^?* k!ےL?+A`@?/X2?*) 6*9|޿/IahTٿUv?Q+?ΫB??$O⿎՗ֿ7%e?&M7( `)lNo?`ur|??~?jp#f꿤Q(BqN<ۿ1>:?dg }Mh댘?kd%ݿ=M? GY N?+F?iݿ*QD ?;AQ?/9R ^@o?Gؿ˂vǿ)?ǁ'b|Dݿ?$1 @}@z?ÿ3dl$?\ڂ%@K3,];ܿ^tKc?ߍut6?VFY?^@)<ܨ2?-AFR󤕧Vٿ[fJ+^࿬7ҿ!rؿyPLG¿{ aa:~J ؿޯ?No67?d9]J?<8?Ϗ uĿXa*?E=dds`@?+y0 z<?eڿu2D >ˆ୴%?6 #?^o?Ch? $;<4 ϮۿSA[ϿHyf-?mF?{FῈWn0vѿrߦ%ѿ1 Oj?ٷ?5;h?{{?v n?r:󿫵a?B ٿBM?←gS>H?|b0\?j?\t6G@?ob;̿`dur ?ot!?,KT?æ\&P &Ĝbǥ?]0k?oM) ?ӿpP?b#9ؿ XS}Ѥro?͟jJ?Z/06?a`o+u?uNW修/?òwzP?X s?+2?󄓂pտ]?Q@_b?AL@D\@V/Կ>S>P@ G?h<@?.\/῰O6JUf?]:Ƹ`@jK8?C4Vn ?PlQS-ܧ?5Z?nx!?:2?ի,lo0C?p ?:ds?Z&ca׿%&v迹5A|.6z ?G00t7?^aݿڱU? dпt?9t?4rrZgi!??e? Z}߿o!Rz?Zjx{/? }H M?ī{?mBo? b᾵?4")?Y?4k?t'lfH٩俉+6yq?ts?l?)? ?*c3ij?WeN$)=ȿ$p5C?p?= $@M8n࿛)O?͊ vs?#Tm+Rz߿gt! |S? ÷򿣶\m/:ֿz}Q?d ]B֕#v"?s98u??|*3+s?ERpf ?),>f> I.#? ?/EB?z1)#>5Q?sGtp9jqῐleQ?:z?YA$ݿ7 k`*Bw?lYP?*Yw ҤVnTSn?M7T]H108e+]L?)?oοiٿ?^v}oпМ^y@i8*6?OB?*)w߿4?yѿs8 ĕ*Qb??=?-k1?25KF=w6hο7eɓq߿3?J$ESb%4[׿1xr?S-_? rR?ZF dPqֿ"20r?mQے@VDa8I῀58'?)j?R ?v?Cv4?u=~̿1?aٿ?*١Kؿ(OJ ?Sθ ?Ōl~?(X be5nfb?5sBܿYZWn^?A mӿgs^g?a?P 8?<ޓ,[ҿ?!qU.?5]͚?8G?,e U0ڙw?-r}2X'?.)&ej \S?231XىWۿׯS꯷?\E0$?N|?ɫp[?f IwNr/7⿡!7?Iq?_, e%?2~y?~zc ?1Z&뽐?_gS-gt ,?ӫM`p?S?/?/ `[o%s?3f?Z?{?iC̷꿑,<͇-M*v?`01?(AOVoֿku2?p->d?ЂS6q۰?Kɿ$i7@3Dc?;Q3ڂy.W8@Ab?W,6𿁰Y{?>.H`M?_ Yu?!?U0lW|y݀W?:u?8*\?, ?3tkRF?@n2W?)M"^?o8@K,޿>g?디?|){x*~U??4;5?M'r?k?Ly?t16?E ?7?]%l?iYk? ?r]9+@"%?<]0 㿫Ys?Jx?Cv'v?)|*ڿ+(|c?9g9E?Ui%!?adMN?8 ?e4 j]AY X?T?%Ws{kR:t?sӄ?3$4y?-߬@ɿ)B+^RzBuץ=>S>@ x:#LUHg?jەN?*wU?xTe?RDFkݿQ1l;jypZ?믚ǔA?9yٽ%鿧 ]?V/E?.Zd?! *}t*/lbNOFտ >?5 ym?椤3?OPz?iHIp?AӿO 2?otJ?}t?nu?P^? n??|I;/??H_.W o?_vYp6o'^? ;X?7ZR?/gտ !i?" @ a˿T^ ?A+{?ˁY~ڿlh?kZإ+_65p a࿱-?uA?}8c?gƯO?[o?0)@Y?j+㿡G?܉6u=?Z݀8[x4ϫ?QFQ4@ۿ no?XSW]b?EO재=̿|꿺Uy,@_u?+?Ɯ#?]N? ? s*ǿv뿑ТAn׿|/i2?V>6?L~ʸ0 <濧 s/?,JIz$#{Y}k˿L9):m? ô׸DV?UkX2y@y̿P41gy_Zg ,ϿI2?ތ${?(?B?DPY?7\$'cԿy!I=j)qQ? 5s?33[O"?6/?FM?:ݿFjQ8ITz  aˤ\ ?E6ᅬ^ P@*ؿhڌ?M?$@Mj?%'!ʿgAZ̿@,=yQ>N>[? H5ڿ 몿oh?6ޅuH=?{??D :#?+@`F34Hο w?Ὼ,?qTʫXp?5 l*?s#Ъ ?NA¿do*?o n?ѥ&J.|fz0ڿD4"@gk?e,홲A,?JRxj >. FCʮ:g?`CԿ?+|$q3ur?&ɷ02 Ͽ}d(Z࿉YT!K?#A ڿ'iտDb7?f}ʿsA!@R\3?1HW ?7$Ͳ5}?k  j#/I?~ῧ3]?Cz޿ =.|j²ȃ?Aq.==?vދ-&o53?-f?y1uI?Ul?Y43?ђ&Q?*Ndÿ|H1ۭ.E~1١H^?(-$O$=iǸ?D &?zSkT&?GտITTٿqN￀ CU?ƵKb@U<@T@ dֿGw?t?1_vK??k߿sIUs^q/鿳lPU=U'b\}ِ׫ěqDS?oU?&ʀ?5`L/鿢mApCÿ= 3?a˟NN?*njZ⿄솓C?dz?zuo?gާp?ʿ76@'^ӿ8Rſ'g\?[(j ?a 5P4R?ߩXյ?O/#Qh?d??H? ?-e?+{DG퀝v.j?!|ݿu?! 8%?T(ĿыsnX|mٿ쮣?Nu@y{?!k?i|?8R?\V/f߲?W 1:&ȴ῏e࿤M ߿}?|N*2+o\ݿ!z??&˳c@6?=RSX,?W?'fG6?uk֑ҿ1U`(@3Sп?fTL7`o/D4?PDT?waAz_+%0 i ]F?T @qަ?X>|?f{Q׿kρ?WN.`?PK$޿`?E[B]?|j?ǫ,?O%/ 5?Ze’zG. y@e?r|%c?f7H?+LpٿϠx쿑@a?@ڿ} %ݲr?ƺNIѐ)k?_ Ob!lp@~HW?4`r 保1yL}6h3)?,'nY0ʿH @ܪQ?ĽPq@?˒6Կa?_`j?)+M? п9;LO?2GH޿&y?5_/t?Dsop?R_D?v?a^1J?^f[,?VW?s¡+?x\fb?'gb}Th?oȑ?y 3l濸Vg4? +D{ˬѿĂRĿ+dC ?b=* "ݿ`?Ugg`?`;|xW_٭nHٿat|ܿW/j??O t?)?۫@{B?zfF%?p`Yڿu?h{A?,ܨr݊?@I}.?sN"?GhsVh 쿳^?S5?~o?Qzrֿ:{3I45#?A. h?XzNɿN?66̲濜 !>g3YVq3 Կ'1[_쿿T)῅LDO?jVyNRF~Yѿ%45)$?P=֜X? ho]@$\U?lA8}VʶMZQɦѿW )&WW`? 4߁F𿮊Xg?k ?MA пaFݒοX1fPd@u?3+.+*?TId?\lq/2пw "?cbϦ>?JaF?I(Կ,'ۿ8ǐſ ˮO.?^գ?QI/?XɟZο?MZ?̓9pa?dvTk?}5O7?+m?Vm M? f׿~ -Nwؗ0:=f}:T~ ge|b?Ƀؿp0neſO#޿WwԿ?[id}뿢n ?'Tڭ剀?cʢͳ?6!`FF? ?M'1.T?Tl٤I2ki?+ϓ=?35?#A}݁A?Es^DIw?2?͖k\Yſ@ϷL?u3dnaֹF|d%{? |¼9LҿV^ ?A.iV?DI=AҿҝǠ?:U?vi?gK?{c=7K[ĿvU?~?=hŲ?:_&5aܿ.ո9;<|? ke⿁͠QHɿ?\$?W%"4ZM^\?|@s3ݿ;Y?aV0U?!tk?L?X5+Ng?ݟsH?$c"ɵ:.q5p?:Tu:|; ];R%{ϊ_!鿲;t?b#Q4J?W$x?)ǁs z9?,?Ooiays??#?xD䩫10?N~ ne?$-Fc+?;NxOL,?2֗ Sv]@?y?i5 ?@q0?J{0j'?2o?`tvC? M)`@{$?\s?Xu迪Ix$ýta!?|#pk~y$>%7п~V?EBϥv?}WֿG0?`k?h?lلȯ?Qg%5?rFO7:? AYaӿvg,%?N/??#>%J! 뿌2;j>?J˿̹p?*?v\?^rE1y#֓$R*NϿ1~?S `ZC?GCOLp32x:cLAÃ?^?lX/[|vkLC͂Q&kĠݿI?h-e?uK;Bfѿ ,5?胂?]o! u.8ʿu:x?jǜHZ [?^Fύ?RWοť2NI@VX ?T:O?9 T0?7R's?do)?/+UΚ忻R:D9[1B쿙X?en?ϔDSW?aܿ=C?'ȼy9?ĞtW gfw?=v^Tv?0" LpǑ2?r^!? ()) D-^_ 9iؿr]T?h\B?\ȿQPhпx&Kۿ}P|?c4_|쿊WI?H wѿKI?|?եz?@^D?N`đO׿B`bH[.bB?qYq2?,W?Ix@п؂q?WBpٿʧ[? ?G$οjQ?HÀn'Oo )?Fj?+ڿ*WO?J.@R2e?a߆˹? .h?ߗ2 ?F@%?ґwl@HIn+(ޛ[E8翚EzDck~"?_tl-vʿ}?85w6?x"Y~?2G??$13s>mh??v3ysӇt0oM\v-?ξ7ٿa{濿 ]lj?.oo!?,?Zi޿'ٿ~ݿ5*?l?8QDC?]wڟ'࿚i_ C?G;*?K? .wP_dc?7?{뿲 3$ʙCV?i3T :&14?~xO. hS?ik ?}[ѿ\UտA?6_xSMl?7tW:,?8dH«?'P-0ؿ֦8!Rf濔sj!?P?hZ￟V?Y?eM$?1;(?!E?vOͿ4i䦾?qT? ?d8=?Sm?.y{? @튨t?0k2yY4q[OzCa@?M(Z迷&o?,ɳ?CpcRп:?qBʖ? h?le(-?fWɼ⿔AciԬoΉ7+d?Rԧj$Ɓ?_pu9f<3ĄW*ylʿ7? nL3d?:N_ڇ^7H?t]l޿B賿G6r?1+t?2b0+C?|nǾ!?>?ce޿_#@k{\pW?d\pf?z.fEB]]E?T9\)v`ExοY\?mK{?ti*2@N[ HA?튣ܿM!`ہyr@V04?G[? 䈭ῘnϿaΧ.'?J@5鿺JdN^ݨ@V?fS} >ڹE c?F܎?[ K,@z@H۝iɿB< x?`zW(m?#-f ҏ?L? 2@>?ro?)6z'2Fi O8e޿WNp ?ޣ?WVLnM7Fj-?#Ler@xR?}M?8@j 2?P.,5&mOnc?˜OU!?\<_?:2S?ks ~ CɓKuP߿kx0? sӘ?2F-ѿ_S^ɿ5@D=R?"ٿFB(9$ I?(5\ÿ@b<?&连1Zu?(z?0?):{tX?֓Bt?ɑ)4?_6{TѿG?Ɨb9@Zbm.xJ?_fҘ"?{Ϸ#T?18 Mxd?x ?-`Åٿa[ {NpLڿMuL}?P!Z}? 4Fj}qjQ7͹4b5(w`?# 2- ?ٔ>{Cb LU? }+?߮F5f{ſ ;?ǡ\?aD5n?,=[?B?WOZ?H"I?8_٪?w[t ![?|cQ.d?/ h4ޖ?b(Vn?UNdQCܿtm?|Y0?ak?Th"ᅪvӂ?($@M俛{"+΅?|l?kBX #PĊt?$9ZJy?c? Ȼsi4`e?\\g*Wv;??*}Dž?bgl#E|w??"?O?W adſb d@ߜYԿWZ?e?2Va~㿮7w ٿ /Y,6zeZl:n?t 9[@Id,^"v0\tS=܉Ï9?ѽp?9X,dN1bҿ`΅M?>ƁX>俭)QL?&17-ڢ?NW~~?M`s?l]9?(z;?I aFqE%˓?\ \¿!y?QK?woK?ie".?N2ڿo`{ֿ$*$?hXr,9п9gܿ.1?Rֹٿs'U}?1$Ŀ]&W(X?kZ 7?JbE?UO?m7m?IWj?ʾ>?ƷLұ3Y/¿JHh5?w"+ ?*Pź+` ldl?&j@։2q3:??쿠)zο6u[?e-H %SpN|RIڪy?f޿T?;rÿ{[ä?jIV?|UQ?X?:LܿX,6pW忓K.?M+Ψo??b}Mֿ?!q?@U?5 \y?B/]?sIRNm ?⩆2/@*?R0迖 x ٿc/BG??ωa?g+#$տ[1ӿiy`:??g&x0_?y۩t?VY5OZ?e>R?kUKD??w;"?p(p?Xh^x<!V,j4C K?<=?BG>ߣsn@? Ƣ @د@ɘќҿ^c(?z;?صB N?C.K㿣]F)0 ѿ2K?e HT?%`>~.ſqnXUV?^?+؜N噿3ѿK_%g?9 $+8?q*c0Q/w?z /b?9]O,L?.N^1Q?3.+BNN:d?\tP.N0?eG$ ? 8l?;?!N_ tC@|5lM! M'=. y*n9?}5&8(9?5q]G?D_Rbѿu`俭9jU. ?si?/` ,҂CӿCwK?V/"Hٿ=G?5@z?xNJy n~V^ 1?LIcv@MZ?*p(ӿB?? [?ֲe~hٿ"eVсп^!e+OAb?!?V}?-?>?3EI!b?=,Q׿sO k 9 '^Gzw\d'?*?FԿ|#蝍? ny?](kZ<?ץCM/82D ?*)?W[ɋ'?$3z_@XM/u߿>_+?g:]ǟ wm9fÿLE[??Qz꠿l!?LmS+jeֿ/1Fn ?ԎEO-ܿg?3ު>b?k>?%Vv?bѰ?gEak)BO;?M?*=?i??"S?T;Hk02?>?L?`A$萿qۿbe&?Xi1뿀1zݿQʧ?uf?!4?y4]/uֿG:z8Oklȿ? ?鷐e?5?CPN? Ȓ"ȝk)@>T`?Q"΅(ֿ ??)wY?#E_w9")ٟa^?݌?Cl&?oE'B1f_c{ƿs?jK`ƿBp?%խ?Z=i?fI?4 ?o5?8:ڿD} g5?pbCbUXr#ӿb{q?d@?ԧVd?7fftMF?{@_?d|uON?~g?O^+@X?xX ?FWE?Ts?<??ˎB,?wă￰jj?!b?Ѽ8Կ96?Zп5M$̿R(}4#?] Rq?4;L aֿ@(x޶T&`ՓԿ$ ?^iH?w7n?!KN?{:r?7N¤zI&L ?43ؿ؍#Q?;58@kIſkO?GRޜ?\ ?֖\俿7@AiN˿WVc|7AT?eVgeǿԹS? ɿq0?wL{/o?P 簐 5!?v<$@n7/_ n?X#*x?_ܥ9?/[ hH?`\L]'ٿU^/?4Y=?4ZERB8LVs[࿀ju ߿>?= T?pI hO?8Et?(QG?A~Aѿ$#8+OԿx9?]yYƿO?t?=D?oe6?~?Ѭz? ?5};B!ѿ|!ua? {8a+6PiDd{m!D'?gt{?1,*7?:A2?y>?ߨ-?u ~ÿNܧRrտ+,G!?10:?k"?W$?O>qӿrN[?Fmd?ţ?"2?&6Q` ?@_濹`Zbۿ?W!?jX?.h.?5:K[B?٩'?z#Zc̙֊t@M{?ΐʀ-ѿ4*ABiO֎? B?*yc^?UoV;'Byg*cۿń?>_`?I^A?(l]j(g?wyL?8o?`4Bq߿+ ?"z=dտ|d?@SAֿ<>9nO?ITA՘޿9zV迯cNӮ?8'Rѿ*wPNc2e2񿊻}SKG5E3|r@-c?wx{ͿH 1gi{;e_s^e4ؗ`ɿ8VUю޿*TʿK? шC?l?bY浿%?+Q?LM?ҕ?5H? ,(?τ?dc3="^-?+c?3? ~U &ѿ0ue6M?KM@b7s` `?s6jRmV?1?.rQmL$dzypEx?y ގw¿FC]Cf?&?5.О?;l_p?n?pv&1?ߏ?L?h?!iӿFB?y5?l⧤?/.|A?C=fN?cr?!(pmῖ?౿?Lya ANf ɟ;71ҿp?RaM{C9Y1Ȅܿ&L/ѿwC+7PE߿ܡe?ſGD_?U3?s۫h?gtG.ÿNn@?Q?*? 4Uտ^ޯIEq?F>Э5?@?)Q?'e5뿥E6Ϳ(#l?A} Pfɿ8Q^9 ?$'KڿޥB?hl?AQ俄8pr?ɽ? ZȿhU,Ԑ տAGB?ԿL'q?ez ?,]˷?߹?J`p?l8z?3 v8L Ȱ <8 ?ݔ?'p|hz;?T9_? ! ˿ǚ.&?BJY?^ N?'5Z䔞y2Qq?erT[ܿL3Z =?\٦C9wFm?Ay[WO濆?P!?d٦?I?b2Ջ?x_6cTb;5?{0S?,[⿑&1_}[?Kѿ90KnU7e?(؜?[ ߿>nF }ns9M?b?kӿQD迂}Fc?W?ip$)D𿺙y*X&蹛*Ҝj&;os?l?o;lʿ8 n?Xy?xv?or'̿U~OM8?ҥNԿo?eUԣ? 0+6?F|>\п %Rq8`'/ʿ+|@?8X*|?8m CCKI̗"?U0j=ԿݚӿZQʩٚ?MlgS?/Q@̪??/_Ώ@@3(ݿ" P?kmؿH 2?t* οp]r:znsN?O;OJ] ?iơ迪tٿ2A >6=? ei$&?H[@IU`Msѿ=‡G?GY-3v5Ӊo_魹?NCvҿ}3#ɦ?}D?d? ?]59t? 7n4{߿pѽgGI4Q?|!(&/ƒYy?VM/o ٿ'?f?#o\`;* U7{?q?,zb?A q?止?˱kܷ?H;hS$?D,.2D@Q}P?+ :^?X@l;h?p?ϿS^?w$V?b?cyX|1?l%8]?qЧ?*N? ?LSk࿹avcC62a?z;$O?(5qK?5)90d] ?a+?fK?]d߶YۿO(?K`M?.!iԁrTϛ^տmmɿ տ2I}*? @*@.X 5(6u2~~Uw\(?.d򹀏Sw?ؒiٿJ%׿T ^Ts=?1k6?hA?HQ+x ! A x x xJ xS xL x# x x# x C x 4` J` Z` \` U`  ` 1` ` C6? U#c ^   D &[BZUb2<U^ J%&  J^ JQ J J. J : J. J0 J Z J 4 J F J B`  Z J .C # C (  QWVO]. <   G [V           )  '  x10A鱀)"fl #@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @3 @ @ @ @ @ @ @X @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @'  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @'    xб 1mVSrtz+ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ T @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ ^ 3 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @5 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @.ViTables-3.0.0/examples/misc/000077500000000000000000000000001311223072700157725ustar00rootroot00000000000000ViTables-3.0.0/examples/misc/external_file.h5000066400000000000000000002105001311223072700210470ustar00rootroot00000000000000HDF  @` TREEHEAPXa1H (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1 ` *@(dUU2R 0SNOD 0TITLEA linked array (CLASSCARRAYTREEPU (VERSION1.1ViTables-3.0.0/examples/misc/fnode.h5000066400000000000000000000307301311223072700173260ustar00rootroot00000000000000HDF  1` TREEHEAPXfnode_test@ (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.0`q` ホJ (CLASSEARRAY (VERSION1.0SNOD/H (TITLE 0 EXTDIM > 0 NODE_TYPEfile @ NODE_TYPE_VERSION TREE  This is a test text line. And this is another one. Of course, file methods can also be used.This is a new line.  H content_typetext/plain; charset=us-ascii 8authorIvan Vilata i Balaguer @creation_date2004-10-20T13:25:25+0200 ` keywords_en3(lp1 S'FileNode' p2 aS'test' p3 aS'metadata' p4 a. ` keywords_ca5(lp1 S'FileNode' p2 aS'prova' p3 aS'metadades' p4 a. (ownerivan Pacl/(dp1 S'ivan' p2 S'rw' p3 sS'@users' p4 S'r' s.ViTables-3.0.0/examples/misc/genericHDF5.h5000066400000000000000000030327211311223072700202630ustar00rootroot00000000000000HDF  5 HEAP0A notearraysdatatypesimagesTREE ( `/20021107174532/SNOD  X l(llHEAPmTREE x  X   d220021107174532 ^d2xSNOD  f00g@p@h8P`jxpkHEAPX @h8HEAPThis file was created for testing purpose. fdaIt contains groups, datatypes, datasets, links.fff??ff&@`@̌@ff@33@@@33 AA(A4A33CAQAff^AlAyAA33AA̘A33AffA̬AAffAAA33AAA33AAA33AAffBBB B33BBB33BffBB"B&B?`@ff@@33 A(A33CAff^AyA33A̘AffAAA33AAA33AffBB33BBffB"B33)B33/B5B;BBBHBNBTBZB_BeB33kBpBffvB{BB33B̅BffBBffB̏B33BBBff&@ff@@(AQAyAAffAffA33A33A33AB33B33B"Bff,B5B>BHBPBZBffbB33kBsB{B́B̅BBffBBBBffBB̡B̤B̧BB33B̯B33BB̶B̸B̺BB33B̿B`@@(Aff^A33AffAAA33ABB"B33/B;BHBTB_B33kBffvBB̅BB̏BB33BB̡B̥BB33BB̳B̶BffBB33B33BBBBBBBBBBBBB̌@33 AQA33A̬A33AAB33B33)B8BHBVBeBsBB33BffBffB33BḄBB33BffB33B̸BB̾B33B33BB33B33BBBB33B33BB33B33B̾BB̸B33BffB33BBff@(AyAffA33A33A33B"B5BHBZB33kB{B̅BffBBffB̡B̧B33B33B̶B̺B33B33BBBBBBBBBB33B33B̺B̶B33B33B̧B̡BffBBffB̅B{B33kBZB33@33CAAAA33B&B;BPBeB33yB̅BBBB̥BffB33BffBB̿BB33BBBBffBBB33BBffBBBB̡BffB33BBBnBZBDB33/B33BffBAffAlA@ff^AffAAB"B;BTB33kBBBBB̥B33B̳BffB33BBBBBBBBB33BffB̳B33B̥BBBBB33kBTB;B"BBAffAff^A@ff^ff@yAffA33A33B5BPB33kB́BffBB̡BB33B̸B33BffBBffBBffBBffB33B̸B33BB̡BBffB́B33kBPB5B33B33AffAyA@yff3333š5P33ḱ33 A33A33AB33)BHBeBBffB33ḄB33B33BB33BB33BB33BB33BB33B33ḄB33BffBBeBHB33)BB33A33A33 A33 333333)Hšešff33̣3333A̘A33AB8BZB33yBBḄBB̶BBB33BBBBBBBffB̠BB33BpBPB33/B B33AA@ff&33C̬33Bffbššff̦š̸33(AffA33A"BHB33kB̅BB̡B33B̶B33BBBBBB33B̶B33B̡BB̅B33kBHB"B33AffA(A(ff33"H33k̅š̡33̶33šš33̶4AAB33/BVB{BBBB33BBBBB33BBffB33B̦B33BBpB33KB"BA̘A@`l33š;ffb33ff̡33̿š3333̸̢šš33CAA33B;BeB̅BB̥B33BBBBBB33BffBB̡B33BBZB33/BffBffA33 A`yffHpffš3333ffš33̶ffšffffvN"šQA33A33BHBsBffBB33B̸B33B33BB33B33B̸B33BBffBsBHB33B33AQAQ3333Hšsffš33̸33333333̸33šffšsH3333QQAff^AA"BTBBB̥B̳B33BBBBBffB33BBB33kB;BBffA@ffš;33kš33ff33̳̥ššT"ff^ff^AA"BTBlAAff,B_B33BffBffBffBffB33BBBffBBBBffhB5BA33Aff&@33C"V33šff33š33ff̡šp>33ffAA33BNBff~BB̦ByA33A5B33kBffB̡B33B33BBBB33B33B̡BffB33kB5B33AyAy33533kff̡3333šš3333̡ff33kš533yyA33A5B33kBffB̡B33B33BBAffB>BffvBffB̧BffBBffB33BB̶B̦B33BsB;BAyAfff33B33yšš33ffš33̥p833l?ABDB{B̕BB̸BBBBB33ABHBB33B33BBBBBB33B33BBHBB33A33Hš33333333šH3333ABHBB33B33BBBBBB33B33BA33BPB̅BB33B̿BBffB33BB̡BBZB33BffAff&@yH́ff̯3333ff̶̤ffffb"ffffQA33A>B{BB33BBBBB̸B̧BB33kBff,B̘ABZBḄB̶BBBBBffBBpB33/B33A@33C33Bšffš33333333š33Hffff^ff@A33)B33kB33BB̺BBBB33B̥BffB_BffBffA?33AffBffbB̏BB̺B33BBffB33B̠B̅B33KBffBQA533y33̯33̾ffvff23333ff^ABNB33B̡BBBBBB̧BB_B33B̘AfffffffA"B33kBB33B33BBB33B33BB33kB"BffAff"33kš33333333š33k"ffffA"B33kBB33B33BBB33B33BB33kB"BffAff"33kš̬A33)BsB33BffB33BBB̸ḄB33BHBA33 AQVffš3333̾33ffše3333̌@33A8BBB33B33BB33B33BBB8B33Ǎ@3333šeff33̾A33/B{BB33BBBB33B33BpB"B̘A`33;33̡3333ššešy@AHBffB̥B̺BB33B33BffB̏BZBB33CA(ffTffš33šffA5B́B̡B̸BBffB33BBffBPB33A@y3333k33ffff3333k33šy@33APBffBB33BffBB̸B̡B́B5BffAff5̸̡́šff33šA;B̅B̥BBBBffB̡BB33/BffA`Hš33š̶šffv"33@33ATB̏B33B33BBB̳B33B33kBBff^A(š_ššššš_ABBBB̾BBB̳BBeB B(Alffšsšffš̤33ff2ff̌@APB̏BB33BBB̯B33BVB33A33@̘ff,š̸̢̺̟33y"33AHBffB33B33BB33B33BffBHB33A33Hff33333333ffH3333AHBffB33B33BB33B33BffBHB33A33Hff33333333ffH3333AANBBB33BBB̥B́B33)BA(pšffš33ffbff33ffA8BffBB33BB33BffBB>BǍ33\š̺̠ffv3333ClA"Bff~BATBB̳BBBffBB33kBB@ff;3333̥š"ff^ff^A"BB̥B33BBB33BB;BffA33kšff̳šTATBB̳B33AZBB̶B33BBBBPB33Aff&33ffbff̸š33Hffff@B33kBB̺BffBB̯BffB>BffA33šs̡šff33šš5š(A33B{B̤B33BBA_BffBffB33BBBB5B33A33C"33š3333̡pffANBB33BBB̳B33BHBA33ffṿ3333̧šff(̘A;BffBBffBB33BAeBBBB33BBB33B33 A̬Hff3333ffff833QA33)B33B33B33B33B̸B33BVB33Ǎšṣ̣̾̾šš33AVB33B̸B33B33B33B33B33A33kB̡B33BB33B̡B33kB33A3333k̡3333̡33k3333A33kB̡B33BB33B̡B33kB33A3333k̡3333̡33k3333A33kB̡B33BB33B̡B33kB33AApB̤B33BB̺BffBTBffA33 ̅ff33̳šš5l33A>B33BBB33BffB́BB33@33\šš̡̾ffhšff&@B33yB̧BBB̸BB33KBffA4ffBffvB̧BB33B̶B33B;ByA33Bš33š33̥p33?B{BBBB33B̏B5Bff^A̘Hff33̣33kš`@33BBffBBB̳BffB33/B33CAffNB{BBB33B33BB"B@33ffb̸̡̿š>šyAHBB̺BB33BBZBffA(ff,ffšff̧šs33ff&@33B́B33BBB̯B̅B33Bff@3333k̤BB33BBB33BBBš3333šBB33BBB33BBBš3333šBB33BBB33BBBš33 B33B̯BB33B̧BnBA33)š̶š33šT33yADB33BBBBB8B33CAff_̢33̳šff̌33A33yBffBBBffB{BA`33ffš33B̅B33BB33B̡BZBffAyHff33̶ff"ff33A{B33BBB̧B33kB33A(5š̺̺šš5(33A33kB̧BBB33B{B33Aff"ff̶33ffBffBBB̾BffBDBff^Affe̦š33ffšsA5B̕BBB33BB"B̌@ff́š33̠Tš̘AVB̡BBB̯BBAff&̸̏ffšff2BB̶BBBB33/B@33š33šHff^A33kBBBB̥B_BffA33T̡33ffv(A;B33B33BB̳B̅BB`"̏ffff̏"`33BffB̸BB̸BffB33B33ff̸̸ff3333BffB̸BB̸BffB33B33ff̸̸ff3333BffB̸BB̸BffB33B33ff̸̸ff3333BffB̏B̺BB33B̅BffB53333ffv33ff^ANB̡BBB̧B_B̘Affešš̟H33CA{BB33B33BB33/Bff@ff̶ffffš?"B33BB33BBBffB{BAff^P̣š̢NšQAff~B33BBBBffBfff"ff33ffš33y33lATB̤BffB33B̡B33KB33CA33ff̏33š?&BBB"BB33BB33B33kBffAff33k3333š""BB33BB33B33kBffAff33k3333š""BB33BB33B33kBffAff33k3333š""BB33BB&BB̿BBBZBlÁ33̶ššQATB̦BBB33Bff,B?š̾ššš_33Aff~B̳BB33B33B33A4N̤šffff2`33B33BBBffB33)B33B33BḄBHB33 Aff3333še3333AB33BB33BB33A33e3333ff33 AHḄBB33B33B33)B33)3333̣H33 BffBB33B33BeBff,BffBffBBB5Bff&@"33š̡>ff33BB̿BB̤BHB@333333̧P(BffBBBBZBQA33̺ff33ffbšy33A̅B̸BB̯B33kBA33/BBBB33B"B`;̡33š@HB̥BB33B̏BB(Tš33ff^A_B33BBffB̅BA3333kš̶ššffAffvB̳BB̳BffvBffAff2B̟BB33BffB33BTš33̅š̘AsB̳BB33BnB33A33ffffšNšB̕B33BBBff,Bٿ8̡33334AZBffBB̸B33BAff33y5B̡BB33BffB33Ay33k333333kšy33AffB33BB̡B5B5̡š33ff33yA33kB33BB33B33kByA33ff33š̡š55B̡BB33BffB33Ay33k338ḄB33BB33B33A̸̬33šȞ33)BBB̾BffBA33s3333V33 33B33B33B33BffBBQeffffšešQBffB33B33B33B33B33 V33;B̥BBffBBffA33š"@TB33BB̳B33kBff^Aššff^A33kB̳BB33BTB@"š33ffABffBB̥B;B;̥ff>B̧BffB̶BsByAšff3333A{B̸BB̤B5Bff&Hšš33kšQ33BBB̿BffB33Aff̺́33̡ff,ff@PB33BB33BffbB(A33ffš33šBBBB̳BeB(Affšš33ffȀB33BB33B33A̘̺̟"33 A_B33BBffBHB?;̧š3333k33CBffBB33B̅BAff33šffDBffBBBVBff@ff2̥ff33ffh(B̟B33BffB33yByA 33š33šffA33BffB33B33B33A̿ff3333A33BBBffB33Blffv̸š̠"šAHB33BB33BHBH3333HHB33BB33BHBH3333HHB33BB33BHBH3333HHB33BB33BHBH3333HHB33KBBBB8Bff\̳ff̣&(AnB33B33BBByff~ššffA33B33BffB̏BA33̿ff̬33A̕BffBBBA33š̸p4"B̢BNBBB̥B33)B(pffš33ffffAffB33B33BBA33̺ffv33C"ḄBB33BTB?Ḩ33/33 A33kB33BBffBB̘̅33ffšABffBPB33BffB̡B33Bý33ffffff33ABB̸B33kB@5ššš5š@33kB̸BBB33Affffff33́šy33B̡BffB33BPBP33ff̡33šyÁB33BffBTB̳BBBBff33šff^"B̥BB33B;B33kffšABBffB33kB@;33̥"ff^AB33BBBffAš̳TTB̳BBBVB33B33B33BA33ff̸šěHBffB33BBB̬ff33šs33 8B33BḄB33B333333̾ššQ33)BBBB33)BQ̾33333333ḄBB33B8BZB̶BBB33A33ff33Hff@33kB̺BBffBffA33̡33š5(A{B33B33B̅ByA"̧̧"šyA̅B33B33B{B(A533̡33ffAffBB̺B33kBff@\B33BB̏B̬A33̢š33)lA̅BB33BsB@D333333AffBBffBBBffvš33šff^ff,BffBB̡B BffZfff?_B̸BffBBffA_BffBBB33A"š̡šABB̳BHBffv3333š(;BBB33BA33š3333/ff^A̅BBB33kB`@T̶̏ffB̥BB̥BBff̏ffbB̺BffB̅BQA5̯33B̡BB̧B33BffššHš@{B̿B33BsBff@P̶šffš"BBBB33A33ffff33ff,šyABB̸BZBff&33kšeBB33BB33 AH33ff3333)B33B33B33B33Ạ̣33A33B33B33B33)B33ff33H33 AB33BBeBe33š33 HB33BBffB33A33)3333ffhB33B̿BffvB̌@Ź33 33KB̶BBffBQA;šš33ff,BBBB̬Affššff33 B̥BB̟BA33̠̤šAffBBB33B̕33kB33B33B33kB33k333333k33kB33B33B33kB33k333333k33kB33B33B33kB33k333333k33kB33B33B33kB33k333333k33kB33B33B33kB33k333333knB33BB_B̌{šffP33 ABBBBBQ3333ff233ABBB"B̬ffš33ABB̤BffB̡̟33B̦BBffBA33ffš33pB33B̺BTB33 ̅ff̳š533A33BBffBB33̡šB̧BBBffA33)šš33CHB33BB{B`@e3333š_ff@BB̶BBBff^ff"AsB33B̸BHBQff33333333ABBB33A333333ffšQHB̸B33BsBs33̸HšQAffB33B33B33B33š3333B33B33BffBQAH̸33šssBffvBB̶B;B33š̥33BBB̏Bff^AHff3333k`@BB̳B33/Bff33̡B33BBB(AT33š_@̅BBB"Bšš"BB33yBBB33/B̬ffšff33)BBBff~B?sš533A33BB̟BA"ffff́`nB33BffB;B̡šffB̯BBBff@ffh33̸BABB{BB33B"B33̡ššyHB̺B33BZB(ff̧3333B33BB̅Bff@33k33̶š5ffAffBBffBffA5̶3333kff@̅BB33B33B33̧ff(ZB33B̺Bff~BffB̯BB̧šeBB̶Bff2B̕šy33KBBBNBl̟ff33/BB33BffhBšš33BBBBfff?{š33šA̦BB33BBB33BB33šBB33BB33šBB33BB33šBB33BB33šBB33BB33šBB33BB́BBB33A3333ff33kš@ffBffB̡BffA5̸33PšyABBByAP33̸š5ffA̡BffBffB@33kff333333ABB́B́šš3333B33BffB33kB33BB̧BA33)̶33TšyA33BBB33CA_33̳ff33AffBB{B`ff̣š5BffB33BHB̘̏33 33kBBB33Bšp@ffBB̟BffABBB̤BA8̺ffš;ffẠBB̅Bfff?3333̥5BBB>B̢33šٿ́BB̦B33Aff2ffšB̬A̡BBffBff&@̧š33/B̸B33BDBff̠̅BB̡BffAH33̶"33A33BB33kB(š(33kBB33B33A"̶33HffA̡BB̅B̡̅ffHB33B̶B"B3333š33k(ABBB(A33kš33B33BB33AV33ff33B33B̾BHB̬̣33š̌@ffBB33BQAe333333)B̸BB8B33šs33 AffBBffB33 Asš338BB̸B33)B3333ffBBffBff^Aešff5BB33B"Bffš33T̘A̡BBBff̏š33 ffvBB̥BAH33̳33B33B33BBB̧p(ABBffB`@33̟BBB(Asš̤ffPB33B̯B33Aff,̸̺"šB33B̿BHBff̧š33kšQAffBffB̅Bff&ffšš{B33B̡BAZff33335BB̶B33B33š33>BBB@šff^33kBB̥BffAT33;B33B̳BB"ffff"B̳B33B;B33TffḀBB33kBff^š@BBBš33BBB`@33́̕B33BffB(A33yššff^nBB̢B33Affbff̦ffVBBBA33K33>B33BffB33Aff233š&B̺BffBB3333" BffBBffBffffffBBffBffffffBBffBffffffBBffBffffffBBffBffffffBBffBffffffBBBB`ffš@B33Bff~B(ššsff^A̠BBffhB33̤ff\ffABBPBff33DA̯B33B8B3333ff,BB̺BB̸33"BffB̏BB̅B33ffvff^A̡BB_BffHAB33B33/B̶ff"BB̳B33A;3333šTBB̥B33A33kš(BBB`@`@BBBB́B(šffbffAB33B>B33̺33"BB33B33AHff̧š33kB33BffB@̅ffff&@BffB{BQ̡šZffA33B̿B5B̶̸33ff,B33B̯B33BB{Bff^̣šNA33BBffB"33š33TBffB̡B33CȀš?B33BffvBy̥HšA̳B̺BB33)33šZBB̟B(A33ff`@BBpBffB33BsB33338B̸B33BAH33̣šQBBffB̌3333še̬A33B̾B33)B33ff33VBBB33 A333333 ABBVB33ff3333)B̾B33B̬ABB33kBff3333""B33B33BffA33kšBB33kBff3333""B33B33BffA33kšBB33kBff3333""B33B33BffA33kšBB33kBff̕BBffbBff̺ š;BffḄB4A̅33šQḀBB5B̯ffhBBffBٿ\33ABffBBB33̡šffBBBļ33/33B33BBffAnBBZB33̶šTBB33B?šš_33A̳B33B33ANff`33BBeB33ffffHBffBBff@̏3333kAB̺BBBš̟ffBBpBffBBPB33̸33ff33kBffBffB̡ffš533B33BByÁ́šyAB33B33B5ff̡šffBffB33kBff33̸33PBBBšP33A̸B33BffA33kff  !"#)*+,- |mAE@"DM`$dva=ΘqbeZPCG &3MdiCdgnǼwtwpNsyA@.2.#*OTY``"TZA& U04,uupPRcf؆/3:Cą`w}zaeitwѯaTW``5CJ_DDQp6T]QuwH8:QU 8Bqרz (䰲6dmO׃vloLtMevJUe9u}2UlloׄV&-p5IVlڼW:;+%6j/*5.:G˻к|METo>$)A2XQ‡ILhX2Σmo%(滽m7BnIL ppu|#Yi*usX]ŗ__B`{QOqΈNPi@#KV!l|>|~|Y]XF?@ABCDExyz{|}~     @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopq      !"#$%&'()*+,-./0123456789lmnopqrstuvwxyz{|}~456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcde                           ! " # $ % & ' ( ) * + , - ` 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 { | } ~  ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ 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                           ! T U V W X Y Z [ \ ] ^ _ ` 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 { | } ~      ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M                 H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` 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  !"#$%&'()*+,-./0123456789:;<=>?@Atuvwxyz{|}~ <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm      !"#$%&'()*+,-./012345hijklmnopqrstuvwxyz{|}~0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a      !"#$%&'()\]^_`abcdefghijklmnopqrstuvwxyz{|}~$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU     PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI|}~     DEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu   !"#$%&'()*+,-./0123456789:;<=pqrstuvwxyz{|}~89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi      !"#$%&'()*+,-./01defghijklmnopqrstuvwxyz{|}~,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]      !"#$%XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ     LMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} !"#$%&'()*+,-./0123456789:;<=>?@ABCDExyz{|}~     @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopq                   ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 l m n o p q r s t u v w x y z { | } ~  !!4!5!6!7!8!9!:!;!!?!@!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![!\!]!^!_!`!a!b!c!d!e!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!""""""""" " " " " """"""""""""""""""" "!"""#"$"%"&"'"(")"*"+","-"`"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"{"|"}"~""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""(#)#*#+#,#-#.#/#0#1#2#3#4#5#6#7#8#9#:#;#<#=#>#?#@#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###################################################################$$$$$$$$$ $ $ $ $ $$$$$$$$$$$$$$$$$$$ $!$T$U$V$W$X$Y$Z$[$\$]$^$_$`$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${$|$}$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%% %!%"%#%$%%%&%'%(%)%*%+%,%-%.%/%0%1%2%3%4%5%6%7%8%9%:%;%<%=%>%?%@%A%B%C%D%E%F%G%H%I%J%K%L%M%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&& & & & & &&&&&&&&&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W&X&Y&Z&[&\&]&^&_&`&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&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''' '!'"'#'$'%'&'''(')'*'+','-'.'/'0'1'2'3'4'5'6'7'8'9':';'<'='>'?'@'A't'u'v'w'x'y'z'{'|'}'~''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''((((((((( (<(=(>(?(@(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([(\(](^(_(`(a(b(c(d(e(f(g(h(i(j(k(l(m((((((((((((((((((((((((((((((((((((((((((((((((((())))) ) ) ) ) ))))))))))))))))))) )!)")#)$)%)&)')()))*)+),)-).)/)0)1)2)3)4)5)h)i)j)k)l)m)n)o)p)q)r)s)t)u)v)w)x)y)z){)|)})~))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))0*1*2*3*4*5*6*7*8*9*:*;*<*=*>*?*@*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*[*\*]*^*_*`*a***************************************************     hijklmnopq͇̇·χЇч҇ӇԇՇ0123456789\]^_`abcde‰ÉĉʼnƉljȉɉ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԎՎ֎׎؎َڎێ܎ݎ89:;<=>?@A defghijklmȐɐʐː̐͐ΐϐАѐ,-./012345XYZ[\]^_`a’ÒĒŒ !"#$%&'()LMNOPQRSTUxyz{|}~ܕݕޕߕ@ABCDEFGHI     lmnopqrstuЗїҗӗԗ՗֗חؗٗ456789:;<=`abcdefghięřƙǙșəʙ˙̙͙xyz{|}~ܮݮޮ߮@ABCDEFGHI     lmnopqrstuаѰҰӰ԰հְװذٰ456789:;<=`abcdefghiIJŲƲDzȲɲʲ˲̲Ͳ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}طٷڷ۷ܷݷ޷߷<=>?@ABCDE     hijklmnopq̹͹ιϹйѹҹӹԹչ0123456789\]^_`abcde»ûĻŻƻǻȻɻ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY         ! | } ~                  D E F G H I J K L M                     p q r s t u v w x y           8 9 : ; < = > ? @ A                     d e f g h i j k l m           ,-./012345""""""""""D#E#F#G#H#I#J#K#L#M########### $ $$$$$$$$$p$q$r$s$t$u$v$w$x$y$$$$$$$$$$$8%9%:%;%<%=%>%?%@%A%%%%%%%%%%%&&&&&&&&& &d&e&f&g&h&i&j&k&l&m&&&&&&&&&&&,'-'.'/'0'1'2'3'4'5'''''''''''''''''''''X(Y(Z([(\(](^(_(`(a((((((((((( )!)")#)$)%)&)')()))))))))))))))))))))))L*M*N*O*P*Q*R*S*T*U***********++++++++++x+y+z+{+|+}+~++++++++++++++@,A,B,C,D,E,F,G,H,I,,,,,,,,,,,- - - - - -----l-m-n-o-p-q-r-s-t-u-----------4.5.6.7.8.9.:.;.<.=...............//////`/a/b/c/d/e/f/g/h/i///////////(0)0*0+0,0-0.0/0001000000000000000000000T1U1V1W1X1Y1Z1[1\1]111111111112222 2!2"2#2$2%222222222222222222222H3I3J3K3L3M3N3O3P3Q333333333334444444444t4u4v4w4x4y4z4{4|4}44444444444<5=5>5?5@5A5B5C5D5E5555555555566666 6 6 6 6 6IIIIIIIIIITJUJVJWJXJYJZJ[J\J]JJJJJJJJJJJKKKK K!K"K#K$K%KKKKKKKKKKKKKKKKKKKKKHLILJLKLLLMLNLOLPLQLLLLLLLLLLLMMMMMMMMMMtMuMvMwMxMyMzM{M|M}MMMMMMMMMMMN?N@NANBNCNDNENNNNNNNNNNNOOOOO O O O O OhOiOjOkOlOmOnOoOpOqOOOOOOOOOOO0P1P2P3P4P5P6P7P8P9PPPPPPPPPPPPPPPPPPPQQ\Q]Q^Q_Q`QaQbQcQdQeQQQQQQQQQQQ$R%R&R'R(R)R*R+R,R-RRRRRRRRRRRRRRRRRRRRRPSQSRSSSTSUSVSWSXSYSSSSSSSSSSSTTTTTTTT T!T|T}T~TTTTTTTTTTTTTTTTTTDUEUFUGUHUIUJUKULUMUUUUUUUUUUU V VVVVVVVVVpVqVrVsVtVuVvVwVxVyVVVVVVVVVVV8W9W:W;WW?W@WAWWWWWWWWWWWXXXXXXXXX XdXeXfXgXhXiXjXkXlXmXXXXXXXXXXX,Y-Y.Y/Y0Y1Y2Y3Y4Y5YYYYYYYYYYYYYYYYYYYYYXZYZZZ[Z\Z]Z^Z_Z`ZaZZZZZZZZZZZ [!["[#[$[%[&['[([)[[[[[[[[[[[[[[[[[[[[[L\M\N\O\P\Q\R\S\T\U\\\\\\\\\\\]]]]]]]]]]qqqqqqqqq qdqeqfqgqhqiqjqkqlqmqqqqqqqqqqq,r-r.r/r0r1r2r3r4r5rrrrrrrrrrrrrrrrrrrrrXsYsZs[s\s]s^s_s`sasssssssssss t!t"t#t$t%t&t't(t)tttttttttttttttttttttLuMuNuOuPuQuRuSuTuUuuuuuuuuuuuvvvvvvvvvvxvyvzv{v|v}v~vvvvvvvvvvvvvv@wAwBwCwDwEwFwGwHwIwwwwwwwwwwwx x x x x xxxxxlxmxnxoxpxqxrxsxtxuxxxxxxxxxxx4y5y6y7y8y9y:y;y?@ABCDE     hijklmnopq́́΁ρЁсҁӁԁՁ0123456789\]^_`abcdeƒÃăŃƃǃȃɃ$%&'()*+,-tuvwxyz{|}ؘ٘ژۘܘݘޘߘ<=>?@ABCDE     hijklmnopq͚̚ΚϚКњҚӚԚ՚0123456789\]^_`abcdeœÜĜŜƜǜȜɜ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԡա֡סء١ڡۡܡݡ89:;<=>?@A defghijklmȣɣʣˣ̣ͣΣϣУѣ,-./012345XYZ[\]^_`a¥åĥť !"#$%&'()LMNOPQRSTUxyz{|}~ܨݨިߨ@ABCDEFGHI     lmnopqrstuЪѪҪӪԪժ֪תت٪456789:;<= !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\]@ A B C D E F G H I                lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A          d e f g h i j k l m P4Q4R4S4T4U4V4W4X4Y4444444444455555555 5!5|5}5~555555555555555555D6E6F6G6H6I6J6K6L6M66666666666 7 777777777p7q7r7s7t7u7v7w7x7y777777777778898:8;8<8=8>8?8@8A88888888888999999999 9d9e9f9g9h9i9j9k9l9m99999999999,:-:.:/:0:1:2:3:4:5:::::::::::::::::::::X;Y;Z;[;\;];^;_;`;a;;;;;;;;;;; <!<"<#<$<%<&<'<(<)<<<<<<<<<<<<<<<<<<<<<L=M=N=O=P=Q=R=S=T=U===========>>>>>>>>>>x>y>z>{>|>}>~>>>>>>>>>>>>>>@?A?B?C?D?E?F?G?H?I???????????@ @ @ @ @ @@@@@l@m@n@o@p@q@r@s@t@u@@@@@@@@@@@4A5A6A7A8A9A:A;Aa?a@aAaBaCaDaEaaaaaaaaaaabbbbb b b b b bhbibjbkblbmbnbobpbqbbbbbbbbbbb0c1c2c3c4c5c6c7c8c9cccccccccccccccccccdd\d]d^d_d`dadbdcdddeddddddddddd$e%e&e'e(e)e*e+e,e-eeeeeeeeeeeeeeeeeeeeePfQfRfSfTfUfVfWfXfYfffffffffffgggggggg g!g|g}g~ggggggggggggggggggDhEhFhGhHhIhJhKhLhMhhhhhhhhhhh i iiiiiiiiipiqirisitiuiviwixiyiiiiiiiiiii8j9j:j;jj?j@jAjjjjjjjjjjjkkkkkkkkk kdkekfkgkhkikjkkklkmkkkkkkkkkkk,l-l.l/l0l1l2l3l4l5lllllllllllllllllllllXmYmZm[m\m]m^m_m`mammmmmmmmmmm n!n"n#n$n%n&n'n(n)nnnnnnnnnnnpqrstuvwxyԂՂւׂ؂قڂۂ܂݂89:;<=>?@A defghijklmȄɄʄ˄̄̈́΄τЄф,-./012345XYZ[\]^_`a†ÆĆņ !"#$%&'()LMNOPQRSTUxyz{|}~܉݉މ߉@ABCDEFGHI     lmnopqrstuЋыҋӋԋՋ֋׋؋ً456789:;<=`abcdefghičōƍǍȍɍʍˍ͍̍()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}ْؒڒےܒݒޒߒ<=>?@ABCDE     hijklmnopq͔̔ΔϔДєҔӔԔՔ0123456789HIJKLMNOPQtuvwxyz{|}ث٫ګ۫ܫݫޫ߫<=>?@ABCDE     hijklmnopq̭ͭέϭЭѭҭӭԭխ0123456789\]^_`abcde¯ïįůƯǯȯɯ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԴմִ״شٴڴ۴ܴݴ89:;<=>?@A defghijklmȶɶʶ˶̶Ͷζ϶жѶ,-./012345XYZ[\]^_`a¸øĸŸ !"#$%&'()LMNOPQRSTUxyz{|}~ܻݻ޻߻@ABCDEFGHIXYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu4 5 6 7 8 9 : ; < =                     ` a b c d e f g h i           xyz{|}~@ A B C D E F G H I           ! ! ! ! ! !!!!!l!m!n!o!p!q!r!s!t!u!!!!!!!!!!!4"5"6"7"8"9":";"<"="""""""""""""""######`#a#b#c#d#e#f#g#h#i###########($)$*$+$,$-$.$/$0$1$$$$$$$$$$$$$$$$$$$$$T%U%V%W%X%Y%Z%[%\%]%%%%%%%%%%%&&&& &!&"&#&$&%&&&&&&&&&&&&&&&&&&&&&H'I'J'K'L'M'N'O'P'Q'''''''''''((((((((((t(u(v(w(x(y(z({(|(}(((((((((((<)=)>)?)@)A)B)C)D)E)))))))))))***** * * * * *h*i*j*k*l*m*n*o*p*q***********0+1+2+3+4+5+6+7+8+9+++++++++++++++++++,,\,],^,_,`,a,b,c,d,e,,,,,,,,,,,$-%-&-'-(-)-*-+-,-----------------------P.Q.R.S.T.U.V.W.X.Y...........//////// /!/|/}/~//////////////////D0E0F0G0H0I0J0K0L0M00000000000 1 111111111p1q1r1s1t1u1v1w1x1y11111111111EEEEEEEEEE$F%F&F'F(F)F*F+F,F-FFFFFFFFFFFFFFFFFFFFFPGQGRGSGTGUGVGWGXGYGGGGGGGGGGGHHHHHHHH H!H|H}H~HHHHHHHHHHHHHHHHHHDIEIFIGIHIIIJIKILIMIIIIIIIIIII J JJJJJJJJJpJqJrJsJtJuJvJwJxJyJJJJJJJJJJJ8K9K:K;KK?K@KAKKKKKKKKKKKLLLLLLLLL LdLeLfLgLhLiLjLkLlLmLLLLLLLLLLL,M-M.M/M0M1M2M3M4M5MMMMMMMMMMMMMMMMMMMMMXNYNZN[N\N]N^N_N`NaNNNNNNNNNNN O!O"O#O$O%O&O'O(O)OOOOOOOOOOOOOOOOOOOOOLPMPNPOPPPQPRPSPTPUPPPPPPPPPPPQQQQQQQQQQxQyQzQ{Q|Q}Q~QQQQQQQQQQQQQQ@RARBRCRDRERFRGRHRIRRRRRRRRRRRS S S S S SSSSSlSmSnSoSpSqSrSsStSuSSSSSSSSSSS4T5T6T7T8T9T:T;Tt?t@tAtBtCtDtEtttttttttttuuuuu u u u u uhuiujukulumunuoupuquuuuuuuuuuu0v1v2v3v4v5v6v7v8v9vvvvvvvvvvvvvvvvvvvww\w]w^w_w`wawbwcwdwewwwwwwwwwww$x%x&x'x(x)x*x+x,x-xxxxxxxxxxxxxxxxxxxxxPyQyRySyTyUyVyWyXyYyyyyyyyyyyyzzzzzzzz z!z|z}z~zzzzzzzzzzzzzzzzzzD{E{F{G{H{I{J{K{L{M{{{{{{{{{{{ | |||||||||p|q|r|s|t|u|v|w|x|y|||||||||||8}9}:};}<}=}>}?}@}A}}}}}}}}}}}~~~~~~~~~ ~d~e~f~g~h~i~j~k~l~m~~~~~~~~~~~,-./012345DEFGHIJKLM  pqrstuvwxyԕՕ֕וٕؕڕەܕݕ89:;<=>?@A defghijklmȗɗʗ˗̗͗ΗϗЗї,-./012345XYZ[\]^_`a™Ùęř !"#$%&'()LMNOPQRSTUxyz{|}~ܜݜޜߜ@ABCDEFGHI     lmnopqrstuОўҞӞԞ՞֞מ؞ٞ456789:;<=`abcdefghiĠŠƠǠȠɠʠˠ̠͠()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}إ٥ڥۥܥݥޥߥ<=>?@ABCDE     TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}ؾپھ۾ܾݾ޾߾<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTU defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-          t u v w x y z { | }           < = > ? @ A B C D E                     h i j k l m n o p q           0 1 2 3 4 5 6 7 8 9                     \ ] ^ _ ` a b c d e           $%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<= 0!0"0#0$0%0&0'0(0)000000000000000000000L1M1N1O1P1Q1R1S1T1U111111111112222222222x2y2z2{2|2}2~22222222222222@3A3B3C3D3E3F3G3H3I333333333334 4 4 4 4 44444l4m4n4o4p4q4r4s4t4u44444444444455565758595:5;5<5=555555555555555666666`6a6b6c6d6e6f6g6h6i66666666666(7)7*7+7,7-7.7/7071777777777777777777777T8U8V8W8X8Y8Z8[8\8]888888888889999 9!9"9#9$9%999999999999999999999H:I:J:K:L:M:N:O:P:Q:::::::::::;;;;;;;;;;t;u;v;w;x;y;z;{;|;};;;;;;;;;;;<<=<><?<@<A<B<C<D<E<<<<<<<<<<<===== = = = = =h=i=j=k=l=m=n=o=p=q===========0>1>2>3>4>5>6>7>8>9>>>>>>>>>>>>>>>>>>>??\?]?^?_?`?a?b?c?d?e???????????$@%@&@'@(@)@*@+@,@-@@@@@@@@@@@@@@@@@@@@@PAQARASATAUAVAWAXAYAAAAAAAAAAABBBBBBBB B!B|B}B~BBBBBBBBBBBBBBBBBBDCECFCGCHCICJCKCLCMC0W1W2W3W4W5W6W7W8W9WWWWWWWWWWWWWWWWWWWXX\X]X^X_X`XaXbXcXdXeXXXXXXXXXXX$Y%Y&Y'Y(Y)Y*Y+Y,Y-YYYYYYYYYYYYYYYYYYYYYPZQZRZSZTZUZVZWZXZYZZZZZZZZZZZ[[[[[[[[ [![|[}[~[[[[[[[[[[[[[[[[[[D\E\F\G\H\I\J\K\L\M\\\\\\\\\\\ ] ]]]]]]]]]p]q]r]s]t]u]v]w]x]y]]]]]]]]]]]8^9^:^;^<^=^>^?^@^A^^^^^^^^^^^_________ _d_e_f_g_h_i_j_k_l_m___________,`-`.`/`0`1`2`3`4`5`````````````````````XaYaZa[a\a]a^a_a`aaaaaaaaaaaaa b!b"b#b$b%b&b'b(b)bbbbbbbbbbbbbbbbbbbbbLcMcNcOcPcQcRcScTcUcccccccccccddddddddddxdydzd{d|d}d~dddddddddddddd@eAeBeCeDeEeFeGeHeIeeeeeeeeeeef f f f f ffffflfmfnfofpfqfrfsftfufffffffffff4g5g6g7g8g9g:g;g?@ABCDE     hijklmnopq͈̈ΈψЈш҈ӈԈՈ0123456789\]^_`abcdeŠÊĊŊƊNJȊɊ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԏՏ֏׏؏ُڏۏ܏ݏ89:;<=>?@A defghijklmPQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԨը֨רب٨ڨۨܨݨ89:;<=>?@A defghijklmȪɪʪ˪̪ͪΪϪЪѪ,-./012345XYZ[\]^_`a¬ìĬŬ !"#$%&'()LMNOPQRSTUxyz{|}~ܯݯޯ߯@ABCDEFGHI     lmnopqrstuбѱұӱԱձֱױرٱ456789:;<=`abcdefghiijųƳdzȳɳʳ˳̳ͳ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789  \ ] ^ _ ` a b c d e           $!%!&!'!(!)!*!+!,!-!!!!!!!!!!!!!!!!!!!!!P"Q"R"S"T"U"V"W"X"Y"""""""""""######## #!#|#}#~##################D$E$F$G$H$I$J$K$L$M$$$$$$$$$$$ % %%%%%%%%%p%q%r%s%t%u%v%w%x%y%%%%%%%%%%%8&9&:&;&<&=&>&?&@&A&&&&&&&&&&&''''''''' 'd'e'f'g'h'i'j'k'l'm''''''''''',(-(.(/(0(1(2(3(4(5(((((((((((((((((((((X)Y)Z)[)\)])^)_)`)a))))))))))) *!*"*#*$*%*&*'*(*)*********************L+M+N+O+P+Q+R+S+T+U+++++++++++,,,,,,,,,,x,y,z,{,|,},~,,,,,,,,,,,,,,@-A-B-C-D-E-F-G-H-I-----------AAAAAAAAAAAAAAAAAAAAXBYBZB[B\B]B^B_B`BaBBBBBBBBBBB C!C"C#C$C%C&C'C(C)CCCCCCCCCCCCCCCCCCCCCLDMDNDODPDQDRDSDTDUDDDDDDDDDDDEEEEEEEEEExEyEzE{E|E}E~EEEEEEEEEEEEEE@FAFBFCFDFEFFFGFHFIFFFFFFFFFFFG G G G G GGGGGlGmGnGoGpGqGrGsGtGuGGGGGGGGGGG4H5H6H7H8H9H:H;HO?O@OAOBOCODOEOOOOOOOOOOOPPPPP P P P P PhPiPjPkPlPmPnPoPpPqPPPPPPPPPPP0Q1Q2Q3Q4Q5Q6Q7Q8Q9QQQQQQQQQQQQQQQQQQQRR\R]R^R_R`RaRbRcRdReRRRRRRRRRRR$S%S&S'S(S)S*S+S,S-SSSSSSSSSSSSSSSSSSSSSPTQTRTSTTTUTVTWTXTYTTTTTTTTTTThhhhhhhhhhiiiii i i i i ihiiijikiliminioipiqiiiiiiiiiii0j1j2j3j4j5j6j7j8j9jjjjjjjjjjjjjjjjjjjkk\k]k^k_k`kakbkckdkekkkkkkkkkkk$l%l&l'l(l)l*l+l,l-lllllllllllllllllllllPmQmRmSmTmUmVmWmXmYmmmmmmmmmmmnnnnnnnn n!n|n}n~nnnnnnnnnnnnnnnnnnDoEoFoGoHoIoJoKoLoMooooooooooo p pppppppppppqprpsptpupvpwpxpyppppppppppp8q9q:q;qq?q@qAqqqqqqqqqqqrrrrrrrrr rdrerfrgrhrirjrkrlrmrrrrrrrrrrr,s-s.s/s0s1s2s3s4s5sssssssssssssssssssssXtYtZt[t\t]t^t_t`tattttttttttt u!u"u#u$u%u&u'u(u)uuuuuuuuuuuuuuuuuuuuuLvMvNvOvPvQvRvSvTvUvvvvvvvvvvvwwwwwwwwwwxwywzw{w|w}w~wwwwwwwwwwwwww@xAxBxCxDxExFxGxHxIxxxxxxxxxxxy y y y y yyyyylymynyoypyqyrysytyuyyyyyyyyyyy4z5z6z7z8z9z:z;z?@ABCDE     hijklmnopq̛͛ΛϛЛћқӛԛ՛0123456789\]^_`abcdeÝĝŝƝǝȝɝ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԢբ֢עآ٢ڢۢܢݢ¶öĶŶƶǶȶɶ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԻջֻ׻ػٻڻۻܻݻ89:;<=>?@A defghijklmȽɽʽ˽̽ͽνϽнѽ,-./012345XYZ[\]^_`a¿ÿĿſ !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm, - . / 0 1 2 3 4 5                     X Y Z [ \ ] ^ _ ` a            ! " # $ % & ' ( )                     L M N O P Q R S T U                     x y z { | } ~              @ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     ++++++++++T,U,V,W,X,Y,Z,[,\,],,,,,,,,,,,---- -!-"-#-$-%---------------------H.I.J.K.L.M.N.O.P.Q...........//////////t/u/v/w/x/y/z/{/|/}///////////<0=0>0?0@0A0B0C0D0E0000000000011111 1 1 1 1 1h1i1j1k1l1m1n1o1p1q111111111110212223242526272829222222222222222222233\3]3^3_3`3a3b3c3d3e33333333333$4%4&4'4(4)4*4+4,4-444444444444444444444P5Q5R5S5T5U5V5W5X5Y5555555555566666666 6!6|6}6~666666666666666666D7E7F7G7H7I7J7K7L7M77777777777 8 888888888p8q8r8s8t8u8v8w8x8y888888888888999:9;9<9=9>9?9@9A99999999999::::::::: :d:e:f:g:h:i:j:k:l:m:::::::::::,;-;.;/;0;1;2;3;4;5;;;;;;;;;;;;;;;;;;;;;X<Y<Z<[<\<]<^<_<`<a<<<<<<<<<<< =!="=#=$=%=&='=(=)=====================L>M>N>O>P>Q>R>S>T>U>>>>>>>>>>>??????????SSSSSSSSS SdSeSfSgShSiSjSkSlSmSSSSSSSSSSS,T-T.T/T0T1T2T3T4T5TTTTTTTTTTTTTTTTTTTTTXUYUZU[U\U]U^U_U`UaUUUUUUUUUUU V!V"V#V$V%V&V'V(V)VVVVVVVVVVVVVVVVVVVVVLWMWNWOWPWQWRWSWTWUWWWWWWWWWWWXXXXXXXXXXxXyXzX{X|X}X~XXXXXXXXXXXXXX@YAYBYCYDYEYFYGYHYIYYYYYYYYYYYZ Z Z Z Z ZZZZZlZmZnZoZpZqZrZsZtZuZZZZZZZZZZZ4[5[6[7[8[9[:[;[<[=[[[[[[[[[[[[[[[\\\\\\`\a\b\c\d\e\f\g\h\i\\\\\\\\\\\(])]*]+],]-].]/]0]1]]]]]]]]]]]]]]]]]]]]]T^U^V^W^X^Y^Z^[^\^]^^^^^^^^^^^____ _!_"_#_$_%_____________________H`I`J`K`L`M`N`O`P`Q```````````aaaaaaaaaatauavawaxayaza{a|a}aaaaaaaaaaab?b@bAbBbCbDbEbbbbbbbbbbbccccc c c c c chcicjckclcmcncocpcqccccccccccc0d1d2d3d4d5d6d7d8d9dddddddddddddddddddee\e]e^e_e`eaebecedeeeeeeeeeeeee$f%f&f'f(f)f*f+f,f-fzzzzzzzzzztzuzvzwzxzyzzz{z|z}zzzzzzzzzzz<{={>{?{@{A{B{C{D{E{{{{{{{{{{{||||| | | | | |h|i|j|k|l|m|n|o|p|q|||||||||||0}1}2}3}4}5}6}7}8}9}}}}}}}}}}}}}}}}}}}~~\~]~^~_~`~a~b~c~d~e~~~~~~~~~~~$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԃՃփ׃؃كڃۃ܃݃89:;<=>?@A defghijklmȅɅʅ˅̅ͅ΅υЅх,-./012345XYZ[\]^_`a‡ÇćŇ !"#$%&'()LMNOPQRSTUxyz{|}~܊݊ފߊ@ABCDEFGHI     lmnopqrstuЌьҌӌԌՌ֌׌،ٌ456789:;<= !"#$%&'()LMNOPQRSTUxyz{|}~ܣݣޣߣ@ABCDEFGHI     lmnopqrstuХѥҥӥԥե֥ץإ٥456789:;<=`abcdefghiħŧƧǧȧɧʧ˧̧ͧ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}ج٬ڬ۬ܬݬެ߬<=>?@ABCDE     hijklmnopq̮ͮήϮЮѮҮӮԮծ0123456789\]^_`abcde°ðİŰưǰȰɰ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\]@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklmPQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTU          x y z { | } ~              @!A!B!C!D!E!F!G!H!I!!!!!!!!!!!" " " " " """""l"m"n"o"p"q"r"s"t"u"""""""""""4#5#6#7#8#9#:#;#<#=###############$$$$$$`$a$b$c$d$e$f$g$h$i$$$$$$$$$$$(%)%*%+%,%-%.%/%0%1%%%%%%%%%%%%%%%%%%%%%T&U&V&W&X&Y&Z&[&\&]&&&&&&&&&&&'''' '!'"'#'$'%'''''''''''''''''''''H(I(J(K(L(M(N(O(P(Q((((((((((())))))))))t)u)v)w)x)y)z){)|)})`=a=b=c=d=e=f=g=h=i===========(>)>*>+>,>->.>/>0>1>>>>>>>>>>>>>>>>>>>>>T?U?V?W?X?Y?Z?[?\?]???????????@@@@ @!@"@#@$@%@@@@@@@@@@@@@@@@@@@@@HAIAJAKALAMANAOAPAQAAAAAAAAAAABBBBBBBBBBtBuBvBwBxByBzB{B|B}BBBBBBBBBBBC?C@CACBCCCDCECCCCCCCCCCCDDDDD D D D D DhDiDjDkDlDmDnDoDpDqDDDDDDDDDDD0E1E2E3E4E5E6E7E8E9EEEEEEEEEEEEEEEEEEEFF\F]F^F_F`FaFbFcFdFeFFFFFFFFFFF$G%G&G'G(G)G*G+G,G-GGGGGGGGGGGGGGGGGGGGGPHQHRHSHTHUHVHWHXHYHHHHHHHHHHHIIIIIIII I!I|I}I~IIIIIIIIIIIIIIIIIIDJEJFJGJHJIJJJKJLJMJJJJJJJJJJJ K KKKKKKKKKpKqKrKsKtKuKvKwKxKyKKKKKKKKKKK8L9L:L;LL?L@LALLLLLLLLLLLMMMMMMMMM MdMeMfMgMhMiMjMkMlMmMMMMMMMMMMM,N-N.N/N0N1N2N3N4N5NNNNNNNNNNNNNNNNNNNNNXOYOZO[O\O]O^O_O`OaOOOOOOOOOOO P!P"P#P$P%P&P'P(P)PPPPPPPPPPPpdqdrdsdtdudvdwdxdyddddddddddd8e9e:e;ee?e@eAeeeeeeeeeeefffffffff fdfefffgfhfifjfkflfmfffffffffff,g-g.g/g0g1g2g3g4g5gggggggggggggggggggggXhYhZh[h\h]h^h_h`hahhhhhhhhhhh i!i"i#i$i%i&i'i(i)iiiiiiiiiiiiiiiiiiiiiLjMjNjOjPjQjRjSjTjUjjjjjjjjjjjkkkkkkkkkkxkykzk{k|k}k~kkkkkkkkkkkkkk@lAlBlClDlElFlGlHlIlllllllllllm m m m m mmmmmlmmmnmompmqmrmsmtmummmmmmmmmmm4n5n6n7n8n9n:n;nu?u@uAuBuCuDuEuuuuuuuuuuuvvvvv v v v v vhvivjvkvlvmvnvovpvqvvvvvvvvvvv0w1w2w3w4w5w6w7w8w9wwwwwwwwwwwHIJKLMNOPQtuvwxyz{|}؍ٍڍۍ܍ݍލߍ<=>?@ABCDE     hijklmnopq̏͏ΏϏЏяҏӏԏՏ0123456789\]^_`abcde‘ÑđőƑǑȑɑ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԖՖ֖זٖؖږۖܖݖ89:;<=>?@A defghijklmȘɘʘ˘̘͘ΘϘИј,-./012345XYZ[\]^_`ašÚĚŚ !"#$%&'()LMNOPQRSTUxyz{|}~ܝݝޝߝ@ABCDEFGHIXYZ[\]^_`a³óijų !"#$%&'()LMNOPQRSTUxyz{|}~ܶݶ޶߶@ABCDEFGHI     lmnopqrstuиѸҸӸԸոָ׸ظٸ456789:;<=`abcdefghiĺźƺǺȺɺʺ˺̺ͺ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}ؿٿڿۿܿݿ޿߿<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi           x y z { | } ~              @ A B C D E F G H I                     l m n o p q r s t u           4 5 6 7 8 9 : ; < =                     ` a b c d e f g h i           ( ) * + , - . / 0 1                     T U V W X Y Z [ \ ]                ! " # $ %                     H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9   \ ] ^ _ ` a b c d e           $ % & ' ( ) * + , -                     P Q R S T U V W X Y                    ! | } ~                  D E F G H I J K L M                     p q r s t u v w x y           ' ' ' ' ' ' ' ' ' ' $( %( &( '( (( )( *( +( ,( -( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( P) Q) R) S) T) U) V) W) X) Y) ) ) ) ) ) ) ) ) ) ) * * * * * * * * * !* |* }* ~* * * * * * * * * * * * * * * * * * D+ E+ F+ G+ H+ I+ J+ K+ L+ M+ + + + + + + + + + + , , , , , , , , , , p, q, r, s, t, u, v, w, x, y, , , , , , , , , , , 8- 9- :- ;- <- =- >- ?- @- A- - - - - - - - - - - . . . . . . . . . . d. e. f. g. h. i. j. k. l. m. . . . . . . . . . . ,/ -/ ./ // 0/ 1/ 2/ 3/ 4/ 5/ / / / / / / / / / / / / / / / / / / / / X0 Y0 Z0 [0 \0 ]0 ^0 _0 `0 a0 0 0 0 0 0 0 0 0 0 0 1 !1 "1 #1 $1 %1 &1 '1 (1 )1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 L2 M2 N2 O2 P2 Q2 R2 S2 T2 U2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 x3 y3 z3 {3 |3 }3 ~3 3 3 3 3 3 3 3 3 3 3 3 3 3 @4 A4 B4 C4 D4 E4 F4 G4 H4 I4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 l5 m5 n5 o5 p5 q5 r5 s5 t5 u5 5 5 5 5 5 5 5 5 5 5 46 56 66 76 86 96 :6 ;6 <6 =6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 `7 a7 b7 c7 d7 e7 f7 g7 h7 i7 7 7 7 7 7 7 7 7 7 7 (8 )8 *8 +8 ,8 -8 .8 /8 08 18 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 T9 U9 V9 W9 X9 Y9 Z9 [9 \9 ]9 9 9 9 9 9 9 9 9 9 9 : : : : : !: ": #: $: %: : : : : : : : : : : : : : : : : : : : : N N N N N N N N N N 4O 5O 6O 7O 8O 9O :O ;O V ?V @V AV BV CV DV EV V V V V V V V V V V W W W W W W W W W W hW iW jW kW lW mW nW oW pW qW W W W W W W W W W W 0X 1X 2X 3X 4X 5X 6X 7X 8X 9X X X X X X X X X X X X X X X X X X X Y Y \Y ]Y ^Y _Y `Y aY bY cY dY eY Y Y Y Y Y Y Y Y Y Y $Z %Z &Z 'Z (Z )Z *Z +Z ,Z -Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z P[ Q[ R[ S[ T[ U[ V[ W[ X[ Y[ [ [ [ [ [ [ [ [ [ [ \ \ \ \ \ \ \ \ \ !\ |\ }\ ~\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ D] E] F] G] H] I] J] K] L] M] ] ] ] ] ] ] ] ] ] ] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ p^ q^ r^ s^ t^ u^ v^ w^ x^ y^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 8_ 9_ :_ ;_ <_ =_ >_ ?_ @_ A_ _ _ _ _ _ _ _ _ _ _ ` ` ` ` ` ` ` ` ` ` d` e` f` g` h` i` j` k` l` m` ` ` ` ` ` ` ` ` ` ` ,a -a .a /a 0a 1a 2a 3a 4a 5a a a a a a a a a a a a a a a a a a a a a u u u u u u u u u u Dv Ev Fv Gv Hv Iv Jv Kv Lv Mv v v v v v v v v v v w w w w w w w w w w pw qw rw sw tw uw vw ww xw yw w w w w w w w w w w 8x 9x :x ;x x ?x @x Ax x x x x x x x x x x y y y y y y y y y y dy ey fy gy hy iy jy ky ly my y y y y y y y y y y ,z -z .z /z 0z 1z 2z 3z 4z 5z z z z z z z z z z z z z z z z z z z z z X{ Y{ Z{ [{ \{ ]{ ^{ _{ `{ a{ { { { { { { { { { { | !| "| #| $| %| &| '| (| )| | | | | | | | | | | | | | | | | | | | | L} M} N} O} P} Q} R} S} T} U} } } } } } } } } } } ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ x~ y~ z~ {~ |~ }~ ~~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ @ A B C D E F G H I                l m n o p q r s t u Ѐ р Ҁ Ӏ Ԁ Հ ր ׀ ؀ ـ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i Ă ł Ƃ ǂ Ȃ ɂ ʂ ˂ ̂ ͂ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } ؇ ه ڇ ۇ ܇ ݇ އ ߇ < = > ? @ A B C D E      T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } ؠ ٠ ڠ ۠ ܠ ݠ ޠ ߠ < = > ? @ A B C D E      h i j k l m n o p q ̢ ͢ ΢ Ϣ Т Ѣ Ң Ӣ Ԣ բ 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e ¤ ä Ĥ Ť Ƥ Ǥ Ȥ ɤ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y ԩ թ ֩ ש ة ٩ ک ۩ ܩ ݩ 8 9 : ; < = > ? @ A         d e f g h i j k l m ȫ ɫ ʫ ˫ ̫ ͫ Ϋ ϫ Ы ѫ , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ­ í ĭ ŭ ! " # $ % & ' ( ) L M N O P Q R S T U                   d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e $ % & ' ( ) * + , -           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =  ! " # $ % & ' ( )                     L M N O P Q R S T U                     x y z { | } ~              @ A B C D E F G H I                     l m n o p q r s t u           4 5 6 7 8 9 : ; < =                     ` a b c d e f g h i           ( ) * + , - . / 0 1                     T U V W X Y Z [ \ ]                ! " # $ %                     H I J K L M N O P Q                     t u v w x y z { | }           < = > ? @ A B C D E                     h i j k l m n o p q           0 1 2 3 4 5 6 7 8 9 ! ! \! ]! ^! _! `! a! b! c! d! e! ! ! ! ! ! ! ! ! ! ! $" %" &" '" (" )" *" +" ," -" " " " " " " " " " " " " " " " " " " " " P# Q# R# S# T# U# V# W# X# Y# # # # # # # # # # # $ $ $ $ $ $ $ $ $ !$ |$ }$ ~$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ D% E% F% G% H% I% J% K% L% M% 09 19 29 39 49 59 69 79 89 99 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 : : \: ]: ^: _: `: a: b: c: d: e: : : : : : : : : : : $; %; &; '; (; ); *; +; ,; -; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; P< Q< R< S< T< U< V< W< X< Y< < < < < < < < < < < = = = = = = = = = != |= }= ~= = = = = = = = = = = = = = = = = = D> E> F> G> H> I> J> K> L> M> > > > > > > > > > > ? ? ? ? ? ? ? ? ? ? p? q? r? s? t? u? v? w? x? y? ? ? ? ? ? ? ? ? ? ? 8@ 9@ :@ ;@ <@ =@ >@ ?@ @@ A@ @ @ @ @ @ @ @ @ @ @ A A A A A A A A A A dA eA fA gA hA iA jA kA lA mA A A A A A A A A A A ,B -B .B /B 0B 1B 2B 3B 4B 5B B B B B B B B B B B B B B B B B B B B B XC YC ZC [C \C ]C ^C _C `C aC C C C C C C C C C C D !D "D #D $D %D &D 'D (D )D D D D D D D D D D D D D D D D D D D D D LE ME NE OE PE QE RE SE TE UE E E E E E E E E E E F F F F F F F F F F xF yF zF {F |F }F ~F F F F F F F F F F F F F F @G AG BG CG DG EG FG GG HG IG G G G G G G G G G G H H H H H H H H H H lH mH nH oH pH qH rH sH tH uH H H H H H H H H H H 4I 5I 6I 7I 8I 9I :I ;I i ?i @i Ai Bi Ci Di Ei i i i i i i i i i i j j j j j j j j j j hj ij jj kj lj mj nj oj pj qj j j j j j j j j j j 0k 1k 2k 3k 4k 5k 6k 7k 8k 9k k k k k k k k k k k k k k k k k k k l l \l ]l ^l _l `l al bl cl dl el l l l l l l l l l l $m %m &m 'm (m )m *m +m ,m -m m m m m m m m m m m m m m m m m m m m m Pn Qn Rn Sn Tn Un Vn Wn Xn Yn n n n n n n n n n n o o o o o o o o o !o |o }o ~o o o o o o o o o o o o o o o o o o Dp Ep Fp Gp Hp Ip Jp Kp Lp Mp p p p p p p p p p p q q q q q q q q q q pq qq rq sq tq uq vq wq xq yq q q q q q q q q q q 8r 9r :r ;r r ?r @r Ar r r r r r r r r r r s s s s s s s s s s ds es fs gs hs is js ks ls ms P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y Ԋ Պ ֊ ׊ ؊ ي ڊ ۊ ܊ ݊ 8 9 : ; < = > ? @ A         d e f g h i j k l m Ȍ Ɍ ʌ ˌ ̌ ͌ Ό ό Ќ ь , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a Ž Î Ď Ŏ ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  ܑ ݑ ޑ ߑ @ A B C D E F G H I      l m n o p q r s t u Г ѓ ғ ӓ ԓ Փ ֓ ד ؓ ٓ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ĕ ŕ ƕ Ǖ ȕ ɕ ʕ ˕ ̕ ͕ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } ` a b c d e f g h i Į Ů Ʈ Ǯ Ȯ ɮ ʮ ˮ ̮ ͮ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } س ٳ ڳ ۳ ܳ ݳ ޳ ߳ < = > ? @ A B C D E      h i j k l m n o p q ̵ ͵ ε ϵ е ѵ ҵ ӵ Ե յ 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e · ÷ ķ ŷ Ʒ Ƿ ȷ ɷ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y Լ ռ ּ ׼ ؼ ټ ڼ ۼ ܼ ݼ 8 9 : ; < = > ? @ A         d e f g h i j k l m Ⱦ ɾ ʾ ˾ ̾ ; ξ Ͼ о Ѿ , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9 H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9                     \ ] ^ _ ` a b c d e           $ % & ' ( ) * + , -                     P Q R S T U V W X Y                    ! | } ~                  D E F G H I J K L M                     p q r s t u v w x y           8 9 : ; < = > ? @ A                   d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~              @ A B C D E F G H I           # # # # # # # # # # # # # # # # # # # # X$ Y$ Z$ [$ \$ ]$ ^$ _$ `$ a$ $ $ $ $ $ $ $ $ $ $ % !% "% #% $% %% &% '% (% )% % % % % % % % % % % % % % % % % % % % % L& M& N& O& P& Q& R& S& T& U& & & & & & & & & & & ' ' ' ' ' ' ' ' ' ' x' y' z' {' |' }' ~' ' ' ' ' ' ' ' ' ' ' ' ' ' @( A( B( C( D( E( F( G( H( I( ( ( ( ( ( ( ( ( ( ( ) ) ) ) ) ) ) ) ) ) l) m) n) o) p) q) r) s) t) u) ) ) ) ) ) ) ) ) ) ) 4* 5* 6* 7* 8* 9* :* ;* <* =* * * * * * * * * * * * * * * + + + + + + `+ a+ b+ c+ d+ e+ f+ g+ h+ i+ + + + + + + + + + + (, ), *, +, ,, -, ., /, 0, 1, , , , , , , , , , , , , , , , , , , , , T- U- V- W- X- Y- Z- [- \- ]- - - - - - - - - - - . . . . . !. ". #. $. %. . . . . . . . . . . . . . . . . . . . . H/ I/ J/ K/ L/ M/ N/ O/ P/ Q/ / / / / / / / / / / 0 0 0 0 0 0 0 0 0 0 t0 u0 v0 w0 x0 y0 z0 {0 |0 }0 0 0 0 0 0 0 0 0 0 0 <1 =1 >1 ?1 @1 A1 B1 C1 D1 E1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 h2 i2 j2 k2 l2 m2 n2 o2 p2 q2 2 2 2 2 2 2 2 2 2 2 03 13 23 33 43 53 63 73 83 93 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 \4 ]4 ^4 _4 `4 a4 b4 c4 d4 e4 4 4 4 4 4 4 4 4 4 4 $5 %5 &5 '5 (5 )5 *5 +5 ,5 -5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 P6 Q6 R6 S6 T6 U6 V6 W6 X6 Y6 6 6 6 6 6 6 6 6 6 6 J J J J J J J J J J K K K K K K K K K K hK iK jK kK lK mK nK oK pK qK K K K K K K K K K K 0L 1L 2L 3L 4L 5L 6L 7L 8L 9L L L L L L L L L L L L L L L L L L L M M \M ]M ^M _M `M aM bM cM dM eM M M M M M M M M M M $N %N &N 'N (N )N *N +N ,N -N N N N N N N N N N N N N N N N N N N N N PO QO RO SO TO UO VO WO XO YO O O O O O O O O O O P P P P P P P P P !P |P }P ~P P P P P P P P P P P P P P P P P P DQ EQ FQ GQ HQ IQ JQ KQ LQ MQ Q Q Q Q Q Q Q Q Q Q R R R R R R R R R R pR qR rR sR tR uR vR wR xR yR R R R R R R R R R R 8S 9S :S ;S S ?S @S AS S S S S S S S S S S T T T T T T T T T T dT eT fT gT hT iT jT kT lT mT T T T T T T T T T T ,U -U .U /U 0U 1U 2U 3U 4U 5U U U U U U U U U U U U U U U U U U U U U XV YV ZV [V \V ]V ^V _V `V aV V V V V V V V V V V W !W "W #W $W %W &W 'W (W )W W W W W W W W W W W W W W W W W W W W W LX MX NX OX PX QX RX SX TX UX X X X X X X X X X X Y Y Y Y Y Y Y Y Y Y xY yY zY {Y |Y }Y ~Y Y Y Y Y Y Y Y Y Y Y Y Y Y @Z AZ BZ CZ DZ EZ FZ GZ HZ IZ Z Z Z Z Z Z Z Z Z Z [ [ [ [ [ [ [ [ [ [ l[ m[ n[ o[ p[ q[ r[ s[ t[ u[ [ [ [ [ [ [ [ [ [ [ 4\ 5\ 6\ 7\ 8\ 9\ :\ ;\ <\ =\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ] ] ] ] ] ] `] a] b] c] d] e] f] g] h] i] ] ] ] ] ] ] ] ] ] ] q q q q q q q q q q r r r r r r r r r r xr yr zr {r |r }r ~r r r r r r r r r r r r r r @s As Bs Cs Ds Es Fs Gs Hs Is s s s s s s s s s s t t t t t t t t t t lt mt nt ot pt qt rt st tt ut t t t t t t t t t t 4u 5u 6u 7u 8u 9u :u ;u | ?| @| A| B| C| D| E| | | | | | | | | | | } } } } } } } } } } h} i} j} k} l} m} n} o} p} q} } } } } } } } } } } 0~ 1~ 2~ 3~ 4~ 5~ 6~ 7~ 8~ 9~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~   \ ] ^ _ ` a b c d e           $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y Ԅ Մ ք ׄ ؄ ل ڄ ۄ ܄ ݄ ˜ Ø Ę Ř Ƙ ǘ Ș ɘ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y ԝ ՝ ֝ ם ؝ ٝ ڝ ۝ ܝ ݝ 8 9 : ; < = > ? @ A         d e f g h i j k l m ȟ ɟ ʟ ˟ ̟ ͟ Ο ϟ П џ , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ¡ á ġ š ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  ܤ ݤ ޤ ߤ @ A B C D E F G H I      l m n o p q r s t u Ц Ѧ Ҧ Ӧ Ԧ զ ֦ צ ئ ٦ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i Ĩ Ũ ƨ Ǩ Ȩ ɨ ʨ ˨ ̨ ͨ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % п ѿ ҿ ӿ Կ տ ֿ ׿ ؿ ٿ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      T U V W X Y Z [ \ ]                ! " # $ %                     H I J K L M N O P Q                     t u v w x y z { | }           < = > ? @ A B C D E                     h i j k l m n o p q           0 1 2 3 4 5 6 7 8 9                     \ ] ^ _ ` a b c d e           $ % & ' ( ) * + , -                     P Q R S T U V W X Y                    ! | } ~                  D E F G H I J K L M                     p q r s t u v w x y           8 9 : ; < = > ? @ A                     d e f g h i j k l m           , - . / 0 1 2 3 4 5                     X Y Z [ \ ] ^ _ ` a            ! " # $ % & ' ( )                     L M N O P Q R S T U ! ! ! ! ! ! ! ! ! ! 5 5 5 5 5 5 5 5 5 5 d5 e5 f5 g5 h5 i5 j5 k5 l5 m5 5 5 5 5 5 5 5 5 5 5 ,6 -6 .6 /6 06 16 26 36 46 56 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 X7 Y7 Z7 [7 \7 ]7 ^7 _7 `7 a7 7 7 7 7 7 7 7 7 7 7 8 !8 "8 #8 $8 %8 &8 '8 (8 )8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 L9 M9 N9 O9 P9 Q9 R9 S9 T9 U9 9 9 9 9 9 9 9 9 9 9 : : : : : : : : : : x: y: z: {: |: }: ~: : : : : : : : : : : : : : @; A; B; C; D; E; F; G; H; I; ; ; ; ; ; ; ; ; ; ; < < < < < < < < < < l< m< n< o< p< q< r< s< t< u< < < < < < < < < < < 4= 5= 6= 7= 8= 9= := ;= <= == = = = = = = = = = = = = = = > > > > > > `> a> b> c> d> e> f> g> h> i> > > > > > > > > > > (? )? *? +? ,? -? .? /? 0? 1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? T@ U@ V@ W@ X@ Y@ Z@ [@ \@ ]@ @ @ @ @ @ @ @ @ @ @ A A A A A !A "A #A $A %A A A A A A A A A A A A A A A A A A A A A HB IB JB KB LB MB NB OB PB QB B B B B B B B B B B C C C C C C C C C C tC uC vC wC xC yC zC {C |C }C C C C C C C C C C C D ?D @D AD BD CD DD ED D D D D D D D D D D E E E E E E E E E E hE iE jE kE lE mE nE oE pE qE E E E E E E E E E E 0F 1F 2F 3F 4F 5F 6F 7F 8F 9F F F F F F F F F F F F F F F F F F F G G \G ]G ^G _G `G aG bG cG dG eG G G G G G G G G G G $H %H &H 'H (H )H *H +H ,H -H \ \ \ \ \ \ \ \ \ \ t\ u\ v\ w\ x\ y\ z\ {\ |\ }\ \ \ \ \ \ \ \ \ \ \ <] =] >] ?] @] A] B] C] D] E] ] ] ] ] ] ] ] ] ] ] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ h^ i^ j^ k^ l^ m^ n^ o^ p^ q^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 0_ 1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ` ` \` ]` ^` _` `` a` b` c` d` e` ` ` ` ` ` ` ` ` ` ` $a %a &a 'a (a )a *a +a ,a -a a a a a a a a a a a a a a a a a a a a a Pb Qb Rb Sb Tb Ub Vb Wb Xb Yb b b b b b b b b b b c c c c c c c c c !c |c }c ~c c c c c c c c c c c c c c c c c c Dd Ed Fd Gd Hd Id Jd Kd Ld Md d d d d d d d d d d e e e e e e e e e e pe qe re se te ue ve we xe ye e e e e e e e e e e 8f 9f :f ;f f ?f @f Af f f f f f f f f f f g g g g g g g g g g dg eg fg gg hg ig jg kg lg mg g g g g g g g g g g ,h -h .h /h 0h 1h 2h 3h 4h 5h h h h h h h h h h h h h h h h h h h h h Xi Yi Zi [i \i ]i ^i _i `i ai i i i i i i i i i i j !j "j #j $j %j &j 'j (j )j j j j j j j j j j j j j j j j j j j j j Lk Mk Nk Ok Pk Qk Rk Sk Tk Uk k k k k k k k k k k l l l l l l l l l l xl yl zl {l |l }l ~l l l l l l l l l l l l l l @m Am Bm Cm Dm Em Fm Gm Hm Im m m m m m m m m m m n n n n n n n n n n ln mn nn on pn qn rn sn tn un n n n n n n n n n n 4o 5o 6o 7o 8o 9o :o ;o ? @ A B C D E      h i j k l m n o p q ̐ ͐ ΐ ϐ А ѐ Ґ Ӑ Ԑ Ր 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e ’ Ò Ē Œ ƒ ǒ Ȓ ɒ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e « ë ī ū ƫ ǫ ȫ ɫ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y ԰ հ ְ װ ذ ٰ ڰ ۰ ܰ ݰ 8 9 : ; < = > ? @ A         d e f g h i j k l m Ȳ ɲ ʲ ˲ ̲ Ͳ β ϲ в Ѳ , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ´ ô Ĵ Ŵ ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  ܷ ݷ ޷ ߷ @ A B C D E F G H I      l m n o p q r s t u й ѹ ҹ ӹ Թ չ ֹ ׹ ع ٹ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i Ļ Ż ƻ ǻ Ȼ ɻ ʻ ˻ ̻ ͻ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ] @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U                     x y z { | } ~              @ A B C D E F G H I                     l m n o p q r s t u           4 5 6 7 8 9 : ; < =                     ` a b c d e f g h i           ( ) * + , - . / 0 1                     T U V W X Y Z [ \ ]               ! " # $ % H I J K L M N O P Q           t u v w x y z { | } ` a b c d e f g h i           ( ) * + , - . / 0 1 T! U! V! W! X! Y! Z! [! \! ]! ! ! ! ! ! ! ! ! ! ! " " " " " !" "" #" $" %" " " " " " " " " " " " " " " " " " " " " H# I# J# K# L# M# N# O# P# Q# # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ t$ u$ v$ w$ x$ y$ z$ {$ |$ }$ $ $ $ $ $ $ $ $ $ $ <% =% >% ?% @% A% B% C% D% E% % % % % % % % % % % & & & & & & & & & & h& i& j& k& l& m& n& o& p& q& & & & & & & & & & & 0' 1' 2' 3' 4' 5' 6' 7' 8' 9' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ( ( \( ]( ^( _( `( a( b( c( d( e( ( ( ( ( ( ( ( ( ( ( $) %) &) ') () )) *) +) ,) -) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) P* Q* R* S* T* U* V* W* X* Y* * * * * * * * * * * + + + + + + + + + !+ |+ }+ ~+ + + + + + + + + + + + + + + + + + D, E, F, G, H, I, J, K, L, M, , , , , , , , , , , - - - - - - - - - - p- q- r- s- t- u- v- w- x- y- - - - - - - - - - - 8. 9. :. ;. <. =. >. ?. @. A. . . . . . . . . . . / / / / / / / / / / d/ e/ f/ g/ h/ i/ j/ k/ l/ m/ / / / / / / / / / / ,0 -0 .0 /0 00 10 20 30 40 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 X1 Y1 Z1 [1 \1 ]1 ^1 _1 `1 a1 1 1 1 1 1 1 1 1 1 1 2 !2 "2 #2 $2 %2 &2 '2 (2 )2 2 2 2 2 2 2 2 2 2 2 pF qF rF sF tF uF vF wF xF yF F F F F F F F F F F 8G 9G :G ;G G ?G @G AG G G G G G G G G G G H H H H H H H H H H dH eH fH gH hH iH jH kH lH mH H H H H H H H H H H ,I -I .I /I 0I 1I 2I 3I 4I 5I I I I I I I I I I I I I I I I I I I I I XJ YJ ZJ [J \J ]J ^J _J `J aJ J J J J J J J J J J K !K "K #K $K %K &K 'K (K )K K K K K K K K K K K K K K K K K K K K K LL ML NL OL PL QL RL SL TL UL L L L L L L L L L L M M M M M M M M M M xM yM zM {M |M }M ~M M M M M M M M M M M M M M @N AN BN CN DN EN FN GN HN IN N N N N N N N N N N O O O O O O O O O O lO mO nO oO pO qO rO sO tO uO O O O O O O O O O O 4P 5P 6P 7P 8P 9P :P ;P

W ?W @W AW BW CW DW EW W W W W W W W W W W X X X X X X X X X X hX iX jX kX lX mX nX oX pX qX X X X X X X X X X X 0Y 1Y 2Y 3Y 4Y 5Y 6Y 7Y 8Y 9Y Y Y Y Y Y Y Y Y Y Y m m m m m m m m m m m m m m m m m m m m Hn In Jn Kn Ln Mn Nn On Pn Qn n n n n n n n n n n o o o o o o o o o o to uo vo wo xo yo zo {o |o }o o o o o o o o o o o

Copyright 2005-2007 by Carabos Coop. V.
Copyright 2008-2017 by Vicent Mas

GNU GENERAL PUBLIC LICENSE

Version 3, 29 June 2007

Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>

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.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    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 <http://www.gnu.org/licenses/>.

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:

    <program>  Copyright (C) <year>  <name of author>
    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 <http://www.gnu.org/licenses/>.

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 <http://www.gnu.org/philosophy/why-not-lgpl.html>.

ViTables-3.0.0/vitables/__init__.py000066400000000000000000000021041311223072700171400ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __version__ = '3.0.0' __all__ = ["docbrowser", "h5db", "logger", "nodeprops", "plugins", "queries", "preferences", "vttables", "vtwidgets", "utils", "vtsite", "vtapp", "vtgui", "vtsplash"] ViTables-3.0.0/vitables/calculator/000077500000000000000000000000001311223072700171635ustar00rootroot00000000000000ViTables-3.0.0/vitables/calculator/__init__.py000066400000000000000000000000021311223072700212640ustar00rootroot00000000000000 ViTables-3.0.0/vitables/calculator/calculator.py000066400000000000000000000401341311223072700216700ustar00rootroot00000000000000"""This module provides calculator functionality.""" # pylint: disable=W0212 import os import re import logging from qtpy import QtGui from qtpy import QtCore from qtpy import QtWidgets import tables import numpy as np import vitables.utils as vtu import vitables.calculator.evaluator as vtce from vitables.calculator.calculator_dlg import Ui_CalculatorDialog translate = QtCore.QCoreApplication.translate def run(): gui = vtu.getGui() selection_count = len(vtu.getView().selectedIndexes()) question = '' if selection_count == 0: question = translate('Calculator', 'No group is selected. ' 'Relative references are disabled. ' 'Continue?') if selection_count > 1: question = translate('Calculator', 'Multiple groups are selected. ' 'Relative references are disabled. ' 'Continue?') if question: answer = QtWidgets.QMessageBox.question( gui, translate('Calculator', 'Relative references are disabled'), question, buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if answer != QtWidgets.QMessageBox.Yes: return dialog = CalculatorDialog() dialog.exec_() # Marker used as prefix to distinguish identifiers from functions. IDENTIFIER_MARKER = '$' # Regular expression used to find identifiers in an evaluation formula. IDENTIFIER_RE = r'\$[\w.]+' def extract_identifiers(expression): """Return a set of identifiers that appear in the expression.""" return set(re.findall(IDENTIFIER_RE, expression)) def get_current_group(): """Return selected pytables group. If zero or more then one items are selected then None is returned. If a group or file is selected then return it. If a pytables leaf is selected then return group that contains the leaf. """ selected_nodes = vtu.getSelectedNodes() if len(selected_nodes) != 1: return None node = selected_nodes[0] if not isinstance(node, tables.Leaf): return node return node._v_parent def create_group(group, path): """Given ancestor group and a path create a group.""" if not path: return group node_name = path[0] rest_of_path = path[1:] if node_name in group._v_groups: return create_group(group._v_groups[node_name], rest_of_path) if node_name in group._v_children: # child but not a group return None node_group = group._v_file.create_group(group, node_name) return create_group(node_group, rest_of_path) def find_identifier_root(model, identifier): """Find the identifier root group in the model. Identifier is a string, root group is found by matching item name to identifier beggining. The second return argument contains path to to identifier node relative to root. """ root_index = QtCore.QModelIndex() for row in range(model.rowCount(root_index)): index = model.index(row, 0, root_index) name = model.data(index, QtCore.Qt.DisplayRole) if identifier.startswith(name): return (model.nodeFromIndex(index).node, identifier[len(name) + 1:]) return None, None def find_node(start_node, path): """Given group and a list of node names return node referenced by path.""" if not path or start_node is None: return start_node if not isinstance(start_node, tables.Group): return None if path[0] in start_node._v_children: return find_node(start_node._v_children[path[0]], path[1:]) else: return None def build_identifier_node_dict(identifiers, current_group): """Map identifiers to pytables nodes.""" model = vtu.getModel() identifier_node_dict = {} for identifier in identifiers: identifier_ancestor, relative_path = find_identifier_root(model, identifier) if identifier_ancestor is None: identifier_ancestor = current_group relative_path = identifier identifier_node = find_node(identifier_ancestor, relative_path.split('.')) if identifier_node: identifier_node_dict[identifier] = identifier_node return identifier_node_dict class CalculatorDialog(QtWidgets.QDialog, Ui_CalculatorDialog): def __init__(self, parent=None): super(CalculatorDialog, self).__init__(parent) self.setupUi(self) self._logger = logging.getLogger(__name__) self._name_expression_dict = {} self._settings = QtCore.QSettings() self._settings.beginGroup('Calculator') self._restore_expressions() def on_buttons_rejected(self): """Slot for cancel button, save expressions on exit.""" self._store_expressions() self.reject() def on_buttons_clicked(self, button): """Slot for apply button, run and store saved expressions.""" button_id = self.buttons.standardButton(button) if button_id == QtWidgets.QDialogButtonBox.Apply: if self._execute_expression(): self._store_expressions() self.accept() @QtCore.Slot() def on_save_button_clicked(self): """Store expression for future use. Ask user for expression name. If provided name is new add it to saved expressions list widget. Store in/update name expression dictionary. """ current_item = self.saved_list.currentItem() if current_item is None: # Either the list is empty or nothing is selected. current_name = "" else: current_name = current_item.text() name, is_accepted = QtWidgets.QInputDialog.getText( self, translate('Calculator', 'Save expression as'), translate('Calculator', 'Name:'), text=current_name) if not is_accepted: return if name not in self._name_expression_dict: self.saved_list.addItem(name) self._name_expression_dict[name] = (self.statements_edit.toPlainText(), self.expression_edit.toPlainText(), self.result_edit.text()) @QtCore.Slot() def on_remove_button_clicked(self): """Remove stored expression. Delete selected row from saved widget and name expression dictionary. """ current_row = self.saved_list.currentRow() if current_row < 0: QtWidgets.QMessageBox.warning( self, translate('Calculator', 'Nothing selected'), translate('Calculator', 'No saved expression selected ' 'to be removed.')) return removed_item = self.saved_list.takeItem( self.saved_list.currentRow()) del self._name_expression_dict[removed_item.text()] def on_saved_list_itemSelectionChanged(self): """Update expression and result fields from selected item. Find first selected widget name, find name in expression dictionary and update expression and result widgets. """ selected_indexes = self.saved_list.selectedIndexes() if len(selected_indexes) == 0: # KFP 2015-08-04: There is a race condition when removing a # stored expression. Both this method and # ``on_remove_button_clicked`` are called very close to the # same time meaning ``self.saved_list.count()`` can show the # wrong value. return selected_index = selected_indexes[0] name = self.saved_list.itemFromIndex(selected_index).text() statements, expression, destination = self._name_expression_dict[name] self.statements_edit.setText( statements if statements is not None else '' ) self.expression_edit.setText( expression if expression is not None else '' ) self.result_edit.setText( destination if destination is not None else '' ) def _store_expressions(self): """Store expressions in configuration. Save name expression dictionary in 'expression' part of configuration. """ self._settings.beginWriteArray('expressions') for index, (name, (statements, expression, destination)) in enumerate( self._name_expression_dict.items()): self._settings.setArrayIndex(index) self._settings.setValue('name', name) self._settings.setValue('statements', statements) self._settings.setValue('expression', expression) self._settings.setValue('destination', destination) self._settings.endArray() def _restore_expressions(self): """Read stored expressions from settings and update list widget. Load name expression dictionary from 'expressions' part of configuration, update list widget. """ expressions_count = self._settings.beginReadArray('expressions') for i in range(expressions_count): self._settings.setArrayIndex(i) name = self._settings.value('name') statements = self._settings.value('statements') expression = self._settings.value('expression') destination = self._settings.value('destination') self._name_expression_dict[name] = (statements, expression, destination) self.saved_list.addItem(name) self._settings.endArray() def _all_identifiers_found(self, identifiers, identifier_node_dict): """Return false if identifier is not found or references a group.""" for identifier in identifiers: if identifier not in identifier_node_dict: QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Node not found'), translate('Calculator', 'Node "{0}" not found'.format(identifier))) return False if not isinstance(identifier_node_dict[identifier], tables.Leaf): QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Node type'), translate('Calculator', 'Node "{0}" does not contain data. ' 'It is probably a group.'.format(identifier))) return False return True def _create_eval_globals_and_epsression(self, expression, identifier_node_dict): """Transform identifiers into valid python names, update expression.""" eval_globals = {} for index, (identifier, node) in enumerate( identifier_node_dict.items()): variable_name = (identifier.replace('.', '_') + '_calculator_index_' + str(index)) expression = expression.replace( IDENTIFIER_MARKER + identifier, variable_name) eval_globals[variable_name] = node return eval_globals, expression def _get_result_group_and_name(self): """Find or create a group for result based on provided name.""" result_identifier = self.result_edit.text() if not result_identifier: QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Result name'), translate('Calculator', 'The location to store results is not specified')) return None model = vtu.getModel() result_ancestor, relative_path = find_identifier_root( model, result_identifier) if result_ancestor is None: result_ancestor = get_current_group() relative_path = result_identifier relative_path = relative_path.split('.') result_group = find_node(result_ancestor, relative_path[:-1]) if result_group is None: answer = QtWidgets.QMessageBox.question( self, translate('Calculator', 'Create group'), translate('Calculator', 'There is no group "{group}" in ' '"{ancestor}". File "{filename}". Create it?'.format( group='/'.join(relative_path[:-1]), ancestor=result_ancestor._v_pathname, filename=result_ancestor._v_file.filename)), buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if answer != QtWidgets.QMessageBox.Yes: return None result_group = create_group(result_ancestor, relative_path[:-1]) if result_group is None: QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Result name'), translate('Calculator', 'Failed to create group "{group}" inside ' '{ancestor} to hold results. File "{filename}".' ''.format( group='/'.join(relative_path[:-1]), ancestor=result_ancestor._v_pathname, filename=result_ancestor._v_file.filename))) return None result_name = relative_path[-1] if result_name in result_group._v_children: QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Result name'), translate('Calculator', 'Node "{node}" already exists in group "{group}". ' 'File "{filename}". Choose another place to store ' 'results.'.format( node=result_name, group=result_group._v_pathname, filename=result_group._v_file.filename))) return None, None return result_group, result_name def _execute_expression(self): """Execute expression and store results. Check existence of all tables used in the expression and result. """ statements = self.statements_edit.toPlainText() expression = self.expression_edit.toPlainText() identifier_strings = extract_identifiers(expression) identifiers = [i[1:] for i in identifier_strings] current_group = get_current_group() identifier_node_dict = build_identifier_node_dict(identifiers, current_group) if not self._all_identifiers_found(identifiers, identifier_node_dict): return False eval_globals, expression = self._create_eval_globals_and_epsression( expression, identifier_node_dict) results = self._get_result_group_and_name() if results is None: return False result_group, result_name = results try: result = vtce.evaluate(statements, expression, eval_globals) except Exception as e: self._logger.error(str(e)) QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Evaluation error'), translate('Calculator', 'An exception was raised during ' 'evaluation, see log for details.')) return False if not isinstance(result, np.ndarray): if isinstance(result, (list, tuple)): result = np.array(result) else: result = np.array([result]) try: result_group._v_file.create_array( result_group, result_name, obj=result, title='Expression: ' + self.expression_edit.toPlainText()) except Exception as e: self._logger.error(str(e)) QtWidgets.QMessageBox.critical( self, translate('Calculator', 'Result save error'), translate('Calculator', 'An exception was raised while ' 'trying to store results, see log for details.')) return False vtu.getModel().updateTreeFromData() return True ViTables-3.0.0/vitables/calculator/calculator.ui000066400000000000000000000117211311223072700216550ustar00rootroot00000000000000 CalculatorDialog 0 0 640 480 Evaluate expression Saved expressions: <html><head/><body><p>Saved expressions.</p></body></html> <html><head/><body><p>Store expression for future use.</p></body></html> Save <html><head/><body><p>Remove the selected expression from the saved expressions list.</p></body></html> Remove Statements: <html><head/><body> <p>Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.</p> </body></html> Expression: <html><head/><body> <p>The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.</p> <p>The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.mydata&quot;. If &quot;sub_group&quot; is the current group then the string &quot;mydata&quot; can be used as reference.</p> </body></html> Result table: <html><head/><body> <p>Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.myresult&quot;. If &quot;sub_group&quot; is the current group then the string &quot;myresult&quot; can be used as reference.</p> <p>The result table must not exitst.</p> </body></html> QDialogButtonBox::Apply|QDialogButtonBox::Close ViTables-3.0.0/vitables/calculator/calculator_dlg.py000066400000000000000000000147261311223072700225260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'calculator.ui' # # Created: Tue Jul 8 11:45:41 2014 # by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! from qtpy import QtCore from qtpy import QtWidgets try: _encoding = QtWidgets.QApplication.UnicodeUTF8 def _translate(context, text, disambig): return QtWidgets.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtWidgets.QApplication.translate(context, text, disambig) class Ui_CalculatorDialog(object): def setupUi(self, CalculatorDialog): CalculatorDialog.setObjectName("CalculatorDialog") CalculatorDialog.resize(640, 480) self.gridLayout = QtWidgets.QGridLayout(CalculatorDialog) self.gridLayout.setObjectName("gridLayout") self.main_layout = QtWidgets.QHBoxLayout() self.main_layout.setObjectName("main_layout") self.save_layout = QtWidgets.QVBoxLayout() self.save_layout.setObjectName("save_layout") self.saved_label = QtWidgets.QLabel(CalculatorDialog) self.saved_label.setObjectName("saved_label") self.save_layout.addWidget(self.saved_label) self.saved_list =QtWidgets.QListWidget(CalculatorDialog) self.saved_list.setObjectName("saved_list") self.save_layout.addWidget(self.saved_list) self.list_buttons_layout = QtWidgets.QHBoxLayout() self.list_buttons_layout.setObjectName("list_buttons_layout") self.save_button = QtWidgets.QPushButton(CalculatorDialog) self.save_button.setObjectName("save_button") self.list_buttons_layout.addWidget(self.save_button) self.remove_button = QtWidgets.QPushButton(CalculatorDialog) self.remove_button.setObjectName("remove_button") self.list_buttons_layout.addWidget(self.remove_button) self.save_layout.addLayout(self.list_buttons_layout) self.main_layout.addLayout(self.save_layout) self.evaluation_layout = QtWidgets.QVBoxLayout() self.evaluation_layout.setObjectName("evaluation_layout") self.statements_label = QtWidgets.QLabel(CalculatorDialog) self.statements_label.setObjectName("statements_label") self.evaluation_layout.addWidget(self.statements_label) self.statements_edit = QtWidgets.QTextEdit(CalculatorDialog) self.statements_edit.setObjectName("statements_edit") self.evaluation_layout.addWidget(self.statements_edit) self.expression_label = QtWidgets.QLabel(CalculatorDialog) self.expression_label.setObjectName("expression_label") self.evaluation_layout.addWidget(self.expression_label) self.expression_edit = QtWidgets.QTextEdit(CalculatorDialog) self.expression_edit.setObjectName("expression_edit") self.evaluation_layout.addWidget(self.expression_edit) self.result_label = QtWidgets.QLabel(CalculatorDialog) self.result_label.setObjectName("result_label") self.evaluation_layout.addWidget(self.result_label) self.result_edit = QtWidgets.QLineEdit(CalculatorDialog) self.result_edit.setObjectName("result_edit") self.evaluation_layout.addWidget(self.result_edit) self.main_layout.addLayout(self.evaluation_layout) self.main_layout.setStretch(0, 1) self.main_layout.setStretch(1, 3) self.gridLayout.addLayout(self.main_layout, 0, 0, 1, 1) self.buttons = QtWidgets.QDialogButtonBox(CalculatorDialog) self.buttons.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Close) self.buttons.setObjectName("buttons") self.gridLayout.addWidget(self.buttons, 1, 0, 1, 1) self.retranslateUi(CalculatorDialog) QtCore.QMetaObject.connectSlotsByName(CalculatorDialog) def retranslateUi(self, CalculatorDialog): CalculatorDialog.setWindowTitle(_translate("CalculatorDialog", "Evaluate expression", None)) self.saved_label.setText(_translate("CalculatorDialog", "Saved expressions:", None)) self.saved_list.setToolTip(_translate("CalculatorDialog", "

Saved expressions.

", None)) self.save_button.setToolTip(_translate("CalculatorDialog", "

Store expression for future use.

", None)) self.save_button.setText(_translate("CalculatorDialog", "Save", None)) self.remove_button.setToolTip(_translate("CalculatorDialog", "

Remove the selected expression from the saved expressions list.

", None)) self.remove_button.setText(_translate("CalculatorDialog", "Remove", None)) self.statements_label.setText(_translate("CalculatorDialog", "Statements:", None)) self.statements_edit.setToolTip(_translate("CalculatorDialog", "\n" "

Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.

\n" "", None)) self.expression_label.setText(_translate("CalculatorDialog", "Expression:", None)) self.expression_edit.setToolTip(_translate("CalculatorDialog", "\n" "

The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.

\n" "

The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.mydata". If "sub_group" is the current group then the string "mydata" can be used as reference.

\n" "", None)) self.result_label.setText(_translate("CalculatorDialog", "Result table:", None)) self.result_edit.setToolTip(_translate("CalculatorDialog", "\n" "

Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.myresult". If "sub_group" is the current group then the string "myresult" can be used as reference.

\n" "

The result table must not exitst.

\n" "", None)) ViTables-3.0.0/vitables/calculator/evaluator.py000066400000000000000000000007101311223072700215350ustar00rootroot00000000000000"""Function that calls eval for calculator. It is separated into a module in order to import * from numpy and thus simplify writing expressions. (Such import is not allowed inside a function.) """ from numpy import * def evaluate(statements, expression, globals_dict): """Evaluate expression and return results.""" exec(statements) globals_dict.update(globals()) globals_dict.update(locals()) return eval(expression, globals_dict) ViTables-3.0.0/vitables/calculator/test/000077500000000000000000000000001311223072700201425ustar00rootroot00000000000000ViTables-3.0.0/vitables/calculator/test/__init__.py000066400000000000000000000000001311223072700222410ustar00rootroot00000000000000ViTables-3.0.0/vitables/calculator/test/test_calculator.py000066400000000000000000000016321311223072700237060ustar00rootroot00000000000000import sip sip.setapi('QString', 2) sip.setapi('QVariant', 2) import nose.tools as nt import vitables.calculator.calculator as vtc class TestCalculator: """Test calculator functionality.""" def test_extract_identifiers(self): """Test function that extract marked identifiers from an expression.""" empty_set = vtc.extract_identifiers('') nt.assert_true(len(empty_set) == 0) nt.assert_equal(set(['$data']), vtc.extract_identifiers('$data')) nt.assert_equal(set(['$data']), vtc.extract_identifiers('+$data*')) nt.assert_equal(set(['$data']), vtc.extract_identifiers('+$data*$data')) nt.assert_equal(set(['$data', '$data1']), vtc.extract_identifiers('+$data*$data1 + test')) nt.assert_equal(set(['$data', '$test.data1']), vtc.extract_identifiers('+$data*$test.data1 + test')) ViTables-3.0.0/vitables/docbrowser/000077500000000000000000000000001311223072700172035ustar00rootroot00000000000000ViTables-3.0.0/vitables/docbrowser/__init__.py000066400000000000000000000016511311223072700213170ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["bookmarksdlg", "browsergui", "helpbrowser"] ViTables-3.0.0/vitables/docbrowser/bookmarksdlg.py000066400000000000000000000175311311223072700222430ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Here is defined the BookmarksDlg class. This module provides a dialog for deleting bookmarks from the bookmarks list. """ __docformat__ = 'restructuredtext' import sys import os.path from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets translate = QtWidgets.QApplication.translate class BookmarksDlg(QtWidgets.QDialog): """ The dialog for deleting bookmarks. The class defines a modal dialog used to delete entries from the bookmarks list. Bookmarks are displayed in a tree view. As a bonus, they can be visited directly from this dialog by double clicking them in the tree. At the bottom there is a group of buttons made of the ``Delete``, ``OK`` and ``Cancel`` buttons. ``Delete`` removes checked items from the bookmarks list. :Parameters: - `blist`: the bookmarks list - `hbgui`: an instance of :meth:`vitables.docbrowser.browsergui.HelpBrowserGUI` (the parent widget) """ def __init__(self, blist, hbgui): """ Dialog constructor. """ # The HelpBrowser GUI instance from which this dialog has been opened super(BookmarksDlg, self).__init__(hbgui) self.setWindowTitle( translate('BookmarksDlg', 'Bookmarks editor', 'Dialog caption')) dlg_layout = QtWidgets.QVBoxLayout(self) # Add a tree view self.tree = QtWidgets.QTreeView(self) self.tree.setItemsExpandable(False) self.tmodel = QtGui.QStandardItemModel() self.tree.setModel(self.tmodel) self.tmodel.setHorizontalHeaderLabels([ translate('BookmarksDlg', 'Bookmark', 'First column header of the bookmarks table'), translate('BookmarksDlg', 'URL', 'Second column header of the bookmarks table')]) dlg_layout.addWidget(self.tree) # Add a group of buttons self.button_group = QtWidgets.QDialogButtonBox(self) self.ok_button = self.button_group.addButton( translate('BookmarksDlg', '&OK', 'Button label'), QtWidgets.QDialogButtonBox.AcceptRole) self.del_button = self.button_group.addButton( translate('BookmarksDlg', '&Delete', 'Button label'), QtWidgets.QDialogButtonBox.ActionRole) self.cancel_button = self.button_group.addButton( translate('BookmarksDlg', '&Cancel', 'Button label'), QtWidgets.QDialogButtonBox.RejectRole) dlg_layout.addWidget(self.button_group) # We dont work directly on the HelpBrowser bookmarks list, # instead we make a copy. This is convenient if, after doing # some changes in the list, we decide to cancel the changes. self.blist = blist[:] self.fillBookmarksTable() self.show() # Finally we connect signals to slots self.tmodel.itemChanged.connect(self.updateDeleteButton) self.tree.doubleClicked.connect(self.displayBookmark) self.button_group.clicked.connect(self.buttonClicked) self.del_button.setEnabled(False) def fillBookmarksTable(self): """Add entries to the bookmarks table.""" self.tmodel.setColumnCount(2) parent_item = self.tmodel.invisibleRootItem() # Each item of the tree (bookmark) is extracted from the bookmarks list for entry in self.blist : # extracts the short name. Examples: # /home/vmas/estilo.html --> estilo.html # /home/vmas/estilo.html#color --> estilo.html#color shortname = os.path.basename(entry) item = QtGui.QStandardItem(shortname) item.setCheckable(True) item.setEditable(False) item1 = QtGui.QStandardItem(entry) item1.setEditable(False) parent_item.appendRow([item, item1]) self.tree.setExpanded(self.tmodel.indexFromItem(parent_item), True) self.tree.repaint() self.repaint() def displayBookmark(self, index): """ Display a given bookmark in the help browser. When a bookmark is double clicked the `HelpBrowser` window is updated and displays that bookmark. :Parameter index: the index in the bookmarks tree view of the selected bookmark """ # Get the bookmark UID row = self.tmodel.itemFromIndex(index).row() src = self.blist[row] self.parent().browser.displaySrc(src) def updateDeleteButton(self, item): """ Enable/disable the ``Delete`` button. The state of the ``Delete`` button depends on the presence/abscence of checked items in the bookmarks list. Every time an item is clicked the whole bookmarks tree is traversed looking for checked items. The``Delete`` button state is updated accordingly. :Parameter item: the bookmarks tree item checked/unchecked """ parent_item = self.tmodel.invisibleRootItem() # Iterate over the QTreeWidget looking for checked items enabled = 0 row = 0 item = parent_item.child(row) while item != None: if item.checkState() == QtCore.Qt.Checked: enabled = 1 break row = row + 1 item = parent_item.child(row) self.del_button.setEnabled(enabled) def buttonClicked(self, button): """ Action selector method. Depending on the button clicked in the button group the appropriate method is called. :Parameter button: the clicked button """ role = self.button_group.buttonRole(button) # OK button clicked if role == QtWidgets.QDialogButtonBox.AcceptRole: gui = self.parent() gui.browser.bookmarks = self.blist self.accept() # Delete button clicked elif role == QtWidgets.QDialogButtonBox.ActionRole: self.deleteBookmarks() # Cancel button clicked elif role == QtWidgets.QDialogButtonBox.RejectRole: self.reject() def deleteBookmarks(self) : """Delete all selected bookmarks.""" parent_item = self.tmodel.invisibleRootItem() # Iterate over the QTreeView looking for checked items deleted_rows = [] row = 0 item = parent_item.child(row) while item != None: if item.checkState() == QtCore.Qt.Checked: deleted_rows.append(row) row = row + 1 item = parent_item.child(row) # Items with highest model indexes are removed first from the model # This way deleting an item does not modify the model index of the # remaining items deleted_rows.reverse() for row in deleted_rows: self.tmodel.takeRow(row) del self.blist[row] # After deletion we udpate the dialog self.del_button.setEnabled(0) if __name__ == '__main__': APP = QtWidgets.QApplication(sys.argv) DLG = BookmarksDlg(['uno', 'dos'], None) APP.exec_() ViTables-3.0.0/vitables/docbrowser/browsergui.py000066400000000000000000000350161311223072700217520ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Here is defined the HelpBrowserGUI class. This module creates the main window for the documentation browser. """ __docformat__ = 'restructuredtext' import re from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.vtsite import DOCDIR translate = QtWidgets.QApplication.translate class HelpBrowserGUI(QtWidgets.QMainWindow) : """ The main window of the documentation browser. :Parameters: - `browser`: an instance of the docs browser controller :meth:`vitables.docbrowser.helpbrowser.HelpBrowser` - `parent`: the parent widget. """ def __init__(self, browser, parent=None) : """ Initializes the browser. """ super(HelpBrowserGUI, self).__init__(parent) self.setIconSize(QtCore.QSize(22, 22)) self.setWindowTitle(translate('HelpBrowserGUI', 'Documentation browser', 'The window title')) self.icons = vitables.utils.getHBIcons() self.setWindowIcon(self.icons['vitables_wm']) self.browser = browser # The browser widget self.text_browser = QtWidgets.QTextBrowser() self.text_browser.setSearchPaths([DOCDIR]) self.setCentralWidget(self.text_browser) self.text_browser.setAcceptRichText(True) self.text_browser.setReadOnly(1) # The popup menus self.actions = self.setupActions() self.initPopups() self.connectSignals() self.setupHistoryCombo() self.statusBar().showMessage(translate('HelpBrowserGUI', 'Ready...', 'Status bar startup message')) def setupActions(self): """Provide actions to the menubar and the toolbars. """ actions = {} actions['exitBrowser'] = QtWidgets.QAction( translate('HelpBrowserGUI', 'E&xit', 'File --> Exit'), self, shortcut=QtGui.QKeySequence.Quit, triggered=self.browser.exitBrowser, icon=self.icons['application-exit'], statusTip=translate('HelpBrowserGUI', 'Close Help Browser', 'Status bar text for the File --> Exit action')) actions['zoomIn'] = QtWidgets.QAction( translate('HelpBrowserGUI', 'Zoom &in', 'View --> Zoom in'), self, shortcut=QtGui.QKeySequence.ZoomIn, triggered=self.browser.zoomIn, icon=self.icons['zoom-in'], statusTip=translate('HelpBrowserGUI', 'Increases the font size', 'Status bar text for the View --> Zoom in action')) actions['zoomOut'] = QtWidgets.QAction( translate('HelpBrowserGUI', 'Zoom &out', 'View --> Zoom out'), self, shortcut=QtGui.QKeySequence.ZoomOut, triggered=self.browser.zoomOut, icon=self.icons['zoom-out'], statusTip=translate('HelpBrowserGUI', 'Decreases the font size', 'Status bar text for the View --> Zoom out action')) actions['goHome'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Home', 'Go --> Home'), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.text_browser.home, icon=self.icons['go-first-view'], statusTip=translate('HelpBrowserGUI', 'Go to the first visited page', 'Status bar text for the Go --> Home action')) actions['goBackward'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Backward', ' Go --> Backward'), self, shortcut=QtGui.QKeySequence.Back, triggered=self.text_browser.backward, icon=self.icons['go-previous-view'], statusTip=translate('HelpBrowserGUI', 'Go to previous page', 'Status bar text for the Go --> Backward action')) actions['goForward'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Forward', ' Go --> Forward'), self, shortcut=QtGui.QKeySequence.Forward, triggered=self.text_browser.forward, icon=self.icons['go-next-view'], statusTip=translate('HelpBrowserGUI', 'Go to next page', 'Status bar text for the Go --> Forward action')) actions['goReload'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Reload', 'Go --> Reload'), self, shortcut=QtGui.QKeySequence.Refresh, triggered=self.text_browser.reload, icon=self.icons['view-refresh'], statusTip=translate('HelpBrowserGUI', 'Reload the current page', 'Status bar text for the Go --> Reload action')) actions['bookmarksAdd'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Add bookmark', 'Bookmarks --> Add bookmark'), self, shortcut=QtGui.QKeySequence('Ctrl+Alt+N'), triggered=self.browser.addBookmark, icon=self.icons['bookmark_add'], statusTip=translate('HelpBrowserGUI', 'Bookmark the current page', 'Status bar text for Bookmarks --> Add bookmark action')) actions['bookmarksEdit'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Edit bookmarks...', 'Bookmarks --> Edit bookmarks'), self, shortcut=QtGui.QKeySequence('Ctrl+Alt+E'), triggered=self.browser.editBookmarks, icon=self.icons['bookmarks'], statusTip=translate('HelpBrowserGUI', 'Edit bookmarks', 'Status bar text for Bookmarks --> Edit bookmarks action')) actions['bookmarksClear'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&Clear All', 'Bookmarks --> Clear bookmark'), self, shortcut=QtGui.QKeySequence('Ctrl+Alt+C'), triggered=self.browser.clearBookmarks, statusTip=translate('HelpBrowserGUI', 'Clear all existing bookmarks', 'Status bar text for Bookmarks --> Add bookmark action')) actions['about'] = QtWidgets.QAction( translate('HelpBrowserGUI', '&About HelpBrowser', 'Help --> About HelpBrowser'), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.browser.aboutBrowser, statusTip=translate('HelpBrowserGUI', 'About HelpBrowser', 'Status bar text for Help --> About HelpBrowser action')) actions['aboutQt'] = QtWidgets.QAction( translate('HelpBrowserGUI', 'About &Qt', 'Help --> About Qt'), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.browser.aboutQt, statusTip=translate('HelpBrowserGUI', 'About Qt', 'Status bar text for the Help --> About Qt action')) actions['clearSession'] = QtWidgets.QAction( translate('HelpBrowserGUI', 'Clear history', ''), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.browser.clearHistory, icon=self.icons['edit-clear-history'], statusTip=translate('HelpBrowserGUI', 'Clear the content of the history combobox', '')) return actions def initPopups(self) : """ Setup the menubar and the toolbar of the main window. The menubar contains the menus `File`, `Go`, `Bookmarks` and `Help`. The toolbar contains the buttons: `home`, `backward`, `forward`, `combobox` and `clear history`. """ # Create the File menu and add actions/submenus/separators to it file_menu = self.menuBar().addMenu( translate('HelpBrowserGUI', "&File", 'The File menu entry')) file_actions = ['exitBrowser'] vitables.utils.addActions(file_menu, file_actions, self.actions) # Create the View menu and toolbar view_menu = self.menuBar().addMenu( translate('HelpBrowserGUI', "&View", 'The View menu entry')) view_toolbar = QtWidgets.QToolBar( translate('HelpBrowserGUI', 'View operations', 'Toolbar title'), self) self.addToolBar(view_toolbar) view_actions = ['zoomIn', 'zoomOut'] vitables.utils.addActions(view_menu, view_actions, self.actions) vitables.utils.addActions(view_toolbar, view_actions, self.actions) # Create the Go menu and toolbar go_menu = self.menuBar().addMenu(translate('HelpBrowserGUI', "&Go", 'The Go menu entry')) go_toolbar = QtWidgets.QToolBar( translate('HelpBrowserGUI', 'Go operations', 'Toolbar title'), self) self.addToolBar(go_toolbar) go_actions = ['goHome', 'goBackward', 'goForward', 'goReload'] vitables.utils.addActions(go_menu, go_actions, self.actions) vitables.utils.addActions(go_toolbar, go_actions, self.actions) # Create the Bookmarks menu and toolbar self.bookmarks_menu = self.menuBar().addMenu( translate('HelpBrowserGUI', "&Bookmarks", 'Bookmarks menu entry')) bookmarks_toolbar = QtWidgets.QToolBar( translate('HelpBrowserGUI', 'Bookmarks operations', 'Toolbar title'), self) self.addToolBar(bookmarks_toolbar) bookmark_actions = ['bookmarksAdd', 'bookmarksEdit', 'bookmarksClear', None] vitables.utils.addActions(self.bookmarks_menu, bookmark_actions, self.actions) vitables.utils.addActions(bookmarks_toolbar, bookmark_actions[:2], self.actions) # Create the Help menu and add actions/submenus/separators to it help_menu = self.menuBar().addMenu( translate('HelpBrowserGUI', "&Help", 'The Help menu entry')) help_actions = ['about', 'aboutQt'] vitables.utils.addActions(help_menu, help_actions, self.actions) # Create the History toolbar history_toolbar = QtWidgets.QToolBar( translate('HelpBrowserGUI', 'History operations', 'Toolbar title'), self) self.addToolBar(history_toolbar) history_actions = ['clearSession'] vitables.utils.addActions(history_toolbar, history_actions, self.actions) go_selector = QtWidgets.QLabel( translate('HelpBrowserGUI', 'Go: ', 'Text of the Go: label'), history_toolbar) history_toolbar.addWidget(go_selector) self.combo_history = QtWidgets.QComboBox(history_toolbar) self.combo_history.setSizeAdjustPolicy( QtWidgets.QComboBox.AdjustToContents) history_toolbar.addWidget(self.combo_history) def connectSignals(self): """ Connect signals to slots. Signals coming from GUI are connected to slots in the docs browser controller, :meth:`vitables.docbrowser.helpbrowser.HelpBrowser`. """ self.combo_history.activated[str].connect(self.browser.displaySrc) # This is the most subtle connection. It encompasses source # changes coming from anywhere, including slots (home, backward # and forward), menus (Go and Bookmarks), clicked links and # programatic changes (setSource calls). self.text_browser.sourceChanged.connect(self.browser.updateHistory) self.text_browser.backwardAvailable.connect( self.browser.updateBackward) self.text_browser.forwardAvailable.connect( self.browser.updateForward) # The Bookmarks menu is special case due to its dynamic nature. # The menu content vary every time a bookmark is added/deleted # In order to track changes and keep it updated, the menu is reloaded # every time it is about to be displayed. self.bookmarks_menu.aboutToShow.connect(self.updateRecentSubmenu) def updateRecentSubmenu(self): """Update the content of the Bookmarks menu.""" # Clear the current bookmarks from the Bookmarks menu for action in self.bookmarks_menu.actions(): if re.search("^(\s?\d)", action.text()): self.bookmarks_menu.removeAction(action) # and refresh it index = 0 for filepath in self.browser.bookmarks: index += 1 action = QtWidgets.QAction('{0:>2}. {1}'.format(index, filepath), self.bookmarks_menu) action.setData(filepath) self.bookmarks_menu.addAction(action) action.triggered.connect(self.browser.displaySrc) def setupHistoryCombo(self): """ Initializes history combobox. """ # Setup combobox self.combo_history.setEditable(0) self.combo_history.setWhatsThis(translate('HelpBrowserGUI', """

Page selector

Select the page you want to visit.
""", 'WhatsThis text for the combobox of visited pages') ) for item in self.browser.history : self.combo_history.addItem(item) def closeEvent(self, event) : """ Reimplements the event handler for `QCloseEvent` events. Before the close event is accepted we need to do some stuff. This can be done in two different ways: via event filters or reimplementing the event handler. We have chosen the second possibility. :Parameter event: the event being handled """ # When the help browser window is closed via File --> Exit # the exitBrowser is called and its history is saved. # But if we close the window with the # close button then history is not saved at all. # We fix this misbehavior by overwriting this method. self.browser.exitBrowser() QtWidgets.QMainWindow.closeEvent(self, event) ViTables-3.0.0/vitables/docbrowser/helpbrowser.py000066400000000000000000000212301311223072700221070ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ The controller of the Users' Guide browser is implemented in this module. The documentation browser is used for browsing the HTML version of the Guide which is distributed along the source code in every supported platform. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.docbrowser import bookmarksdlg from vitables.docbrowser import browsergui translate = QtWidgets.QApplication.translate class HelpBrowser(QtCore.QObject) : """ This is the controller of the ``ViTables`` documentation browser. Features: * reasonably good understanding of ``HTML`` format * navigation toolbar * session capable - filenames of files opened during the session are available at any moment - last session can be restored next time we open the `HelpBrowser` * basic bookmarks management """ def __init__(self) : """ Initializes the browser. Restore history and bookmarks from disk and makes the browser window. """ super(HelpBrowser, self).__init__() self.vtapp = vitables.utils.getVTApp() # Get the bookmarks and the navigation history self.bookmarks = self.vtapp.config.hb_bookmarks self.history = self.vtapp.config.hb_history # create the GUI self.gui = browsergui.HelpBrowserGUI(self) # The working directory used in QFileDialog calls self.working_dir = vitables.utils.getHomeDir() # The GUI setup is slow so it is not shown until the setup is # done (it avoids displaying an ugly empty widget) self.displaySrc('index.html') self.gui.show() def displaySrc(self, src=False): """ Displays a document in the `HelpBrowser` window. This slot is called when: - :meth: `vitables.docbrowser.bookmarksdlg.BookmarksDlg.displayBookmark` is launched - a new item is activated in the `History` combo - an entry is selected in the `Bookmarks` menu :Parameter src: the path of the file being displayed """ if src is False: # entry selected in the Bookmarks menu action = self.gui.sender() src = action.data() src = QtCore.QDir(src).dirName() src = QtCore.QDir().fromNativeSeparators(src) url = QtCore.QUrl(src) self.gui.text_browser.setSource(url) ######################################################### # # File menu related slots # ######################################################### def exitBrowser(self) : """ Quit the `HelpBrowser`. Before quitting this slot saves session and bookmarks. Then all browser windows are closed. The saved state corresponds to the window on which Exit is invoqued. """ # Close all browsers self.vtapp.config.hb_history = self.history self.vtapp.config.hb_bookmarks = self.bookmarks self.vtapp.doc_browser = None self.gui.close() ######################################################### # # View menu related slots # ######################################################### def zoomIn(self) : """Increases the font size of the displayed source.""" self.gui.text_browser.zoomIn(2) def zoomOut(self) : """Increases the font size of the displayed source.""" self.gui.text_browser.zoomOut(2) ######################################################### # # Go menu related slots # ######################################################### def updateHome(self) : """ Enables/disables the ``Go --> Home`` menu item. If the history list is empty the menu item is disabled. Otherwise it is enabled. """ if self.gui.text_browser.source(): self.gui.actions['goHome'].setEnabled(1) else: self.gui.actions['goHome'].setEnabled(0) def updateForward(self, available) : """Enables/disables the ``Go --> Forward`` menu item. :Parameter available: a boolean. Indicates if a Next page is available. """ self.gui.actions['goForward'].setEnabled(available) def updateBackward(self, available) : """Enables/disables the ``Go --> Backward`` menu item. :Parameter available: a boolean. Indicates if a Previous page is available """ self.gui.actions['goBackward'].setEnabled(available) ######################################################### # # Bookmarks menu related slots # ######################################################### def addBookmark(self) : """ Add the current page to the bookmarks menu. """ src = self.gui.text_browser.source().toString() src = QtCore.QDir.fromNativeSeparators(src) src = src.replace('///', '/') if self.bookmarks.count(src) : # if the page is already bookmarked we do nothing pass else : # The page is not bookmarked so we append it to the bookmarks list. self.bookmarks.append(src) def editBookmarks(self) : """ Raise the dialog for editing bookmarks. """ # update bookmarks list edit_dlg = bookmarksdlg.BookmarksDlg(self.bookmarks, self.gui) edit_dlg.exec_() def clearBookmarks(self) : """Clear all bookmarks.""" self.bookmarks = [] ######################################################### # # History related slots # ######################################################### def clearHistory(self) : """ Clear the history of visited pages. """ self.history = [] self.gui.combo_history.clear() self.updateHome() def updateHistory(self, src) : """ Updates the contents of the combo selector. Combo selector has to be updated when: - a new file is opened - a link is clicked in the current document - a bookmark is opened The history combobox is a visual representation of the `history list`, so entries will occupy the same position in both, the list and the combo. :Parameter src: the path being added to the combo """ url = QtCore.QDir.fromNativeSeparators(src.toString()) url = url.replace('///', '/') if url not in self.history: self.history.append(url) self.gui.combo_history.addItem(url) self.gui.combo_history.setCurrentIndex(self.history.index(url)) self.updateHome() ######################################################### # # Help menu related slots # ######################################################### def aboutBrowser(self) : """ Shows a message box with the application `About` info. """ QtWidgets.QMessageBox.information(self.gui, translate('HelpBrowser', 'About HelpBrowser', 'A dialog caption'), translate('HelpBrowser', """

HelpBrowser

HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs.

Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit.""", 'About Help browser text') ) def aboutQt(self) : """ Shows a message box with the `Qt About` info. """ caption = translate('HelpBrowser', 'About Qt', 'A dialog caption') QtWidgets.QMessageBox.aboutQt(self.gui, caption) ViTables-3.0.0/vitables/h5db/000077500000000000000000000000001311223072700156545ustar00rootroot00000000000000ViTables-3.0.0/vitables/h5db/__init__.py000066400000000000000000000020171311223072700177650ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["dbdoc", "dbstreemodel", "dbstreeview", "groupnode", "leafnode", "linknode", "nodeitemdelegate", "rootgroupnode", "tlink_editor", "tnode_editor"] ViTables-3.0.0/vitables/h5db/dbdoc.py000066400000000000000000000155421311223072700173100ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a thin wrapper to the `tables.File` class. The module provides methods for opening and closing PyTables databases. It also contains methods for editing nodes (but not data stored in nodes). """ __docformat__ = 'restructuredtext' import os import uuid import logging import tables from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate class DBDoc(QtCore.QObject): """ A database contained in an hdf5/PyTables file. :Parameters: - `filePath`: full path of the DB - `mode`: indicate the open mode of the database file. It can be 'r'ead-only or 'a'ppend - `is_tmp_dbdoc`: True if this object represents the temporary database """ def __init__(self, filepath, mode, is_tmp_dbdoc=False): """ Makes a data structure that defines a given database. A `DBDoc` instance is defined by the next attributes: - filepath - filename - mode - h5file, the File instance returned when filePath is opened """ super(DBDoc, self).__init__() self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # The opening mode self.mode = mode # The full path of the database self.filepath = filepath # The filename of the database self.filename = os.path.basename(filepath) # The tables.File instance self.h5file = self.openH5File() # The hidden group is used as an intermediate storage # in cut operations self.hidden_group = None if is_tmp_dbdoc: self.h5file.create_group('/', '_p_query_results', 'Hide the result of queries') self.h5file.flush() def openH5File(self): """Open the file tied to this instance.""" h5file = None # If read-write access is required then test file writability if self.mode != 'r' and os.path.isfile(self.filepath): if not os.access(self.filepath, os.W_OK): self.mode = 'r' self.logger.warning( translate('DBDoc', """File access in read-write mode """ """is denied. It will be opened in read-only """ """mode.""", 'A logger error message')) try: h5file = tables.open_file(self.filepath, self.mode) except IOError as inst: self.logger.error(translate('DBDoc', "{0}", 'A logger error message').format(inst)) except: vitables.utils.formatExceptionInfo() self.logger.error( translate('DBDoc', "Please, if you think it is a bug, report it to " "developers.", 'A logger error message')) return h5file def closeH5File(self): """Closes a tables.File instance.""" try: self.h5file.close() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def getFileFormat(self): """ The format of the database file. This is an accessor method intended to be used by external classes. :Returns: the format of the database file """ file_format = None if self.h5file: if self.h5file._isPTFile: file_format = 'PyTables file' else: file_format = 'Generic HDF5 file' return file_format def get_node(self, where): """ The node whose path is where. :Parameter where: the full path of the retrieved node """ try: node = self.h5file.get_node(where) return node except tables.exceptions.NoSuchNodeError: self.logger.error( translate('DBDoc', """Cannot open node {0} in file {1} """, 'Error message').format(where, self.filepath)) vitables.utils.formatExceptionInfo() return None def list_nodes(self): """:Returns: the recursive list of full nodepaths for the file""" return [node._v_pathname for node in self.h5file.walk_nodes('/')] # # Editing databases # def copy_file(self, dst_filepath): """ Copy the contents of this file to another one. .. Note:: Given two open files in a ``ViTables`` session, overwriting one of them via ``File --> Save As...`` command may work or not. It depends on the operating system. On Unices it works because a process can delete or truncate a file open by a different process (unless file is blocked). On Windows it seems to work fine too. If the overwriting is not done via ``ViTables`` but in an interactive session it fails, due (probably) to `HDF5` memory protection. :Parameter dst_filepath: the full path of the destination file """ try: self.h5file.copy_file(dst_filepath, overwrite=True) except tables.exceptions.HDF5ExtError: self.logger.error( translate('DBDoc', """Unable to save the file {0} as """ """{1}. Beware that only closed files can be """ """safely overwritten via Save As...""", 'A logger error message').format(self.filepath, dst_filepath)) vitables.utils.formatExceptionInfo() def createHiddenGroup(self): """ Create a hidden group for storing cut nodes. """ group_name = '_p_' + str(uuid.uuid4()) self.hidden_group = '/' + group_name self.h5file.create_group('/', group_name, 'Hide cut nodes') self.h5file.flush() ViTables-3.0.0/vitables/h5db/dbstreemodel.py000066400000000000000000001255621311223072700207120ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a model (in the `MVC` sense) representing the tree of databases. The model is populated using data structures defined in the :mod:`vitables.h5db.rootgroupnode`, :mod:`vitables.h5db.groupnode` and :mod:`vitables.h5db.leafnode` modules. """ __docformat__ = 'restructuredtext' import tempfile import os import sys import re import logging import tables from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.h5db import dbdoc from vitables.h5db import rootgroupnode from vitables.h5db import groupnode from vitables.h5db import leafnode from vitables.h5db import linknode from vitables.h5db import tnode_editor from vitables.h5db import tlink_editor translate = QtWidgets.QApplication.translate def _get_node_tooltip(node): """Takes one of vitables nodes and return tooltip text. :Parameters node: a node from the tree model """ tooltip_lines = [] attrset = node.node._v_attrs if not hasattr(node.node, 'target'): if hasattr(attrset, 'TITLE') and bool(str(attrset.TITLE)): tooltip_lines.append(attrset.TITLE) tooltip_lines.append('{0}: {1}'.format(node.node_kind, node.name)) tooltip_lines.extend( ['{0}: {1}'.format(name, str(getattr(attrset, name))) for name in attrset._v_attrnamesuser]) return '\n'.join(tooltip_lines) # Map qt display role onto a function that gets data from a node. _ROLE_NODE_GET_FUNCTION_DICT = { QtCore.Qt.DisplayRole: lambda n: getattr(n, 'name'), QtCore.Qt.ToolTipRole: _get_node_tooltip, QtCore.Qt.StatusTipRole: lambda n: getattr(n, 'as_record'), QtCore.Qt.DecorationRole: lambda n: getattr(n, 'icon'), QtCore.Qt.UserRole: lambda n: getattr(n, 'filepath'), QtCore.Qt.UserRole + 1: lambda n: getattr(n, 'nodepath'), QtCore.Qt.UserRole + 2: lambda n: getattr(n, 'node_kind') } class DBsTreeModel(QtCore.QAbstractItemModel): """ The tree of databases model. The data is read and written from and to data sources (i.e., HDF5/PyTables files) by the model. :Parameters vtapp: the VTAPP instance """ def __init__(self, vtgui, vtapp): """Create the model. """ # The underlying data structure used to populate the model self.root = rootgroupnode.RootGroupNode(self) super(DBsTreeModel, self).__init__(parent=None) self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # The dictionary of open databases self.__openDBs = {} # Create the temporary database that will contain filtered tables self.tmp_filepath = '' self.tmp_dbdoc = self.__createTempDB() # The Cut/CopiedNodeInfo dictionary self.ccni = {} self.vtapp = vtapp self.vtgui = vtgui # Sets used to populate the model self.fdelta = frozenset([]) self.gdelta = frozenset([]) self.ldelta = frozenset([]) self.links_delta = frozenset([]) self.rowsAboutToBeRemoved.connect(self.closeViews) def mapDB(self, filepath, db_doc): """Maps a file path with a :meth:`dbdoc.DBDoc` instance. :Parameters: - `filepath`: the full path of an open database. - `db_doc`: a :meth:`dbdoc.DBDoc` instance. """ self.__openDBs[filepath] = db_doc def removeMappedDB(self, filepath): """Remove a :meth:`dbdoc.DBDoc` instance from the tracking dict. :Parameter filepath: the full path of the database being untracked """ del self.__openDBs[filepath] def getDBDoc(self, filepath): """Returns the DBDoc instance tied to a given file path. :Parameter filepath: the full path of an open database. """ if filepath in self.__openDBs: return self.__openDBs[filepath] else: return None def getDBList(self): """Returns the list of paths of files currently open. The temporary database is not included in the list. """ filepaths = list(self.__openDBs.keys()) try: filepaths.remove(self.tmp_filepath) except ValueError: pass return filepaths def checkOpening(self, filepath): """ Check if a database can be open. :Parameter filepath: the full path of the file """ try: # Check if file doesn't exist if os.path.isdir(filepath): error = translate('DBsTreeModel', 'Openning cancelled: {0} is a folder.', 'A logger error message').format(filepath) raise ValueError elif not os.path.isfile(filepath): error = translate('DBsTreeModel', 'Opening failed: file {0} cannot be found.', 'A logger error message').format(filepath) raise ValueError # Check if file is already open. elif self.getDBDoc(filepath) is not None: error = translate('DBsTreeModel', 'Opening cancelled: file {0} already open.', 'A logger error message').format(filepath) raise ValueError except ValueError: self.logger.error(error) return False # Check the file format try: if not tables.is_hdf5_file(filepath): error = translate('DBsTreeModel', 'Opening cancelled: file {0} has not HDF5 format.', 'A logger error message').format(filepath) self.logger.error(error) return False except (tables.NodeError, OSError): error = translate('DBsTreeModel', """Opening failed: I cannot find out if file {0} has HDF5 """ """format.""", 'A logger error message').format(filepath) self.logger.error(error) return False else: return True def openDBDoc(self, filepath, mode='a', position=0): """ Open an existing hdf5 file and load it into the tree model. :Parameters: - `filepath`: full path of the database file we wish to open. - `mode`: the opening mode of the database file. It can be 'r'ead-only 'w'rite or 'a'ppend """ is_open = False if self.checkOpening(filepath): # Open the database and add it to the tracking system db_doc = dbdoc.DBDoc(filepath, mode) self.mapDB(filepath, db_doc) # Populate the model with the dbdoc root_node = rootgroupnode.RootGroupNode(self, db_doc, self.root) self.fdelta = frozenset([root_node]) self.gdelta = frozenset([]) self.ldelta = frozenset([]) self.links_delta = frozenset([]) self.insertRows(position, 1) is_open = True return is_open def closeDBDoc(self, filepath): """ Close the hdf5 file with the given file path. The temporary database can't be closed by the user. It is automatically closed when the application exits. :Parameter filepath: the full path of the file being closed """ for row, child in enumerate(self.root.children): if child.filepath == filepath: # Deletes the node from the tree of databases model/view self.remove_rows(row) # If needed, refresh the copied node info try: if self.ccni['filepath'] == filepath: self.ccni = {} except KeyError: pass # Close the hdf5 file db_doc = self.getDBDoc(filepath) if db_doc.hidden_group is not None: db_doc.h5file.remove_node(db_doc.hidden_group, recursive=True) db_doc.closeH5File() # Update the dictionary of open files self.removeMappedDB(filepath) break def createDBDoc(self, filepath, is_tmp_db=False): """ Create a new, empty database (:meth:`vitables.h5db.dbdoc.DBDoc` instance). :Parameters: - `filepath`: the full path of the file being created. - `is_tmp_db`: True if the `DBDoc` is tied to the temporary database """ try: QtWidgets.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) # Create the dbdoc try: db_doc = dbdoc.DBDoc(filepath, 'w', is_tmp_db) except (tables.NodeError, OSError): self.logger.error( translate('DBsTreeModel', """File creation failed due to unknown""" """reasons! Please, have a look to the """ """last error displayed in the logger. If you """ """think it's a bug, please report it to """ """developers.""", 'A file creation error')) return None # Track the just created dbdoc self.mapDB(filepath, db_doc) # Populate the model with the dbdoc root = rootgroupnode.RootGroupNode(self, db_doc, self.root, is_tmp_db) self.fdelta = frozenset([root]) self.gdelta = frozenset([]) self.ldelta = frozenset([]) self.links_delta = frozenset([]) self.insertRows(0, 1) finally: QtWidgets.qApp.restoreOverrideCursor() return db_doc def __createTempDB(self): """ Create a temporary database where filtered tables will be stored. The database will have a hidden group where cut nodes can be stored until they are pasted somewhere else. """ # Create the database self.logger.info( translate('DBsTreeModel', 'Creating the Query results file...', 'A logger info message')) (f_handler, filepath) = tempfile.mkstemp('.h5', 'FT_') os.close(f_handler) self.tmp_filepath = vitables.utils.forwardPath(filepath) db_doc = self.createDBDoc(self.tmp_filepath, True) return db_doc def deleteNode(self, index): """Delete a node. Delete the selected node from the model and from the database where it lives. :Parameter index: the index of the selected node """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) node = self.nodeFromIndex(index) # Deletes the node from the database node.editor().delete(node.nodepath) # Deletes the node from the tree of databases model/view parent = self.parent(index) position = node.row() self.remove_rows(position, parent=parent) # If needed, refresh the copied node info. This info must # not be cleared when pasting a CUT node overwrites other # node try: if self.ccni['is_copied'] and \ (self.ccni['filepath'] == node.filepath) and \ self.ccni['nodepath'].startswith(node.nodepath): self.ccni = {} except KeyError: pass finally: QtWidgets.qApp.restoreOverrideCursor() def copy_node(self, index): """Mark a node from the tree of databases view as copied. :Parameter index: the index of the selected node """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) node = self.nodeFromIndex(index) self.ccni = {'is_copied': True, 'nodename': node.name, 'filepath': node.filepath, 'nodepath': node.nodepath, 'target': getattr(node, 'target', None)} finally: QtWidgets.qApp.restoreOverrideCursor() def cutNode(self, index): """Cut a `tables.Node`. The cut node is stored in a hidden group of its database. :Parameter index: the index of the selected node """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) node = self.nodeFromIndex(index) self.ccni = {'is_copied': False, 'nodename': node.name, 'filepath': node.filepath, 'nodepath': node.nodepath, 'target': getattr(node, 'target', None)} # Moves the node to a hidden group in its database node.editor().cut(node.nodepath) # Deletes the node from the tree of databases model/view parent = self.parent(index) position = index.row() self.remove_rows(position, parent=parent) # If position > 0 then the above sibling will be selected # else the parent group will be selected if position == 0: current = parent else: current = self.index(position - 1, 0, parent) self.vtgui.dbs_tree_view.selectNode(current) finally: QtWidgets.qApp.restoreOverrideCursor() def pasteNode(self, index, childname, overwrite=False): """Paste a tables.Node. Paste the last copied/cut node under the currently selected group. :Parameters: - `index`: the index of the selected node (the parent group) - `childname`: the name of the node being pasted - `overwrite`: True if a node is being overwritten """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) parent = self.nodeFromIndex(index) # If the overwritten node (if any) exists in the tree of # databases view then delete it if overwrite: self.overwriteNode(parent, index, childname) # Paste the copied/cut node in the destination database db_doc = self.getDBDoc(parent.filepath) if self.ccni['target']: editor = tlink_editor.TLinkEditor(db_doc) else: editor = tnode_editor.TNodeEditor(db_doc) src_node = self.copiedNode() editor.paste(src_node, parent.node, childname) # Paste the node in the tree of databases model/view self.lazyAddChildren(index) parent.updated = True # Select the pasted node self.selectIndex(index, childname) finally: QtWidgets.qApp.restoreOverrideCursor() def copiedNode(self): """The tables.Node currently copied/cut. """ src_filepath = self.ccni['filepath'] if self.ccni['is_copied']: src_nodepath = self.ccni['nodepath'] else: dirname = self.getDBDoc(src_filepath).hidden_group basename = self.ccni['nodename'] src_nodepath = '{0}/{1}'.format(dirname, basename) return self.getDBDoc(src_filepath).get_node(src_nodepath) def create_group(self, index, childname, overwrite=False): """Create a `tables.Group` under the given parent. :Parameters: - `index`: the index of the parent node - `childname`: the name of the group being created - `overwrite`: True if a node is being overwritten """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) parent = self.nodeFromIndex(index) # If the overwritten node (if any) exists in the tree of # databases view then delete it if overwrite: self.overwriteNode(parent, index, childname) # Create the group in the PyTables database parent.editor().create_group(parent.nodepath, childname) # Paste the node in the tree of databases model/view self.lazyAddChildren(index) parent.updated = True # Select the pasted node self.selectIndex(index, childname) finally: QtWidgets.qApp.restoreOverrideCursor() def rename_node(self, index, new_name, overwrite=False): """Rename a node. :Parameters: - `index`: the index of the node being renamed - `new_name`: the new name of the node - `overwrite`: True if a node is being overwritten """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) node = self.nodeFromIndex(index) initial_nodepath = node.nodepath parent_index = self.parent(index) parent = self.nodeFromIndex(parent_index) if overwrite: self.overwriteNode(parent, parent_index, new_name) # Rename the node in the PyTables database node.editor().rename(node.nodepath, new_name) # Rename the node in the databases tree view # The renamed node's children must be updated too self.updateDBTree(index, new_name, node) # If needed, refresh the copied node info try: if self.ccni['filepath'] == node.filepath: if self.ccni['nodepath'].startswith(initial_nodepath): self.ccni = {} except KeyError: pass finally: QtWidgets.qApp.restoreOverrideCursor() def updateDBTree(self, index, new_name, node): """ After renaming a PyTables node update the tree of databases model/view. The following data must be updated: - name (DisplayRole) - nodepath (UserRole+1) - status tip (StatusTipRole) :Parameters: - `index`: the index of the node being renamed - `new_name`: the new name of the node - `node`: the node being renamed """ # Update the renamed tree item self.setData(index, new_name, QtCore.Qt.DisplayRole) old_nodepath = node.nodepath dirname = os.path.split(old_nodepath)[0] new_nodepath = \ ('{0}/{1}'.format(dirname, new_name)).replace('//', '/') self.setData(index, new_nodepath, QtCore.Qt.UserRole+1) if hasattr(node, 'target'): self.setData(index, '{0}'.format(node.node), QtCore.Qt.StatusTipRole) else: self.setData(index, '{0}->{1}'.format(node.filepath, new_nodepath), QtCore.Qt.StatusTipRole) # Update the item children, if any for child_index in self.walkTreeView(index): child_node = self.nodeFromIndex(child_index) child_nodepath = child_node.nodepath.replace(old_nodepath, new_nodepath, 1) self.setData(child_index, child_nodepath, QtCore.Qt.UserRole+1) if hasattr(child_node, 'target'): self.setData(child_index, '{0}'.format(child_node.node), QtCore.Qt.StatusTipRole) else: self.setData(child_index, '{0}->{1}'.format(child_node.filepath, child_node.nodepath), QtCore.Qt.StatusTipRole) def move_node(self, src_filepath, childpath, parent_index, overwrite=False): """Move a `tables.Node` to a different location. :Parameters: - `src_filepath`: the full path of the source database - `childpath`: the full path of the node being moved - `parent_index`: the model index of the new parent group - `overwrite`: True if a node is being overwritten """ try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) parent_node = self.nodeFromIndex(parent_index) # full path of the destination database and new parent dst_filepath = parent_node.filepath parentpath = parent_node.nodepath # # Check if the nodename is already in use # (nodename, overwrite) = self.validateNodename( src_filepath, childpath, dst_filepath, parentpath) if nodename is None: return nodename # If the overwritten node (if any) exists in the tree of # databases view then delete it if overwrite: self.overwriteNode(parent_node, parent_index, nodename) # Move the node to the PyTables database pt_node = self.getDBDoc(src_filepath).get_node(childpath) db_doc = self.getDBDoc(src_filepath) if hasattr(pt_node, 'target'): editor = tlink_editor.TLinkEditor(db_doc) else: editor = tnode_editor.TNodeEditor(db_doc) movedname = editor.move(childpath, self.getDBDoc(dst_filepath), parentpath, nodename) finally: QtWidgets.qApp.restoreOverrideCursor() return movedname def validateNodename(self, src_filepath, childpath, dst_filepath, parentpath): """ :Parameters: - `childpath`: the full path of the node being moved - `dst_filepath`: the full path of the destination database - `parentpath`: the full path of the new parent group """ nodename = os.path.basename(childpath) dst_dbdoc = self.getDBDoc(dst_filepath) parent = dst_dbdoc.get_node(parentpath) sibling = getattr(parent, '_v_children').keys() # Nodename pattern pattern = "[a-zA-Z_]+[0-9a-zA-Z_ ]*" info = [translate('DBsTreeModel', 'Node move: nodename already exists', 'A dialog caption'), translate('DBsTreeModel', """Source file: {0}\nMoved node: {1}\n""" """Destination file: {2}\nParent group: {3}\n\n""" """Node name '{4}' already in use in that group.\n""", 'A dialog label').format\ (src_filepath, childpath, dst_filepath, parentpath, nodename), translate('DBsTreeModel', 'Rename', 'A button label')] # Validate the nodename nodename, overwrite = vitables.utils.getFinalName( nodename, sibling, pattern, info) self.vtgui.editing_dlg = True return (nodename, overwrite) def overwriteNode(self, parent_node, parent_index, nodename): """Delete from the tree of databases a node being overwritten. :Parameters: - `parent_node`: the parent of the overwritten node - `parent_index`: the model index of the new parent group - `nodename`: the name of the node being deleted """ child = parent_node.findChild(nodename) child_index = self.index(child.row(), 0, parent_index) self.deleteNode(child_index) def walkTreeView(self, index): """Iterates over a subtree of the tree of databases view. :Parameter index: the model index of the root node of the iterated subtree """ for prow in range(0, self.rowCount(index)): child = self.index(prow, 0, index) yield child for crow in range(0, self.rowCount(child)): yield self.index(crow, 0, child) def indexChildren(self, index): """Iterate over the children of a given index. :Parameter index: the model index whose children are being retrieved """ for row in range(0, self.rowCount(index)): yield self.index(row, 0, index) def selectIndex(self, parent, name): """Select in the tree view the index with the given parent and name. :Parameters: - `parent`: the parent of the model index being selected - `name`: the name tied to the model index being selected """ for child in self.indexChildren(parent): node = self.nodeFromIndex(child) if node.name == name: self.vtgui.dbs_tree_view.selectNode(child) def updateTreeFromData(self, parent_index=None): """Update tree of expanded nodes from hdf5 data. This function should be used if the structure of a file was updated through pytables functions. It is better to use model functions but they need to be better documented and expanded to be usefull. This function is a temporary fix. """ parent_index = parent_index if parent_index else QtCore.QModelIndex() self.lazyAddChildren(parent_index) for index in self.indexChildren(parent_index): self.updateTreeFromData(index) def flags(self, index): """Returns the item flags for the given index. This is a reimplemented function used by the model to indicate to views which items can be dragged, and which will accept drops. :Parameter index: the index of a given item. """ # Every item in the model is enabled and selectable default_flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable if not index.isValid(): return default_flags node = self.nodeFromIndex(index) node_kind = node.node_kind # If a database is in read-only mode items cannot be edited db_doc = self.getDBDoc(node.filepath) if db_doc.mode == 'r': flags = default_flags # The root group of a database cannot be moved or renamed elif node_kind == 'root group': flags = QtCore.Qt.ItemIsDropEnabled | default_flags # A regular group of a database can be moved, renamed and dropped elif node_kind == 'group': flags = QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled \ | QtCore.Qt.ItemIsEditable | default_flags # A leaf of a database can be moved and renamed but not dropped else: flags = QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsEditable \ | default_flags return flags def data(self, index, role): """Returns the data stored under the given role for the item referred to by the index. :Parameters: - `index`: the index of a data item - `role`: the role being returned """ if not index.isValid(): data = None return data node = self.nodeFromIndex(index) if role in _ROLE_NODE_GET_FUNCTION_DICT: return _ROLE_NODE_GET_FUNCTION_DICT[role](node) else: return None def setData(self, index, value, role=QtCore.Qt.EditRole): """Sets the role data for the item at index to value. :Parameters: - `index`: the index of a data item - `value`: the value to be set - `role`: the role being set """ if not index.isValid(): result = False node = self.nodeFromIndex(index) if role == QtCore.Qt.DisplayRole: node.name = value self.dataChanged.emit(index, index) result = True elif role == QtCore.Qt.StatusTipRole: node.as_record = value self.dataChanged.emit(index, index) result = True elif role == QtCore.Qt.DecorationRole: node.icon = value self.dataChanged.emit(index, index) result = True elif role == QtCore.Qt.UserRole: node.filepath = value self.dataChanged.emit(index, index) result = True elif role == QtCore.Qt.UserRole+1: node.nodepath = value self.dataChanged.emit(index, index) result = True elif role == QtCore.Qt.UserRole+2: node.node_kind = value self.dataChanged.emit(index, index) result = True else: result = False return result def headerData(self, section, orientation, role): """Returns the data for the given role and section in the header with the specified orientation. :Parameters: - `section`: the header section being inspected - `orientation`: the header orientation (horizontal or vertical) - `role`: the role of the header section being inspected """ if (orientation, role) == (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole): return translate('DBsTreeModel', 'Tree of databases', 'Header of the only column of the tree of databases view') return None def columnCount(self, index): """The number of columns for the children of the given index. :Parameter index: the model index being inspected. """ return 1 def rowCount(self, index): """The number of rows of the given model index. :Parameter index: the model index being inspected. """ node = self.nodeFromIndex(index) if node == self.root: nrows = len(node) else: nrows = 0 if node.node_kind in ('group', 'root group'): nrows = len(node) return nrows def hasChildren(self, index): """Finds out if a node has children. The goal of this reimplementation is to provide an inexpensive way for views to check for the presence of children and draw the appropriate decoration for their parent item. The decoration (if any) consists in the small +/- symbols used for expanding/collpasing the node. In principle, it is painted only if the node's children have been added. As we populate our model in a lazy way (see :meth:`lazyAddChildren` and :meth:`vitables.h5db.dbstreeview.DBsTreeView.updateExpandedGroup` methods) we want the decoration to be painted whenever the node has children, *even if the children have not been added to the model yet (so we can't use the underlying data store, we must use the data source). This way the user will know that the node has children*. :Parameter index: the index of the node being inspected. """ if not index.isValid(): # self.root fulfils this condition return True parent = self.nodeFromIndex(index) if hasattr(parent.node, '_v_nchildren'): return getattr(parent.node, '_v_nchildren') else: return False def index(self, row, column, parent): """Creates an index in the model for a given node and returns it. This is a reimplementation of the index method. It creates an index for a tree node (i.e. :meth:`RootGroupNode`, :meth:`GroupNode` and :meth:`LeafNode` instances) specified by a row, a column and a parent index. Every node except the root one will be tied to an index by this method. :Parameters: - `row`: the row of the node relative to its parent - `column`: the column of the node relative to its parent - `parent`: the index of the node's parent """ if self.hasIndex(row, column, parent): group = self.nodeFromIndex(parent) try: node = group.childAtRow(row) return self.createIndex(row, column, node) except IndexError: return QtCore.QModelIndex() return QtCore.QModelIndex() def nodeFromIndex(self, index): """Retrieves the tree node with a given index. :Parameter index: the index of a tree node """ if index.isValid(): return index.internalPointer() else: return self.root def parent(self, child): """The parent index of a given index. :Parameter child: the child index whose parent is being retrieved. """ node = self.nodeFromIndex(child) if node is self.root: return QtCore.QModelIndex() parent = node.parent if parent is self.root: return QtCore.QModelIndex() grandparent = parent.parent row = grandparent.rowOfChild(parent) return self.createIndex(row, 0, parent) def lazyAddChildren(self, index): """Add children to a group node when it is expanded. Lazy population of the model is partially implemented in this method. Expanded items are updated so that children items are added if needed. This fact improves enormously the performance when files whit a large number of nodes are opened. :Parameter index: the index of the activated item """ if not index.isValid(): return node = self.nodeFromIndex(index) if node.node_kind not in ('group', 'root group'): return group = node.node # Find out if children have to be added by comparing the # names of children currently added to model with the # names of the whole list of children model_children = frozenset([node.childAtRow(row).name for row in range(0, len(node))]) children_groups = frozenset(getattr(group, '_v_groups').keys()) children_leaves = frozenset(getattr(group, '_v_leaves').keys()) children_links = frozenset(getattr(group, '_v_links').keys()) self.gdelta = children_groups.difference(model_children) self.ldelta = children_leaves.difference(model_children) self.links_delta = children_links.difference(model_children) self.fdelta = frozenset([]) new_children = (len(self.gdelta) + len(self.ldelta) + len(self.links_delta)) if not new_children: return else: self.insertRows(0, new_children, index) def insertRows(self, position=0, count=1, parent=QtCore.QModelIndex()): """Insert `count` rows before the given `position`. Inserted rows will be children of the item represented by the `parent` model index. This method is called during nodes population and when files are opened/created. Warning! This method is MONKEY PATCHED if the DBs Sorting plugin is enabled. If it is the case the working code will be in module vitables.plugins.dbstreesort.dbs_tree_sort :Parameters: - `position`: the position of the first row being added. - `count`: the number of rows being added - `parent`: the index of the parent item. :Returns: True if the row is added. Otherwise it returns False. """ # Add rows to the model and update its underlaying data store self.layoutAboutToBeChanged.emit() first = position last = position + count - 1 self.beginInsertRows(parent, first, last) node = self.nodeFromIndex(parent) for file_node in self.fdelta: self.root.insertChild(file_node, position) for name in self.gdelta: group = groupnode.GroupNode(self, node, name) node.insertChild(group, position) for name in self.ldelta: leaf = leafnode.LeafNode(self, node, name) node.insertChild(leaf, position) for name in self.links_delta: link = linknode.LinkNode(self, node, name) node.insertChild(link, position) self.dataChanged.emit(parent, parent) self.endInsertRows() self.layoutChanged.emit() # Report views about changes in data top_left = self.index(first, 0, parent) bottom_right = self.index(last, 0, parent) self.dataChanged.emit(top_left, bottom_right) return True def remove_rows(self, position, count=1, parent=QtCore.QModelIndex()): """Removes `count` rows before the given row. This method is called when an item is cut/deleted/D&D. :Parameters: - `position`: the position of the first row being removed. - `count`: the number of rows being removed - `parent`: the index of the parent item. :Returns: True if the row is removed. Otherwise it returns False. """ # Remove rows from the model and update its underlaying data store self.layoutAboutToBeChanged.emit() first = position last = position + count - 1 self.beginRemoveRows(parent, first, last) group = self.nodeFromIndex(parent) del group.children[position] self.dataChanged.emit(parent, parent) self.endRemoveRows() self.layoutChanged.emit() return True def closeViews(self, parent, start, end): """When a leaf with a view is about to be removed then close the view. :Parameters: - `parent`: model index under which items are going to be removed - `start`: position of the first removed index - `stop`: position of the last removed index """ nodepaths = [] for position in range(start, end+1): node = self.nodeFromIndex(self.index(position, 0, parent)) nodepaths.append(node.nodepath) filepath = node.filepath for window in self.vtgui.workspace.subWindowList(): if window.dbt_leaf.filepath == filepath: wpath = window.dbt_leaf.nodepath for path in nodepaths: if re.match(path, wpath): window.close() break def supportedDropActions(self): """Setup drag and drop behavior of the model.""" return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction def mimeTypes(self): """Returns a list of MIME types that can be used to describe a list of model indexes or a list of filepaths. """ return ["application/x-dbstreemodeldatalist", "text/uri-list"] def mimeData(self, indexes): """Returns a QMimeData object that contains serialized items of data corresponding to the list of indexes specified. When a node is dragged the information required to drop it later on is encoded by this method and returned as a QMimeData object. :Parameter indexes: a list of indexes """ mime_data = QtCore.QMimeData() encoded_data = QtCore.QByteArray() stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.WriteOnly) # Only one item selections are allowed in the tree of databases # view so indexes contains always one element for index in indexes: if index.isValid(): filepath = self.data(index, QtCore.Qt.UserRole) nodepath = self.data(index, QtCore.Qt.UserRole+1) row = str(index.row()) stream.writeQString(filepath) stream.writeQString(nodepath) stream.writeQString(row) self.initial_parent = self.parent(index) # Store the MIME type of the object and the encoded description of that # object in the QMimeData object mime_data.setData("application/x-dbstreemodeldatalist", encoded_data) return mime_data def dropMimeData(self, data, action, row, column, parent): """Handles the data supplied by a drag and drop operation that ended with the given action. :Parameters: - `data`: the data being dropped. - `action`: the action being performed (copy or move). - `row`: the row under the item where the operation ends. - `columns`: the column under the item where the operation ends. - `parent`: the index of the item where operation ends. :Returns: True if item is dropped. Otherwise it returns False. """ # Examine the MIME type if not (data.hasFormat("application/x-dbstreemodeldatalist") or data.hasFormat("text/uri-list")): return False if action == QtCore.Qt.IgnoreAction: return True if column > 0: return False # If the dropped object is one or more files then open them if data.hasFormat("text/uri-list"): uris_list = data.urls() # Transform every element of the sequence into a path and open it for uri in uris_list: path = uri.path() if sys.platform.startswith('win'): path = path[1:] if os.path.isfile(path): self.vtapp.fileOpen(path) return True # If the dropped object is a tree node then update the tree parent_node = self.nodeFromIndex(parent) encoded_data = data.data("application/x-dbstreemodeldatalist") # Moving is not allowed if the parent group remains the same initial_parent = self.initial_parent if parent == initial_parent: return False stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.ReadOnly) while not stream.atEnd(): # Decode the encoded data filepath = stream.readQString() nodepath = stream.readQString() initial_row = int(stream.readQString()) # A node cannot be moved on itself if (parent_node.filepath, parent_node.nodepath) == (filepath, nodepath): return False # Move the node to its final destination in the PyTables database new_name = self.move_node(filepath, nodepath, parent) if new_name is None: return False # Remove the dragged node from the model self.remove_rows(initial_row, parent=initial_parent) # If needed, refresh the copied node info try: if self.ccni['filepath'] == filepath: if self.ccni['nodepath'].startswith(nodepath): self.ccni = {} except KeyError: pass # Add the dropped node to the model self.lazyAddChildren(parent) parent_node.updated = True # Select the pasted node self.selectIndex(parent, new_name) return True ViTables-3.0.0/vitables/h5db/dbstreeview.py000066400000000000000000000316031311223072700205540ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a view for the tree of databases model. This view is used to display the tree of open databases. Each top level node of the tree contains the object tree of a `PyTables`/`HDF5` database. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from vitables.h5db.nodeitemdelegate import NodeItemDelegate translate = QtWidgets.QApplication.translate class DBsTreeView(QtWidgets.QTreeView): """ A view for the databases tree model. :Parameters: - `vtapp`: the VTAPP instance - `model`: the model for this view """ dbsTreeViewCreated = QtCore.Signal(QtWidgets.QTreeView) def __init__(self, vtapp, vtgui, model, parent=None): """Create the view. """ super(DBsTreeView, self).__init__(parent) # The model self.setModel(model) self.dbt_model = model self.smodel = self.selectionModel() self.vtapp = vtapp self.vtgui = vtgui # The custom delegate used for editing items self.setItemDelegate(NodeItemDelegate(vtgui, self)) self.setObjectName('dbs_tree_view') # The frame specification self.frame_style = {'shape': self.frameShape(), 'shadow': self.frameShadow(), 'lwidth': self.lineWidth(), 'foreground': self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.WindowText)} # Setup drag and drop self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) self.setDragEnabled(True) self.setAcceptDrops(True) self.setDropIndicatorShown(True) # Misc. setup self.setRootIsDecorated(True) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) # Whether selections are done in terms of single items, rows or columns self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems) # Whether the user can select one or many items # Changed from SingleSelection to ExtendedSelection in commit 403a4c3 # but I don't know why. I revert it to SingleSelection or a # tables.ClosedNodeError is randomly raised when a group is moved to a # different file self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setWhatsThis(translate('DBsTreeView', """

The Tree of databases

For every open database this widget shows the object tree, a graphical representation
of the data hierarchy stored in the database.""", 'WhatsThis help for the tree pane')) # Connect signals to slots self.customContextMenuRequested.connect(self.createCustomContextMenu) self.activated.connect(self.activateNode) self.expanded.connect(self.updateExpandedGroup) self.collapsed.connect(self.updateCollapsedGroup) self.dbt_model.layoutChanged.connect(self.updateColumnWidth) def updateColumnWidth(self): """Make sure that a horizontal scrollbar is shown as needed. This is a subtle method. As the tree view has only 1 column its width and the width of the viewport are always the same so the horizontal scrollbar is never shown. As the contents width changes every time the layout changes (rows are inserted or deleted) by resizing column to contents when it happens we ensure that the column and the viewport will have different width and the scrollbar will indeed be added as needed. """ self.resizeColumnToContents(0) def activateNode(self, index): """Expand an item via `Enter`/`Return` key or mouse double click. When the user activates a collapsed item (by pressing `Enter`, `Return` or by double clicking the item) then it is expanded. If the user activates the node by double clicking on it while the `Shift` key is pressed, the item is edited (if editing is enabled). Lazy population of the model is partially implemented in this method. Expanded items are updated so that children items are added if needed. This fact improves enormously the performance when files whit a large number of nodes are opened. This method is a slot connected to the activated(QModelIndex) signal in the ctor. :Parameter index: the index of the activated item """ modifiers = QtWidgets.QApplication.keyboardModifiers() if (modifiers & QtCore.Qt.ShiftModifier) or \ (modifiers & QtCore.Qt.ControlModifier): return node = self.dbt_model.nodeFromIndex(index) if node.node_kind.count('group'): if not self.isExpanded(index): self.expand(index) elif node.has_view: ## Activate already-open window. # wrkspc = self.vtgui.workspace pcurrent = QtCore.QPersistentModelIndex(index) for window in wrkspc .subWindowList(): if pcurrent == window.pindex: wrkspc.setActiveSubWindow(window) else: self.vtapp.nodeOpen(index) def updateCollapsedGroup(self, index): """After collapsing a group update its icon. This method is a slot connected to the `collapsed(QModelIndex)` signal in the ctor. :Parameter index: the index of the collapsed group """ node = self.dbt_model.nodeFromIndex(index) if node.node_kind == 'group': self.dbt_model.setData(index, node.closed_folder, QtCore.Qt.DecorationRole) self.smodel.clearSelection() self.smodel.setCurrentIndex(index, QtCore.QItemSelectionModel.SelectCurrent) self.update(index) def updateExpandedGroup(self, index): """After a group expansion, update the icon and the displayed children. Lazy population of the model is partially implemented in this method. Expanded items are updated so that children items are added if needed. This fact reduces enormously the opening times for files whit a large number of nodes and also saves memory. This method is a slot connected to the `expanded(QModelIndex)` signal in the ctor. :Parameter index: the index of the expanded item """ node = self.dbt_model.nodeFromIndex(index) node_kind = node.node_kind if node_kind == 'group': self.dbt_model.setData(index, node.open_folder, QtCore.Qt.DecorationRole) if node_kind in ['group', 'root group']: if not node.updated: self.dbt_model.lazyAddChildren(index) node.updated = True self.smodel.clearSelection() self.smodel.setCurrentIndex(index, QtCore.QItemSelectionModel.SelectCurrent) def createCustomContextMenu(self, pos): """ A context menu for the tree of databases view. When an item of the tree view is right clicked, a context popup menu is displayed. The content of the popup depends on the clicked element. :Parameter pos: the local position at which the menu will popup """ index = self.indexAt(pos) if not index.isValid(): kind = 'view' else: node = self.dbt_model.nodeFromIndex(index) kind = node.node_kind pos = self.mapToGlobal(pos) self.vtgui.popupContextMenu(kind, pos) def selectNode(self, index): """Select the given index. :Parameter `index`: the model index being selected """ self.smodel.clearSelection() self.smodel.setCurrentIndex(index, QtCore.QItemSelectionModel.SelectCurrent) def mouseDoubleClickEvent(self, event): """Specialised handler for mouse double click events. When a node is double clicked in the tree of databases pane: - if the node can be renamed and the `Shift` key is pressed then rename the node - if the node is a leaf with no view and the `Shift` key is not pressed then open the node - if the node is a collpased group and the `Shift` key is not pressed then expand the group :Parameter event: the event being processed """ modifier = event.modifiers() current = self.currentIndex() if modifier == QtCore.Qt.ShiftModifier: if current.flags() & QtCore.Qt.ItemIsEditable: self.edit(current) else: self.activateNode(current) def dragMoveEvent(self, event): """ Event handler for `QDragMoveEvent` events. Dragging icons from the Desktop/Files Manager into the tree view is supported. :Parameter event: the event being processed. """ # The dragged object (one or more files) has a MIME type (namely # text/uri-list) and some associated data (the list of URLs of the # dragged files). All that information can be accessed via the event # MimeData() method. # The widget should examine that information and accept the drop if # appropriate. mime_data = event.mimeData() if mime_data.hasFormat('text/uri-list'): event.setDropAction(QtCore.Qt.CopyAction) event.acceptProposedAction() else: return QtWidgets.QTreeView.dragMoveEvent(self, event) def dropEvent(self, event): """ Event handler for `QDropEvent` events. This event is sent when a drag and drop action is completed. In our case if an icon is dropped on the tree view then the icon URL is converted to a path (which we assume to be an `HDF5` file path) and ``ViTables`` tries to open it. :Parameter event: the event being processed. """ # The dropped object (one or more files) has a MIME type (namely # text/uri-list) and some associated data (the list of URLs of the # dropped files). All that information can be accessed via the event # MimeData() method. # The widget should examine that information and launch the required # actions. mime_data = event.mimeData() if mime_data.hasFormat('text/uri-list'): if self.dbt_model.dropMimeData( mime_data, QtCore.Qt.CopyAction, -1, -1, self.currentIndex()): event.setDropAction(QtCore.Qt.CopyAction) event.accept() self.setFocus(True) else: QtWidgets.QTreeView.dropEvent(self, event) def focusInEvent(self, event): """Specialised handler for focus events. Repaint differently the databases tree view frame when it gets the keyboard focus so that users can realize easily about this focus change. :Parameter event: the event being processed """ self.setLineWidth(2) self.setFrameStyle(QtWidgets.QFrame.Panel|QtWidgets.QFrame.Plain) pal = self.palette() pal.setColor(QtGui.QPalette.Active, QtGui.QPalette.WindowText, QtCore.Qt.darkBlue) QtWidgets.QTreeView.focusInEvent(self, event) def focusOutEvent(self, event): """Specialised handler for focus events. Repaint differently the databases tree view frame when it looses the keyboard focus so that users can realize easily about this focus change. :Parameter event: the event being processed """ self.setLineWidth(self.frame_style['lwidth']) self.setFrameShape(self.frame_style['shape']) self.setFrameShadow(self.frame_style['shadow']) pal = self.palette() pal.setColor(QtGui.QPalette.Active, QtGui.QPalette.WindowText, self.frame_style['foreground']) QtWidgets.QTreeView.focusOutEvent(self, event) if __name__ == '__main__': import sys APP = QtWidgets.QApplication(sys.argv) TREE = DBsTreeView() TREE.show() APP.exec_() ViTables-3.0.0/vitables/h5db/groupnode.py000066400000000000000000000104561311223072700202360ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a data structure to be used for the model of the databases tree. The data structure is equivalent to a (non root) group node in a `PyTables` file. """ __docformat__ = 'restructuredtext' import vitables.utils from vitables.h5db import tnode_editor from vitables.nodeprops import nodeinfo from vitables.nodeprops import grouppropdlg class GroupNode(object): """ A group node in the tree of databases model. :Parameters: - `parent`: the parent of the node. - `name`: the name of the node """ def __init__(self, model, parent, name): """Create a group node for the tree of databases model. A GroupNode represents a (non root) group of a `HDF5` file and has a parent (another group node of the tree of databases model) and a name. """ self.dbt_model = model self.updated = False self.children = [] self.parent = parent self.node = parent.node._f_get_child(name) self.node_kind = 'group' self.has_view = False # Attributes that the tree of databases view will use # name --> DisplayRole # nodepath --> ToolTipRole # as_record --> StatusTipRole # icon --> DecorationRole self.name = name parentpath = parent.nodepath if parentpath.endswith('/'): parentpath = parentpath[:-1] self.nodepath = '{0}/{1}'.format(parentpath, name) self.filepath = parent.filepath self.as_record = '{0}->{1}'.format(self.filepath, self.nodepath) icons = vitables.utils.getIcons() self.closed_folder = icons['folder'] self.open_folder = icons['document-open-folder'] self.icon = icons['folder'] def __len__(self): """The number of children of this grup.""" return len(self.children) def insertChild(self, child, position=0): """Insert a child in a group node. :Parameters: - `child`: the node being inserted - `position`: the insertion position """ self.children.insert(position, child) def childAtRow(self, row): """The row-th child of this node. :Parameter row: the position of the retrieved child """ assert 0 <= row <= len(self.children) return self.children[row] def rowOfChild(self, child): """The row index of a given child. :Parameter child: the child node whose position is being retrieved. """ for pos, node in enumerate(self.children): if node == child: return pos return -1 def row(self): """The position of this node in the parent's list of children. """ if self.parent: return self.parent.children.index(self) return 0 def findChild(self, childname): """The child node with a given name. :Parameter childname: the name of the wanted child node. """ for node in self.children: if node.name == childname: return node return None def editor(self): """Return an instance of `TNodeEditor`. """ return tnode_editor.TNodeEditor(self.dbt_model.getDBDoc(self.filepath)) def properties(self): """The Properties dialog for this node. """ info = nodeinfo.NodeInfo(self) grouppropdlg.GroupPropDlg(info) ViTables-3.0.0/vitables/h5db/leafnode.py000066400000000000000000000077021311223072700200110ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a data structure to be used for the model of the databases tree. The data structure is equivalent to a leaf node in a `PyTables` file. """ __docformat__ = 'restructuredtext' import tables import vitables.utils from vitables.h5db import tnode_editor from vitables.nodeprops import nodeinfo from vitables.nodeprops import leafpropdlg class LeafNode(object): """ A leaf node in the tree of databases model. :Parameters: - `parent`: the parent of the node. - `name`: the name of the node """ def __init__(self, model, parent, name): """Create a leaf node for the tree of databases model. A LeafNode represents a leaf of a `HDF5` file and has a parent (a group node of the tree of databases model) and a name. """ self.dbt_model = model self.parent = parent self.node = parent.node._f_get_child(name) self.has_view = False # Attributes that the tree of databases view will use # name --> DisplayRole # nodepath --> ToolTipRole # as_record --> StatusTipRole # icon --> DecorationRole self.name = name parentpath = parent.nodepath if parentpath.endswith('/'): parentpath = parentpath[:-1] self.nodepath = '{0}/{1}'.format(parentpath, name) self.filepath = parent.filepath self.as_record = '{0}->{1}'.format(self.filepath, self.nodepath) # Set the node icon icons = vitables.utils.getIcons() if isinstance(self.node, tables.Table): self.node_kind = 'table' self.icon = icons['table'] elif isinstance(self.node, tables.VLArray): self.node_kind = 'vlarray' data_type = self.node.atom.type if data_type in ['vlstring', 'vlunicode']: self.icon = icons['vlstring'] elif data_type == 'object': self.icon = icons['object'] else: self.icon = icons['vlarray'] elif isinstance(self.node, tables.EArray): self.node_kind = 'earray' self.icon = icons['earray'] elif isinstance(self.node, tables.CArray): self.node_kind = 'carray' self.icon = icons['carray'] elif isinstance(self.node, tables.Array): self.node_kind = 'array' self.icon = icons['array'] elif isinstance(self.node, tables.UnImplemented): self.node_kind = 'image-missing' self.icon = icons['image-missing'] def row(self): """The position of this node in the parent's list of children. """ if self.parent: return self.parent.children.index(self) return 0 def editor(self): """Return an instance of `TNodeEditor`. """ return tnode_editor.TNodeEditor(self.dbt_model.getDBDoc(self.filepath)) def properties(self): """The Properties dialog for this node. """ info = nodeinfo.NodeInfo(self) leafpropdlg.LeafPropDlg(info) ViTables-3.0.0/vitables/h5db/linknode.py000066400000000000000000000102261311223072700200320ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a data structure to be used for the model of the databases tree. The data structure is equivalent to a link node in a `PyTables` file. """ __docformat__ = 'restructuredtext' import tables import vitables.utils from vitables.h5db import tlink_editor from vitables.nodeprops import nodeinfo from vitables.nodeprops import linkpropdlg class LinkNode(object): """ A leaf node in the tree of databases model. :Parameters: - `parent`: the parent of the node. - `name`: the name of the node """ def __init__(self, model, parent, name): """Create a link node for the tree of databases model. A LinkNode represents a link (soft or external) of a `PyTables` file and has a parent (a group node of the tree of databases model) and a name. """ self.dbt_model = model self.parent = parent self.node = parent.node._f_get_child(name) self.has_view = False self.target = self.node.target if hasattr(self.target, 'extfile'): self.link_type = 'external' else: self.link_type = 'soft' # Attributes that the tree of databases view will use # name --> DisplayRole # nodepath --> ToolTipRole # as_record --> StatusTipRole # icon --> DecorationRole self.name = name parentpath = parent.nodepath if parentpath.endswith('/'): parentpath = parentpath[:-1] self.nodepath = '{0}/{1}'.format(parentpath, name) self.filepath = parent.filepath self.as_record = '{0}'.format(self.node) # Set the node icon icons = vitables.utils.getIcons() if isinstance(self.node(), tables.Table): self.node_kind = 'table' self.icon = icons['link_table'] elif isinstance(self.node(), tables.VLArray): self.node_kind = 'vlarray' data_type = self.node().atom.type if data_type in ['vlstring', 'vlunicode']: self.icon = icons['vlstring'] elif data_type == 'object': self.icon = icons['object'] else: self.icon = icons['link_vlarray'] elif isinstance(self.node(), tables.EArray): self.node_kind = 'earray' self.icon = icons['link_earray'] elif isinstance(self.node(), tables.CArray): self.node_kind = 'carray' self.icon = icons['link_carray'] elif isinstance(self.node(), tables.Array): self.node_kind = 'array' self.icon = icons['link_array'] elif isinstance(self.node(), tables.UnImplemented): self.node_kind = 'image-missing' self.icon = icons['image-missing'] def row(self): """The position of this node in the parent's list of children. """ if self.parent: return self.parent.children.index(self) return 0 def editor(self): """Return an instance of `TLinkEditor`. """ return tlink_editor.TLinkEditor(self.dbt_model.getDBDoc(self.filepath)) def properties(self): """The Properties dialog for this node. """ info = nodeinfo.NodeInfo(self) linkpropdlg.LinkPropDlg(info) ViTables-3.0.0/vitables/h5db/nodeitemdelegate.py000066400000000000000000000101361311223072700215260ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Here is defined the NodeItemDelegate class. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate class NodeItemDelegate(QtWidgets.QItemDelegate): """ A custom delegate for editing items of the tree of databases model. The delegate is used for editing the text of items of the tree of databases model, i.e., the item's DisplayRole. In other words, it is used to edit the name of the nodes in a database object tree. """ def __init__(self, vtgui, parent=None): """ Creates the custom delegate. """ super(NodeItemDelegate, self).__init__(parent) self.current_name = None self.vtgui = vtgui def setEditorData(self, editor, index): """ Edits the data of an item with a given index. This method is automatically called when an editor is created, i.e., when the user double click an item while the `Shift` key is pressed. :Parameters: - `editor`: the editor widget - `index`: the index of the item being edited """ node_name = index.model().data(index, QtCore.Qt.DisplayRole) self.current_name = node_name editor.setText(node_name) def setModelData(self, editor, model, index): """ Update the model with the just edited data. This method is called automatically when an editor is closed, i.e., when the user editing ends. :Parameters: - `editor`: the editor widget - `model`: the model whose data is being setup - `index`: the index of the item being edited """ suggested_nodename = editor.text() node = model.nodeFromIndex(index) # A GroupNode or a LeafNode instance parent = node.parent # # Check if the nodename is already in use # sibling = getattr(parent.node, '_v_children').keys() # Note that current nodename is not allowed as new nodename. # Embedding it in the pattern makes unnecessary to pass it to the # rename dialog via method argument and simplifies the code pattern = """(^{0}$)|""" \ """(^[a-zA-Z_]+[0-9a-zA-Z_ ]*)""".format(self.current_name) info = [translate('NodeItemDelegate', 'Renaming a node: name already in use', 'A dialog caption'), translate('NodeItemDelegate', """Source file: {0}\nParent group: {1}\n\nThere is """ """already a node named '{2}' in that parent group.\n""", 'A dialog label').format\ (parent.filepath, parent.nodepath, suggested_nodename)] # Validate the nodename nodename, overwrite = vitables.utils.getFinalName(suggested_nodename, sibling, pattern, info) if nodename is None: editor.setText(self.current_name) return # Update the underlying data structure model.rename_node(index, nodename, overwrite) self.closeEditor.emit(editor, 0) # Update the application status bar self.vtgui.updateStatusBar() ViTables-3.0.0/vitables/h5db/rootgroupnode.py000066400000000000000000000114741311223072700211430ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a data structure to be used for the model of the databases tree. The data structure is equivalent to a root group node in a `PyTables` file. """ __docformat__ = 'restructuredtext' import vitables.utils from vitables.h5db import tnode_editor from vitables.nodeprops import nodeinfo from vitables.nodeprops import grouppropdlg class RootGroupNode(object): """ A root group node in the tree of databases model. Root group nodes are top level nodes (i.e., they have no parent). :Parameters: - `data_source`: the data source of the node. - `parent`: the parent of the node. - `tmp_db`: True if the node is tied to the temporary database """ def __init__(self, model, data_source=None, parent=None, tmp_db=False): """Create the root group node for the tree of databases model. The root of the tree of databases model is a RootGroupNode with no parent and no data source. Any other RootGroupNode represents a root group of a HDF5 file and has a parent (the root of the tree of databases model) and a data source (the HDF5 file). """ self.dbt_model = model self.updated = False self.children = [] self.parent = parent self.name = 'root node' self.filepath = None self.node_kind = 'root group' if data_source: self.node = data_source.get_node('/') self.has_view = False # Attributes that the tree of databases view will use # name --> DisplayRole # nodepath --> ToolTipRole # as_record --> StatusTipRole # icon --> DecorationRole if tmp_db: self.name = 'Query results' else: self.name = data_source.filename self.nodepath = '/' self.filepath = data_source.filepath self.as_record = '{0}->{1}'.format(self.filepath, self.nodepath) self.mode = data_source.mode icons = vitables.utils.getIcons() if tmp_db: self.icon = icons['dbfilters'] elif self.mode == 'r': self.icon = icons['file_ro'] else: self.icon = icons['file_rw'] def __len__(self): """The number of children of this grup.""" return len(self.children) def insertChild(self, child, position=0): """Insert a child in a group node. :Parameters: - `child`: the node being inserted - `position`: the insertion position """ self.children.insert(position, child) def childAtRow(self, row): """The row-th child of this node. :Parameter row: the position of the retrieved child """ assert 0 <= row <= len(self.children) return self.children[row] def rowOfChild(self, child): """The row index of a given child. :Parameter child: the child node whose position is being retrieved. """ for pos, node in enumerate(self.children): if node == child: return pos return -1 def row(self): """The position of this node in the parent's list of children. """ if self.parent: return self.parent.children.index(self) return 0 def findChild(self, childname): """The child node with a given name. :Parameter childname: the name of the wanted child node. """ for node in self.children: if node.name == childname: return node return None def editor(self): """Return an instance of `TNodeEditor`. """ return tnode_editor.TNodeEditor(self.dbt_model.getDBDoc(self.filepath)) def properties(self): """The Properties dialog for this node. """ info = nodeinfo.NodeInfo(self) grouppropdlg.GroupPropDlg(info) ViTables-3.0.0/vitables/h5db/tlink_editor.py000066400000000000000000000120161311223072700207150ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides editing capabilities for PyTables soft and external links. The module defines methods for deleting, cutting, copying, pasting and moving links. """ __docformat__ = 'restructuredtext' import os import tables import vitables.utils class TLinkEditor(object): """ An editor for `tables.Link` instances. """ def __init__(self, dbdoc): """ Initialises the tables.Link editor. :Parameter h5file: the tables.File instance being operated """ if not dbdoc.hidden_group: dbdoc.createHiddenGroup() self.h5file = dbdoc.h5file self.hidden_group = dbdoc.hidden_group def delete(self, nodepath): """Delete a link. :Parameters: - `nodepath`: the full path of the node/link being deleted """ try: link = self.h5file.get_node(nodepath) link.remove() self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def cut(self, nodepath): """Moves a link to a hidden group of its database. The cut node must be stored somewhere or it will no be possible to paste it later. Storing it in the same database is extremely fast independently of the node size. Storing it in other database (i.e. in the temporary database) would have a cost which depends on the size of the cut node. :Parameters: - `nodepath`: the path of the node being cut """ nodename = os.path.basename(nodepath) try: # The hidden group should contain at most 1 node for node in self.h5file.list_nodes(self.hidden_group): self.h5file.deleteNode(node._v_pathname) link = self.h5file.get_node(nodepath) link.move(newparent=self.hidden_group, newname=nodename) self.h5file.flush() except(tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def paste(self, link, parent, childname): """Copy a link to a different location. :Parameters: - `link`: the tables.link instance being pasted - `parent`: the new parent of the node being pasted - `childname`: the new name of the node being pasted """ try: link.copy(newparent=parent, newname=childname, overwrite=True, createparents=False) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def rename(self, nodepath, new_name): """ Rename the selected link from the object tree. :Parameters: - `nodepath`: the full path of the node being renamed - `new_name`: the node new name """ try: link = self.h5file.get_node(nodepath) link.rename(new_name) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def move(self, childpath, dst_dbdoc, parentpath, childname): """Move a ink to a different location. :Parameters: - `childpath`: the full path of the node being moved - `dst_dbdoc`: the destination database (a :meth:`DBDoc` instance) - `parentpath`: the full path of the new parent node - `childname`: the name of the node in its final location """ try: dst_h5file = dst_dbdoc.h5file parent_node = dst_h5file.get_node(parentpath) link = self.h5file.get_node(childpath) if self.h5file is dst_h5file: link.move(newparent=parentpath, newname=childname) else: link.copy(newparent=parent_node, newname=childname) dst_h5file.flush() src_where, src_nodename = os.path.split(childpath) self.h5file.remove_node(src_where, src_nodename, recursive=1) self.h5file.flush() return childname except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() return None ViTables-3.0.0/vitables/h5db/tnode_editor.py000066400000000000000000000133611311223072700207110ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides editing capabilities for PyTables leaves and groups. The module defines methods for deleting, cutting, copying, pasting and moving nodes. Also group creation is supported. """ __docformat__ = 'restructuredtext' import os import tables import vitables.utils class TNodeEditor(object): """ An editor for `tables.Leaf` and `tables.Group` instances. """ def __init__(self, dbdoc): """ Initialises the Leaf/Group editor. :Parameter h5file: the DBDoc instance being operated """ if not dbdoc.hidden_group: dbdoc.createHiddenGroup() self.h5file = dbdoc.h5file self.hidden_group = dbdoc.hidden_group def delete(self, nodepath): """Delete a node. :Parameters: - `nodepath`: the full path of the node/link being deleted """ try: self.h5file.remove_node(where=nodepath, recursive=True) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def cut(self, nodepath): """Moves a node to a hidden group of its database. The cut node must be stored somewhere or it will no be possible to paste it later. Storing it in the same database is extremely fast independently of the node size. Storing it in other database (i.e. in the temporary database) would have a cost which depends on the size of the cut node. :Parameters: - `nodepath`: the path of the node being cut """ nodename = os.path.basename(nodepath) try: # The hidden group should contain at most 1 node for node in self.h5file.list_nodes(self.hidden_group): self.delete(node._v_pathname) self.move(nodepath, self, self.hidden_group, nodename) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def paste(self, src_node, parent, childname): """Copy a node to a different location. :Parameters: - `src_node`: the tables.Node instance being pasted - `parent`: the tables.Group where src_node will be pasted - `childname`: the new name of the node being pasted """ try: self.h5file.copy_node(src_node, newparent=parent, newname=childname, overwrite=True, recursive=True) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def rename(self, nodepath, new_name): """ Rename the selected node from the object tree. :Parameters: - `nodepath`: the full path of the node being renamed - `new_name`: the node new name """ where, current_name = os.path.split(nodepath) try: self.h5file.rename_node(where, new_name, current_name, overwrite=1) self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def create_group(self, where, final_name): """ Create a new group under the given location. :Parameters: - `where`: the full path of the parent node - `final_name`: the new group name """ try: if final_name in self.h5file.get_node(where)._v_children.keys(): self.h5file.remove_node(where, final_name, recursive=True) self.h5file.create_group(where, final_name, title='') self.h5file.flush() except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() def move(self, childpath, dst_dbdoc, parentpath, childname): """Move a node to a different location. :Parameters: - `childpath`: the full path of the node being moved - `dst_dbdoc`: the destination database (a :meth:`DBDoc` instance) - `parentpath`: the full path of the new parent node - `childname`: the name of the node in its final location """ try: dst_h5file = dst_dbdoc.h5file parent_node = dst_h5file.get_node(parentpath) if self.h5file is dst_h5file: self.h5file.move_node(childpath, newparent=parent_node, newname=childname, overwrite=True) else: self.h5file.copy_node(childpath, newparent=parent_node, newname=childname, overwrite=True, recursive=True) dst_h5file.flush() src_where, src_nodename = os.path.split(childpath) self.h5file.remove_node(src_where, src_nodename, recursive=1) self.h5file.flush() return childname except (tables.NodeError, OSError): vitables.utils.formatExceptionInfo() return None ViTables-3.0.0/vitables/i18n/000077500000000000000000000000001311223072700156115ustar00rootroot00000000000000ViTables-3.0.0/vitables/i18n/vitables_es_ES.qm000066400000000000000000002461221311223072700210460ustar00rootroot00000000000000T2so>s`,nnEE~@QK YCW/nCtE:>/B)C/~IULjY7nX(c3c5b{ow.7zrn+6 sq+, ob` ׮l(NX}%)4]H,2D/D?%l/Yhr9NT+v}6~J[jnN`!xt$v!Ԟ \:[~7Lcu 0J!5.L? CpSb%Yt]6(`9 `9 `S%5hx i/R (II9I<-,|,, [O3Uab02 -9vY2ߟ.83z~uuv2 1# ^6!2oR"02`1N5:NY@P4>DZRUZ&}˅5xF;BH5M H5H5=zŽEMYY1s<ItN։9ް'r?q4%ve,E k({!"Ci*t*Dv*I_*vN`#=b<gS7ek aSlm/'e8.RKrx6 r.3n"(^*lml&|S^ODg =b 0:iCtP˥C HELQhieStsZ4e Ori3O>  ( :xC7D)F)UI~WKPO]fdzEz>HWK>;9W9|]$5`U5a<nt_]r n++,ZG Xo w wc  N *9y +>B! 2(< 2.~ M߮5 U `X lahd lam laz vL* t<  U E / (c; . - < ߲p h  y  ݕ M>l #dH 8f0 ;f >d F. S m3k w5$ . F *b - dd >  I- } Z^l ^ , ! ,g , 1 ե ڨ u` =b 3" }; ` Te< D > - D ?2 L. {ƎuM {Ǝ8 k % i 5Tk d6 - ɬ . WU5_ KG! * Rqa  yI ? #^   # :] G 3 b s!0  nr ͳ^j' : Gc  넓1: ?$& >A1 . n aE ]. $cZI ;> B B(S B(R I~~ Vj i$j j mnS {h3N Bh T+ %8 np ` <  Q vK}\pE/387B8/*V`lW`g>tl:yE^Zz]#|}Efo;4{e!1ݹ@c^Vf%r(Pg)r,B-j/xmQ;ys[~Iqvڮ 3[BgBmaOe~="* Autor:Author:  AboutPageDescripcin: Desription:  AboutPageCarpeta:Folder:  AboutPage$Nombre del mdulo: Module name:  AboutPage,Descripcin del pluginPlugin description AboutPageVersin: Version:  AboutPage8<qt><p>Plugin que proporciona una vista alternativa para arrays con el mismo nmero de filas. <p>El usuario selecciona los arrays que desea ver agrupados. Entonces selecciona la entrada de men Nodo -> Agrupa arrays y los arrays se visualizan de la forma esperada por el usuario.</qt>

Plugin that provides an alternative view for arrays with the same number of rows.

The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.ArrayColsOrganizer@Agrupa arrays en una vista nicaGroup Arrays into a unique viewArrayColsOrganizerl Error: "{0}" no puede convertirse a un objeto Python.5 Error: "{0}" cannot be converted to a Python object. AttrEditor Error: el valor "{0}" esta fuera de rango o no concuerda con su tipo de datos.@ Error: "{0}" value is out of range or mismatches its data type. AttrEditorV Error: el valor "{0}" est fuera de rango.$ Error: "{0}" value is out of range. AttrEditorr Error: el valor "{0}" no concuerda con su tipo de datos.- Error: "{0}" value mismatches its data type. AttrEditord Error: el nombre de atributo "{0}" est repetido.) Error: attribute name "{0}" is repeated. AttrEditorf Error: el campo Nombre est vaco en la fila {0:d}) Error: empty field Name in the row {0:d} AttrEditor&Aadir&AddAttrPropDialog&Borrar&DeleteAttrPropDialog*Atributos de &Sistema&System attributesAttrPropDialog*Atributos de &Usuario&User AttributesAttrPropDialog&Qu es esto &What's thisAttrPropDialog<qt> <h3>Tabla de edicin de atributos de usuario</h3> Aqu puedes editar los atributos de usuario para este nodo. Es bastante fcil. <p>Para aadir un atributo pulsa el botn <b>Aadir</b>. En la tabla se insertar una nueva fila. Introduce el nombre del atributo y su valor en las celdas correspondientes. Por ltimo, selecciona el tipo de dato del atributo en el combobox de la columna Tipo de Dato. Para borrar un atributo seleccionalo pulsando en cualquiera de sus celdas y pulsa el botn <b>Borrar</b>.</p> <p>Ten en cuenta que PyTables almacena los atributos escalares como arrays escalares de Numpy, por eso no pueden guardarse como objetos Python, ni siquiera si eliges el tipo de dato Python en el combobox. Ten en cuenta tambin que los atributos multidimensionales (aparte de listas y tuplas de Python) no estn soportados.</p> </qt>

User's attributes editing table

Here you can perform the editing of user's attributes for this node. It is quite straightforward.

For adding an attribute click the Add button. A new row will be added to the table. Enter the attribute name and its value in the corresponding cells. Finally, select the attribute datatype in the combobox of the DataType column. In order to delete an attribute just select it by clicking any of its cells, then click the Delete button.

Beware that PyTables stores scalar attributes as numpy scalar arrays so you will be unable to save them as Python objects even if you choose the Python datatype in the combobox selector. Also note that multidimensional attributes other than Python lists and tuples are not supported.

AttrPropDialog*Atributos de sistema:System attributes:AttrPropDialog*Atributos de usuario:User attributes:AttrPropDialogX Ests a punto de borrar el atributo: {0} . You are about to delete the attribute: {0}  AttrPropDlgCancelarCancel AttrPropDlgTipo de datoDatatype AttrPropDlg BorrarDelete AttrPropDlg NombreName AttrPropDlgjPor favor, selecciona el atributo que quieres borrar.+Please, select the attribute to be deleted. AttrPropDlg4Borrar atributo de usuarioUser attribute deletion AttrPropDlg ValorValue AttrPropDlg&Cancelar&Cancel BookmarksDlg&Borrar&Delete BookmarksDlg&Aceptar&OK BookmarksDlgMarcadorBookmark BookmarksDlg(Editor de marcadoresBookmarks editor BookmarksDlgURLURL BookmarksDlg Error: se han detectado problemas durante la lectura de registros. El conjunto de datos podra estar corrompido.> Error: problems reading records. The dataset maybe corrupted.Buffer:Error de lectura de datos: {}Data read error: {}Buffer2Problemas leyendo los registros. El conjunto de datos parece estar comprimido con la librera {0}. Comprueba que esta librera est instalada, por favor.Problems reading records. The dataset seems to be compressed with the {0} library. Check that it is installed in your system, please.BufferSe lanz una excepcin durante la evaluacin, consulta el fichero de log para ver los detalles.?An exception was raised during evaluation, see log for details. CalculatorSe lanz una excepcin mientras se intentaba almacenar los resultados, consulta el fichero de log para ver los detalles.KAn exception was raised while trying to store results, see log for details. CalculatorCrear grupo Create group Calculator&Error de evaluacinEvaluation error CalculatorSe han seleccionado varios grupos. Las referencias relativas estn desactivadas Continuar?IMultiple groups are selected. Relative references are disabled. Continue? CalculatorNombre:Name: CalculatorNo se ha seleccionado ningn grupo. Las referencias relativas estn desactivadas.Continuar?ANo group is selected. Relative references are disabled. Continue? Calculator$Nodo no encontradoNode not found CalculatorTipo de nodo Node type CalculatorDReferencias relativas desactivadas Relative references are disabled Calculator(Nombre del resultado Result name Calculator:Error al guardar el resultadoResult save error Calculator.Guardar expresin como Save expression as CalculatorNo se ha especificado ningn lugar para almacenar los resultados.The location to store results is not specified Calculatorf<html><head/><body> <p>Referencia al destino para la expresin resultante. Una referencia es un string construido mediante la unin de nombres de grupos que lleva a los datos por puntos. Por ejemplo: &quot;filename.h5.some_group.sub_group.myresult&quot;. Si &quot;sub_group&quot; es el grupo actual entonces la cadena &quot;myresult&quot; puede usarse como referencia.</p> <p>La tabla de resultados no debe exisitir.</p> </body></html>

Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.myresult". If "sub_group" is the current group then the string "myresult" can be used as reference.

The result table must not exitst.

CalculatorDialog<html><head/><body> <p>Conjunto de sentencias de Python que se ejecutarn antes de evaluar la expresin. Puede usarse para importar mdulos adicionales o realizar clculos preliminares para simplificar la expresin.</p> </body></html>

Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.

CalculatorDialog:<html><head/><body> <p>Los resultados de la expresin se guardarn en la tabla de resultados. Este campo debe contener una expresin vlida que devuelva un array de PyTables, una lista o un escalar.</p> <p>La expresin puede contener referencias a nodos abiertos. Una referencia puede ser absoluta y empezar con un nombre de fichero o relativa al grupo actual. Una referencia es un string construido mediante la unin de nombres de grupos que lleva a los datos por puntos. Por ejemplo: &quot;filename.h5.some_group.sub_group.mydata&quot;. Si &quot;sub_group&quot; es el grupo actual entonces la cadena &quot;mydata&quot; puede usarse como referencia.</p> </body></html>u

The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.

The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.mydata". If "sub_group" is the current group then the string "mydata" can be used as reference.

CalculatorDialog<html><head/><body><p>Borra la expresin seleccionada de la lista de expresiones guardadas.</p></body></html>g

Remove the selected expression from the saved expressions list.

CalculatorDialog|<html><head/><body><p>Expresiones guardadas.</p></body></html>:

Saved expressions.

CalculatorDialog<html><head/><body><p>Almacenar la expresin para su uso futuro.</p></body></html>H

Store expression for future use.

CalculatorDialog(Evaluar la expresinEvaluate expressionCalculatorDialogExpresin: Expression:CalculatorDialog BorrarRemoveCalculatorDialog(Tabla de resultados: Result table:CalculatorDialogGuardarSaveCalculatorDialog,Expresiones guardadas:Saved expressions:CalculatorDialogSentencias: Statements:CalculatorDialog Error de configuracin: la configuracin {0} de la aplicacin no puede guardarse.B Configuration error: the application setting {0} cannot be saved.ConfigFileIOExceptionAviso de configuracin: la configuracin {0} de la aplicacin no puede leerse. Se utilizar su valor por defecto.c Configuration warning: the application setting {0} cannot be read. Its default value will be used.ConfigFileIOExceptionhError: no puede abrirse el nodo {0} del fichero {1} ) Error: cannot open node {0} in file {1} DBDoc Aviso: se ha denegado el acceso al fichero en modo lectura-escritura. El fichero se abrir en modo solo lectura.X Warning: file access in read-write mode is denied. It will be opened in read-only mode.DBDocPor favor, si crees que esto es un bug, informa de ello a los desarrolladores.:Please, if you think it is a bug, report it to developers.DBDoc0No se puede guardar el fichero {0} como {1}. Ten en cuenta que solamente los ficheros cerrados se pueden sobreescribir con garantas via Guardar como...jUnable to save the file {0} as {1}. Beware that only closed files can be safely overwritten via Save As...DBDoc{0}{0}DBDoc Autor:Author: DBTreeSortPageDescripcin: Desription: DBTreeSortPageCarpeta:Folder: DBTreeSortPage$Nombre del mdulo: Module name: DBTreeSortPage,Descripcin del pluginPlugin descriptionDBTreeSortPage.Algoritmo de ordenacinSorting algorithmDBTreeSortPageVersin: Version: DBTreeSortPage La creacin del fichero fall debido a razones desconocidas! Por favor, consulta el ltimo error mostrado en el panel de log. Si crees que es un bug, por favor informa de ello a los desarrolladores. File creation failed due to unknownreasons! Please, have a look to the last error displayed in the logger. If you think it's a bug, please report it to developers. DBsTreeModelFCreando el fichero Query results..."Creating the Query results file... DBsTreeModelNMover nodo: el nombre de nodo ya existe"Node move: nodename already exists DBsTreeModelfApertura cancelada: el fichero {0} ya est abierto.)Opening cancelled: file {0} already open. DBsTreeModelrApertura cancelada: el fichero {0} no tiene formato HDF5.0Opening cancelled: file {0} has not HDF5 format. DBsTreeModelFallo de apertura: no se puede averiguar si el fichero {0} tiene formato HDF5.>Opening failed: I cannot find out if file {0} has HDF5 format. DBsTreeModeldFallo de apertura: no se encuentra el fichero {0}.)Opening failed: file {0} cannot be found. DBsTreeModelNApertura cancelada: {0} es una carpeta.$Openning cancelled: {0} is a folder. DBsTreeModelRenombrarRename DBsTreeModelFichero fuente: {0} Nodo movido: {1} Fichero destino: {2} Grupo padre: {3} Nombre de node '{4}' ya existe en ese grupo. xSource file: {0} Moved node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group.  DBsTreeModel.rbol de bases de datosTree of databases DBsTreeModel`<qt><p>Plugin que proporciona capacidades de ordenacin al rbol de DBs.<p>Por el momento solo dos algoritmos estn soportados: ordenacin humana (o natural) y alfabtica.</qt>

Plugin that provides sorting capabilities to the tree of DBs.

At the moment only two sorting algorithms are supported: human (a.k.a. natural sorting) and alphabetical.DBsTreeSortingPage<qt> <h3>El rbol de bases de datos</h3> Para cada base de datos abierta este panel muestra el rbol de objetos, una representacin grfica<br> de la jerarqua de datos almacenada en esa base de datos.</qt>

The Tree of databases

For every open database this widget shows the object tree, a graphical representation
of the data hierarchy stored in the database.
 DBsTreeView <qt><p>plugin que ofrece la posibilidad de exportar a formato CSV.<p>Casi cualquier conjunto de datos de PyTables puede ser exportado. Cuando se exportan tablas, una cabecera con el nombre de los campos puede insertarse en la primera lnea del fichero CSV.</qt>

Plugin that provides export to CSV files capabilities.

Any kind of PyTables dataset can be exported. When exporting tables, a header with the field names can be inserted at top of the CSV file. ExportToCSV\Ficheros CSV (**.csv);; Todos los ficheros (*) CSV Files (*.csv);;All Files (*) ExportToCSV$E&xportar a CSV...E&xport to CSV... ExportToCSVtEl conjunto de datos est vaco. No hay nada que exportar.!Empty dataset. Nothing to export. ExportToCSVExportarExport ExportToCSVExportar ha fallado porque el contenedor de destino es una carpeta.;Export failed because destination container is a directory. ExportToCSVvExportar ha fallado porque el fichero de destino ya existe.6Export failed because destination file already exists. ExportToCSVTExportando conjunto de datos a formato CSVExporting dataset to CSV format ExportToCSVxSalvar el conjunto de datos como texto plano con formato CSV0Save the dataset as a plain text with CSV format ExportToCSVPArray escalar. No hay nada que exportar. Scalar array. Nothing to export. ExportToCSVAlgunos campos no son escalares. No se puede exportar la tabla a formato CSV.CSome fields aren't scalars. I can't export the table to CSV format. ExportToCSVEl nodo seleccionado tiene ms de 2 dimensiones. No puede ser exportado a formato CSV.NThe selected node has more than 2 dimensions. I can't export it to CSV format. ExportToCSVEl nodo seleccionado es un VLArray. No puede ser exportado a formato CSV.@The selected node is a VLArray. I can't export it to CSV format. ExportToCSVModo de acceso: Access mode:  FilePropPageBase de datosDatabase FilePropPageNombre:Name: FilePropPage"Nmero de hijos: Number of children:  FilePropPage Ruta:Path: FilePropPageGrupo raz Root group FilePropPage Tipo:Type: FilePropPage.Propiedades del ficheroFile properties GroupPropDlg*Propiedades del grupoGroup properties GroupPropDlgNombre del hijo Child name GroupPropPage GrupoGroup GroupPropPageTipoType GroupPropPage grupogroup GroupPropPagehojaleaf GroupPropPage enlacelink GroupPropPage@Agrupa Arrays en una nica vistaGroup Arrays into a unique view GroupedArraysp<html><h3>Navegador de Ayuda</h3> El Navegador de Ayuda es un instrumento muy simple para mostrar la versin HTML de la Gua del Usuario sin necesidad de usar programas externos. <p>Y lo mejor de todo... est escrita en PyQt, el binding de Python para Qt. </html>3

HelpBrowser

HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs.

Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit. HelpBrowser:Acerca del Navegador de AyudaAbout HelpBrowser HelpBrowserAcerca de QtAbout Qt HelpBrowser<&Acerca del Navegador de Ayuda&About HelpBrowserHelpBrowserGUI &Aadir marcador &Add bookmarkHelpBrowserGUI &Atrs &BackwardHelpBrowserGUI&Marcadores &BookmarksHelpBrowserGUI&Borrar Todos &Clear AllHelpBrowserGUI*&Editar marcadores...&Edit bookmarks...HelpBrowserGUI&Fichero&FileHelpBrowserGUIA&delante&ForwardHelpBrowserGUI&Ir&GoHelpBrowserGUI &Ayuda&HelpHelpBrowserGUI&Inicio&HomeHelpBrowserGUI&Recargar&ReloadHelpBrowserGUI&Tamao&ViewHelpBrowserGUI<qt><h3>Selector de pgina</h3>Selecciona la pgina que quieres visitar.</qt>[

Page selector

Select the page you want to visit.
HelpBrowserGUIAcerca de &Qt About &QtHelpBrowserGUI:Acerca del Navegador de AyudaAbout HelpBrowserHelpBrowserGUIAcerca de QtAbout QtHelpBrowserGUI$Marcar esta pginaBookmark the current pageHelpBrowserGUI4Operaciones con marcadoresBookmarks operationsHelpBrowserGUI6Borrar todos los marcadoresClear all existing bookmarksHelpBrowserGUIBBorrar el historial de navegacin Clear historyHelpBrowserGUIvBorra el contenido del combobox del historial de navegacin)Clear the content of the history comboboxHelpBrowserGUI2Cerrar Navegador de AyudaClose Help BrowserHelpBrowserGUI:Reduce el tamao de la fuenteDecreases the font sizeHelpBrowserGUI4Navegador de documentacinDocumentation browserHelpBrowserGUI &SalirE&xitHelpBrowserGUIFEditar los marcadores del documentoEdit bookmarksHelpBrowserGUI2Operaciones de navegacin Go operationsHelpBrowserGUI0Ir a la pgina siguienteGo to next pageHelpBrowserGUI.Ir a la pgina anteriorGo to previous pageHelpBrowserGUI>Ir a la primera pgina visitadaGo to the first visited pageHelpBrowserGUI Ir a:Go: HelpBrowserGUITOperaciones con el historial de navegacinHistory operationsHelpBrowserGUI<Aumenta el tamao de la fuenteIncreases the font sizeHelpBrowserGUIListo...Ready...HelpBrowserGUI(Recargar esta pginaReload the current pageHelpBrowserGUI2Operaciones con el tamaoView operationsHelpBrowserGUI&AumentarZoom &inHelpBrowserGUI&Reducir Zoom &outHelpBrowserGUIZ<qt><p>Plugin que proporciona la capacidad para importar ficheros CSV.<p>Los ficheros CSV pueden importarse en cualquiera de los siguientes contenedores de PyTables: Array, EArray, CArray y Table.<p>Cuando se importa el fichero a una tabla se dispone de deteccin automtica de cabeceras <p>Hay que tener en cuenta que importar ficheros grandes es una operacin potencialmente lenta porque el fichero completo tiene que leerse del disco, transformarse y almacenarse nuevamente en el disco, por tanto hay una gran cantidad de lectura/escritura al disco.</qt>

Plugin that provides import CSV files capabilities.

CSV files can be imported into any of the following PyTables containers: Array, EArray, CArray and Table.

When a file is imported into a Table automatic header detection is provided.

Beware that importing large files is a potentially slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO. ImportCSVZFicheros CSV (*.csv);; Todos los Ficheros (*) CSV Files (*.csv);;All Files (*) ImportCSV DatosData ImportCSVLa primera lnea contiene una cabecera de tabla o contiene datos?GDoes the first line of the file contain a table header or regular data? ImportCSVCabeceraHeader ImportCSV,I&mportar desde CSV...I&mport from CSV... ImportCSVImportarImport ImportCSV$Importar &Array...Import &Array... ImportCSV&Importar &CArray...Import &CArray... ImportCSV&Importar &EArray...Import &EArray... ImportCSV$Importar &Tabla...Import &Table... ImportCSVLImportar un Array desde un fichero CSV Import Array from plain CSV file ImportCSVNImportar un CArray desde un fichero CSV!Import CArray from plain CSV file ImportCSVNImportar un EArray desde un fichero CSV!Import EArray from plain CSV file ImportCSVNImportar una tabla desde un fichero CSV Import Table from plain CSV file ImportCSVImportar ha fallado porque el contenedor de destino es una carpeta.;Import failed because destination container is a directory. ImportCSVvImportar ha fallado porque el fichero de destino ya existe.6Import failed because destination file already exists. ImportCSVImportar ha fallado porque no puede crearse el fichero de destino.9Import failed because destination file cannot be created. ImportCSV:Importando fichero CSV en {0}Importing CSV file into {0} ImportCSVPor favor, asegrate de que ests importando un conjunto de datos homogneo.?Please, make sure that you are importing a homogeneous dataset. ImportCSVLResolviendo el rol de la primera lneaResolving first line role ImportCSV(Etiqueta informativa InfoLabelInputNodeNameDlg"Nombre del nodo:  Node name: InputNodeNameDlg*Propiedades del arrayArray properties LeafPropDlg.Propiedades de la tablaTable properties LeafPropDlg-- LeafPropPageCompresin: Compression:  LeafPropPageTipo de dato: Data Type:  LeafPropPageBase de datosDatabase LeafPropPage Espacio de datos Dataspace LeafPropPageDimensiones: Dimensions:  LeafPropPage Campo Field name LeafPropPageNombre:Name: LeafPropPage Ruta:Path: LeafPropPage FormaShape LeafPropPage Forma:Shape:  LeafPropPageTipoType LeafPropPage Tipo:Type: LeafPropPageanidadonested LeafPropPageGeneralGeneralLinkPropDialogNombre:Name:LinkPropDialog Ruta:Path:LinkPropDialogDestino:Target:LinkPropDialog Tipo:Type:LinkPropDialog,Propiedades del enlaceLink properties LinkPropDlg&Copiar&CopyLogger<qt><h3>La Consola</h3>Es el panel en el que queda registrado el resultado de determinadas operaciones ejecutadas por el usuario.<p>Los errores de ejecucin y las excepciones tambin se registran en la consola.</qt>K

The Logger

This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user.

Also execution errors and exceptions are logged in the console. Logger&Borrar Todo Cl&ear AllLoggerVCopia el texto seleccionado al PortapapelesCopy selected text to clipboardLogger Borra la consolaEmpty the LoggerLogger"Seleccionar &Todo Select &AllLoggerTSelecciona todo el contenido de la consola Select the whole Logger contentsLogger Error: agrupamiento de Arrays cancelado. No todos los arrays seleccionados tienen el mismo nmero de filas.g Error: grouping arrays, operation cancelled. Not all the selected arrays have the same number of rows. MenuUpdaterA&grupa arrays &Group Arrays MenuUpdater"&Desagrupa Arrays&Ungroup Arrays MenuUpdaterRDesagrupa arrays agrupados anteriormente."Ungroup previously grouped arrays. MenuUpdaterUsa un nico widget para mostrar Arrays como si fueran columnas de una TableIUse a unique widget to display Arrays as if they where columns of a Table MenuUpdaterVRenombrar un nodo: el nombre ya est en uso$Renaming a node: name already in useNodeItemDelegateFichero fuente: {0} Grupo padre: {1} Ya hay un nodo llamado '{2}' en el grupo padre. ^Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. NodeItemDelegateGeneral General  PreferencesPlugins Plugins  PreferencesApariencia Look & Feel PreferencesLo sentimos, no hay disponible informacin acerca de este plugin2Sorry, there are no info available for this plugin PreferencesCancelarCancelQueriesManagerDLimpiando el fichero Query resultsCleaning the Query results fileQueriesManager BorrarDeleteQueriesManagerLLa consulta a la tabla {0} ha fallado!Query on table {0} failed!QueriesManagerAlgunas columnas de la tabla contienen datos multidimensionales, anidados o de tipo Complex. Estos campos no pueden consultarse y no se han includo en el selector Columna del dilogo de consultas.Some table columns contain multidimensional, nested or Complex data. They cannot be queried so are not included in the Column selector of the query dialog.QueriesManager4La tabla {0} no contiene columnas que puedan ser consultadas. Todas las columnas estn anidadas, son multidimensionales o tienen el tipo de datos Complex.vTable {0} has no columns suitable to be queried. All columns are nested, multidimensional or have a Complex data type.QueriesManagerfLa tabla {0} est vaca. No hay nada que consultar.%Table {0} is empty. Nothing to query.QueriesManager11 QueryDialog <qt> <h3>Sintaxis de las consultas</h3> Una consulta en una tabla es simplemente una <em>cadena</em> que contiene una expresin Python que implica <em>como mnimo una columna</em> , y quizs algunas constantes y variables externas, todo ello combinado con operadores algebraicos o funciones. Ten en cuenta que los operadores <tt>&</tt>, <tt>|</tt> and <tt>~</tt> se usan para las comparaciones lgicas y tienen mayor precedencia que los operadores lgicos, as que recomendamos <em>usar siempre parntesis con los operadores lgicos</em>.</p> <p>La siguiente tabla muestra algunas consultas y sus expresiones equivalentes en Python.</p> <div align='center'><table border='1'> <tr><th>Consulta</th><th>Expresin Python</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>Puedes encontrar informacin detallada acerca de las consultas en el Apndice B de la gua de usuarios de PyTables.</p> </qt>%

Conditions syntax

A condition on a table is just a string containing a Python expression that involves at least one column , and maybe some constants and external variables, all combined with algebraic operators or functions. Beware that &, | and ~ operators are used for logical comparisons. They have higher precedence than logical operators so we recommend to always use parenthesis around logical operators.

The following table shows some examples of conditions and their equivalent Python expressions.

ConditionPython expression
a & (b == c) a and b == c
(0 < x) & (x < 1) 0 < x < 1
a + b > c a + b > c
where(a > b, 3, 4)

You can find detailed information about conditions in the Appendix B of the PyTables users guide.

 QueryDialog<qt> El nombre de la columna en la que se aadirn los ndices de las filas seleccionadas. </qt>o The name of the column where the indices of the selected rows will be added.  QueryDialog<qt> Nombre de la tabla a la que se aadirn los resultados de la consulta. </qt>W The name of the table where the query results will be added.  QueryDialog(<qt> Los nombres de las columnas que pueden ser consultadas. Deben cumplir los siguientes requerimientos: <ul><li>no deben estar anidados</li> <li>deben tener un tipo de datos escalar</li> <li>su tipo de datos no puede ser <code>complejo</code></li></ul> Las columnas cuyos nombres contengan blancos se asignan automticamente a variables cuyos nombres no contienen blancos. Para consultar estas columnas se usarn los nombres de sus variables asociadas. </qt> The names of the searchable columns. They must fulfill the following requirements:
  • must be not nested
  • must have a scalar data type
  • their data type cannot be complex
Columns whose names contains blanks are automatically mapped to variables whose names contain no blanks. For querying those columns the mapped variables will be used.
 QueryDialog<qt> Los operadores que pueden usarse en una consulta dada. Estos operadores pueden ser lgicos, de comparacin y aritmticos.<br>No todos los operadores estn disponibles en todos los tipos de dato. </qt> The operators that can be used in a given condition. Operators can be logical, comparison and arithmetic.
Not all operators are available for every data type.
 QueryDialog<qt> El conjunto de funciones que puede aparecer en una consulta. Incluye funciones para seleccionar datos, funciones trigonomtricas y funciones para nmeros complejos. Para facilitar el uso, los argumentos se incluyen automticamente cuando se inserta una funcin. El significado de los argumentos es: <ul><li>N: nmero</li><li>B: booleano</li> <li>F: nmero en coma flotante</li><li>C: nmero complejo</li></ul> </qt> The set of functions that can appear in a condition. It includes functions for doing selections, trigonometric functions and functions on complex numbers. For ease of use, arguments are automatically included when a function is inserted. The arguments meaning is:
  • N: number
  • B: boolean
  • F: float
  • C: complex
 QueryDialog"Opciones globalesGlobal options QueryDialogNombre:Name: QueryDialogOrig_ndicesOrig_idx QueryDialogBndices originales en la columna:Original indices into column: QueryDialogConsultaQuery condition QueryDialogRango de filas Range of rows QueryDialogInicio:Start: QueryDialogIntervalo:Step: QueryDialogFin:Stop: QueryDialogVEl rango de filas includas en la consulta.(The range of rows included in the query. QueryDialogrIntroduce un nombre para la columna de ndices, por favor.Enter a name for the column of indices, pleaseQueryDlg<Nueva consulta a la tabla: {0}New query on table: {0}QueryDlgEl nombre elegido para la columna de ndices ya est en uso. Por favor, elige otro nombre.YThe chosen name for the column of indices is already in use. "Please, choose another one.QueryDlgEl nombre elegido para la columna de ndices no es vlido porque contiene el carcter '/'QThe chosen name for the column of indicesis not valid. It contains '/' charactersQueryDlgEl nombre elegido ya est en uso. Por favor, utiliza un nombre diferente.>The chosen name is already in use. Please, choose another one.QueryDlgEl valor de inicio es mayor que el valor de finalizacin. Por favor, escoge otro valor.KThe start value is greater than the stop value. Please, choose another one.QueryDlgPEl valor de inicio debe ser mayor que 0.'The start value must be greater than 0.QueryDlgEl valor de stop es mayor que el nmero de filas. Por favor, elige otro valor.NThe stop value is greater than the number of rows. Please, choose another one.QueryDlgSobreescribir Overwrite RenameDlgRenombrarRename RenameDlg(Etiqueta informativa InfoLabel RenameNodeDlgNuevo nombre:  New name:  RenameNodeDlg Color del f&ondo &BackgroundSettingsDialog &Color del fondo'The label of the workspace color button &BackgroundSettingsDialog&Fuente&FontSettingsDialog<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html>V

En un lugar de La Mancha,

de cuyo nombre no quiero acordarme,

no ha mucho tiempo vivia un hidalgo..

SettingsDialog&Plugins disponiblesAvailable pluginsSettingsDialog4Ejemplo del color de fondoBackground color sampleSettingsDialogHAjusta el estilo global de ViTables.)Choose the global style of ViTables here.SettingsDialogPulsa sobre un elemento en este rbol para seleccionar los ajustes que quieres cambiar.Click an item in this tree to select the settings you want to change. Beware that the listed plugins are *loaded* plugins (i.e. the are working in the current ViTables session) not just enabled plugins.SettingsDialogHConfigura la apariencia de ViTables.(Configure the look and feel of ViTables.SettingsDialog`Configura el comportamiento inicial de ViTables.+Configure the startup behavior of ViTables.SettingsDialogdPersonaliza la fuente y los colores de la consola.(Customise font and colors of the Logger.SettingsDialog Color del &texto F&oregroundSettingsDialogdAqu puedes ajustar la fuente usada en la consola.0Here you can choose the font used in the Logger.SettingsDialog Si est seleccionado, recupera la ltima sesin de trabajo (ficheros abiertos y vistas). Si no, ViTables empieza con una sesin vaca.If checked, the last working session -i.e. open files and views- will be restored. If not, ViTables will start with an empty session.SettingsDialogConsolaLoggerSettingsDialog2Recupera la ltima sesinRestore last sessionSettingsDialogZAjusta el color de fondo del rea de trabajo.,Setup the background color of the workspace.SettingsDialog2Ajusta el color de fondo.Setup the background color.SettingsDialog4Ajusta el color del texto.Setup the text color.SettingsDialogLEmpieza en l ltima carpeta de trabajoStart in last working directorySettingsDialog InicioStartupSettingsDialog EstiloStyleSettingsDialog.La lista de plugins disponibles. Los plugins marcados estn activados (pero no necesariamente cargados), el resto estn desactivados (pero no necesariamente descargados). Por favor, ten en cuenta que los cambios en esta lista tendrn efecto la prxima vez que arranques ViTables.The list of all available plugins. If a plugin is checked then it is enabled (but not necessarely loaded), if it is unchecked then it is disabled (but not necessarely unloaded). Please, note that changes in the check state of plugins will take effect the next time you start ViTables.SettingsDialogLa carpeta de trabajo usada para abrir el primer fichero. Su valor por defecto es la carpeta actual si ViTables se arranca desde una consola. Si arranca desde un men o un icono de escritorio el valor por defecto es la carpeta home del usuario. Si el checkbox est seleccionado entonces se usa la ltima carpeta usada en la sesin anterior.1The working directory used when opening the very first file. It defaults to the current directory if ViTables has been launched from the command line or to the user's home directory if ViTables started from a menu or a desktop icon. If the checkbox is checked then the last entered directory will be used.SettingsDialogAparienciaViTables settingsSettingsDialogrea de trabajo WorkspaceSettingsDialog`Puedes previsualizar los ajustes de Fuente aqu.(You can preview your Font settings here.SettingsDialog<qt> <p>Plugin que proporciona un formato agradable para los campos de tiempo. <p>Soporta no solo el tipo de datos de tiempo nativo de PyTables sino tambin series temporales generadas (y almacenadas en tablas de PyTables) via Pandas y scikits.timeseries. </qt>(

Plugin that provides nice string formatting for time fields.

It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. TimeFormatterPage Autor:Author: TimeFormatterPageLconfigura el formato de fechas y horasConfigure time formatTimeFormatterPageDescripcin: Desription: TimeFormatterPageCarpeta:Folder: TimeFormatterPage$Nombre del mdulo: Module name: TimeFormatterPage,Descripcin del pluginPlugin descriptionTimeFormatterPage"Fecha de ejemplo: Sample date: TimeFormatterPage4Formato de fechas y horas: Time format: TimeFormatterPageHoyTodayTimeFormatterPageVersin: Version: TimeFormatterPageL Ests a punto de borrar el nodo: {0} ' You are about to delete the node: {0} VTApp&Acerca&AboutVTApp&Licencia&LicenseVTApp&Gracias A &Thanks ToVTApp <qt> <h3>ViTables {0}</h3> ViTables es una herramienta grfica para ver conjuntos de datos almacenados en ficheros PyTables y HDF5. Est escrita en PyQt , los binding de Python para Qt.<p> Para ms informacin ver <b>http://www.vitables.org</b>.<p> Por favor, informa de los bugs que encuentres y de la funcionalidad que eches en falta al <em>Grupo de Usuarios de ViTables</em>.<p> ViTables usa software de terceros, que tiene su propio copyright. Para ms detalles ver la nota de copyright de los paquetes individuales. </qt>

ViTables {0}

ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.

For more information see http://www.vitables.org.

Please send bug reports or feature requests to the ViTables Users Group.

ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. VTAppF<qt> Alexey Naydenov por sus numerosas y valiosas contribuciones.<p> Kamil Kisiel y Max Bohnet por solucionar bugs.<p> Dmitrijs Ledkovs por sus contribuciones al sistema de empaquetado.<p> y por sus paquetes para Debian. Al equipo Oxygen por su fantstico conjunto de iconos.<p> Toda la gente que ha informado de bugs y ha hecho sugerencias. </qt> Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.

Kamil Kisiel and Max Bohnet for fixing bugs.

Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.

Oxygen team for a wonderful icons set.

All the people who reported bugs and made suggestions. VTAppAcerca de QtAbout QtVTAppRAcerca de los nodos de tipo UnImplementedAbout UnImplemented nodesVTApp,Acerca de ViTables {0}About ViTables {0}VTAppLAcerca de conjuntos de datos ilegiblesAbout unreadable datasetsVTApp Los datos contenidos en este nodo no son accesibles.<br> La combinacin de tipos de datos y/o espacios de datos de este nodo todava no est disponible en PyTables.<br>Si quieres ver est clase de nodo implementada en PyTables, por favor, contacta con los desarrolladores.Actual data for this node are not accesible.
The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.
If you want to see this kind of dataset implemented in PyTables, please, contact the developers.VTAppCancelarCancelVTApp:Configurando la aplicacin...Configuration setup...VTApp,Copiando un fichero...Copying a file...VTApp CrearCreateVTApp CrearA button labelCreateVTApp6Creando un fichero nuevo...Creating a new file...VTApp,Creando un nuevo grupoCreating a new groupVTApp`Creando un nuevo grupo: el nombre ya est en uso)Creating a new group: name already in useVTApp<Creando la interfaz grfica...Creating the GUI...VTApp BorrarDeleteVTAppTFichero Guardar Como: el fichero ya existe!File Save as: file already existsVTApp~Ficheros HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Todos los Ficheros (*)3HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*)VTApp~Ficheros HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Todos los Ficheros (*) Filter for the Save As... dialog3HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*)VTAppPNo se ha ledo la lista de ficheros HDF5List of HDF5 files not readVTAppLa creacin del nuevo fichero fall porque el fichero ya existe.5New file creation failed because file already exists.VTApp$Borrado de un nodo Node deletionVTAppTPegar un nodo: el nombre de nodo ya existe#Node paste: nodename already existsVTApp AbrirOpenVTApppFallo de apertura: {0} incorrecto en la lnea {1} de {2},Opening failed: wrong {0} in line {1} of {2}VTApp(Abriendo ficheros...Opening files...VTApp@Abriendo la lista de ficheros...Opening the list of files...VTApp PegarPasteVTApp>Recuperando la ltima sesin...Recovering last session...VTAppRenombrarRenameVTApp&Renombrando un nodoRenaming a nodeVTAppZRenombrando un nodo: el nombre ya est en uso$Renaming a node: name already in useVTAppDSelecciona un fichero para abrirloSelect a file for openingVTAppLo siento, los datos de este nodo no estn accesibles.<br>El nodo no se copiar.SSorry, actual data for this node are not accesible.
The node will not be copied.VTAppFichero origen: {0} Nodo copiado: {1} Fichero destino: {2} Grupo padre: {3} El nombre de nodo '{4}' ya est en uso en ese grupo. ySource file: {0} Copied node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. VTAppLFichero origen: {0} Grupo padre: {1} $Source file: {0} Parent group: {1} VTAppNFichero origen: {0} Grupo padre: {1} %Source file: {0} Parent group: {1} VTAppFichero origen: {0} Grupo padre: {1} Ya hay un nodo llamado '{2}' en ese grupo padre. ^Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. VTAppCarpeta de destino: {0} El nombre de fichero {1} ya est en uso en esa carpeta. GTarget directory: {0} File name {1} already in use in that directory. VTAppCarpeta de destino: {0} La base de datos Query results no puede sobreescribirse.HTarget directory: {0} The Query results database cannot be overwritten.VTAppCarpeta de destino: {0} El fichero que se est guardando no puede sobreescribirse a s mismo.DTarget directory: {0} The file being saved cannot overwrite itself.VTApp$Nmeros de versinVersion NumbersVTAppViTables {0} Copyright (c) 2008-2013 Vicent Mas. Todos los derechos reservados.EViTables {0} Copyright (c) 2008-2013 Vicent Mas. All rights reserved.VTAppno disponible not availableVTApp&&Acerca de ViTables&About ViTablesVTGUI&Cascada&CascadeVTGUI&Borrar&ClearVTGUI&Cerrar&CloseVTGUI&Copiar&CopyVTGUI$&Conjunto de datos&DatasetVTGUI&Borrar&DeleteVTGUI&Fichero&FileVTGUI &Ayuda&HelpVTGUIM&inimizar Todo &Minimize AllVTGUI&Ms...&More...VTGUI&Nuevo Grupo... &New group...VTGUI&Nuevo...&New...VTGUI &Nodo&NodeVTGUI&Abrir Vista &Open viewVTGUI&Abrir...&Open...VTGUI &Pegar&PasteVTGUI &Preferencias...&Preferences...VTGUI&Consulta... &Query...VTGUI&Renombrar... &Rename...VTGUI&Recuperar Todo &Restore AllVTGUI &Guardar como... &Save as...VTGUIC&onfiguracin &SettingsVTGUI&Mosaico&TileVTGUI"Gua del &Usuario &User's GuideVTGUI&Ventana&WindowVTGUI<qt> <h3>El rea de trabajo</h3> Es el rea donde se muestran las hojas abiertas del rbol de objetos. Pueden mostrarse al mismo tiempo una gran cantidad de tablas y arrays. <p>Las diferentes vistas se pueden mostrar en mosaico o en cascada. </qt>

The Workspace

This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously.

The diferent views can be tiled as a mosaic or stacked as a cascade. VTGUIAcerca de &Qt About &QtVTGUIhDistribuye las vistas del rea de trabajo en cascada*Arranges open windows in a cascade patternVTGUIhDistribuye las vistas del rea de trabajo en mosaico'Arranges open windows in a tile patternVTGUIC&errarC&loseVTGUIC&errar Vista C&lose viewVTGUICalcular... Calculate...VTGUIfCambia el modo de visualizacin del rea de trabajoChange the workspace view modeVTGUI:Cambiar modo de visualizacinChange view modeVTGUIPulsa para abrir un fichero Mantn pulsado para abrir un fichero reciente9Click to open a file Click and hold to open a recent fileVTGUICerrar &Todos Close &AllVTGUICerrar &TodoWindows -> Close All Close &AllVTGUI2Cierra todos los ficherosClose all filesVTGUI.Cierra todas las vistasClose all viewsVTGUI8Cierra la vista seleccionadaClose the active viewVTGUI<Cierra el fichero seleccionadoClose the selected fileVTGUIJCierra la vista del nodo seleccionado#Close the view of the selected nodeVTGUI$Configura ViTablesConfigure ViTablesVTGUI Ayuda contextual Context helpVTGUI4Copia el nodo seleccionadoCopy the selected nodeVTGUI*Crea un nuevo ficheroCreate a new fileVTGUI^Crea un nuevo filtro para la tabla seleccionada*Create a new filter for the selected tableVTGUIZCrea un nuevo grupo bajo el nodo seleccionado*Create a new group under the selected nodeVTGUICor&tarCu&tVTGUIVista actual Current ViewVTGUI4Corta el nodo seleccionadoCut the selected nodeVTGUIBorrar &Todos Delete &AllVTGUI4Borra el nodo seleccionadoDelete the selected nodeVTGUILMuestra informacin acerca de ViTables"Display information about ViTablesVTGUI\Muestra informacin acerca de la biblioteca Qt(Display information about the Qt libraryVTGUITMuestra el contenido del nodo seleccionado)Display the contents of the selected nodeVTGUI &SalirE&xitVTGUI4Operaciones Sobre FicherosFile operationsVTGUI Sistema de Ayuda Help systemVTGUIZMinimiza todas las vistas del rea de trabajo%Minimize all windows on the workspaceVTGUI.Operaciones Sobre NodosNode operationsVTGUI2Abrir Ficheros &RecientesOpen R&ecent FilesVTGUIAbre un ficheroOpen an existing fileVTGUIJAbrir un fichero en modo solo-lectura'Open an existing file in read-only modeVTGUI0Abre la Gua del UsuarioOpen the ViTables User's GuideVTGUIFPega el ltimo nodo copiado/cortadoPaste the last copied/cut nodeVTGUIProp&iedades...Prop&erties...VTGUI$Consultas a TablasQueries on tablesVTGUICierra ViTables Quit ViTablesVTGUI0Abrir en Solo-Lectura...Read-only open...VTGUIListo...Ready...VTGUI.Borra todos los filtrosRemove all filtersVTGUI:Renombra el nodo seleccionadoRename the selected nodeVTGUIrRecupera todas las vistas minimizadas del rea de trabajo.Restore all minimized windows on the workspaceVTGUILEjecuta un clculo en tablas abiertas.!Run calculation on opened tables.VTGUIhGuarda una copia renombrada del fichero seleccionado(Save a renamed copy of the selected fileVTGUI$Mostrar &VersionesShow &VersionsVTGUIvMuestra el dilogo de propiedades para el nodo seleccionado0Show the properties dialog for the selected nodeVTGUIxMuestra las versiones de las bibliotecas usadas por ViTables3Show the versions of the libraries used by ViTablesVTGUI|El nodo actualmente seleccionado en el rbol de bases de datos9The node currently selected in the Tree of databases paneVTGUI,Barras de herramientasToolBarsVTGUIViTables {0} ViTables {0}VTGUIVAyuda del tipo Qu es esto? para un widgetWhats this? help for a widgetVTGUIViTables-3.0.0/vitables/i18n/vitables_ru_RU.qm000066400000000000000000001357231311223072700211100ustar00rootroot00000000000000PT2P-os`ntEeE8~r9Wn C|*tE`)/BC/~wmY7n;c_Zc5Cgow.8zrKv+/6as+%% ׮lh#Nt~#cR= 0345.5 ?CMSb{YQ.]6|`9 fn`9 `S%rh/R w+IIhI* ,,i,O3^Bb@mv<ߟ.$3gzVuQvW?!2L0*1N@P4RU^'Zk}˅PF'IH55H5tpH5E5OIP։%ް?kq4Rek!"CGb_*R`#pb< >gSlm/8.3R4N6rnt^qlJdl>S^7g  0{:iwC_HEdL_Q] G*d<t s"e/i'i-O> :xCFI~`POw-fdzEYzYk19;q9U5]ntAnV]OS L XL  N\J +>. 2 2.V Um `Zm laFU laJ la| vL" t(  (c  ( ߲M?  y M>I #d2% 8f ;fc6 S m3 w5p . / d > oS I } Z^Z , , 11 ե u =C }z Te D -P D + L.Q {ƎQ {Ǝ b %X G 5TI^ D ɬ WU KGI RN g y + E W #e :@ G b( cn et1 T s A K ͳ^G ' 넓< ?$J >, .]n n ] $c= B}: I~ i$H js@ mnScv {h37 BF TB %} }?/3B8hV`l;`g>jitl&z]#^o|{e c[^Wo%N-jmQ's[~2vڮ3>BF BJ~q^20BL &Group ArraysArrayColsOrganizerR;LB5@=0B82=K9 <5B>4 >B>1@065=8O <0AA82>2

Plugin that provides an alternative view for arrays with the same number of rows.

The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.ArraysColsOrganizertH81:0: "{0}" =5 <>65B 1KBL ?@5>1@07>20=> 2 >1J5:B Python.5 Error: "{0}" cannot be converted to a Python object. AttrEditorH81:0: "{0}" ?@52KH5=8O 4>?CAB8<>3> 7=0G5=85 8;8 =5A>2?045=85 B8?0.@ Error: "{0}" value is out of range or mismatches its data type. AttrEditorDH81:0: "{0}" ?@52KH5=85 7=0G5=8O.$ Error: "{0}" value is out of range. AttrEditorfH81:0: "{0}" 7=0G5=85 =5 A>2?0405B A B8?>< 40==KE.- Error: "{0}" value mismatches its data type. AttrEditorxH81:0: ?>2B>@=>5 8A?>;L7>20=85 "{0}" 4;O 8<5=8 0BB@81CB0. ) Error: attribute name "{0}" is repeated. AttrEditorNH81:0: ?CAB>5 ?>;5 Name 2 AB@>:5{0:d} ) Error: empty field Name in the row {0:d} AttrEditorH>4B25@645=85 C40;5=8O 0BB@81CB0 {0}. You are about to delete the attribute: {0}  AttrPropDlgB<5=8BLCancel AttrPropDlg"8? 40==KEDatatype AttrPropDlg#40;8BLDelete AttrPropDlg<OName AttrPropDlg>K15@8B5 0BB@81CB 4;O C40;5=8O.+Please, select the attribute to be deleted. AttrPropDlg$#40;5=85 0BB@81CB0User attribute deletion AttrPropDlg=0G5=85Value AttrPropDlg&B<5=8BL&Cancel BookmarksDlg&#40;8BL&Delete BookmarksDlg&@8<5=8BL&OK BookmarksDlg0:;04:0Bookmark BookmarksDlg" 540:B>@ 70:;04>:Bookmarks editor BookmarksDlg !AK;:0URL BookmarksDlgtH81:0 GB5=8O 70?8A59. >7<>6=> ?>2@5645=8O =01>@0 40==KE.> Error: problems reading records. The dataset maybe corrupted.Buffer0H81:0 GB5=8O 40==KE: {}Data read error: {}BufferH81:0 GB5=8O 70?8A59. 01>@ 40==KE <>65B 1KBL A60B ?@8 ?><>I8 181;8>B5:8 {0}. #1548B5AL 2 55 CAB0=>2:5 =0 0H59 A8AB5<5.Problems reading records. The dataset seems to be compressed with the {0} library. Check that it is installed in your system, please.Bufferx ?@>F5AA5 2KG8A;5=8O 2>7=8:;> 8A:;NG5=8O, 45B0;8 2 6C@=0;5.?An exception was raised during evaluation, see log for details. Calculator ?@>F5AA5 A>E@0=5=8O @57C;LB0B0 2>7=8:;> 8A:;NG5=8O, 45B0;8 2 6C@=0;5.KAn exception was raised while trying to store results, see log for details. Calculator!>740BL 3@C??C Create group Calculator"H81:0 2KG8A;5=8OEvaluation error CalculatorK1@0=> 1>;55 >4=>9 3@C??K. B=>A8B5;L=K5 AAK;:8 =5 2>7<>6=K5. @>4>;68BL?IMultiple groups are selected. Relative references are disabled. Continue? Calculator<O:Name: Calculator@C??0 =5 2K1@0=0. B=>A8B5;L=K5 AAK;:8 =5 2>7<>6=K5. @>4>;68BL?ANo group is selected. Relative references are disabled. Continue? Calculator#75; =5 =0945=Node not found Calculator"8? C7;0 Node type CalculatorDB=>A8B5;L=K5 AAK;:0 701;>:8@>20=K Relative references are disabled Calculator&<O 4;O @57C;LB0B>2 Result name Calculator@H81:0 ?@8 A>E@0=5=88 @57C;LB0B0Result save error Calculator.!>E@0=8BL 2K@065=85 :0:Save expression as CalculatorT5 7040=> <5AB> 4;O A>E@0=5=8O @57C;LB0B>2.The location to store results is not specified Calculatorx<html><head/><body> <p>5AB> 4;O A>E@0=5=8O @57C;LB0B>2 2KG8A;5=89. !AK;:0 =0 =01>@ 40==KE ?@54AB02;O5B A>1>9 AB@>:C, A>AB>OICN 87 8<5= 3@C?? @0745;5==KE B>G:0<8. 0?@8<5@: &quot;filename.h5.some_group.sub_group.myresult&quot;. A;8 &quot;sub_group&quot; O2;O5BAO B5:CI59 3@C??>9, B> 2 :0G5AB25 AAK;:8 <>6=> 8A?>;L7>20BL AB@>:C &quot;myresult&quot;.</p> <p>"01;8F0, 2 :>B>@CN 1C45B A>E@0=5= @57C;LB0B, =5 4>;6=0 ACI5AB2>20BL.</p> </body></html>

Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.myresult". If "sub_group" is the current group then the string "myresult" can be used as reference.

The result table must not exitst.

CalculatorDialog<html><head/><body> <p>01>@ 2K@065=89 O7K:0 python, :>B>@K5 1C4CB 2K?>;=5=5K ?5@54 2KG8A;5=85< 2K@06=8O. 0==>5 ?>;5 <>65B 1KBL 8A?>;L7>20=> 4;O 8<?>@B0 <>4C;59 8;8 ?@5420@8B5;L=KE 2KG8A;5=89 4;O C?@>I5=8O 2K@065=8O.</p> </body></html>

Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.

CalculatorDialog<html><head/><body> <p> 57C;LB0B 2KG8A;5=8O 40==>3> 2K@065=8O 1C45B A>E@0=5= 2 B01;8F5. 0==>5 ?>;5 4>;6=> A>45@60BL 2K@065=85, :>B>@>5 2>72@0I05B pytables <0AA82, A?8A>: 8;8 A:0;O@.</p> <p>K@065=8O <>3CB A>45@60BL AAK;:8 =0 703@C65==K5 40==K5. !AK;:8 <>3CB 1KBL ;81> 01A>;NB=K<8 8 =0G8=0BLAO A 8<5=8 D09;0 8;8 >B=>A8B5;L=K<8. !AK;:0 =0 =01>@ 40==KE ?@54AB02;O5B A>1>9 AB@>:C, A>AB>OICN 87 8<5= 3@C?? @0745;5==KE B>G:0<8. 0?@8<5@: &quot;filename.h5.some_group.sub_group.mydata&quot;. A;8 &quot;sub_group&quot; O2;O5BAO B5:CI59 3@C??>9, B> 2 :0G5AB25 AAK;:8 <>6=> 8A?>;L7>20BL AB@>:C &quot;mydata&quot;.</p> </body></html>u

The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.

The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: "filename.h5.some_group.sub_group.mydata". If "sub_group" is the current group then the string "mydata" can be used as reference.

CalculatorDialog<html><head/><body><p>#40;8BL 2K45;5==>5 2K@065=8O 87 A?8A:0.</p></body></html>g

Remove the selected expression from the saved expressions list.

CalculatorDialog|<html><head/><body><p>!>E@0=5==K5 2K@065=8O.</p></body></html>:

Saved expressions.

CalculatorDialog<html><head/><body><p>!>E@0=8BL 2K@065=8O 4;O 40;L=59H53> 8A?>;L7>20=8O.</p></body></html>H

Store expression for future use.

CalculatorDialog&KG8A;8BL 2K@065=85Evaluate expressionCalculatorDialogK@065=8O: Expression:CalculatorDialog#40;8BLRemoveCalculatorDialog0"01;8F0 4;O @57C;LB0B>2: Result table:CalculatorDialog!>E@0=8BLSaveCalculatorDialog,!>E@0=5==K5 2K@065=8O:Saved expressions:CalculatorDialog><<0=4K: Statements:CalculatorDialogH81:0 :>=D83C@0F88: =0AB@>9:8 ?@8;>65=8O {0} =5 <>3CB 1KBL A>E@0=5=K.B Configuration error: the application setting {0} cannot be saved.ConfigFileIOException@54C?@5645=85: =0AB@>9:8 ?@8;>65=8O {0} =5 <>3CB 1KBL?@>G8B0=K. C4CB 8A?>;L7>20=K 7=0G5=8O ?> C<>;G0=8N.c Configuration warning: the application setting {0} cannot be read. Its default value will be used.ConfigFileIOException`H81:0: =5 2>7<>6=> >B:@KBL C75; {0} 2 D09;5 {1}) Error: cannot open node {0} in file {1} DBDoc@54C?@5645=85: >B:070=> 2 >B:@KB88 D09;0 2 @568<5 GB5=85/70?8AL. $09; 1C45B >B:@KB B>;L:> 4;O GB5=8O.X Warning: file access in read-write mode is denied. It will be opened in read-only mode.DBDoc>60;C9AB0, 5A;8 C 0A 5ABL ?>4>7@5=85 > =5:>@@5:B=>9 @01>B5 ?@>3@0<<K, A>>1I8B5 @07@01>BG8:0<.:Please, if you think it is a bug, report it to developers.DBDoc5 2>7<>6=> A>E@0=8BL D09; {0} :0: {1}. ">;L:> 70:@KBK5 D09;K <>3CB 1KBL 157>?0A=> ?5@570?8A0=K G5@57 Save As...jUnable to save the file {0} as {1}. Beware that only closed files can be safely overwritten via Save As...DBDoc{0}{0}DBDoc658725AB=0O >H81:0 ?@8 A>740=88 D09;0. 1@0B8B5 2=8<0=85 =0 ?>A;54=NN >H81:C. A;8 >=0 A2O70=0 A =5:>@@5:B=>9 @01>B>9 ?@>3@0<<K, B> A>>1I8B5 @07@01>BG8:0<. File creation failed due to unknownreasons! Please, have a look to the last error displayed in the logger. If you think it's a bug, please report it to developers. DBsTreeModelP!>740=85 D09;0 A @57C;LB0B0<8 70?@>A0..."Creating the Query results file... DBsTreeModelJ5@5<5I5=85 C7;0: C75; C65 ACI5AB2C5B"Node move: nodename already exists DBsTreeModel8B<5=0: D09; {0} C65 >B:@KB.)Opening cancelled: file {0} already open. DBsTreeModelFB<5=0: D09; {0} =5 2 D>@<0B5 HDF5.0Opening cancelled: file {0} has not HDF5 format. DBsTreeModel`H81:0: =5 2>7<>6=> >?@545;8BL D>@<0B D09;0 {0}.>Opening failed: I cannot find out if file {0} has HDF5 format. DBsTreeModel6H81:0: D09; {0} =5 =0945=.)Opening failed: file {0} cannot be found. DBsTreeModelJB<5=0 >B:@KB8O: {0} O2;O5BAO ?0?:>9.$Openning cancelled: {0} is a folder. DBsTreeModel5@58<5=>20BLRename DBsTreeModelAE>4=K9 D09;: {0} 5@5<5I5==K9 C75;: {1} $09; =07=0G5=8O: {2}  >48B5;LA:0O 3@C??0: {3} #75; A 8<5=5< {4} C65 ACI5AB2C5B 2 MB>9 3@C??5.xSource file: {0} Moved node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group.  DBsTreeModel$5@52> 107K 40==KETree of databases DBsTreeModelb;038= ?>72>;ONI89 A>@B8@>20BL 45@52> 107K 40==KE

Plugin that provides sorting capabilities to the tree of DBs.

At the moment only two sorting algorithms are supported: human (a.k.a. natural sorting) and alphabetical.DBsTreeSortingPage$5@52> 107K 40==KE

The Tree of databases

For every open database this widget shows the object tree, a graphical representation
of the data hierarchy stored in the database.
 DBsTreeViewJ04AB@>9:0 4;O M:A?>@B0 2 D>@<0B5 CSV

Plugin that provides export to CSV files capabilities.

Any kind of PyTables dataset can be exported. When exporting tables, a header with the field names can be inserted at top of the CSV file. ExportToCSV>CSV D09; (*.csv);;A5 D09;K (*) CSV Files (*.csv);;All Files (*) ExportToCSV"&-:A?>@B 2 CSV...E&xport to CSV... ExportToCSV(CAB>9 =01>@ 40==KE.!Empty dataset. Nothing to export. ExportToCSV-:A?>@BExport ExportToCSVl-:A?>@B =5 C40;AO B0:, :0: 2K1@0=K9 >1J5:B ?>4:0B0;>3.;Export failed because destination container is a directory. ExportToCSVxH81:0 ?@8 A>740=88 =>2>3> D09;0, B0: :0: >= C65 ACI5AB2C5B.6Export failed because destination file already exists. ExportToCSVF-:A?>@B =01>@0 40==KE 2 D>@<0B5 CSVExporting dataset to CSV format ExportToCSVH!>E@0=8BL =01>@ 40==KE 2 D>@<0B5 CSV0Save the dataset as a plain text with CSV format ExportToCSVN4=><5@=K9 <0AA82, M:A?>@B =5 2>7<>65=. Scalar array. Nothing to export. ExportToCSVx5:>B>@K5 87 ?>;59 =5 O2;ONBAO G8A;0<8. -:A?>@B =5 2>7<>65=.CSome fields aren't scalars. I can't export the table to CSV format. ExportToCSVK1@0==K9 C75; 8<55B @07<5@=>ABL 1>;LH5 2-E. -:A?>@B 2 CSV =5 2>7<>65=.NThe selected node has more than 2 dimensions. I can't export it to CSV format. ExportToCSVvK1@0==K9 C75; O2;O5BAO VLArray. -:A?>@B 2 CSV =5 2>7<>65=.@The selected node is a VLArray. I can't export it to CSV format. ExportToCSV!2>9AB20 D09;0File properties GroupPropDlg!2>9AB20 3@C??KGroup properties GroupPropDlg<O =0A;54=8:0 Child name GroupPropPage @C??0Group GroupPropPage"8?Type GroupPropPage 3@C??0group GroupPropPage;8ABleaf GroupPropPage AAK;:0link GroupPropPageHelpBrowser3

HelpBrowser

HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs.

Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit. HelpBrowser HelpBrowserAbout HelpBrowser HelpBrowser QtAbout Qt HelpBrowser &HelpBrowser&About HelpBrowserHelpBrowserGUI$>1028BL &70:;04:C &Add bookmarkHelpBrowserGUI &0704 &BackwardHelpBrowserGUI&0:;04:8 &BookmarksHelpBrowserGUI&G8AB8BL 2A5 &Clear AllHelpBrowserGUI4& 540:B8@>20BL 70:;04:8...&Edit bookmarks...HelpBrowserGUI &$09;&FileHelpBrowserGUI&?5@54&ForwardHelpBrowserGUI&5@59B8&GoHelpBrowserGUI&!?@02:0&HelpHelpBrowserGUI &><>9&HomeHelpBrowserGUI&1=>28BL&ReloadHelpBrowserGUI&84&ViewHelpBrowserGUIK1>@ AB@0=8F5[

Page selector

Select the page you want to visit.
HelpBrowserGUI  &Qt About &QtHelpBrowserGUI HelpBrowserAbout HelpBrowserHelpBrowserGUI QtAbout QtHelpBrowserGUIH!>740BL 70:;04:C A B5:CI59 AB@0=8F59Bookmark the current pageHelpBrowserGUI*#?@02;5=85 70:;04:0<8Bookmarks operationsHelpBrowserGUIDG8AB8BL 2A5 ACI5AB2CNI85 70:;04:8Clear all existing bookmarksHelpBrowserGUI G8AB8BL 8AB>@8N Clear historyHelpBrowserGUI G8AB8BL 8AB>@8N)Clear the content of the history comboboxHelpBrowserGUI*0:@KB85 4>:C<5=B0F88Close Help BrowserHelpBrowserGUI.#<5=LH8BL @07<5@ H@8DB0Decreases the font sizeHelpBrowserGUI*@>A<>B@ 4>:C<5=B0F88Documentation browserHelpBrowserGUI &KE>4E&xitHelpBrowserGUI, 540:B8@>20BL 70:;04:8Edit bookmarksHelpBrowserGUI*#?@02;5=85< ?5@5E>4>< Go operationsHelpBrowserGUI85@59B8 : A;54CNI59 AB@0=8F5Go to next pageHelpBrowserGUI:5@59B8 : ?@54K4CI59 AB@0=8F5Go to previous pageHelpBrowserGUIH5@59B8 : ?5@2>9 ?>A5I5==>9 AB@0=8F5Go to the first visited pageHelpBrowserGUI5@59B8:Go: HelpBrowserGUI!?@02:0History operationsHelpBrowserGUI.#25;8G8BL @07<5@ H@8DB0Increases the font sizeHelpBrowserGUI>B>2...Ready...HelpBrowserGUI21=>28BL B5:CICN AB@0=8FCReload the current pageHelpBrowserGUI #?@02;5=85 284><View operationsHelpBrowserGUI&#25;8G8BLZoom &inHelpBrowserGUI#&<5=LH8BL Zoom &outHelpBrowserGUIT04AB@>9:0 4;O 8<?>@B0 40==KE 87 CSV D09;0

Plugin that provides import CSV files capabilities.

CSV files can be imported into any of the following PyTables containers: Array, EArray, CArray and Table.

When a file is imported into a Table automatic header detection is provided.

Beware that importing large files is a potentially slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO. ImportCSV>CSV D09; (*.csv);;A5 D09;K (*) CSV Files (*.csv);;All Files (*) ImportCSV 0==K5Data ImportCSVr'B> A>45@68B ?5@20O AB@>:0? 03>;>2>: B01;8FK 8;8 40==K5?GDoes the first line of the file contain a table header or regular data? ImportCSV03>;>2>:Header ImportCSV"&<?>@B 87 CSV...I&mport from CSV... ImportCSV <?>@BImport ImportCSV0<?>@B8@>20BL &<0AA82...Import &Array... ImportCSV0<?>@B8@>20BL &CArray...Import &CArray... ImportCSV0<?>@B8@>20BL &EArray...Import &EArray... ImportCSV2<?>@B8@>20BL &B01;8FC...Import &Table... ImportCSVB<?>@B8@>20BL <0AA82 87 D09;0 CSV Import Array from plain CSV file ImportCSVB<?>@B8@>20BL <0AA82 87 D09;0 CSV!Import CArray from plain CSV file ImportCSVB<?>@B8@>20BL <0AA82 87 D09;0 CSV!Import EArray from plain CSV file ImportCSV6<?>@B B01;8FK 87 D09;0 CSV Import Table from plain CSV file ImportCSV`<?>@B =5 C40;AO, B0: :0: >1J5:B C65 ACI5AB2C5B.;Import failed because destination container is a directory. ImportCSV\<?>@B =5 C40;AO B0:, :0: D09; C65 ACI5AB2C5B.6Import failed because destination file already exists. ImportCSVh<?>@B =5 C40;AO, B0: :0: D09; =5 <>65B 1KBL A>740=.9Import failed because destination file cannot be created. ImportCSV,<?>@B CSV D09;0 2 {0}Importing CSV file into {0} ImportCSV\#1548B5AL, GB> 8<?>@B8@C5<K5 40==K5 >4=>@>4=K.?Please, make sure that you are importing a homogeneous dataset. ImportCSV<?@545;5=85 B8?0 ?5@2>9 AB@>:8Resolving first line role ImportCSV !2>9AB20 <0AA820Array properties LeafPropDlg!2>9AB20 ;8AB0Table properties LeafPropDlg-- LeafPropPage<O ?>;O Field name LeafPropPage $>@<0Shape LeafPropPage"8?Type LeafPropPage2;>65==K9nested LeafPropPage!2>9AB20 AAK;:8Link properties LinkPropDlg&>?8@>20BL&CopyLogger C@=0;K

The Logger

This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user.

Also execution errors and exceptions are logged in the console. Logger&G8AB8BL 2A5 Cl&ear AllLoggerV!:>?8@>20BL 2K45;5==K9 C75; 2 1CDD5@ >1<5=0Copy selected text to clipboardLoggerG8AB8BL 6C@=0;Empty the LoggerLogger&K45;8BL 2A5 Select &AllLogger>K45;8BL 2A5 A>45@68<>5 6C@=0;0 Select the whole Logger contentsLogger& 0718BL 3@C??C&Ungroup Arrays MenuUpdater<#1@0BL 3@C??8@>20=85 <0AA82>2."Ungroup previously grouped arrays. MenuUpdaterA?>;L7>20BL A?5F80;878@>20==K9 M;5<5=B 4;O >B>1@065=8O <0AA82>2 2 2845 AB>;1F>2 B01;8FKIUse a unique widget to display Arrays as if they where columns of a Table MenuUpdaterR5@58<5=>20=85 C7;0: 8<O C65 8A?>;L7C5BAO$Renaming a node: name already in useNodeItemDelegateAE>4=K9 D09;: {0}  >48B5;LA:0O 3@C??0: {1} #75; A 8<5=5< {2} C65 ACI5AB2C5B 2 @>48B5;LA:>9 3@C??5.^Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. NodeItemDelegate 1I85 General  Preferences ;038= Plugins  Preferences=5H=89 284 Look & Feel Preferences8?8A0=85 ?;038=0 >BACBAB2C5B2Sorry, there are no info available for this plugin PreferencesB<5=8BLCancelQueriesManagerHG8AB:0 D09;0 A @57C;LB0B0<8 70?@>A0Cleaning the Query results fileQueriesManager#40;8BLDeleteQueriesManagerDH81:0 ?@8 70?@>A5 87 B01;8FK {0}!Query on table {0} failed!QueriesManager5:>B>@K5 87 AB>;1F>2 A>45@60B <=>3> @07<5@=K5, 2;>65==K5 8;8 :><?;5:A=K5 40==K5. 0?@>A : =8< =5 2>7<>65=.Some table columns contain multidimensional, nested or Complex data. They cannot be queried so are not included in the Column selector of the query dialog.QueriesManager,"01;8F0 {0} =5 A>45@68B AB>;1F>2, :>B>@K5 <>3CB 1KBL 8A?>;L7>20=K 2 70?@>A5. A5 AB>;1FK 2;>65=K, 1>;LH>9 @07<5@=>AB8 8;8 A>45@60B :><?;5:A=K5 40==K5.vTable {0} has no columns suitable to be queried. All columns are nested, multidimensional or have a Complex data type.QueriesManagerL"01;8F0 {0} ?CAB0O. 0?@>A =52>7<>65=.%Table {0} is empty. Nothing to query.QueriesManagerF2548B5 8<O 4;O AB>;1F0 A 8=45:A0<8.Enter a name for the column of indices, pleaseQueryDlg8>2K9 70?@>A 87 B01;8FK: {0}New query on table: {0}QueryDlgnK@0==>5 8<O AB>;1F0 C65 8A?>;L7C5BAO. K15@8B5 4@C3>5.YThe chosen name for the column of indices is already in use. "Please, choose another one.QueryDlgvK@0==>5 8<O AB>;1F0 A 8=45:A0<8 =5 <>65B 1KBL 8A?>;L7>20=>QThe chosen name for the column of indicesis not valid. It contains '/' charactersQueryDlg^K@0==>5 8<O C65 8A?>;L7C5BAO. K15@5B5 4@C3>5.>The chosen name is already in use. Please, choose another one.QueryDlgj0G0;L=>5 7=0G5=85 1>;LH5 :>=5G=>3>. K15@8B5 4@C3>5.KThe start value is greater than the stop value. Please, choose another one.QueryDlgV0G0;L=>5 7=0G5=85 4>;6=> 1KBL 1>;LH5 =C;O.'The start value must be greater than 0.QueryDlg0:A8<0;L=>5 7=0G5=85 1>;LH5 G8A;0 AB@>:. K15@8B5 4@C3>5 7=0G5=85.NThe stop value is greater than the number of rows. Please, choose another one.QueryDlg5@570?8A0BL Overwrite RenameDlg5@58<5=>20BLRename RenameDlgF;038= 4;O >B>1@065=8O ?>;O 2@5<5=8(

Plugin that provides nice string formatting for time fields.

It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. TimeFormatterPage>>4B25@645=85 C40;5=8O C7;0 {0}' You are about to delete the node: {0} VTApp& ?@>3@0<<5&AboutVTApp&8F5=78O&LicenseVTApp&;03>40@=>AB8 &Thanks ToVTApp

ViTables {0}

ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.

For more information see http://www.vitables.org.

Please send bug reports or feature requests to the ViTables Users Group.

ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. VTApp Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.

Kamil Kisiel and Max Bohnet for fixing bugs.

Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.

Oxygen team for a wonderful icons set.

All the people who reported bugs and made suggestions. VTApp QtAbout QtVTApp. =5@50;87>20==KE C7;0EAbout UnImplemented nodesVTApp ViTables {0}About ViTables {0}VTApp4 =5G8B05<KE =01>@5 40==KEAbout unreadable datasetsVTAppActual data for this node are not accesible.<br> The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.<br>If you want to see this kind of dataset implemented in PyTables, please, contact the developers.Actual data for this node are not accesible.
The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.
If you want to see this kind of dataset implemented in PyTables, please, contact the developers.VTAppB<5=8BLCancelVTApp0!>740=85 :>=D83C@0F88...Configuration setup...VTApp(>?8@>20=85 D09;0...Copying a file...VTApp!>740BLCreateVTApp!>740BLA button labelCreateVTApp0!>740=85 =>2>3> D09;0...Creating a new file...VTApp*!>740=85 =>2>9 3@C??KCreating a new groupVTAppV!>740=85 =>2>9 3@C??K: 8<5 C65 8A?>;L7C5BAO)Creating a new group: name already in useVTApp!>740=85 GUI...Creating the GUI...VTApp#40;8BLDeleteVTAppR!>E@0=5=85 D09;0 :0:: D09; C65 ACI5AB2C5B!File Save as: file already existsVTAppf$09;K HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;A5 D09;K (*)3HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*)VTAppf$09;K HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;A5 D09;K (*) Filter for the Save As... dialog3HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*)VTAppHH81:0 ?@8 GB5=88 A?8A:0 D09;>2 HDF5List of HDF5 files not readVTAppxH81:0 ?@8 A>740=88 =>2>3> D09;0, B0: :0: >= C65 ACI5AB2C5B.5New file creation failed because file already exists.VTApp#40;5=85 C7;0 Node deletionVTAppbAB02:0 C7;0: C75; A 40==K< 8<5=5< C65 ACI5AB2C5B#Node paste: nodename already existsVTAppB:@KBLOpenVTAppfH81:0 ?@8 >B:@KB88: >H81:0 {0} 2 AB@>:5 {1} 87 {2},Opening failed: wrong {0} in line {1} of {2}VTApp"B:@KB85 D09;0...Opening files...VTApp2B:@KB85 A?8A:0 D09;>2...Opening the list of files...VTAppAB028BLPasteVTAppF>AAB0=>2;5=85 ?@54K4CI59 A5AA88...Recovering last session...VTApp5@58<5=>20=85RenameVTApp&5@58<5=>20=85 C7;0Renaming a nodeVTAppR5@58<5=>20=85 C7;0: 8<O C65 8A?>;L7C5BAO$Renaming a node: name already in useVTAppK15@8B5 D09;Select a file for openingVTAppz0==K5 4;O 40==>3> C7;0 =54>ABC?=K. #75; =5 1C45B A:>?8@>20=.SSorry, actual data for this node are not accesible.
The node will not be copied.VTAppAE>4=K9 D09;: {0} 5@5<5I5==K9 C75;: {1} $09; =07=0G5=8O: {2}  >48B5;LA:0O 3@C??0: {3} #75; A 8<5=5< {4} C65 ACI5AB2C5B 2 MB>9 3@C??5.ySource file: {0} Copied node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. VTAppVAE>4=K9 D09;: {0}  >48B5;LA:0O 3@C??0: {1}$Source file: {0} Parent group: {1} VTAppVAE>4=K9 D09;: {0}  >48B5;LA:0O 3@C??0: {1}%Source file: {0} Parent group: {1} VTAppAE>4=K9 D09;: {0}  >48B5;LA:0O 3@C??0: {1} #75; A 8<5=5< {2} C65 ACI5AB2C5B 2 @>48B5;LA:>9 3@C??5.^Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. VTAppT>4:0B0;>3 {0}. $09; {1} C65 8A?>;L7C5BAO.GTarget directory: {0} File name {1} already in use in that directory. VTApp>4:0B0;>3 {0}. 070 40==KE A 70?@>A0<8 =5 <>65B 1KBL ?5@570?8A0=0.HTarget directory: {0} The Query results database cannot be overwritten.VTAppf>4:0B0;>3{0}. $09; =5 <>65B ?5@570?8A0BL A0< A51O.DTarget directory: {0} The file being saved cannot overwrite itself.VTApp 5@A88Version NumbersVTAppViTables {0} Copyright (c) 2008-2013 Vicent Mas. All rights reserved.EViTables {0} Copyright (c) 2008-2013 Vicent Mas. All rights reserved.VTApp=5 4>ABC?=> not availableVTApp& ViTables&About ViTablesVTGUI0A:0&4&CascadeVTGUI&G8AB8BL&ClearVTGUI&0:@KBL&CloseVTGUI&>?8@>20BL&CopyVTGUI01>@ &40==KE&DatasetVTGUI&#40;8BL&DeleteVTGUI &$09;&FileVTGUI&!?@02:0&HelpVTGUI&8=8<878@>20BL &Minimize AllVTGUI&>;LH5...&More...VTGUI$!>740BL &3@C??C... &New group...VTGUI&!>740BL...&New...VTGUI &#75;&NodeVTGUI&B:@KBL 284 &Open viewVTGUI&B:@KBL...&Open...VTGUI&AB028BL&PasteVTGUI&0AB@>9:8...&Preferences...VTGUI0&?@>A... &Query...VTGUI"&5@58<5=>20BL... &Rename...VTGUI"&>AAB0=>28BL 2A5 &Restore AllVTGUI"!>E@0=8BL &:0:... &Save as...VTGUI&0AB@>9:8 &SettingsVTGUI&;8B:8&TileVTGUI& C:>2>4AB2> &User's GuideVTGUI &:=>&WindowVTGUI0A=>2=0O @01>G0O >1;0ABL

The Workspace

This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously.

The diferent views can be tiled as a mosaic or stacked as a cascade. VTGUI  &Qt About &QtVTGUIF 07<5AB8BL 2K45;5==K5 >:=0 :0A:04><*Arranges open windows in a cascade patternVTGUIF 07<5AB8BL 2K45;5==K5 >:=0 ?;8B:0<8'Arranges open windows in a tile patternVTGUI&0:@KBLC&loseVTGUI&0:@KBL 284 C&lose viewVTGUI0;L:C;OB>@... Calculate...VTGUIP7<5=8BL @568< >B>1@065=8O @01>G59 A@54KChange the workspace view modeVTGUI47<5=8BL @568< >B>1@065=8OChange view modeVTGUI4=> =060B85 4;O >B:@KB8O D09;0. 060BL 8 C45@6820BL 4;O >B:@KB8O =5402=> 8A?>;L7>20==>3> D09;09Click to open a file Click and hold to open a recent fileVTGUI0:@KBL &2A5 Close &AllVTGUI0:@KBL &2A5Windows -> Close All Close &AllVTGUI"0:@KBL 2A5 D09;KClose all filesVTGUI 0:@KBL 2A5 >:=0Close all viewsVTGUI(0:@KBL 0:B82=K9 284Close the active viewVTGUI.0:@KBL 2K45;5==K9 D09;Close the selected fileVTGUI80:@KBL 284 2K45;5==>3> C7;0#Close the view of the selected nodeVTGUI67<5=8BL =0AB@>9:8 ViTablesConfigure ViTablesVTGUI&>=B5:AB=0O A?@02:0 Context helpVTGUI4>?8@>20BL 2K45;5==K9 C75;Copy the selected nodeVTGUI$!>740BL =>2K9 D09;Create a new fileVTGUIV!>740BL =>2K9 D8;LB@ 4;O 2K45;5==>9 B01;8FK*Create a new filter for the selected tableVTGUI(!>740BL =>2CN 3@C??C*Create a new group under the selected nodeVTGUIK&@570BLCu&tVTGUI"5:CI89 284 Current ViewVTGUI0K@570BL 2K45;5==K9 C75;Cut the selected nodeVTGUI#40;8BL &2A5 Delete &AllVTGUI.#40;8BL 2K45;5==K9 C75;Delete the selected nodeVTGUI<>:070BL 8=D>@<0F8N > ViTables"Display information about ViTablesVTGUI4B>1@078BL 8=D>@<0F8N > Qt(Display information about the Qt libraryVTGUILB>1@078BL A>45@60=85 2K45;5==>3> C7;0)Display the contents of the selected nodeVTGUI &K9B8E&xitVTGUI  01>B0 A D09;0<8File operationsVTGUI!8AB5<0 ?><>I8 Help systemVTGUI.8=8<878@>20BL 2A5 >:=0%Minimize all windows on the workspaceVTGUI 01>B0 A C7;0<8Node operationsVTGUI$B:@KBL &?>A;54=85Open R&ecent FilesVTGUIB:@KBL D09;Open an existing fileVTGUIVB:@KBL ACI5AB2CNI89 D09; B>;L:> 4;O GB5=8O'Open an existing file in read-only modeVTGUI@B:@KBL @C:>2>4AB2> ?>;L7>20B5;OOpen the ViTables User's GuideVTGUI`AB028BL ?>A;54=89 A:>?8@>20==K9/2K@570==K9 C75;Paste the last copied/cut nodeVTGUI&!2>9AB20...Prop&erties...VTGUI"0?@>A 87 B01;8FKQueries on tablesVTGUI$K9B8 87 ?@>3@0<<K Quit ViTablesVTGUI*B:@KBL 4;O GB5=8O...Read-only open...VTGUI>B>2...Ready...VTGUI&#40;8BL 2A5 D8;LB@KRemove all filtersVTGUI:5@58<5=>20BL 2K45;5==K9 C75;Rename the selected nodeVTGUI\>AAB0=>28BL @07<5@ 2A5E <8=8<878@>20==KE >:>=.Restore all minimized windows on the workspaceVTGUIj@>8725AB8 2KG8A;5=8O =04 40==K<8 87 >B:@KBKE B01;8F.!Run calculation on opened tables.VTGUI>!>E@0=8BL D09; ?>4 =>2K< 8<5=5<(Save a renamed copy of the selected fileVTGUI5@A&88Show &VersionsVTGUIHB>1@078BL A2>9AB20 2K45;5==>3> C7;00Show the properties dialog for the selected nodeVTGUIh>:070BL 8=D>@<0F8N > 25@A8OE 8A?>;L7C5<KE 181;8>B5:3Show the versions of the libraries used by ViTablesVTGUIZK45;5==K9 M5;5<5=B 2 >:=5 45@520 107K 40==KE9The node currently selected in the Tree of databases paneVTGUI"=>?:8 C?@02;5=8OToolBarsVTGUIViTables {0} ViTables {0}VTGUI&><>IL 4;O M;5<5=B0Whats this? help for a widgetVTGUI ) , ViTables-3.0.0/vitables/icons/000077500000000000000000000000001311223072700161455ustar00rootroot00000000000000ViTables-3.0.0/vitables/icons/16x16/000077500000000000000000000000001311223072700167325ustar00rootroot00000000000000ViTables-3.0.0/vitables/icons/16x16/application-exit.png000066400000000000000000000015121311223072700227110ustar00rootroot00000000000000PNG  IHDRabKGD pHYsvv}ՂtIME  )xoIDATxڍkTW?7o^f2$'u\4?Ԫ *Em.ڕJv]A6]tbn\ؒt!313̼_yxt!҅spUk~hݛ}[ `w{je匪_t/5E ʹTΝcX$􌷶F$:@'E|6aD\I߀"[JT6Cd1:Fg0Zby_wV p~r+s( Ey_Q[¼ m a)s [782ٯ.&m2dȴ P7VjrNr*ji?1^.i;ju-_7ATV=buwp"@Al [YB$CZV;[_MxPZ#*jR!:yIENDB`ViTables-3.0.0/vitables/icons/16x16/array.png000066400000000000000000000002611311223072700205550ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  d_tIME -#=;>IDAT8c ceźD1!sb( $@!`1НGh D;|Qt*IENDB`ViTables-3.0.0/vitables/icons/16x16/bookmark_add.png000066400000000000000000000013731311223072700220610ustar00rootroot00000000000000PNG  IHDRaIDAT8}MhTgޛ 77Q$Ăh@"XUP]((JMWh(B&Sݨ i7mRL)P&ڦt~2wE8x,9yp^Tʱ m#T UZj~:_ȥ3LeSPM熵?A sPȀJ/fuկ2 b*Ubh!=t O7BJo|g4Es蚎xȩѲ7ևU[|UJ.]W!b4o`Ҩ5 $Vz?ksisIDF^>7$2'ꂥNIw/uqVʟ>`PȈDAF ̌XG27$_,{ w-֏6Ke=]6p;mIENDB`ViTables-3.0.0/vitables/icons/16x16/bookmarks.png000066400000000000000000000014311311223072700214270ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYsu85tIME 9 ~IDATxڍKHQqV`PFDPHRIE(peERB)pQ醂$)Y c&23?rN'+=p8;1V^2vd76@:63Y\.u5;DBSTmp93}w6jbu8Ssw=Qy/CJJLj ៮S|{чg\dGFEjfQiZny釈`A'^!m3nw<8ZSFo)=pYp dIdU@I2`!pp&85&44 xz;ɧvFsYR$ }Ij)4z\\c`[E}(|ɚ|04!3&QVE0󣿣c#j[g:eH Ry`"}6ӇO>|ֲl/Jbٔ4 ,ūz\B ŅR=^hbn2M H>H@aA"ƪ*r  ,9E ,핎UU6̩( nQ sCwb&Y6s񄅏 ,MN06?;٭\ٓZX`֬mUF\SzO[.%~<{sIENDB`ViTables-3.0.0/vitables/icons/16x16/carray.png000066400000000000000000000003161311223072700207210ustar00rootroot00000000000000PNG  IHDRa pHYs  d_IDAT8 Du5ˁ~&zGKy9b J,<2vr Tg|\ Q.l%QB\Eb+3D&>dZ$" 7DnmXߺxIENDB`ViTables-3.0.0/vitables/icons/16x16/configure.png000066400000000000000000000013151311223072700214210ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs^tIME7WMIDATxڍ]HqƏFldEGaBY]Uaز.jЖԄH؇5c.f`F_LPY cn6vkms<AL$b++H>>h1B>ԍC edydNkuRYM +_?Q2|NamʶAnXp8 T ܝL&X0t)<@*c(B!pUU~7%k9h[Ys/ۢ_y3ss's-D>`? W70ذ>tW)mVuFIXOA`Lhtpp[{k1s߇\.d=^k8MY_gr7@4x3$Wȑw‹8R`^N[REDly#O8ChWXSM᠖bL mu߂t:-"IΨ1HĚAD[|5tjdP*멁=SSq.`Xs(=&6Wwq`,.hxٗ_m_ BNIENDB`ViTables-3.0.0/vitables/icons/16x16/delete_filters.png000066400000000000000000000011361311223072700224330ustar00rootroot00000000000000PNG  IHDRa%IDAT8kQϼyLm4PBH YE+54Y 7.ҿUAt*](B[0HblI8i޼*iŅs{U'dY_?X46$Q߮#j5l1@}B7b.F5f;׋ݝ`A>{cqvL&\,c` ݆K߾d P8p{pxszzz*JAu!tnW3砌>84岶0gOUUH)8VzZzNG.j*?B BWyر|inM} %  "&LL>AF*  ɛahe!"V0Lf٪eYn.kpo$I>;0;;cJ( 0|D6kkk]z>8*dCj'If18Ny~^7`TQ35Jj:IENDB`ViTables-3.0.0/vitables/icons/16x16/dialog-cancel.png000066400000000000000000000015201311223072700221200ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATxڥMHqƟ|:3~jiA u D vB'!(I:DI*iV~E&+NL u鹼&=f ] +\[;wm M싗A^ߖXgc_촃wA ay`P-in>UfCYi޾!X.CQ1&TU8XAƆo 1-)'++>_6Sڝ&EY햤,a< G|mfǀR~)Z@ln131e䪱k[ZDI OOPЄ8m?. [y m+Ʀg-Cnēb0 kAAGMeq  at5h8,466!2 &n'`sr-Ag#2Y !j?$WVpKefvXTUU !ѯ qDJH~#/S̅7HbjSVO7qr$3l4"6@#Xq hK=E}KoocA&8B阋ᚚUNs VIQIK)J1{"؊].F 4IENDB`ViTables-3.0.0/vitables/icons/16x16/dialog-ok.png000066400000000000000000000011311311223072700213020ustar00rootroot00000000000000PNG  IHDR(-SsBITO pHYs:tEXtSoftwarewww.inkscape.org<PLTE;7 5 9 #5>777 <;:: : 9 ; : ?"B!C"? = ; : 7 %K7Y'M1U2M5V5Z5\3Z0W4V9_5S1F0@1>4?/Mv*DS,Hi-F]3LW5LZ6R^;ToD_yD`MjzOjPmQkRoTpUqVpZv[v[w]z_|`}b}b~bbc{defgghiioptt}~ȫm-tRNS !.38G2sC2] `IENDB`ViTables-3.0.0/vitables/icons/16x16/document-close.png000066400000000000000000000012461311223072700223640ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<#IDATxukAJ~R1UIsAx[[<޼+*BVE%л? H5X"BnwV6yy2!c YG t`+?]m!* n5 c4Y8ۻ872T R^+J{}߇>*NNB!ΪB9ߑʸTZ[Wxs:.*Riv \OSҴg `lBN$<#+%T0cI6l[aH⑰eYh4rDR^'\tJAgj#C۶ ݵ(< pg$,-O_أxIRccQIENDB`ViTables-3.0.0/vitables/icons/16x16/document-new.png000066400000000000000000000011031311223072700220400ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATxڍkSQsrAR*9݌uS?h%ԂC j=BM%͇p_?q}.+\,e/gr@I0ƞAkmJvxiMΥ%6NO>W AMcX R)o@{Nˋe#5B vYgnVФtIWL&{\832w" N> ǁNAhB/c䥯DTc р/R!=LL~ Q )ˤ$S4NS&%)&! er t$=EB_l6 @` Mۂ6jT ?7M`6{qq{|E˙80h4-v6+gm8:oxwa\$ÕJŘy nVFu:*VP`qt,܄ Q0L7Zij5b;R^]bl]}}X*X(h&+f`tNtƘ~g@g~Whj[IIENDB`ViTables-3.0.0/vitables/icons/16x16/document-open.png000066400000000000000000000010231311223072700222110ustar00rootroot00000000000000PNG  IHDR(-SsBITO pHYs B(xtEXtSoftwarewww.inkscape.org<PLTEBBBA!d#k#l)q1f1w:~ACH|KTUhnrxy~~씥ᘼ.` tRNS<>? /IDATAJQ/ < ;nt2cUH 77s|MgL^j⼌];k9vLB&`$fI"b&\ IlY S $p?,!ՀIENDB`ViTables-3.0.0/vitables/icons/16x16/document-save-as.png000066400000000000000000000015071311223072700226160ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATxڝ[HSq?l6Hl 2X-SbF$(GADt/ *n%/vjs,9y@]}v#qEkAyHM?Y.ϯΙWzd "@lc ) &N ^2(EʖqMuOt[}>eH"a֠008y1d +O7# 5 UUEX\8 &ȵ<ݚF(eߴ$2bOMhvTQ~mG֛!-/0izpp=RcL~M.G/Cl(SɰH23%Lnm3sbt.6 p ƻם4l[ޡ/(LY{Do<'7 jl\q%"wVK?}X6FA?'+g$Y8V6nt^~n38 rIO7PqB:EdYy`DA ݓl'bb;Wap:B!խV+X bqJ5 $r&Rń^@$уQEG03elYŬl.*eJ@d}ii'-Ŷp"!4cæ@D3)fD[BIENDB`ViTables-3.0.0/vitables/icons/16x16/edit-copy.png000066400000000000000000000007451311223072700213430ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYsu85tIME#;bgeIDATxڕJ@g7^<VTJ%w:l蚐||owV|FpXH~!CMW71`5U7 A)8٦s&q  - v9Nȩ5+/FHl61sH VV^# =y" 1L{U3gHS`@l6`> hBD( :z=u]Qݬv+7ggZ?&ߐo$ fY /_ TJa8Q)hȀ4M1sj'w&65*%~.W8}/}>45 "[hf +0h q{+}IENDB`ViTables-3.0.0/vitables/icons/16x16/edit-cut.png000066400000000000000000000005601311223072700211570ustar00rootroot00000000000000PNG  IHDR7sBITUF pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxm1jQE@M. 2L Hkeq@H3CAH5AEs/ݏC/3ZZFQ6Uc¤+aRi~ev4[ [Jaf33%\dG="FRh̊b-ik`eM.0ʛ[_m=Wn†xㅎюߡzN|(!Xsr 䋰(IENDB`ViTables-3.0.0/vitables/icons/16x16/edit-delete.png000066400000000000000000000012011311223072700216170ustar00rootroot00000000000000PNG  IHDR(-SsBITO pHYs:tEXtSoftwarewww.inkscape.org<PLTEnmj++$xuJI`]4*G?!#$'1&+J?J@LCVL#!#!>4C:j#j# {<2Y![!93 33MH::92  >>D?NJFF VVWTe`b^`]caha/*0,2-2.sqmmvu鍉cA!4tRNS222HHHHHHIIIJKOPQRnbIDATE("vwwbbwϡt 6 #όЧ_>rMͅfD|y&ΓȘؠ?lq?tl7"4aVjcdzVVM}YxlcC@F8,\Ckzl?IENDB`ViTables-3.0.0/vitables/icons/16x16/edit-paste.png000066400000000000000000000010211311223072700214710ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATxڅSOP4qf?_j,,$+)N2q&2&I4z\~^wW%`t:+|~}8gtڀHf!(J_d28VT*Bir| !(d۶mr<UUq(IٌqLSj a|9bXM3˝ 0 Ƙp!+{1v_Ǔod~Z}4-ۉ=6/-eHCIENDB`ViTables-3.0.0/vitables/icons/16x16/edit-rename.png000066400000000000000000000003651311223072700216360ustar00rootroot00000000000000PNG  IHDRRsBITO pHYs:tEXtSoftwarewww.inkscape.org<'PLTEO$tRNS;Nq1IDATc` "@ X`}&،W77{&DIENDB`ViTables-3.0.0/vitables/icons/16x16/file_ro.png000066400000000000000000000014741311223072700210650ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME  0IDAT8u]e3;ik֖іD҅ EK"B^Ex]]hJ.YAI([e]⊂hͮlyI9p8@q=,/(F|ݳ8KK 7S9 /.]913=41qs.Qȡ W;#m9<ڳɧ1sf4ETNhxC#yBvGU̖֯싣o^`Kcʅ)N9صrqV_5QlM蔿b\ӻSn7WLk@9F*g'96uDy_g^yَfд/JAi:aS\I= R{RO>cMk&3Ө@!ڞ`3 HgkhO=6Lչdf0P[? =D57Հd13{cyDJ{P5sx5ە:\H.IENDB`ViTables-3.0.0/vitables/icons/16x16/file_rw.png000066400000000000000000000021451311223072700210710ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbdb, 3fx?ç_JkXX9o^8~O&fbf@<hÏr*zw-2ݷLSl5Ïo@9t@ <@Sx .ǷZ9:W|>CsW߻}G 11367)eN bLpm27W1{AFX!߹[<4/b XkqiXT<{ 01#Þ[D݊x.ݻp@  430|dc|]ޓ 5_2V^.. b{߹v00o0 ,|'-)^(2Ô@25  O2H3Vr}[Znb w?15@ͿD!>>Y |~~AQR*;"=`ZSc_։ǸAJ^T6,6¿ K=EŻG XXc7 //n4yxĒtxXx0|3 `3  3? ~?\{- (񟓁/+~20A DIRQ-t;}/ ? XfbNQfe ?%dMk؁a ~b矌?t_0;POV~]^G_G~ca8  N=IENDB`ViTables-3.0.0/vitables/icons/16x16/folder-new.png000066400000000000000000000011021311223072700214740ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxڕ?has+S) BC6q\ v(UADE\ŹJɤE!Q)mj{wAxy=jO!OcvJOJuTv_bE[Y~Uy%8}oiwIQ9LčvþWtkUݲ4ʙœZCʯhM\8B|ӖSKyUL&_ gqyl8ƕUü2k 0SۤmV >ۼS@ ؿU梐gzlHh|huɉA<Ç]A.0Ʊph@x#?@,b-a# ߳n|G&㺝 Ҏq,C<% 7וo4XUq]W|s87{J~|l},X&Z#V+Jt,Kt"U6g #F+[._@=s5^x@"G &O *W+X/`3i1a9q=y7dB9kF>mL!R#Fy$N})J}+P-L{.R.W1O{2\5Ry6Y7`9^AnChDiDjMlMsOuW}W~XYZ[x[]_abbcfhilnopqstw{|}؂΄ʄۅljωՌˍ㎱䏰ԏۑϑԒȔ˕͗ЙҚبڱߒ7tRNS &-01Vafi]bKGDhQIDAT]JAd]q(  VJ@Ty _T/!wfIV+>F¯nh{ϝq-~缸K-b4"̯ Ϛ%vIENDB`ViTables-3.0.0/vitables/icons/16x16/help-contents.png000066400000000000000000000012541311223072700222250ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<)IDATxڍOa( ABd"1. &,?`\L0 D BwzV!\'}wZ=ϣ>'~-ޟ4.rcO/s\ro an`i# j$->z.wȚ<>.=%-ٌKgJ25\2> urYXxģK|0J q]3h'qՇ sK#=ͻT>ȸ*]%?> 5/0KAL8˳etOGDdoNZ@u7P$3I%5,Hc-iiӈ h6*+]|Ow m,ږO6/ F+**^!gpmժxۛ76YHy=;/ٹVC}IENDB`ViTables-3.0.0/vitables/icons/16x16/image-missing.png000066400000000000000000000014011311223072700221650ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<~IDATxڅS]HSa~2V"N&~".*1 +"&$o҂aŵ6yv}psM9yy_8A^_aeyIRӆa y f :u8()vZR5 (0% $YF::(6'KGtl +mm(X(6X곧qؖ# Cp9+ ޛd X?x uL_<fQ+; #?(bۦxZ\5Ђ$~G}h'`Tl*6bp"Jsek"vb-\-PdoᚙE2o'OP7b`wPCh ,CMkh|83gg1?xQ:t [ Y]UcbVfЋitg%-~xOlt1mi=ǎ% Tau|<_N@OZ\^߀`0`$0XMu7EO[O#Gf4@8i iLr˲ȶm- }>N}}'8r,@ }VH#;7V e [(2r[儯IENDB`ViTables-3.0.0/vitables/icons/16x16/link_array.png000066400000000000000000000007671311223072700216050ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  d_tIME&(˖wIDAT8˥O(q?w3\DvvXݸIa80'b%sbEIy?ɶ=~o#<= lț!w ;@ /Yz }RHJd䨏? 4:dR-ž .hۯ^>g )TTe!XE{,.sC4x@ɂ|ܘx+ 8}@tez Gxjg5:u6 ڼw60nKCb?θ ꩺ--%]mA3L4֢lo* _?-iPAzɴ;;G|@Ck3 jQ2׷ⵟLD# U2`p%aÃmhA*5 i DdG (uz{_nX=K'Cj ѓ!#{OO]ރpUʟX=vT2 <b=Ký2qόIENDB`ViTables-3.0.0/vitables/icons/16x16/link_table.png000066400000000000000000000015251311223072700215470ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME))TIDAT8˥Mheϛ4i4q[[LV;dl &EKϊ ^RC=yQPq(c =ꪶii~Ix><̋s9@@g'x)-vXXP߹r@OE\ݴ|`j:_}+V.uy޾\1Yh'qZ"pBB`ޛAu&05YX) %1Z#DS| B| չ%J}#h&YPGeŧbus Č]{p095gCy .}2 uӳ>E kƝ[[^O 3E|KgZ91}6@DK8#;70 BX߄= +E`afl~z458ș¦25$s8PCPɗ^=6n3cWCNE,|I$p`$I1f.D<a1^?^/C]MAwaQ ͞3x=8"pp.9 89B 'BsʏJ%_S|Ӄ\&T"@Պo@00Kp {M?)T"J~oj7S}vu"\äFZtA`PoTE.E M4;(qtyS,sTQ%VN~b%V%VڙUs%}IENDB`ViTables-3.0.0/vitables/icons/16x16/list-remove.png000066400000000000000000000005141311223072700217060ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATx풱0@EIt2ѧYɸ;;/Չ7`s#bhOB$:I5-SJ/hP۠A}ǀXcj":8e/ éL @7 8]]?ص\3p`g <%}eOXY @@ ͕8[?Lx>"?mcA[Ÿ LLAl, 9^׎ &`( ߂Of 8D9&ps202H=Oᯉ*(Ajdwy{1$21Jl,ܬXX30m 2x"H ^ty 20 o۬B~12x5×$@v##ۻOnl`$9xsp'/p>t't90<4;b M g2]@(e߶FQ bǠANlYX|f48H9n M `#?X`F(ffyFg_ќ/ Hda#@ !~8䀜@U r Q(%7 YֲB $8 @r9?`! Tk@,u!Lr`ХO/`8 R@AIA%%9Y ̏Pͳ߁0W+͡@yDۭq`aЪ3lx\c@,,, ?f}3++ÍO_a0\{ & LoO0ȗ l@O(,՗ 2v _e~#'ο`0Kfu2o| |R/23@Aҹ(ѻټ/ G}~`xQó ~5`xvMNwr xX?0|x̠,%&b k + .1`eW l J :|? ma; gç~-0fay3W g Xr92 aYDL: fVoVMS?Yeǹ`Jl\yx!@1R 7A׏IENDB`ViTables-3.0.0/vitables/icons/16x16/vlarray.png000066400000000000000000000002411311223072700211150ustar00rootroot00000000000000PNG  IHDRa pHYs  d_SIDAT8c C#D X` to iĊ DbhĈ7PΦ=lIENDB`ViTables-3.0.0/vitables/icons/16x16/vlstring.png000066400000000000000000000002731311223072700213120ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  d_tIME2l e#;IDAT8cB@, GFJÀ . F`ćř ./nIENDB`ViTables-3.0.0/vitables/icons/16x16/zoom-in.png000066400000000000000000000014271311223072700210340ustar00rootroot00000000000000PNG  IHDRabKGD pHYs^tIME .hIDATxڝoHqSŴgj*'Q+BTР MIE AIAԆ=u3rŴ;uNw* / EQF"p"X]YuGZZMM}f;A (ς|ai/5uF"۬Rl|ScY'D7n^@G4vX,+q> k) P e&ɽ1D} M- ]wQU[kVY`O~HE>`8f@$x<ҲKȚfv\`r~gg'kdFcZw>4M`08Nĺwc'J2m{(p8>+H8\hqyyy.Qooo5}>_oL&?)_iUIENDB`ViTables-3.0.0/vitables/icons/16x16/zoom-out.png000066400000000000000000000014221311223072700212300ustar00rootroot00000000000000PNG  IHDRabKGD pHYs^tIME 0:-9IDATxڝ[HSqmnkSsRi6‰P 4ߺЃ ЋO{)!a$tI7s@ ndzs!P+{0vVLD yVGX{GǠK(4YBFG smFݩ7]SYbM&̗yYf+%Cwz2rJf[Vj$ Ψb:bz}5$՚.+x@ v1ٙUTLaɡ1g(*)-Ms/JKf !d)Xu*ǞIhEl ZN#BYaq{-TDKs54PJT0 Qv+a+onnn(Y^^TF]p:Rh ) f$jIEE6S0Hd]n'z٘ިZp[TɕƦvssn_OOMN|ø>]Yu|dzdꚚ$x~$ N:;;x7t:Z,x(@$Aѭk8A4LX,|>wdV êjkkK!ppVWWkZ !V}KIENDB`ViTables-3.0.0/vitables/icons/22x22/000077500000000000000000000000001311223072700167245ustar00rootroot00000000000000ViTables-3.0.0/vitables/icons/22x22/application-exit.png000066400000000000000000000021561311223072700227100ustar00rootroot00000000000000PNG  IHDRĴl; pHYsϐtIME  ҡabKGDIDATxڵ_hUƿgfw6ِ MIMI`#DHE҆C4(J+bOyRԧXi(H$&6knSEnٝٹ3lZ"ss࿨ B W sv{קzT6˃w{ ܿ{|<%A-/M]]pDV?=! N=oU.ߔceiT_F&sg1t]@ϝ=9^X;hLm{$wc!N$0}IN\K /"n*WHP`EJK>]4nm*;KtקtW{*cUBe™3i kc[o/ e$zzyR(RC^ ։VASbQº:1 ٮnܔ\>BuVV079u9ľz0w}7wbaJ-%?ʭ<ϡlw$k#f!j$O=Ͽ 2@'2qzҳ֑=O\XQx}dbZ_ĥp.J)!bUć)<UwX)t 딤-'{V D IK^ 1H e} Bzu7P|8@#F߄Ik3l`368Sŷ $Mt#0'FАY$uᣨ} |?'fEgBR?B<Qk8}5h4 4~iIFxeNu{d:`lS4(=H$557߂Jb ~L#eWKpK6 (:@8e:>53owk/…$Y~0#8+cPbA gs(@/ bF "V [SXr}{ۣ/&"0 J I#,=@Iә2 j<Xf<) fy56؅'>Z?(!3*?lIENDB`ViTables-3.0.0/vitables/icons/22x22/bookmark_add.png000066400000000000000000000077371311223072700220650ustar00rootroot00000000000000PNG  IHDRĴl; pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxڌKl\q;xb7@0BPJT !PJ ! X`ZvM*u.xlBЈ&q5~9]88V|_?wrO-jDQ\7c 6}e)Y Z-Ñ{25o61!R޸z_G_zJIqhOJ扱yyD}z-to~lޣIBBs=\\pܓc㏍d IOGRn\1?b}} MqO 5)ݴwϾ/6/K[ɲ@ $1Rʖ_ܶ{ !nBDɌWJK%$> td-A 26w9u{Ç{p `5d);FM4{baym /B.Bl⽣F&8+zm_|]ۇ.XI: $$5jaLZjZ2ip'umdϰt` d1MN Q.J`E!nI6OzT;NTpTV!AA܆$ qZ׷y,CP` 4󧂯Te-.*XQp;qQ=9HX]Ydk`1ҝh d{^ok̅zV}-?iɌLe.Ϳsʹ8)K@Eҁ5dz;i8 up$QL-{/4Dho".4wf^d5w]JVB $& ߢ;O gShtS7&T|W+HLtv C}a<;FZt8afZ[M TV !N;; @*t&4wt}8ũ~`\f!ج%ow0Մ6 `#ӟNӫV ju1W5BljE:#H&|U_0I[VB*y;u>Qb]'uuKײ#kQ<ָZ|- ?'{DC =S)gːqW?qNۧb訫Fݛ^i4_cGRp,X\53xE ~#]Q2A<)ɦBɰTf &઀ƟKL!h6A <@_w@\[IENDB`ViTables-3.0.0/vitables/icons/22x22/bookmarks.png000066400000000000000000000022701311223072700214230ustar00rootroot00000000000000PNG  IHDRĴl;sRGB pHYsu85tIME 5O~bKGD8IDATxڥ[hUg{&iiQF UЇAAo"  KZba>B՘hҘ˶̙㷓V|TcaMϊ-ql-ړ/ZЃ"0]5ia <nO.avNj_bU (TȻ|Ѹ4P/HA)5.nnjAl(ޢNG4u߼߼,Գ @Sz8k~+>lJAS@ȅ?%4֝X("JQS餇o 5B?a {iJ"96H1 <0Har4LO<%K=^3=B_~s,ޕMMI>thzyktrAEq$ZK/#iuǰu rO}!fJ$M_QYIENDB`ViTables-3.0.0/vitables/icons/22x22/dbfilters.png000066400000000000000000000007021311223072700214070ustar00rootroot00000000000000PNG  IHDRabKGDawIDATxڥ?"Av jb Dt1`H > ho`H- ݟ(7Z83;̿{Wԯꋗt:PV11jP&5&K$ CjJrL$v;=89, <ùO c1iJdY|&2%uzu$c0En"kߢ*"*"^5cf}}}ٜ5}s"~vIE:  t<mp/I0bdb ^pw瑻i%t8*`hd8-NYl6V7iR*nm—qP}>_, `Y /7Gr- [eeqmmm*缵0AD"MNN(~runn4M;rBA411A}}}TZZ:9tuu? B^B!F0%[^A^s8&BrWi.r9LӜ/q/X4v8`+z@eY$.Ḇ~DIENDB`ViTables-3.0.0/vitables/icons/22x22/document-close.png000066400000000000000000000017721311223072700223620ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsaa0UtEXtSoftwarewww.inkscape.org<wIDATxڵohe?[tT6i7{U|h E nӕU¾o9G;0[ZM!GմjMM$4m=Ls$m _y ]׹|!ā+di_,4Nph(d ihhp{t$I`Ѕ%MpE8NMcdè\6X~oxx!f 6ߏg_~# b?҈r2\i1ű1 O}0OtʣPs8]b/5(76 ECaN) ǪR<_ oì~8ؠ\m}^F.4t7XZ9Ӷr!mx.1O@ӳozJB´.- }}$Ϝawk~}u2K`4wJ062AϧЪa rGS")p{(Iq2^+6ˇ1dݼ>99zfW(ؚPsLn:-t:12rh0$tr6lXVdYcVn\`E2L cBH$5B2nVdYsssD1F?޺Ѯ`QhRaI4%Y&_jolb]Y]Mp`0jOH$f /"C:Yͷߍ*o E>b FVeXqp8_SxC?ym孲KVOJzIENDB`ViTables-3.0.0/vitables/icons/22x22/document-new.png000066400000000000000000000015511311223072700220410ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATxڕk` uXv*  "d/QAt? VwUP:h=̥6ٮi/n{ǛᗗjBփvO {_$$ZDKn!7ma=d7Iah@Z8@;}  ] ]?S<,Ick@w&{S=uy"LN<=A#=g!$_5&'2.W\~>3 G?G"C.|{ٲQ(N _s8|$/@W]R-'UHa~74Xףk8omoUѽ&r(ʶk{ چ4"Sw5 "Tj+Pmq=yo' Nw"~w>!vI)lvBЀfwV&wSeuiv;,˒."t%#7 #̂n¾I,// aT*NժNԱs}||G}kڧlW(PxzҼvL6MM4KDtr98xB<~"7ZlŋRtmA K"hr$)~|rZ ̻(2TZ~X?TQ| cJs g:-%F)}>:qg2] ߑ}:`[:'Tkl2tC)hXk Pڕ|gr|sY&O Z"P_, uJinsO˩=5<FZ7ȶzcu#FL7 5\lАR4(n 6W560v$t# 0 oŠ^pJ=(dDF`E2g" wWT| 5ï?;S0 V$`!'nMBtf͆QG(\eY^lw1Z ou"fتghꭼ<}D0#WM;JW/pj]{8tg{8xK/qTyIENDB`ViTables-3.0.0/vitables/icons/22x22/document-save-as.png000066400000000000000000000023211311223072700226030ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<NIDATxڵmlE{* J[l b@LK/Z*؊Zb%! /@BP 1AH  UFP- \KKzwۻٻu6Yf63>8t]`ieUO ȱm}s=N%~C((J 7[عm H`NCC]ݔc~\ ]ะ0b3veeb{#yi:!( Wҭ D.1԰g{W+oM_&<Ӏ?\D$*k]Op,LWC dYú Rlm0XZC$GoX茅g; TmcaS-o9+9_U$` `9=13i?:#&uJ.=qgzV,QXE (3y[lfױs3ޢy&xf*65A!I\Ī-R>EF~&ol%A&+ޱ,sBV^⦪du]2nL0$28"R̚ZH<4iΟ"+/;n~LKNK/OSiڗjG͵YHE D~*Sn1M|guR\m s]_ҥ%0<tx%-f}/Ư'ɉM{`3Sk@# ;_;גBqa3 Ԟ' (ݔA8MH6@#Sh* 1X17jjh"@_K<Z;G3@Cִ9{kvMnzC[b\Q_V.TZ5 gb?gVN-=!ЦVӓz+{pJ/2y |󪵥f@ls U!op*YLERW)+8<;іn邏blin%߾'iUJ9  pKQKCG 𺿉B=3oxZCpl0ԅ|]"k_c|Yx>nh^pޟf\SA4S2+*iri>Z?xd2v 9"|v ƒ?a %Oө_tW{?v Sp,#7[BUtޝB.-jku^5d9Zo6AcwGhtt"H+|\,|<:0ꀛw]:&=ƻP 6Q('38ø2w0,6R\cd=yјqypx$2w4u< )|0u eDHl7_c~HFK'4*vaTFoO1rmX 8$c}$G2&-вj`FyY1 P8~o88E=5uC%bPQQQDnIENDB`ViTables-3.0.0/vitables/icons/22x22/edit-copy.png000066400000000000000000000010031311223072700213210ustar00rootroot00000000000000PNG  IHDRj sBITO pHYsvv}ՂtEXtSoftwarewww.inkscape.org<PLTE%%$&&&(((ĮWvtRNS$'017LMeevW9%IDATx]A! D; W|ݺEI>JX< zٿ 6C0s$ftJb`{fi v//F٫/Ds!UՍ4`Ҽ8j\(l+P7>v yhũL0o{͑WxR/)E}JIENDB`ViTables-3.0.0/vitables/icons/22x22/edit-cut.png000066400000000000000000000011001311223072700211400ustar00rootroot00000000000000PNG  IHDRnsBITUF pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxڕOHqtahKCCRz AyPt < g#b a%f[Pα-7(lsH;1HnbsG}| 7'ű3ƔM6 ӝ黣aPA^٭Ic?T =B)lEJK˸ki\mKR-C-C^_fU=v]ifW+^ufIW*X/o%޸<էY&(@,؀360s S J%pb! JkdL{Ǐ;k7o1QBʜ\䤍'++67Lˆr钫XaTZ;gw%!(X=0}lPUɑLm{.| ԔmR[\k(#YT ?tt@g&&\][TO?ːԨM@?p]A(A DGZFk`djmk߂ԩ6jc5 c+]`hfWWpV|KЀŽG-sn:IF` Ah+Ptۑ#!ehMՅϕ]bcBWj"|:4Vh8VTCi^T ?_[: (#hC`ˈ^{2 \qva;q>6`19_/;ާ42LƖϞaƋ8$X'- n8L~S=}z![VxhXtNn)AFPrw gղ {{Q'-Top蓾^EЖFn<7reff܀҆Avi~ށGZX*]B2|FE}Ij코}Lz ^IENDB`ViTables-3.0.0/vitables/icons/22x22/edit-paste.png000066400000000000000000000014031311223072700214670ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsaa0UtEXtSoftwarewww.inkscape.org<IDATxڝOQ㪌aDPA^[ $[7/A.]cREl![-Z렸uF~agx;od/x|0NJZ*PL&mDFF3T$IAk+˗r;ʸ\.|kNͮ/Q5 zTzĂE! ݋D" $ fbSpXۇA^N#aJvҧ93fn[K/ (+0D͘*i͑^.@/fOi>x<~[Sh˲ D~E&]52k Jd?IEGpAL 34'9T.V, 48:Taj1.>טx<~{R>1ica߯uczـV.`Ʊh4*_YsZG]]}:]=vfvkBV7^\=yX.,\Ԟwv@apƓ5_YЯH;"+ a{ 73e3z l6o`Љq ̥CwCI&^t</cKc͡L?~xvsFDf,IENDB`ViTables-3.0.0/vitables/icons/22x22/file_ro.png000066400000000000000000000023131311223072700210500ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  tIME 547OXIDAT8˵[hTWϙ1ɭZbx"Z+}IkҦ"4HE-*C>DшT6P4K$ZdܬF3̹}0'aTOج`8jjӃ}.EH4 Ƈ8g'OxF 3E1't\3`UX?Osy>1r]q3= CChml8'6Q૦͛WZZy8#G@,.оܸpt<βY^<>4!n< ̇?;p;rÓm<`Zb)ςݻhk{eбСף2ȭ[N9m9nu]JNeΝ!Z[˒ŋ')aӦy㍍bneekI5PL?V ի#!HB:No3S)ibZ54?cyyDc1|Jx~V1L?3w[mP7 /@ڀKVqU&S)(mY/TnA.ϓI**"P  `l7Ĵ,Rٲ}_ 4 JYRX^J1[Aj) WR}0MJjހr ЮV 7dl YI$QAKܹCF#9 HcXm]Osb1F_dža#z9ᄌUV2sBd4"a̮aڢEp.IS0 `~Oj67]!aˌp~*u(=xp5-gbbTlδ{iK)5 \785 ]KPSIENDB`ViTables-3.0.0/vitables/icons/22x22/file_rw.png000066400000000000000000000031511311223072700210610ustar00rootroot00000000000000PNG  IHDRĴl;gAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?-@12I!x1A0 ̅60|(m7P/ß?@@5\@ o^bBDc8,k ķRSU_[:1 |07b#VrZh3hiH3윲iw} x ހ`VE>>][W0+34>b!asBo_60`bf'Е6 L ~10|Ě䟪;d gg +n[o0j00|Kٓ -dk@!qe  33^ZV.&f?_0xAC!9KQ]@ADm݆ѥ3: S3|;?~1_/1z ( /-'߾``bz2 #wWapĹF0la>`aho` ted'W;>|l`kƳϯ_g`c@ eu(]npz1c 21x{AA!PϏ҆ԭk_@r7o0Q4? :0\t8_A.q1pʥŰd/'G ˧_oWT>kob6a&I &f&P#ؒ?1L; JY:Le}ro^o}z @,|sv6'w_m ;/h~ L ` 8xT>ZG2;#x^1p  Fo{hOp.^Pưی@eo?-5na'0/F`,ؾd@BB1xTt30Qc 7H0qIZRѐ9<#+.V9TqCvB$TA +xvEɊv5N0Wnugl6H+;CO՟s6z@?݋O/L`߀2G [@ ~6>wO lL j0ص0 >?tdY@Cr߀9Ƿ ?~~} O,, 4jË7__1p3X 202 :hv%p 4AāAG@@GT3cbb JCP8Ԫ~1&?d!/Z: )+{ !jo(-(@B/(͙Xf*o312cto^> m0V)@۞FzIENDB`ViTables-3.0.0/vitables/icons/22x22/folder-new.png000066400000000000000000000016331311223072700214770ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATxڥMh\U=sL2N~Ei)BH)Eb`BnJ+wn `vFMҦI'ddkt6ژv~pሪ0dT,!kIugD߰/u6*,_K?5{vCChMA@|St6zmͯ9,?O߇vMF_ HnHCGe]z4#H'(oҟ淲{P>z2{ЗkP Q~3x/嘩UQ`9ҾO1Fpz/X> ;>&x7Oߘ.ڿ{;!58<~+|+^yw[tøcH&WO5[̀24FнxK0_h `}$S{*RYΦV6d$xi\c) lJr̻ e0)r+Be`*Mٔj1' ٔ`Vbe8 PKn`a.ޱKXq)<yM4 U`\nnGN4Otf7m6i.<՝@Tꦬ 'ONo IENDB`ViTables-3.0.0/vitables/icons/22x22/go-first-view.png000066400000000000000000000023041311223072700221330ustar00rootroot00000000000000PNG  IHDRj sRGB pHYs B(xtIME  GTJPLTE#T&\6e'\ &M%Y&Z9n%Z)P=%YAz%Z,V&\ !C$YG$W0]$X$V #G!P$V%X6f#T#W= %K#Co'Fq?$V=r#V%Y/Y $E)Z>w-^}YbkuB6>XMbCנ p(* ϱ1!Qlv̈́*.(+3;oCncӑrΡZ,,egɤpj7 $grk+Z!>MnsX)̽&,.)FzcƐɻ0vў]B,96v8^(&R)Xk[ ?ƙ}}+Dm|z2[A/S8^,(\MY;AǤI!d)\.oNNcf3 d~9uIENDB`ViTables-3.0.0/vitables/icons/22x22/go-previous-view.png000066400000000000000000000014611311223072700226630ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATxڵKHqǿ>VZ*hQ^"0&!"( 0JdP*>(}Σ(J`W>Ïg>!e˸bo/(6ió9NIϹ4iyYWڇlZ/CZ{(7eXZ AoZ,s%'/i7..j{r//u-GJ䣻 A r6Zk ]r;vWH@)e -hi@nmg!jPSISQZP.Vpd aR8,wCh# ;1h0PP#Y"k2+›˥(fR]B`R<lɑnh"{Ao^yD^ dy8N.oL⤟˝z;+STVrg .NMl3cDF RFWvpa .deS.^gnˋ7U%1MSJMXzXߟ\.-4~#H iF‘$I~0bjۗ߼zp$"]źDL>x"̝{G?wncnvP/oӿ&@ RQSIu2J+w2M:8}"8 =A|IENDB`ViTables-3.0.0/vitables/icons/22x22/help-contents.png000066400000000000000000000020361311223072700222160ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsaa0UtEXtSoftwarewww.inkscape.org<IDATxڅKUs3= ӓh2A IpИ( Y՝d Vĵn"B"*р1:>0N_u[0Nw4拈9i2_ܼVocil.⮴~s QBں0 /4, 3@ P/~pcx»+?zzssV J)<z|o243(sZp0SٓuÉ`!b uZ16b:z>_Fӎ+`` cfFYTKWc Qha67[ "H,okCH1!kɍE\1*XXNp 1icAexh=J$|gP+2(}W.p~YoFLFO-Ӳʋo#cE=w2-I rN#UkH2M>>^\L/,ࡴr-ij\^%BDƬ3o+zakg:}3q5&uܯƗA^}KǫݵҐջ2HEY5bq')ޔ<8@8e5߁ <+Tkm8\-lv>nL qV.ߏf\ fv/6@٧hgG|:|gbx 7s۽'ϯ ثEtR7@Q@2w/ J.^B<(B63A %63Q3"h[׭ϫ*!%Yd^t|,ɘ9PIENDB`ViTables-3.0.0/vitables/icons/22x22/view-refresh.png000066400000000000000000000024031311223072700220370ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATxڵ[lTU>s3ә5\,۪D NgRʴޔP-I4 JJ TZ 4rDCo<4&Ac:{ƄI[A_xZzҨzv>kSdAOTaOa$3ﶻ=a(@g֕|ZhPO _/D*t}҅_ov~lو+a3մ|yЅe&g)D\+~>#a v|q>#bXnطV;f傾t@Ůi^EY=zpC {5]H:Wumcm1֟Y.Gv{6) SA~_>v-HjL j^ɞcBHoN1UBD)"ј K.E#?9j0bA}#9˸/MZV/'1#$o}maXr| 縟⤰EF/)+eP]1(ڧ-G_) `1^wsu8R\ؽEۊ橬To͐jR0! p~D޵<}^³{h.[qTvx1o<侖 PT];C,s*j$a JA iMfOS`5@\0\<'J*Wdg.:_ۧJ5s: }|{ᖚK ,҃)*I0}#nJ+qJWv^zu( r5Buh'B'!c[Vb*K+n܇m۬AI'𚢔Ns.#-"h\ 2dbqRHnM9H>}M:]5YM R"nB?ө(8S98wYGc[m(D31Āp!s码#r?paH=+.\sDq2F,8!y4̗P첫6߅,Oj22',x~JcYrtVR RVenP.8' &xxf[coU0ͨc3 TKuM!..{ʽlIENDB`ViTables-3.0.0/vitables/icons/22x22/zoom-in.png000066400000000000000000000022471311223072700210270ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs cytIME ({O4IDATxڵ_L[U0n-mdtpfMfH&dfK|$A3 &S7l#۔ ʟB<{0!|_N_=s^GFFl-H ALW_0ǒٳSHʂ $:VZp ޜ._&]7yW,[j^R$&wU ⍳ \278 x7gM8Jyzą*"8hN2̪㨡Ϡ}|xÁ8#LrfDI'(T1DZ"$P^5yCYFq.p/ IH̐$"(Oms>fZ.S|';l \KCc=gT#-J91P((հ|AUG H.G\^4 `FX$Z YA}ǧFwV{G￝d^9f @匒*do^YIGi>R e2X1 ~"i{]v2J|AZ ues䉓#eY\XX( Q|>;5R^L5ۖ<]/g~ʧD"W <n::dYYӹ=.]kj(*Bt:---7 Xs@MQzx7㿞*@)1qؼrLpiXm2~r{rrrHD"mAן UN{r->,?h4 ;pjS)3qܦH69@``q0 _D"QBvFնz?%_a2  nIENDB`ViTables-3.0.0/vitables/icons/22x22/zoom-out.png000066400000000000000000000022251311223072700212240ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs cytIME 2:"IDATxڵ_L[UϹz{oKKK٤0 8 523 |%cdMͶɡl&&:`>HT {$>u'|;9tww۽^)e$RUuSt_[{Z̲,zZ? Au M+> P$޺U \ -|}XǬYxC3~]OD _B۷?f*J+ǁAWg1ɗ- V]S@(-L;w8? e6J)oijPܾibSssˍ/Ved:2Hbg4->Zdj<Ѩ$1v»5Fke_ 1 N4>6q":ܾ 9#sv~M{IHqzvT4ѫon @| EM%@tG6Ĺb7EyӉ1 SVƐ2h'4 5r Aɚci'6)%4Ps9̈́h%1لyS27FSNv"B$ĽC-~$(iN@dE bESTq86<22V,ՙٙ&-mM"m8KBPS4eSEoi~oO>1>.Xj!wԒ$4!DIqMyYęlQQ`(ZM  w< H e[ۙLz*k|}ed䅌3eee(ޅ㸭PhWvvLACpd%¿,m6[r$Rr``naaabee< L#FF(yyyxKKKwGGs?f$i3"A{]Áb"jk~=0;;gWnX):U TW+rsllL$ ].)pqq!e=ђQ@ 4M =̆`0xcmmb\ς 0tFFc2IENDB`ViTables-3.0.0/vitables/icons/64x64/000077500000000000000000000000001311223072700167405ustar00rootroot00000000000000ViTables-3.0.0/vitables/icons/64x64/preferences-desktop-theme.png000066400000000000000000000046251311223072700245250ustar00rootroot00000000000000PNG  IHDR@@iq pHYs^tIME  ACbKGD "IDATx[lg؎8䲐[M%.U*Z R>uRZ QK-` ve(YnI$Ď=Gcy-Θ|s3w˙7]ӄDw;wVCRZ@#7nsDaӦM= ^vء\v,̝;Mzs2+` m7lWq躎þcr;:ܑccGBu}}N^رc+nEev&lۖ( 44X;}FH鎎|ӧ`phTK$K`e\X> _/4{.x o7GHѩpztNQULdUe<V~:A"9!@Z #`Y&TU7,{t]/ ͘ Q P\zU~3fK5i8}4/_."(IΝ;zL</%ƅ tR P7|TTT=@I$hmmńOeٛPT>=eo֬YUwa9.UH_d |3)dSŋ7TCd; ŧ8< PٓOW b/:)Sd7н@<heor',g Fq(ؽ{7-[&>F`Ea$!6<>c֭U2zk۶@CU3#΁A)tX,{Cxzt TġEf ld]@HpoGF [Aq%lt3#'Rh{`C~#7Tsʠ 1"ɓ@qEuFdrUt~kLRer`===qx&+``Rq@#S!6 }!SS+4E@΍ƙ;B##qT1J ܶ.|;+,'ȑ.ps獤o)~æ aː̄C(Y8Tvwo(z  t>61&Pr,<*s80L[ 0$D8{; І |JgSlP|Zy8B%IQ%XZU%uskniH̶-mH=8~<0h=FDa::0`qgWӯ\ל뵺^^Y5*$}/#u)-y,Xk<<..,z&c O2e5f"H13;s^?`Sxu-KRK@0CAusMξF J[7kMe^Y vM(eڈt԰qr˸|a0dM65^SS˦Oob1I!_! {{{~N=m9$,D\"8e+DePi4M4)T \)k˖- !o }\kxڂ1d͛7OF.vIrtK"c8C#e;Q/GxëTUIENDB`ViTables-3.0.0/vitables/icons/64x64/preferences-other.png000066400000000000000000000130551311223072700230720ustar00rootroot00000000000000PNG  IHDR@@iq pHYs7\7\ǤbKGDIDATx[Pg>F F(X`.(6"^邊H^[aM$[k4$7}>/s3?3wu>3 {s.-`f:Ց@fΚA~>d=u?UϞdiՓzY7.+{+J5FTkCS@?2t 2:MVuUԄ4knfԤKNN}6|߈6zBDYSh.EjZ1@Ϟ=? O&>MElzc.),\k֮7o(a=\MIii)!-K@|bZ2xPl\4yy{t70!4ýqcsu Yʀ>}D{]uu3{a_E-(̣KTZG竔 '_\Ou~o^~-|=~$߹\ 0Yo;k*WIѱe%z 3u2h=v rD1ي2~GWdN'oS7| yM{Z4nݺA^>sgRXDoTt߾V(S_eDۯ򳟞_VK6otFDݒH7o}M>W*BÃT[{㈀//aD,^Z^ ;wmWlix5 |~ѢBղqӇfgػop_~>_~=zΩ"Nv﬷jJh4۷*|z(GԾ~>6Õ?ܰN>O<~ گ]O@qq}@2tsW-cwr^~e?ϟEΝ?p@0~fРV$G۶ouת}ǶIɉϳs8"2\%!g't0ppr6lyNyi l¢D~?y?O@흻w855%#]tT .^@)R0_\L*XWT肃yEhz`! hĿVBDzTiR(;w>`Ūe۶h> F2iu˗7v+^}_%-Hۊ>PAt \MT1Quiマ5׮_S:uҺ[S$Y`G^ `t:Djo/p="ڽZWsg/;߱(Kyټ(Mضc׾{?C>E>$"K2`C-[7SŲru~A[W邯s&;>| <~ ŕ({weAYٙEx퓧?:u̙*ݧǏ~a5 CÇC5_y;)/)fo__Oe+VLO/e=GD"@oş}~Qf(_rY|O e/_Nŋi%ZUWiJM[#1y8ngމã0^pݗY3^HW_rbRrsWs#r޾c<{ΤeKnӶڽ|0}? M]>LY H'?F,D=g7Y xU$$WB-[dK+KivrnjT} 2;U "yri:0k[ (-[Zܩs'ڭ f9o҄۳cOcy͙ P-!AhX;#9^ݫ&Ov9MÁӇј=,(Ą xnqvIokjW `Ҥ 1Oغ1mvKX_/}uC ey!ߺ?ӛ{!.[v26?lPhN5Ӑ`H[o'ԹK'ŵVH2\Xus!;;ȣFb[[[FV"e&عK=--oWkL6 '6ሀ a#lz- .Ӝe1# "䞖2Me&F]ihby]zɰGc 4a`/B-VӘ}~_P8)%3 مb9 nfQvJ'A>awh߁(.!5~dM`eQ1 uё?bQs7 #`FG>~>kx^FmLy5Hs;'p 4p@"N#9oJMKlmdT1rxD8NeF@$#'L 5995bm DD|||NE1r9RDT4e=כp @NLJdYZy~vV[23nuWa^ LyAA豣TۓܧfK _b⛉&Ioq:]T F 刈E "d47ڂ1H#R ?^)y(wyٌ3RVNϞ92ӧs!$+"B܂lx-}YӲ %UtԷ_2Hnc*iTt(.]~1qQWD>\#eWWW-Rg됰`0Wdh_t NF`v}/1Ь5moDŢI~tw.] s3B3N!=_Hσ~ 7l(j4>K0bsht"MmپQmllDnIlo)2xXYY%>!O enxLLk_âJ`/n 꽦fU}nVYD>A*-'Ou/_Wo6J (}wmȫXv*A|!.Aaɒ`ߴfQ;TDM-ESGԵDUKpb23y W#eCL F*@!!&ziy?J+Zbic]4Z !"71?5 K©MW?v7oώ8] H:bz b1tii i1eVu O T8u kpĸaÆM/n1_' %}K{55m?1_2_0!fR7nжm8mժ0o1տv7AA:ұf5R:\ wM[KԒziRW꼦q2uR^:$i֚@7z"zTXtSoftwarex+//.NN,H/J6XS\IENDB`ViTables-3.0.0/vitables/icons/64x64/preferences-plugin.png000066400000000000000000000105011311223072700232400ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATx[{\}~yI1~"bHy !DjTEjOJ*UVPڪUAEUK(4&Rc;;s=3g,ޝq~g3|y쒈wp6Ddbcx+E?f, B!(hI!_ @m&3NM]%_V Q"aA1̢ԋ?D#;]x /]{/^!0bFF )ܲ !PSr*?pp#|4ƅ+ĒDi v6[7?E5"IDe})I\/o 9D՝B>kވ~D}< ޙI"/ˇ@5Mx(FPO籘Ա̡XXu*Dxޖ#f<H  K5(,;fktP Bϒ] Y;B*=8Z[iE ߙy+dO gQl2#m Mic(;=_߹zi߃uY>Lyu5ى0R$ޒgg$[! LH(Yww V ! rD몥2r0ޱ6P1!7:^9ֽ޲Yq:CuH$fDD0yB%L5HDvWj?H!pay׏w2s/ gv݆˫{SVs->Q'0֞KA Uekh +1c|Rcc BO JF$,0i6=վ?RG [.s?e'0P_Gb 7CZAuG~*D_Pt2S6t MM4fR$ Fy*/ T0PHSAh^\nY?zP fF'i‹x}hO=y/'׾KcˤR(R6Wsz#0<{9! 96#O6byGp0wc"I;ǿ dr7pq͘۩Lk.>ۭq%̋"Q@|baD#Gim>1k}Xi##j@yFl)fB kgb>Pǽo@!Ifhr# tX{Sw?ǻm)*!D$.vn:]?JjPGKspCEh.:VE#U3 D0h׶V ]R^%!GD&bjȓ؜\JFZYߖ 6eK7ܶ!6&PB;_9: 3)6s9a\mVCIEiHYkI7l{ j"h# >.,poB!veSen8 k!aq+ j}Vĺ85Xg% 6eW펛mpH3*I&Y V H/}9"> T@`0#@1"'oE)NR~-u@Rg7ĕ0pE :!i SzYЗlzb`gDKjs@Wq"׾>JV@ͭ{ zztNZh.R&' fI`XUtlNjJ+%H̶H}H]!?Y\C$4 l0- = j@*#S!ѲCbk좤*`Zfz,&Smsy{ZT~cg'r?w8u**GR-:O_ґxݱ5'BY{Fa 1b:E6{՞/"vwmzsU)DS5`sV}8j0f0?L{gP1(dhE7y q/2m ;hɆ'~" ^#-|]d.8IENDB`ViTables-3.0.0/vitables/icons/vitables.ico000066400000000000000000000163561311223072700204650ustar00rootroot00000000000000h6 00F( @rrPzG ӭD,(DPPPxa6/jwRve,,,';edt %kr`o>H ?nٸ/7&$$ &}e=ֲܾ?k`iS ںmܾضF ڹձc;d_2dEW\02%uVcb6,>_aO N7 #0m"$()+.@Z81) &ZFqZf?Z A3KoZgZZpU9! 'D/*I;r QL 5YTmSjhR`tjX4MyR+?I~!Gs 1x)Wac9_x{mV fZ:ބgex][68z|\xhުިij.ձۻ :Mtrr y y(D9H x`{e9//Z+$A559aX6 6Σ'>r&׵ DV$Lh! !IP]1jvZβJFF$>ƨgx!Kr"+I1SAo`gEuܾ";eٸֲR jzah E <WtӮI|ض; 4#<*G_ݶRR^bהRݼڶ݊0ڶԊݶȱh^RhbVv Q^݊Z („!^h^DAqJi;~ݼd5iݶh/  ,Yii^g73ii-KccccM{`iiݚP)>cccccWFii&8UCccccᾡlccccH#iiicccccccc@cccciiiccccccccccccccc Iiiilccccccccccccccccc߭j+iiiiccccccc<EcccccccΙlccc\L|iiii*ccccccccΙccccccccccccet9=iiii}cccccccccwcccccccm*ccccxXiiiiiccccccccccccccccc\'o`siiii]kfGŨccccccccnncccc%iiiiiTO :ўзNcccc_Biiiiii^ra:$?1iiiiiԂ6Ԗ.iiiiiݶp2iiiݼ0ݦݶz"[uyS4RbݦRݒR6ƔbǻݑݶRݦݶhb݂ݻ^60ݢR^b^ݦ^0ݼh݂ۢ?ViTables-3.0.0/vitables/icons/vitables_file.ico000066400000000000000000000163561311223072700214640ustar00rootroot00000000000000h6 00F( @hy^^Cr G S gB AJ'Q2^1-08| qyWGS{I##Q"'^m7^fmR!m\~Eb":tI} ^)Q$=&PS &P&QI|777=@?;;;;;*!5 >, +6A.89 " 8:88$8$2#)88D88-1/'3(04&BCBj"l~c'-T$[5`4W&MQ(d 6'!rhsBpeS -tSKX|OUPI%;Q_@mF T &f&*(c}Nj%=H $HTrAoOs S&TU##%<%>(d(c@l}rFFFFFFFFFFFFFFFFFFFFFri<f4Yn=w(; whtX &.K5Uw>2HC jk\GGGw % aGGR~GGV[ww`O GGGG1GGE^ww- xGGG60GGGGGdGGB'wW _GGGGs,GGGG GG|wJ LGGGGGvGGGGQcGy]owww }{GGGG8)GGGGyPGGpSw T!+NbGGGeGG:m"* u9/AD7Z@ Iz?g q $$$$ll#M 3?? (0` snM}$,|]*%W+0ROG 'euI|)*iW'`ja1}$Yeu~D B.6 V~d<5<lQN#h!"s O'B <~a P$#U{OIb'-7] '`xjEk}##1AnhR#;7Nq$#fJ'y+~ "-M3Wd  -#'RT"U_19LP!?kwTM## ocV#*$={/P>irmi)H "<* (dx4X'aG Q(VVW#<#&#(#)$*$+$-'armge888888888888888888888888888888888888888888888888888888888888ʢ ֤ֈѣ%{WDpEu 1X03_e]7^5ÎG)gdy~sŴJ ;#KTs/axޯ4VQ[vޑ"R BK޽(/.`ކP_9t޽‚ޮwzLɩ+ޒOȴ ސ*'ޫjbh-fM@6SޟZޝk:|<@r$iFl}߶mqcUo&CFNH㹹An, IץӀ=2\Y!?>????ViTables-3.0.0/vitables/icons/vitables_logo.png000066400000000000000000001105561311223072700215140ustar00rootroot00000000000000PNG  IHDR^SesBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwxTǿ $HJQ"J)A\E,` *"݂D)H $g~9̙l6tD"zc0m{~1R%DR2Êr($H|%R%DrÊ?˝Bˑ"''Gw{ii)JJJBRgϢHwӧuFupȑCɓ'aۅ].;v}ݎ }|0䠬N)H{ߢm3}UEƾ(^E羐J 0uT|1yyy۷/ѹsgVl2šK.HMMŞ={m. w}7Zhd1ǹ8mڴ`P>}ѣZl;bؼyf7xԩt邌 u[ii)Ґ>GRR郝;wj:u*n3s`ܸq5r\.̘1ӧZjݻäI0bbAnnn=J"?ؾo*HSaz Lv(55}.8H59~8{Hvv6d$''#(B.\H"Cl6Yd q8G%]tQINȡCȑ#GH׮]+noݺ5ٶm[@ȑ#믿&C^}Uҭ[7uݻItt4Yv-9{,5j2d}ڴiwĉdΝM6d…smܸ.ܞF͛P⦛n"_=#( Yz5Yx _uϕE,K˩O֔~n=vIV+)((Ь:u*6lX=J"EQKN8Ay)?{O;LۑEv>M ˈ$8t::rWE<x^.uPmA3f )))!SN%iii駟&&M"1cƐҀz$""/Bz-rO8A;wB+ /nIΝϭ[&[n%^_$##Bȿ/r5ר۷mF %ҪU+'NH:a٣F"Ǐ=wZZ?ruב$2bUNJ>C?Y|O9[l!QQQӺzwH.]Hfe]FKu'|Bq2eBΝKmFOZhARSSɓO>I<!䜠/Ytܙk׎jy<3]v$%%<vĉ%\BH߾} L>JJJȽKIv̙35oo'999j.rl2ҭ[7ҪU+/޽;3gv͛+VtDa7|CI|gHKȍ<:k3y'HYY9)//'eeen 6nv}D Mԫ%dСC_~>?sqƀIӦMIqq1!{ >\O\\*: Zf R?nݚDGGJwN~ǀׇ~HRSSU;ȣ>n/++#lݺ8=eܹ}>Fo߮{4ҲeKn:r r뭷[nBի%\I|,CB5k+~ϟME!̙3X,2r!rQB!']tQ2YYY9r$&| IHH | !7|oߞo߾dܸqB,YBL%۷oW=5,/&m۶^2`r!yfJyBH=OVZE !\. 2=z$55̟?(o+ϫW&͚5#n;% +^8NSO@Ao hi{r߿%GNRRZZJnk,@Bjgff"557oj8~8ƍB$''kkٲWTTٞ OQXX#G`:t\t:p8p8|Uvڅ'| ,d%::())Aqq1!>u-^;v_M6)#77~ӧOn^HJJ5o׿дiSDGGCHII͛eo?)S 997pe˖{E~бcGL2/V{nBгgOX,j'EQl2L6 :t@-Rp7cذaHNNs=~jǏE]~aԨQjbؽ{7q=l6tD 7l 4 !k%Ze;L}+.2svg JCؿ?  6tj۷^z20h ̘1~>))IXzDbn?rUW]Պ֭[_f?K$oj{ 7܀suGqq1SZOy{=.S_~0 ͅhă>sb޼yxem'O{~]w6oތ l6MCoxlٲ:t PRRpڵ{j#*;;=zP%%%;0n8{#nTTT'-܂#FࡇBEE֯_^zbĉxG4ۺv튽{= ө6{AΝqp8՗b+߿C Y4 sEDD]v0LԩSuٱc:[zP-[ƍիWc…hܸ1ja\s ߏݻwlx<(//o o&M3gh ٳ1}t|G6m"""|f#oߎo(b`ĉ8x 6l؀wy?Oٽ{Fqq1{wJLLDddyî]r4ڳcbXp!wN:|DPEǃiӦ[nAAAfc!9K`C:y[+XBE7Y=l^Ѻuk|Xl&N>u TΝ;Gشi6mڤr0ax衇vz!|Xd >S̝;>(J^x1ӱuV<ĠAuAp7e˖j]s<3f_ԩSq==^{5]/_ &h1ow:*Suڵ 55&L@Ft9tz!O?4ZVO|111O"99>}:֯_H}K.[oB\}x Պ+V`(((رc1e>~xlذVUno6 \Rs_'|H^5k`ر(,,=60^T+2׷;b6h4d:JfhTś -w0i$8N̝;r@ /DrZ?rᩧoQу߂\rE8 P"O?P!á0uT޽vH$=<##F۫,#I,p1n=;k\슢@c|/,].j=޲eK~pqqqo}M8#G<# noܹsa0SOi/\?p֏b00`9n\rAË;˅ɓ'cĈjp@E%F5uq{<5̇ֈ:Ms> igddǔ)Scܸqx Q!xPZZ\<#0an7$"wΝSNoJعs'ڵ Vs!6mMcǎaxwш^z AZZ{1u={0c ,_ڵ&/99?<&MS57"66_}.t5ĨQ`z˅KjEEEKjrJ7K.ŋ5ѧ%!!\_~3gN,34 e!!*V-uө 9;M4^uSW[П{9̙3gƈ#j*˘5k,X;ef0rH5H; Le˗/G֭1zhl6<ػwwl2yСڷoѣG$"IIIhѢ=*Kq7AcǎŮ]gϞHKKCFcƍ}HKK >o<=`Ȑ!hѢFvI<7ofq/)cر/QZZ[z5"##1d@qqbϢcǎh֬맶qme˖ҥ ,Y9}t1bZj &V?uW[n>Y(mڴ^ѣG@ewǝwމm")) 7|A!)) ;vW_}{}%9\̈́,_={gnk :9xC:]Yk]XqgEMHP %%ضm֮]3g7ހ`7ߌ[TZeǎdKIIA\\*@.]"##1sL8rߏT<*b4i^}Ub˖-yHr*>(FU8CD3K=2VzU:2Om8orj 999O?K.꾡^2;P)1JÆ > O(~!&OkݺuCtt46lۍ#GmڴA4iii6l7o1c`ݺuGDD ""GY-[ .?vłȑ#Xj7oZN;Ѽyso5H.TXw:/9r{WsQD /}ީSKsQ~z&E.\=Vʕ+q1\/\ա.smۆt,Z{__EE 4,YYYp8xG0~x?eee711'l DDDnã>tQvcǎ>}:222`4\dd$֬Y5k %%F±cǪ]B?OpWdX%"03%)7;TpQtD7+xX~ߌ_UrgjرcQŋZt8XzzO]|r͹h.@ e.WSHKK cڴi"##Uݮ];x<|~ZUQ>\y„9˗/GJJ VX>}}W_}"~s6AH4kr.]$l69Qw=U?/r xիWc͚5j^nrM|lڴ ԜsSƎٳgĉp5<f͚UV 6mBii)Z$''cطo$ӷo_,\2W|^P\\,bhHOOǎ;0k,u[VV֬Y2B`2кuݍH똊Çѷoߐ9x-q!-&9|N?]~M X,Z_|r;w\yyyHNNٳgϫi.(lڴ O<Frvm(((믿EQϪQ~)-ZCK.tgc;y$.kBshׯ3uVi`=.H$ H';;g̺ dDXXy֐y,πRGS!#:HAH$/2K9z b6*`̇xCRGR|SQ .tD"i sرzWm : \ǯ:$1hDZ笨u-R%$-B( ?Rt þj\Nz>TK*;vyR%$a3֢(PUCFrg1>>7*Q9&T8CɅKAH$0﫥b@c1|5`ؑ_? AeX0RYZ|bҁstD" xۦ( _muoMYz.k|te)!@8}C.CH$0wVX~|>ex|uBٺW*EPJPiG3eX2qqP{ˊ*dBX1$4j#H$l*+gϞСChѢӁ`[uA jj@Ү?&sзjʫC$伥@[[tD"%nӧOcQZZ Rte0xʂ>_}Y5v$PDrVw^Y@ߋeAqDrU;v \s v-;s)fӄW98]@nzĔ.*}Q,tq*]/K$I'GqQuS0(.?%F} :LA!ouQ76~<#*>;@o9a wK$IгP8}昳МjD`8[}t#C .:wVƍxVEF D"-BcKC$>1teU z٧Q,1]ٹ@V 綈F,`76_D D"V>A )I! sBcL߮O 6W4t_,82pAolq j7>HJK$x tXv̀;B-t3@Z#M#,nXL^3Y^DZcDo_HAH$Hf=MQ2MYuѕC׊)| (@h@F(,Oܐ5#bKD"0gpCD¯r^X(1mn.z*&s@ D"jcױc}&8a:1GATtnא5wj;%\R%DZ~&.á s <6"鿋8`.?\s-lйxAy,ͩZ޼uΊ9pC D" ʓ_hjPEQfpD*9[GvhM]BSNPx>QC-mҁ^hGZҒc*yyŞ7)A$zQ5ňX:b##+"}h6m AAMqS4*:ZݬF]J Q.HkD/MQ(e`n$l?=+nFмx'.և`c 1j?{NL֍ 7Vt@,")E DBys>+?6$ujcHT/ ]YvSeJ1U^~lz_v$t" 6/,ԗ.]"wEs]]gb?}08C7LO $-#BSV0˪v]4$7ƊdYQOSK$!Z|; ._"ruOV^zqN?'4簘:`Q Mqow{0%[TEnxB=.HapXg`<?TAguh(yp퇚&ΏQؑo -uVÍD"(r8( >3{<x<3W#+aZQ+AOQ_W̞@x 3HonKzI:/޼X oK$+ : ,9g8Dx7μZ_A5z7ZkOrjzIr@)t [_췈K {V9]ff=k)ьtDҠ]:EQAa˖-(,,TrCZ47lY묾z}+PBhw YT[ :69F <]Nj}UpإK$(;,0`5Q[ALןnwsCw[Y`2q:]6߯? J% G³V䂆i.vQV\)9ooF8#.?] 1@roC,0q cP o2 F|y ,t#nK$0woznvh,y? >w Rp*ۃU+C[fMXq uW&:2UZVVλq,nK$0@[[w!f$ܥr/ՙQ3ԑpA?g/ t G3#qO;;f՟}_Ŗh-pŢ."{Uv FkoWuI|+CgwSV҃xv}w/g)61]4״< I;Μr6.6 6 :wCZtDR˰FԀg#8<@z^:_7Jm _* ggi-t^44.Hj>M+ivu]io4zJUa,]{m :\+60| 5cYqEh\(+%s@ D" !z a6^0l9)܏ "ja ^[J6OA9Y軾.~~=vΔo)GOpNDDDTF8?.6Mbqcp.HB75Ncs߹ w߀QzE[́~4)& /N!`T9\$0w40)$$$ 55hٲ*l4:Ί8]x;'J"s@ D"!z+.rAp(D`%uwXw 驪M]6=A:p[OVkF#͛UVhԨp,8ΊU.v>(+!X` H$ah˛qNvXFSF仾[ szOW- R9>8+WQ{2)8LB݅ŋnf1 hҤ 7o xbbFPoVTY7;}yȱS\FQs+BH$AOE}q<4"s7Z]v${Hj\kIzpeoF %)8VS 8'00d|A~ } ␘f͚8'zbk :le.' g1K$ MG zII 222ФIzr-nPX,TQC :,zHA#G˓q 6sw{Ư0hڴ)5k xbb"Vz.>/3+4+8kvvߠ4GtDR-,sVY+=++ 1>3dffH`("2X4ߍJ*HmŞFwB'^#&(V^<=ZuFٌ4kL]ۜB]բi~f]|zS9kufI w}Ҷc !p\={6^~enA8|N`Fyh62Ǽw="O0pr+**{!??_=fSۼiӦF(pLd}h:)cǍvJgr> ?繨AYK$ $}((//Lj#euH 2ٓnv_ͪ]Bc5v0+O_g@|Ŗ9s۷oGrr23AwG^Vk\ ~jf4ͦ~sQ׆#]$ Ms>N'F+ \TU֐tmYg] Bk#+4Li֭C9z,H|zV:_g[|V8. ]yK$Eϟ?~-lIPQ,%Ft%XE2`X+ 2 HJJBYY+VKMG)~i]E^_/ 9+Uͪ6hY|] N.H /At:1{lu+Rgꯞ<;~Gf=ldZ#ә C$'Bvv6"""nɰZ>Q߼=UqZ4:kStO9;߹(;k[Vnv|z )JDV#ߏ( >dgڴITU1 _Rٗ_֮WO`lОϩXLqG+w)O <5`anhTEC :ۇNj+ /Erŧne^QltDCЊX@ zr)jﶥk.pqg+[FX9!aM6XfPOi &Mߋ&ΡNGG=AmzB\;uD8,R%I;' //ǎk gbA0S 2o$;Z!68n񜐙Ƽʾy7(ȋdy˝I>)+g> \& vKdYH}>@tyR%I5a-u޹ke^t7F! ?LWy4"l[t= eZ% \<|:?-oBx^_g٬޼%ξ:2R%I@ܫ碢"cNwDUNYﶥ۵^qg+d8 E&AZ}]٢/PQHEPYwHxw>ZڬQȳŠ'/w DV{U M) Ɵ" =P?ei}2Xзgˏ_ OpAS Om(B#NڪDMb sS Z(w^0y>k7>xk,Ɩv FMc|s@ D"֒a?x\?Yuˁ Ty wdU lo1-z: :|Q•lY6wP-sΎC :V0Yqd="?τZz ~;$)/2ızŢ +0+ ǝIEy\Ʉ:m۶lB'NAjX4lDbz]EQ`6UX,~y1@vZDq>9 ]"ouu}bӦM~:|]x 'ɕlT6bѩYd8_~95"$ /gHn9,<7FDbɖ dvw>7hٴ|\6Vٺ9pX=E8H$*ل#^nSO=s|(`@J\ѥq 6r"Gi 1faѼyz}zxY,T=1Yz.}޵Oҳ\$[(" }/kvvqUm])$F@{<\.:u ={_xh:9\j޶>V>;?H Ego_zU}tjQu}7=˟} ۱oZH IDAT𖺞(ˋmѱ )JDlvraڴiXlH`?aUHd8[!˓ Wd /jԭ'"׵('&J׷ hX^$?1gS^/^빝Uĝ8ՓV,t.=?/"yYQy.D!HAH$[nl?VEtĉPPPPe6s\ 1m^{-맊"f[Z,[.{n=\_*!_YϢ-?VOLy+z~5<"kO":=^.Dt ew6dIm^< ,&IwQ?Y u9Vzס!]!ߟ}XKrp`۶m7n0@ڵ+5|SgHg\3kuhrLj<3"KZ^$qD-C|{>ueSk݇~~`fV׆$$zY]|,R.@ńc&)=׵GM܁}H_/_nʫ*>h%~j;]tb߾}?ZeoÈ#|D]DmQ"YbSqٟ7WYG }WCi6JgXԳrm:oE^|W8ѫ$0- 6s5&U vjuo^6J{ϕwy/-qʲ6/#^(9kir煄{ I}}܃"KWÊAQ:h5.60kk5^6PN/ з@[~sY g!p3J,I}@"`\v٣p]tH>cѨ۪gM'VmO|ᵩ$\nq}kwX³Nӽg.Lz[Ka(˪v=/4x\.)MC5uy)Y, 2{͛lHY=p7DVT8B _Vϑ(,/ӴT?\*^AnO8fۧOn'0~/xsqNj[ɫФM}BxX^\8w\p:*-^':b &&VwDGzf쬸fZf$ m>suSH\١gh9zKBKλ[+aH ƌArj=Jil66@pAc픟qAiwN&؆>Ĝ7˾O۪e7 á *"TC( JtpߕyZPVU#nfYA޵KŐY1bqN[䬰ھ_b trd2i<9鳍{%Gm\|#_CRT.ޞ3aZ(NERX,g ʈ_=r/ \ ^'ʐ[XQ~ ꟤]BEEFPޫrEjPG IZl6u#Qw3۞uZ"wƄȽN 9v}bkh ]["wuuסD ,?vB4ca>~P'( Sj؛_ժyHbm ? ː&I^/~w:$ux)JJib ޵xQQQݮc߆^Gjm#5(7 qŢYez>ֹhnm^E.vz\@_AdbfS1rz S龖#TG'sl). cqQ_x<k`[s}[@CV}G@YYz'66尃x-†D@yy9f3V+V+lʙX`M2{߳5v;ʌeZ5:(k=qv8i YUP#yq𝱋=@`)//P|#}^i KjBDkGŏ zAU ‘OQbY˜wK׃5/cU坎 '0i,@l4%1fU׽AeeejRrUD(*ܮ/_E ~(7k@]ZB.̅h֥ΏOW]3%fye#ǎ2l6fo4$ [v֥#|ǘG83^o?X#.:6"U -+VC{5'O}. [kjߦA*p\BzUkTQ~pC.N UY˜y"b==^@7Qk ikR=;e=nl7 HBA.w#P|;=l4? '!z u+a8K2ũX\ܹjCq-z^)QjWTTU6j:G6@cn6zE}3oD=5q8 vK$.D[r==\tv92\%C'3.+~r^ nK٬I( gGG(t4";RE#?5}ӹNI?$zݯժ䰻6;o l_ywwu"txat:v Y=^6bMBEbŠ2cq{t!V4H^`qp©i, _$Tk:;mG}Ѷp) B?2?O]D(:ty9!aP#F0+XK.gJr}V[2m+ج:c2PldXy+#x6".*^?Uo {,8YH%ޏuF t*Bf`:>@On7\K Ib l7Nh7w>X`rE\s=CP.w.eQs9σ쏋p&8Lm--%@qôㅠ˰hXnx$Qfꗀa=p 'ʐSq"TqÁ^m.>0 =mT֌A{,ri kIX|KEXz hP>vUSC^A5 K 冻iU` `cDc vK6Uv_p|NZX,p\KXJ,ŞӮ@;\bЦdhJH6؊ecr6$"5K ׌Z_ A#} l`k]Ͼ;DN" 4ڬ&0ߋP[L#^lׂǪzOV={ߦ$=[ư=/PAk,.UWwއ `8tu bVٟ` A& -o{_$YˬgzIF!BBel8c`Yk^^a{6] ae!!4\=WwOu=//2R"*{}{_`wt-Ӑ`Sĭp<h Ar5sA] 9/} >N8oa}N+ 0 0`z&BFnP̪l*]_ [ [ \|m˯ 0o)sSϓřyd-gLe6>0KSaa@ea-VAWȯrV0gcD*\mgIs9cu80y:Ú2`a8gnVQ뀞 P_{頛3 r(Q9 OANP_)8?iYtBn*!HDm{ά|֏}=u7z>T3o@.fkrvJWJӯ usqZgW%2lp?yOhٳ=<-jxdp#f0.,#-T$3_ȵ li~q%^8FMoLKbX 3wVx[~Φ3 |L 5seNy8 O`c]!wh]֥75+B\yo8 )-K^6|@n0/U\r%AfqzX3*~Mnoq\#M .vN-:y@Q0 #`q/ՙ\= tAT'tNB!@ rc1;GF轨o}?j)ۀgnj\PHFjt7OQA^'0sQ|vt*RGӿ1}$ #GkԮؗ? G*T\fcp?%a<Gas 3et;]s)T6m~?F]tM+~ "I`Bx  FOZ B.Q;0 CvΕ%yJ\ lf7ߒ#Ձ!c ݈sr\C0t9"w H-_[\Xz{3L,0(?̉oa/Ys=[*,J vA8#cs>``J7~F~Ud`ݵ͠BZmZ& wM躀iqu81\~*ZD:͕p:NdYX[鴖Nw.[r- '"_oNVs˜8FmsUzVC (8r,tO?V:yW_Dzb?~zʆ=`fYBoY=Gލ Y(}ĿG`8k={&n"E㎌?K f|A)㰥%v^(9 _l6:VY,ކfMY9[Z װUߤ 5mzp뜓TXօKh6]CXvqb+w qBeZrGt={_ Ŷ|:4V>k8z nw,݋{,0{qZH݁(]:L}0Fwu~ y=e,D؄E4[C!V&s˸{̷1yQ J)=әF3g_5.ԋisXC8{=HerTzS}pQ*y)s'46":$\Pl67c. VtwJ-Nw"W׸YABon lr&$gD^O7u}$Wzp}DrsSy7 IDAT[Jv=hM:pوtb{ꯠZC$ /2R z46rAXN-+*4tu]3q\l}z=4J_'B0-Lt\]٘++@fR®ũŖRTo].?2̗)R8XpK' @I9?Uu2Ojq$t@*1OkV5-+Ff1_+d0%h<$sz=a }B7:j@4:C輜y\kwVR )W*[|1M!l52s?hK2]wTض۞RK<xsƕV]tY鹢{G!JBT=.\J8MlN?Ɂ{z0<<ut@8vԝA.'԰e)xX;4\=g+G'q[RRʟ{8Ԟrg|ޒiHVXD]C?YP& `9~KO oG.Z~|tE~ew1sPX\R3\hF[ WrEWU\te OR*i,3 kތs`l{]c}TߌzHV2]JXR\8r^?!@r EZzY-Kp$yp O?C-cuHd.<32aP {tAqdSo^8Ney}e((\iUԓX1(&GڝDݑZv{C߳Y0iC9= #=E"H{3שƞ2LxHCYxf%PF:ĥ{So 6+W+STX Ҷm~0ҵ j[{CF"|vBzpFT|CR$D+wT C_B h3kI+c[,GԿ!z&}R%չY:׉Ip/HP@6E9c# Ë>ƝA]Oy yJ#: vX9'Һfף&L܀zZ_:RaKQ-:/$2/oÚ#j>xUηT*#"sc:Sg YN ǃѳR _FWH$qGN4:둻@ul:~÷^xX Ne3ǝ\`\.UY M㩸WKWw-([TI~|&MwatU|gjΟ4}pBu.H:.7Go)`"aBc(b\0 akAfہ,f+| NマBGÒ$Ra(cxjvt *C_ڊ˗aeFoבcxk[ђ,y :| S~TnU(Kk&A袅.WgYX1S^i*oG='NSUGz/#{ @` H {VwSZ+8!v"\㥱-/Uud粌dE.ev6Xӈ;que\z¬j*+Bu^(mF͝-3cʵcit7};KQ6_F70.~Q*`B(O0ok$PiRFI k-? L6CvÊ~}oSsY c"u.łAV2 \<[ m]kV0!Gk賮[48Q|Mv@7V/Yqs1I-gaa*4V(7_šq,I\*q ]_C\[iL ;Rx2ٝ#\}Hl]*[\pakU@*`HEYSW㼷UՃW@y" (QYlMtX+0b(BcX{'Ԇ?)n\'t~7UHYڈNtvവ֏5po^G.)ȗ_("F= F lbDnj?ۯ_W?K~:Ԙ뺅N E7}ƾ35D˝gJ ROp Jo@\C@F9 G/Voŏr̀%Q_;7MEڝ"0?宨:o[Nq0KX*10RƤ'9.gLWN\&iּ Us%v3Sb"S>>3J+_xr!%hk簢 ְmya,3qa rY<+\I6tJ)c?qoǏ*]t: )s -N_ʠM<\g㍅艏Fq8xVjйVﱘ`SW㈷ +Quli绅d_G!N끮S70/ 'P8O(]~dنsr,tŔCw|+S¾r7.p^̓Nǀrp=2F! RkTU)˱^iJ$`fI\ߋ݂:Nl?Eyīh7IXj;q ۝_yv`zU%{)u98x,u]؅8؟y6M?˜*c$y 'skƠfԥ$_Qr}mJUG(ҽVW(3wh @̣Hph.+wϕZvl$h)/8P<;@2UDAR&F] ~bߌߋTnB܄=܃20rw;̂zԶ<;l;4dS)U&(cL~t߁gʷéMc>857-:rFy2qBaGq8BM vLg"~@Y y9v$y U~bHG\sv{ŕyЁF.J=ipNAJY@Dw}C2tG6hDJV!t0xY8:MtVR8\NsEya'ߙ ɜ[ry\|} 8 5I+V 'pvNooL{dKt:/^\{P\pk6jRv]X}H)a oh}g<2hv4 y+6zbYҎJ)L_p<]lZF^VXHQI,/u]ZI8kKxڎj3 G@,,qN'cX._[\QйuppPQEŨ>J`DK' ݎR]+ƾ^W[H-3Vaa\3왾:ԣJWޮ֘=HKF,T1zH+m^:ʹuXa/O8Z0/r9&UO[taVx;?1=\y .'fdNQeNs/KI _]J)xf9.jZ,+3F.bA\NhR!yzX{#$Ƞ ʩ#\\oS ssZm>2<&S?tLhr kuЗZ.8xt tgQ gJ9FE!pB$.ҭJRE2sB`6b196_{)7i~L&zs\20`n[6ӳ'׼DL {0TYpʗ6Xi.]aAR:a)X |ŵ A)F>v`62hg*g ;x-a!5:;/lB+htH˛s3"[ty[VlK"]Id2>lkk$t=L*p;-EG:r N}NEK v:O Z׿0̶]s#LMf QD3d\G V5SwGRV ﶿo{~lm٪bMC=Hi0jOiS+"/ghw¶N6sNRttRL%#r ך^(wRZwA$N\I<[Y1yR\΍%o\'ʣʼC BI@ -nFJ[6\q?Z̀l}")rB iOE>P$Bʜo |߬m qy$)?Ii%6?n܄y}}84r6WHr:^7u:"5Gs:n D[ ( 8rSϡhlf)#V^9`Qtqq|]SFŘ=p˵s]"Ia!͐(݁ۿmB#xGSU0lͼlcϢA7"_g?"]wSo ^R7s;\WKt|,ChK= R/od_'{]=;R 2WDUkq^ml%jfKK\eϥrrғN^隟u$^.wyú#b9SpueEa)aԼ,x_f.-s떬/ @mӝȞC$ޅPX4uLez`JN[``L5-nU7S0L06 ތ_|u9~r?*ը_*e[hh܇s`{yn3Z ݨta`< 17?C+>2sHy)LDŽYk0KT&T|}X]%K~%w1qdrbOF'\?b/ΚDaI ;fo^ِuӕ5X\pB̔Rw۶ql⚃D#[xJN^NZХx(!^Սw"⧑f 0c2~9o_u/;߂ ǾWE: T㗻xb꺙6X u'ކm:E",]|aXx8rG*SY=i%:'̳p2JW\su,Nx-}sIr&F W~lK5x?)luJvBw^0f[CWuz5U3:zʡ@)0l9`Gg*[.o|r \.S2\MUAGU.Otӹ|AR_{&6gu"6h pLl/pP0pA֗36 Wf=R%X, z?am9T}-Ii , B̈́d2P}_J9Z{jG·}|1A1609LĹ~m8ߘpّ`)֯R)TK>Z:~7z*d8*SŝxvßHݶmTUTUjeM.Ҹ/C0 ZOU,B'p' H;=AXΞ so¬w<]n';I4N_1X \㌽y/ZBbϯzسӘ\(JnpWT}' ʨ/&oľqoReY(>"/~9kCrZgǕe`Ԡ9584-lL/W6&wslY!s%Ǟ Kڥ3Ŵ&NV7ຩb:Ul#<1Z-] L_ٌ.uZ1ͯljag+UAzݗ Sv> #v~_$ہOAH規v6{&WH!j'"El:¢xWdb.1$R~q8lk*Oa#k,@[.] U@@\IpiU\?`yrK\qڅ'˯Y`.Ӛ!cfYM݈ݸ.5d1¶mJ@r{;p"?._IDAT>@gspE)t: l6~ g@ZZ5FoO ]V9'u u ]F~E읬\{=0tVK:k'ݛpлNmؖz[2טi,,y01nw;^]֚ TB ?8F G'tqP(yƽHWNR?3yϯ~݌>U1QAp4LE'Wx}= lb K]jhpތud@zPc:%̪_{MpǷI0 yk"FuA S*nc@¶ Zv.P^c $RSMa^』}ȣz1Qwf; WX< &N)ӕBUms5Sc_CAM`TP4+R)o^6?QU&jW@UU/=, _z "B2qE'f9Fc߯b 6l k4ڜ8}C8\Y4FG9bBެ!m(B{$6X]!t3js޾2W{7}jIo.8p`{f@rjFzLaXAEdNJml8] eQt:(y )Z;2ףw *JJ0==i2nO̙HnhHJɺ[QT*T*@Q*PVPK6"[௉Td<ΐ?\E͢Ĉ`8 >/nkX6)&灦51[,H *;_T* FހIg̼rfK!{x{?D'8*ۃ$.b|ˇB^GVC\[)UPj$)ddYȹƃ)oc馷4&a\+]Zi F[*Z6n5Nl[o#w5.ln=)\TGҲ <`F..f!'ZZRxKkϼxZ$ӉISJx:⿗RIaBgr+ɐgˣ@Rp‰Jݐ'B?7 yD3]7؟=xHB Z65nIӸBDmA:\D)\VeYmehX˶Iv0Tyr'{aFluP=sPYrs$ t֢# _7\]\pd&ҥuCZ?81ȥѵ@q͟,2^.cP9̥5JmR6l,Ƃtsss%N/N>.ۅ=%&a5rZTlHy=-IWWH*ryCLʶuS8k v+1Ync'$t4|9M+o,fBHNz'tMA(;[ͺz`<lVkPm# Vv.~漞xx:צeAj]Kcb' BG.9g)X8q)p7]Nj 's :1W$y:uKNyt=4|.pB">Q"\7d!L1/~|^g]d9,Ƈ9’ tQ{ 0ܶZ.>y|50Y״:9иR+RSEuf.w]Yx{rrh/q|$.)lҹ@m?f)Ho'9~u]7@hamҌ;$tØu./lA*RtA(w:R7:q MIJ뺾#\ffKK1lŒ!t)tठb:HCt=ݲuuBTFNBPZ);CeZ7J!]'L@pOTd; $6E#u*.a ~_]8h>Z:&aе ';^O S"Tn9&Y1o_vknAJR篥RCqenqF6߸R6:Ku4 >iI゗;Jx&,O'n-of;Ձ{IR¯WszQ9c4"V'>un8mF:b iakG*vM$I2Qƕ+]ڃy)8u,Yas,LB֓i˜T'H犖|:' =atNa hb'ǖn.d"s`:(%O_ F1rNJeFW~I0A#^3)ȁFͬs:MXNF9Jmɕ!jS(j3 ).t]"IA*:}sj#"v hey+=:6aa $]T^t^< #s6&+=leY:Q )FW7ڭ Ճ>ӑ{3kt)χZ^)F\BPי v^ֹ*'$1C`uTӊԺ%,M3B8W[,_KHKveN:ai]|#KE@Kʍ5k)ܢrH?:ZQ ㌽NB׾mo#VƙC:%?ߡ$  bq@&aN#v4o+uڬn*,R4#KW:_:Mz'NpP„ .0x۴:~uucK*6d&mѬm_e1ΥT;l9[ V&D篻4^p2ma6a׊f eEVD㰛A%qv\s hMuo~߅wq ǟ  }q6`.T*l> ;]Gn:盼[PϹ_71WYJ4=c{[E+YYα:YZyCXg> }pp^ $H A< `bbY$H AK 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H A 'H Aiصk, $H A65'֕;IENDB`ViTables-3.0.0/vitables/icons/vitables_logo.svg000066400000000000000000000637101311223072700215260ustar00rootroot00000000000000 image/svg+xml © 2005-2007 by Cárabos Coop. V.© 2008-2017 by Vicent Mas ViTables-3.0.0/vitables/icons/vitables_wm.png000066400000000000000000000014741311223072700211750ustar00rootroot00000000000000PNG  IHDR DqPLTE       1 !#/38 <# 3mK,M-R0T1X3Y4Z4_7a9 G GHJe<KM%Q SuD^PvE_RhY2^QQR>e|rbTBhyChyWYHluZ\aZvjtc\wiyin]q[prtw}~ۀ߃84ж&#$)25JVu7tRNS@fbKGDH pHYs  tIMErDIDATxڅe[0 Aqw6v 4C$܋\ib2 Me`ib딂r\ffQ.x͌is&p8$^>ڕ-]/ j7-&9xs I4>h#Fmq8GC9@A1ozNIO`<PIZ~ i<Zt_oxjF/> IU#<\qPu`~h6n`hyM ,4WfprRDs6s BMX(4D M3d}d7K jEP @l>F aYBqKWG~CNEthXgO\"#UT2Y2X22Z+2d2NP/g2c[2$Q>3!)%' -`E]e<&CWM.8I4L*J@0;_V5R2  22fS 1BHk9aK^D, 7?6:GjAilOF(bh=( @kwZj>jf.9hW&*07*hYiUsf\)G II ^1_3!9%>(Ejw[vt?i]k}  ^2+#),Edg444tw;4444A444;h 44q4444SR444;444444444444O;;44444ʈ4444j4418 ;;$4444K4444@44+:7;;}44444S`44;;;3ҙM$44_T>2;;;x?J65;;;;*|6I;;;;;;" ]&[G;;;ַ\VH ;;mbQr;<;;fcLl;(e/p;;D߽;Y.;;z&%944k;oF^444#44444{=4444Ⱶ Cq444uXB!444P0v44'N-`4444KޜV)>04+i ZWi!!sa~yUn?(0` jx\s>iG :M#g+2=o_3'l~n<%S~$Ey@KO\hRumJF: Yl+Ha, 1 \y5YQ^oNp, 3yc=S- 3<dt+A Y)UJ#;/GHT! EunsTAu<I}w6 bh0QXw~:atb+DbVd#MzkM 3nmN$NF "'Z.[jLzhBz/78A6\pD (CdtZ#!HDORgxU#XpLR%C\/;E;eH8^/?>DsoN 2UvrBpL_|f?P`pNP %?kwZKV<Q~`6-4){ */!8R`IJ2P{vz7 )E;ceTT!)7\% #,J.OBMFRhTb~{E K Y*^1JTtgpݟ}n:qiL9cocoLDWӟ@:^\뗗`k.~8Ӽ5 @'^i\qS?1\m pm  -39X\𗗗vsGeџ5RQwGY:H㗗Z yUA◗rE%+p*&(U[pz=B E$◌l2&#|"]:֬م÷,95oM%<;ėtV{jI{ڃuLoKlSb!◗ _NO)_zgdp _ CCicmx4h p>?2cԐakc1mF00i967f ȭm^94ppP zm).Wm ΗpC>aIϼ엗u ph2C/g??`???ViTables-3.0.0/vitables/logger.py000066400000000000000000000177011311223072700166710ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """This module provides a console (named Logger) to ``ViTables``. Warning and error messages delivered to users by the application are displayed in this console. Also some messages about the result of the operations requested by users are shown in the console. This is a read-only console, its main purpose is to feed users with important information regarding its working session (so it is called Logger). Users can't enter commands in the Logger. :Parameter parent: the parent widget of the Logger """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate class Logger(QtWidgets.QTextEdit): """ Console that receives all informational application messages. All messages delivered by application to user are displayed in the Logger. This messages include the status of user requested operations, the result of this operations, and also error messages. This is possible because the class reimplement the write() method, so it can be used to catch both, ``sys.stdout`` and ``sys.stderr``, just by redirecting them to an instance of this class. """ def __init__(self, parent=None): """Create the Logger widget and configure it. """ super(Logger, self).__init__(parent) self.setAcceptRichText(True) self.setReadOnly(1) self.setMinimumHeight(50) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.setWhatsThis(translate('Logger', """

The Logger

This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user.

Also execution errors and exceptions are logged in the console. """, 'WhatsThis help for the logger')) self.setStyleSheet("background-color: #ffffff") # The frame especification self.frame_style = {'shape': self.frameShape(), 'shadow': self.frameShadow(), 'lwidth': self.lineWidth(), 'foreground': self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.WindowText)} # Connect signals to slots self.customContextMenuRequested.connect(self.createCustomContextMenu) def write(self, text): """ Catch the messages sent to the standard output and the standard error. The caught messages are displayed in the `Logger` using this method. The implementation is done via QTextEdit.append method because this method adds the text at the end of the console so, even if the user clicks somewhere in the console or there is selected text, the printed text will not mess the console. :Parameter text: the text being written """ current_color = self.textColor() if text in ['\n', '\r\n']: return if text.startswith('\nError: '): self.setTextColor(QtGui.QColor('red')) elif text.startswith('\nWarning: '): self.setTextColor(QtGui.QColor(243, 137, 8)) self.append(text) # Warning! Append() doesn't change the cursor position # Because we want to reset the current color **at the end** of # the console in order to give the proper color to new messages # we must update the cursor position **before** the current # color is reset self.moveCursor(QtGui.QTextCursor.EndOfLine) self.setTextColor(current_color) def flush(self): """ Stopgap function to allow use of this class with logging.StreamHandler. """ pass def createCustomContextMenu(self, pos): """ Popup the context logger menu. :Parameter pos: the local position at which the menu will popup """ vtapp = vitables.utils.getVTApp() # Make the menu edit_menu = QtWidgets.QMenu(self) # QtGui.Qpalette.Window constant is 10 edit_menu.setStyleSheet("background-color: {0}".format(10)) self.copy_action = QtWidgets.QAction( translate('Logger', "&Copy", 'Logger menu entry'), self, shortcut=QtGui.QKeySequence.Copy, triggered=vtapp.gui.makeCopy, statusTip=translate('Logger', 'Copy selected text to clipboard', 'Status bar text for the logger context menu -> Copy action')) edit_menu.addAction(self.copy_action) self.clear_action = QtWidgets.QAction( translate('Logger', "Cl&ear All", 'Logger menu entry'), self, triggered=self.clear, statusTip=translate('Logger', 'Empty the Logger', 'Status bar text for the logger context menu -> Clear action')) edit_menu.addAction(self.clear_action) edit_menu.addSeparator() self.select_action = QtWidgets.QAction( translate('Logger', "Select &All", 'Logger menu entry'), self, triggered=self.selectAll, statusTip=translate('Logger', 'Select the whole Logger contents', 'Status bar text for the logger context menu -> Select All')) edit_menu.addAction(self.select_action) edit_menu.aboutToShow.connect(self.updateEditMenu) edit_menu.popup(self.mapToGlobal(pos)) def updateEditMenu(self): """Update items availability when the menu is about to be shown.""" # Copy is enabled when there is some selected text cursor = self.textCursor() self.copy_action.setEnabled(cursor.hasSelection()) # Clear All and Select All are enabled when there is some text has_content = not self.document().isEmpty() self.clear_action.setEnabled(has_content) self.select_action.setEnabled(has_content) def focusInEvent(self, event): """Specialised handler for focus events. Repaint differently the `Logger` frame when it gets the keyboard focus so that users can realize easily about this focus change. :Parameter event: the event being processed """ self.setLineWidth(2) self.setFrameStyle(QtWidgets.QFrame.Panel|QtWidgets.QFrame.Plain) pal = self.palette() pal.setColor(QtGui.QPalette.Active, QtGui.QPalette.WindowText, QtCore.Qt.darkBlue) QtWidgets.QTextEdit.focusInEvent(self, event) def focusOutEvent(self, event): """Specialised handler for focus events. Repaint differently the `Logger` frame when it looses the keyboard focus so that users can realize easily about this focus change. :Parameter event: the event being processed """ self.setLineWidth(self.frame_style['lwidth']) self.setFrameShape(self.frame_style['shape']) self.setFrameShadow(self.frame_style['shadow']) pal = self.palette() pal.setColor(QtGui.QPalette.Active, QtGui.QPalette.WindowText, self.frame_style['foreground']) QtWidgets.QTextEdit.focusOutEvent(self, event) ViTables-3.0.0/vitables/nodeprops/000077500000000000000000000000001311223072700170435ustar00rootroot00000000000000ViTables-3.0.0/vitables/nodeprops/__init__.py000066400000000000000000000017711311223072700211620ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["attreditor", "attrpropdlg", "grouppropdlg", "groupproppage", "leafpropdlg", "leafproppage", "linkpropdlg", "nodeinfo"] ViTables-3.0.0/vitables/nodeprops/attr_prop_dlg.ui000066400000000000000000000362771311223072700222610ustar00rootroot00000000000000 AttrPropDialog 0 0 438 549 0 0 239 239 239 239 239 239 255 255 255 Dialog 0 0 239 239 239 255 255 255 239 239 239 255 255 255 255 255 255 255 255 255 0 239 239 239 239 239 239 255 255 255 &System attributes System attributes: false true 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 QAbstractItemView::DoubleClicked false true &User Attributes User attributes: false true 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 <qt> <h3>User's attributes editing table</h3> Here you can perform the editing of user's attributes for this node. It is quite straightforward. <p>For adding an attribute click the <b>Add</b> button. A new row will be added to the table. Enter the attribute name and its value in the corresponding cells. Finally, select the attribute datatype in the combobox of the DataType column. In order to delete an attribute just select it by clicking any of its cells, then click the <b>Delete</b> button.</p> <p>Beware that PyTables stores scalar attributes as numpy scalar arrays so you will be unable to save them as Python objects even if you choose the Python datatype in the combobox selector. Also note that multidimensional attributes other than Python lists and tuples are not supported.</p> </qt> QAbstractItemView::DoubleClicked false true Qt::Horizontal 40 20 &Add &Delete &What's this Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonsBox rejected() AttrPropDialog reject() 316 260 286 274 ViTables-3.0.0/vitables/nodeprops/attreditor.py000066400000000000000000000267761311223072700216200ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ When a user edits the attributes of a node using the Properties dialog and presses `OK` the attributes correctness is checked by this module. Datatypes and overflow conditions are checked. If no errors are detected the new set of attributes is stored in the `PyTables` node. Otherwise the user is reported about the error and the dialog remains open so the user can fix her mistake. """ __docformat__ = 'restructuredtext' import tables import numpy from qtpy import QtGui from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate def checkSyntax(value): """Check the syntax of a `Python` expression. :Parameters value: the Python expression to be evaluated """ if value[0] in ("'", '"'): # Quotes are not permitted in the first position return False try: eval(value) except (ValueError, SyntaxError): return False else: return True def formatStrValue(dtype, str_value): """ Format the string representation of a value accordingly to its datatype. This function catches datatype errors for boolean values. :Parameters: - dtype: the value data type - str_value: the string representation of a value """ if dtype == 'bool': # Every listed value is valid but none of them would # pass the out of range test later so we use a fake # valid value. # Beware that numpy.array(True).astype('bool')[()] fails # with a TypeError so we use '1' as a fake value if str_value in ['1', 'TRUE', 'True', 'true']: str_value = '1' elif str_value in ['0', 'FALSE', 'False', 'false']: str_value = '0' else: raise ValueError elif dtype.startswith('complex'): # Valid complex literal strings do not have parenthesis if str_value.startswith('(') and str_value.endswith(')'): str_value = str_value[1:-1] return str_value def checkValue(dtype, str_value): """ Check for overflow errors and dtype errors on integer and float values. By default, when overflow occurs in the creation of a ``numpy`` array, it is silently converted to the desired datatype: >>> numpy.array(-4).astype(numpy.uint8) array(252, dtype=uint8) >>> numpy.array(1420).astype(numpy.int8) array(-116, dtype=int8) This behavior can be acceptable for a library, but not for an end user application as ``ViTables`` so we have to catch such cases. :Parameters: - dtype: the value datatype - str_value: the string representation of a value """ dtypes_map = { 'int8': numpy.int8, 'int16': numpy.int16, 'int32': numpy.int32, 'int64': numpy.int64, 'uint8': numpy.uint8, 'uint16': numpy.uint16, 'uint32': numpy.uint32, 'uint64': numpy.uint64, 'float32': numpy.float32, 'float64': numpy.float64, } # For Python objects and strings no overflow can occur if dtype not in dtypes_map: return str_value new_array = numpy.array(str_value).astype(dtype) # Catches unexpected results from conversions # Examples: numpy.array('-23').astype('unint8') -> mismatch dtype # or numpy.array('99999').astype('int8') -> overflow if str(new_array[()]) != str_value: raise RuntimeWarning # If no errors are found return the original value return str_value class AttrEditor(object): """ Setup the attributes entered in the Properties dialog. When the user edits the Attributes Set Instance (see `PyTables` manual for details) of a given node via the Properties dialog and presses `OK` the validity of the new set of attributes is checked. If it is fine then the old `ASI` is replaced by the new one and the dialog is closed. If an error is found in the new set of attributes then the dialog remains opened until the user fixes the mistake. :Parameters: - `asi`: the Attributes Set Instance being updated - `title`: the TITLE attribute entered by the user in the Properties dialog - `user_table`: the table of user attributes edited by the user in the Properties dialog """ def __init__(self, asi, title, user_table): """Initialise the attributes checker.""" self.asi = asi # A dictionary with the attributes that have to be checked self.edited_attrs = {} model = user_table.model() rows = model.rowCount() # Parse the table and get string representations of its cell contents for row in range(0, rows): # As ViTables doesn't support editing ND-array attributes they # are marked in order to be found later name_item = model.item(row, 0) if not name_item.isEditable(): multidim = True else: multidim = False name = model.item(row, 0).text() value = model.item(row, 1).text() dtype_index = model.indexFromItem(model.item(row, 2)) dtype = user_table.indexWidget(dtype_index).currentText() self.edited_attrs[row] = (name, value, dtype, multidim) # Add the TITLE attribute to the dictionary if title is not None: self.edited_attrs[rows] = ('TITLE', title, 'string', False) def checkAttributes(self): """ Check the user attributes table. If empty or repeated names, values mismatching the attribute type or out of range values are found then an error is reported. If the table is OK the node `ASI` is updated and the Properties dialog is closed. The attributes checked here are those of self.edited_attrs dict so the values are all string """ # Error message for mismatching value/type pairs dtype_error = translate('AttrEditor', """\nError: "{0}" value """ """mismatches its data type.""", 'User attributes table editing error') # Error message for overflow values range_error = translate('AttrEditor', """\nError: "{0}" value """ """is out of range.""", 'User attributes table editing error') # Some times it's difficult to find out if the error # is due to a mismatch or to an overflow conversion_error = translate('AttrEditor', """\nError: "{0}" value """ """is out of range or mismatches its data type.""", 'User attributes table editing error') # Error message for syntax errors in Python attributes syntax_error = translate('AttrEditor', """\nError: "{0}" """ """cannot be converted to a Python object.""", 'User attributes table editing error') rows_range = self.edited_attrs.keys() # Check for empty Name cells for row in rows_range: name = self.edited_attrs[row][0] # Empty Value cells are acceptable for string attributes # but empty Name cells are invalid if name == '': return (False, translate('AttrEditor', "\nError: empty field Name in the row {0:d}", 'User attrs editing error').format(int(row + 1))) # Check for repeated names names_list = [] for row in rows_range: name = self.edited_attrs[row][0] if not name in names_list: names_list.append(name) else: return (False, translate('AttrEditor', '\nError: attribute name "{0}" is repeated.', 'User attrs table editing error').format(name)) # Check for dtype, range and syntax correctness of scalar attributes for row in rows_range: name, value, dtype, multidim = self.edited_attrs[row] if multidim == True: continue if dtype == 'python': # Check the syntax of the Python expression if not checkSyntax(value): return (False, syntax_error.format(name)) elif dtype == 'string': dtype = 'str' elif dtype == 'bytes': pass else: # Format properly the string representation of value # and check for dtype and overflow errors try: value = formatStrValue(dtype, value) value = checkValue(dtype, value) except OverflowError: return (False, range_error.format(name)) except ValueError: return (False, dtype_error.format(name)) except RuntimeWarning: return (False, conversion_error.format(name)) # If the attribute passes every test then its entry in the # dictionary of edited attributes is updated self.edited_attrs[row] = name, value, dtype, multidim return (True, None) def setAttributes(self): """ Update edited attributes. This method is called when the user has successfully edited some attribute in the Properties dialog. If it happens then this method updates the `ASI` of the inspected `PyTables` node. """ # Get rid of deleted attributes if 'TITLE' in self.edited_attrs: all_attrs = frozenset(self.asi._v_attrnamesuser + ["TITLE"]) else: all_attrs = frozenset(self.asi._v_attrnamesuser) edited_attrs_names = frozenset([self.edited_attrs[row][0] for row in self.edited_attrs.keys()]) for attr in (all_attrs - edited_attrs_names): try: self.asi._v_node._f_delattr(attr) except (tables.NodeError, AttributeError): vitables.utils.formatExceptionInfo() for row in self.edited_attrs.keys(): # Scalar attributes are stored as # numpy scalar arrays of the proper type name, value, dtype, multidim = self.edited_attrs[row] if multidim == True: continue if dtype == 'python': value = eval('{0}'.format(value)) elif dtype == 'bytes': # Remove the prefix and enclosing quotes value = value[2:-1] value = numpy.array(value).astype(dtype)[()] else: value = numpy.array(value).astype(dtype)[()] # Updates the ASI try: setattr(self.asi, name, value) except AttributeError: vitables.utils.formatExceptionInfo() ViTables-3.0.0/vitables/nodeprops/attrpropdlg.py000066400000000000000000000422311311223072700217610ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module displays in a dialog the node information collected by the :mod:`vitables.nodeprops.nodeinfo` module. Users' attributes can be edited if the database has been opened in read-write mode. Otherwise all shown information is read-only. """ __docformat__ = 'restructuredtext' import os.path import logging import tables from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils from vitables.nodeprops import attreditor translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dynamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_AttrPropDialog = \ loadUiType(os.path.join(os.path.dirname(__file__),'attr_prop_dlg.ui'))[0] class AttrPropDlg(QtWidgets.QDialog, Ui_AttrPropDialog): """ Node properties dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a tabbed dialog that shows some properties of the selected node. First tab, General, shows general properties like name, path, type etc. The second and third tabs show the system and user attributes in a tabular way. Beware that data types shown in the General page are `PyTables` data types so we can deal with `bytes`, `enum`, `time64` and `pseudoatoms` (not all of them are supported by ``numpy``). However data types shown in the System and User attributes pages are ``numpy`` data types because `PyTables` attributes are stored as ``numpy`` arrays. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the Properties dialog.""" vtapp = vitables.utils.getVTApp() super(AttrPropDlg, self).__init__(vtapp.gui) self.setupUi(self) self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # Customise the dialog's pages self.fillSysAttrsPage(info) self.fillUserAttrsPage(info) self.resize(self.size().width(), self.minimumHeight()) # Variables used for checking the table of user attributes self.mode = info.mode self.asi = info.asi def fillSysAttrsPage(self, info): """Fill the page of system attributes. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ # Number of attributes label self.sattrLE.setText(str(len(info.system_attrs))) # Table of system attributes self.sysTable.horizontalHeader().setSectionResizeMode( QtWidgets.QHeaderView.Stretch) self.sysattr_model = QtGui.QStandardItemModel() self.sysattr_model.setHorizontalHeaderLabels([ translate('AttrPropDlg', 'Name', 'First column header of the table'), translate('AttrPropDlg', 'Value', 'Second column header of the table'), translate('AttrPropDlg', 'Datatype', 'Third column header of the table')]) self.sysTable.setModel(self.sysattr_model) # Fill the table bg_brush = self.sysTable.palette().brush(QtGui.QPalette.Window) base_brush = self.sysTable.palette().brush(QtGui.QPalette.Base) for name, value in info.system_attrs.items(): name_item = QtGui.QStandardItem(name) name_item.setEditable(False) name_item.setBackground(bg_brush) # Find out the attribute datatype. # Since PyTables1.1 scalar attributes are stored as numarray arrays # Since PyTables2.0 scalar attributes are stored as numpy arrays # It includes the TITLE attribute # For instance, assume the ASI of a given node is asi. Then # if I do asi.test = 3 -> # type(asi.test) returns numpy.int32 # isinstance(asi.test, int) returns True # asi.test.shape returns () # asi.test2 = "hello" -> # type(asi.test2) returns numpy.string_ # isinstance(asi.test2, str) returns True # asi.test2.shape returns () # Beware that objects whose shape is () are not warranted # to be Python objects, for instance # x = numpy.array(3) -> # x.shape returns () # type(x) returns numpy.ndarray # isinstance(x, int) returns False if isinstance(value, tables.Filters): dtype_name = 'tables.filters.Filters' elif hasattr(value, 'shape'): dtype_name = value.dtype.name else: # Attributes can be scalar Python objects (PyTables <1.1) # or non scalar Python objects, e.g. sequences dtype_name = str(type(value)) dtype_item = QtGui.QStandardItem(dtype_name) dtype_item.setEditable(False) dtype_item.setBackground(bg_brush) value_item = QtGui.QStandardItem(str(value)) value_item.setEditable(False) value_item.setBackground(bg_brush) # When the database is in read-only mode the TITLE attribute # cannot be edited if (name == 'TITLE') and (info.mode != 'read-only'): # The position of the TITLE value in the table self.title_row = self.sysattr_model.rowCount() self.title_before = value_item.text() value_item.setEditable(True) value_item.setBackground(base_brush) self.sysattr_model.appendRow([name_item, value_item, dtype_item]) def fillUserAttrsPage(self, info): """Fill the page of user attributes. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ self.user_attrs_before = [] # Number of attributes label self.uattrLE.setText(str(len(info.user_attrs))) # Table of user attributes self.userTable.horizontalHeader().\ setSectionResizeMode(QtWidgets.QHeaderView.Stretch) self.userattr_model = QtGui.QStandardItemModel() self.userattr_model.setHorizontalHeaderLabels([ translate('AttrPropDlg', 'Name', 'First column header of the table'), translate('AttrPropDlg', 'Value', 'Second column header of the table'), translate('AttrPropDlg', 'Datatype', 'Third column header of the table')]) self.userTable.setModel(self.userattr_model) # Fill the table # The Data Type cell is a combobox with static content dtypes_list = ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float32', 'float64', 'complex64', 'complex128', 'bool', 'bytes', 'string', 'python'] # Brushes used for read-only and writable cells bg_brush = self.userTable.palette().brush(QtGui.QPalette.Window) base_brush = self.userTable.palette().brush(QtGui.QPalette.Base) for name, value in info.user_attrs.items(): name_item = QtGui.QStandardItem(name) value_item = QtGui.QStandardItem(str(value)) dtype_item = QtGui.QStandardItem() dtypes_combo = QtWidgets.QComboBox() dtypes_combo.addItems(dtypes_list) dtypes_combo.setEditable(False) # In PyTables >=1.1 scalar attributes are stored as numarray arrays # In PyTables >= 2.0 scalar attributes are stored as numpy arrays if hasattr(value, 'shape'): dtype_name = value.dtype.name if dtype_name.startswith('bytes'): dtype_name = 'bytes' elif dtype_name.startswith('str'): dtype_name = 'string' else: # Attributes can be scalar Python objects (PyTables <1.1) # or non scalar Python objects, e.g. sequences dtype_name = 'python' self.userattr_model.appendRow([name_item, value_item, dtype_item]) dtypes_combo.setCurrentIndex(dtypes_combo.findText(dtype_name)) self.userTable.setIndexWidget(dtype_item.index(), dtypes_combo) # Complex attributes and ND_array attributes need some visual # adjustments if dtype_name.startswith('complex'): # Remove parenthesis from the str representation of # complex numbers. if (str(value)[0], str(value)[-1]) == ('(', ')'): value_item.setText(str(value)[1:-1]) # ViTables doesn't support editing ND-array attributes so # they are displayed in non editable cells if (hasattr(value, 'shape') and value.shape != ())or\ (info.mode == 'read-only'): editable = False brush = bg_brush else: editable = True brush = base_brush name_item.setEditable(editable) name_item.setBackground(brush) value_item.setEditable(editable) value_item.setBackground(brush) self.user_attrs_before.append((name_item.text(), value_item.text(), dtypes_combo.currentText())) self.user_attrs_before = sorted(self.user_attrs_before[:]) # The group of buttons Add, Delete, What's This self.page_buttons = QtWidgets.QButtonGroup(self.userattrs_page) self.page_buttons.addButton(self.addButton, 0) self.page_buttons.addButton(self.delButton, 1) self.page_buttons.addButton(self.helpButton, 2) # If the database is in read-only mode user attributes cannot be edited if info.mode == 'read-only': for uid in (0, 1): self.page_buttons.button(uid).setEnabled(False) self.helpButton.clicked.connect(QtWidgets.QWhatsThis.enterWhatsThisMode) @QtCore.Slot("QModelIndex", name="on_sysTable_clicked") @QtCore.Slot("QModelIndex", name="on_userTable_clicked") def displaySelectedCell(self, index): """Show the content of the clicked cell in the line edit at bottom. :Parameter index: the model index of the clicked cell """ page = self.tabw.currentIndex() if page == 1: model_item = self.sysattr_model.itemFromIndex(index) self.systemAttrCellLE.clear() self.systemAttrCellLE.setText(model_item.text()) elif page == 2: model_item = self.userattr_model.itemFromIndex(index) self.userAttrCellLE.clear() self.userAttrCellLE.setText(model_item.text()) @QtCore.Slot(name="on_addButton_clicked") def addAttribute(self): """Add a new attribute to the user's attributes table.""" # The Data Type cell is a combobox with static content dtypes_list = ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float32', 'float64', 'complex64', 'complex128', 'bool', 'bytes', 'string', 'python'] name_item = QtGui.QStandardItem() value_item = QtGui.QStandardItem() dtype_item = QtGui.QStandardItem() dtypes_combo = QtWidgets.QComboBox() dtypes_combo.addItems(dtypes_list) dtypes_combo.setEditable(False) self.userattr_model.appendRow([name_item, value_item, dtype_item]) self.userTable.setIndexWidget(dtype_item.index(), dtypes_combo) # Start editing the proper cell. If not, clicking Add+Delete # would result in the deletion of an attribute different to that # just added. It is also more handy as it allows to start editing # without double clicking the cell. self.userTable.edit(name_item.index()) @QtCore.Slot(name="on_delButton_clicked") def delAttribute(self): """ Remove an attribute from the user's attributes table. This slot is connected to the clicked signal of the `Delete` button. An attribute is marked for deletion by giving focus to any cell of the row describing it (i.e. clicking a cell or selecting its contents). """ # If there is not a selected attribute then return current_index = self.userTable.currentIndex() if not current_index.isValid(): self.logger.error( translate('AttrPropDlg', 'Please, select the attribute to be deleted.', 'A usage text')) return # Get the name of the attribute being deleted current_row = current_index.row() current_column = current_index.column() if current_column != 0: current_index = current_index.sibling(current_row, 0) name = self.userattr_model.itemFromIndex(current_index).text() # Delete the marked attribute title = translate('AttrPropDlg', 'User attribute deletion', 'Caption of the attr deletion dialog') text = translate('AttrPropDlg', "\n\nYou are about to delete the attribute:\n{0}\n\n", 'Ask for confirmation').format(name) itext = '' dtext = '' buttons = { 'Delete': (translate('AttrPropDlg', 'Delete', 'Button text'), QtWidgets.QMessageBox.YesRole), 'Cancel': (translate('AttrPropDlg', 'Cancel', 'Button text'), QtWidgets.QMessageBox.NoRole), } # Ask for confirmation answer = vitables.utils.questionBox(title, text, itext, dtext, buttons) if answer == 'Delete': # Updates the user attributes table self.userattr_model.removeRow(current_row) def asiChanged(self): """Find out if the user has edited some attribute. In order to decide if attributes have been edited we compare the attribute tables contents at dialog creation time and at dialog closing time. """ # Get the value of the TITLE attribute. Checking is required # because the attribute is mandatory in PyTables but not in # generic HDF5 files self.title_after = None if hasattr(self, 'title_row'): self.title_after = \ self.sysattr_model.item(self.title_row, 1).text() if self.title_before != self.title_after: return True # Check user attributes self.user_attrs_after = [] for index in range(0, self.userTable.model().rowCount()): name_after = self.userattr_model.item(index, 0).text() value_after = self.userattr_model.item(index, 1).text() dtype_item = self.userattr_model.item(index, 2) dtype_combo = self.userTable.indexWidget(dtype_item.index()) dtype_after = dtype_combo.currentText() self.user_attrs_after.append((name_after, value_after, dtype_after)) if sorted(self.user_attrs_before) != sorted(self.user_attrs_after) : return True return False @QtCore.Slot(name="on_buttonsBox_accepted") def accept(self): """ Overwritten slot for accepted dialogs. This slot is always the last called method whenever the Apply/Ok buttons are pressed. """ # If the file is in read-only mode or the Attribute Set Instance # remains unchanged no attribute needs to be updated if (self.mode == 'read-only') or (not self.asiChanged()): QtWidgets.QDialog.accept(self) return # This is mandatory! # Check the editable attributes aeditor = attreditor.AttrEditor(self.asi, self.title_after, self.userTable) attrs_are_ok, error = aeditor.checkAttributes() # If the attributes pass correctness checks then update the # attributes and close the dialog if attrs_are_ok == True: aeditor.setAttributes() del aeditor QtWidgets.QDialog.accept(self) return # If not then keep the dialog opened else: del aeditor self.tabw.setCurrentIndex(2) self.userAttrCellLE.clear() self.userAttrCellLE.setText(error) ViTables-3.0.0/vitables/nodeprops/group_prop_page.ui000066400000000000000000000245531311223072700226030ustar00rootroot00000000000000 FilePropPage 0 0 465 345 Form Database Name: Path: Type: Access mode: 239 239 239 239 239 239 244 244 244 false true 239 239 239 239 239 239 244 244 244 false true 239 239 239 239 239 239 244 244 244 false true 239 239 239 239 239 239 244 244 244 false true Root group Number of children: 239 239 239 239 239 239 244 244 244 false true 0 0 239 239 239 239 239 239 244 244 244 QAbstractItemView::NoEditTriggers false ViTables-3.0.0/vitables/nodeprops/grouppropdlg.py000066400000000000000000000057001311223072700221430ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module displays in a dialog tables.Group information collected by the :mod:`vitables.nodeprops.nodeinfo` module. Users' attributes can be edited if the database has been opened in read-write mode. Otherwise all shown information is read-only. """ __docformat__ = 'restructuredtext' from qtpy import QtGui from qtpy import QtWidgets from vitables.nodeprops import attrpropdlg from vitables.nodeprops import groupproppage translate = QtWidgets.QApplication.translate class GroupPropDlg(attrpropdlg.AttrPropDlg): """ Group properties dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a tabbed dialog that shows some properties of the selected node. First tab, General, shows general properties like name, path, type etc. The second and third tabs show the system and user attributes in a tabular way. Beware that data types shown in the General page are `PyTables` data types so we can deal with `enum`, `time64` and `pseudoatoms` (none of them are supported by ``numpy``). However data types shown in the System and User attributes pages are ``numpy`` data types because `PyTables` attributes are stored as ``numpy`` arrays. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the Properties dialog.""" super(GroupPropDlg, self).__init__(info) general_page = groupproppage.GroupPropPage(info) self.tabw.insertTab(0, general_page, 'General') self.tabw.setCurrentIndex(0) if info.node_type == 'root group': self.setWindowTitle(translate('GroupPropDlg', 'File properties', 'Dlg caption')) else: self.setWindowTitle(translate('GroupPropDlg', 'Group properties', 'Dlg caption')) general_page.regularGroupPage() self.show() ViTables-3.0.0/vitables/nodeprops/groupproppage.py000066400000000000000000000126311311223072700223120ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ A form with tables.Group information collected by the :mod:`vitables.nodeprops.nodeinfo` module. """ __docformat__ = 'restructuredtext' import os.path from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_GroupPropPage = \ loadUiType(os.path.join(os.path.dirname(__file__),'group_prop_page.ui'))[0] class GroupPropPage(QtWidgets.QWidget, Ui_GroupPropPage): """ Group properties page. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a tabbed dialog that shows some properties of the selected node. First tab, General, shows general properties like name, path, type etc. The second and third tabs show the system and user attributes in a tabular way. Beware that data types shown in the General page are `PyTables` data types so we can deal with `enum`, `time64` and `pseudoatoms` (none of them are supported by ``numpy``). However data types shown in the System and User attributes pages are ``numpy`` data types because `PyTables` attributes are stored as ``numpy`` arrays. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the File Properties page.""" vtapp = vitables.utils.getVTApp() super(GroupPropPage, self).__init__(vtapp.gui) self.setupUi(self) # Customise the dialog's pages self.fillGeneralPage(info) def fillGeneralPage(self, info): """Make the General page of the Properties dialog. The page contains two groupboxes that are laid out vertically. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ if info.node_type == 'root group': self.nameLE.setText(info.filename) self.pathLE.setText(info.filepath) self.pathLE.setToolTip(info.filepath) self.typeLE.setText(info.file_type) self.modeLE.setText(info.mode) else: self.nameLE.setText(info.nodename) self.pathLE.setText(info.nodepath) self.pathLE.setToolTip(info.nodepath) self.typeLE.setText(info.node_type) # Number of children label self.nchildrenLE.setText(str(len(info.hanging_nodes))) # The group's children table table = self.nchildrenTable table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) background = table.palette().brush(QtGui.QPalette.Window).color() table.setStyleSheet("background-color: {0}".format(background.name())) self.children_model = QtGui.QStandardItemModel() self.children_model.setHorizontalHeaderLabels([ translate('GroupPropPage', 'Child name', 'First column header of the table'), translate('GroupPropPage', 'Type', 'Second column header of the table')]) table.setModel(self.children_model) for name in info.hanging_groups.keys(): name_item = QtGui.QStandardItem(name) type_item = QtGui.QStandardItem(translate('GroupPropPage', 'group')) self.children_model.appendRow([name_item, type_item]) for name in info.hanging_leaves.keys(): name_item = QtGui.QStandardItem(name) type_item = QtGui.QStandardItem(translate('GroupPropPage', 'leaf')) self.children_model.appendRow([name_item, type_item]) for name in info.hanging_links.keys(): name_item = QtGui.QStandardItem(name) type_item = QtGui.QStandardItem(translate('GroupPropPage', 'link')) self.children_model.appendRow([name_item, type_item]) def regularGroupPage(self): """Remove widgets regarding root groups. """ # Remove the Access mode widgets self.dblayout.removeWidget(self.modeLabel) self.dblayout.removeWidget(self.modeLE) self.modeLabel.deleteLater() self.modeLE.deleteLater() # Change the title of the group box self.bottomGB.setTitle(translate('GroupPropPage', 'Group', 'Title of the group box')) ViTables-3.0.0/vitables/nodeprops/leaf_prop_page.ui000066400000000000000000000345631311223072700223600ustar00rootroot00000000000000 LeafPropPage 0 0 506 389 Form Database Name: Path: Type: 239 239 239 239 239 239 244 244 244 false true 239 239 239 239 239 239 244 244 244 false true 239 239 239 239 239 239 244 244 244 false true Dataspace Dimensions: 239 239 239 239 239 239 244 244 244 false true Shape: 239 239 239 239 239 239 244 244 244 false true Data Type: 239 239 239 239 239 239 244 244 244 false true Compression: 239 239 239 239 239 239 244 244 244 false true 0 0 239 239 239 239 239 239 244 244 244 QAbstractItemView::NoEditTriggers false ViTables-3.0.0/vitables/nodeprops/leafpropdlg.py000066400000000000000000000056541311223072700217260ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module displays in a dialog tables.Leaf information collected by the :mod:`vitables.nodeprops.nodeinfo` module. Users' attributes can be edited if the database has been opened in read-write mode. Otherwise all shown information is read-only. """ __docformat__ = 'restructuredtext' from qtpy import QtGui from qtpy import QtWidgets from vitables.nodeprops import attrpropdlg from vitables.nodeprops import leafproppage translate = QtWidgets.QApplication.translate class LeafPropDlg(attrpropdlg.AttrPropDlg): """ Leaf properties dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a tabbed dialog that shows some properties of the selected node. First tab, General, shows general properties like name, path, type etc. The second and third tabs show the system and user attributes in a tabular way. Beware that data types shown in the General page are `PyTables` data types so we can deal with `enum`, `time64` and `pseudoatoms` (none of them are supported by ``numpy``). However data types shown in the System and User attributes pages are ``numpy`` data types because `PyTables` attributes are stored as ``numpy`` arrays. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the Properties dialog.""" super(LeafPropDlg, self).__init__(info) general_page = leafproppage.LeafPropPage(info) self.tabw.insertTab(0, general_page, 'General') self.tabw.setCurrentIndex(0) if info.node_type == 'table': self.setWindowTitle(translate('LeafPropDlg', 'Table properties', 'Dlg caption')) else: self.setWindowTitle(translate('LeafPropDlg', 'Array properties', 'Dlg caption')) general_page.arrayPage() self.show() ViTables-3.0.0/vitables/nodeprops/leafproppage.py000066400000000000000000000134251311223072700220670ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ A form with tables.Leaf information collected by the :mod:`vitables.nodeprops.nodeinfo` module. """ __docformat__ = 'restructuredtext' import os.path from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_LeafPropPage = \ loadUiType(os.path.join(os.path.dirname(__file__),'leaf_prop_page.ui'))[0] class LeafPropPage(QtWidgets.QWidget, Ui_LeafPropPage): """ Leaf properties page. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a tabbed dialog that shows some properties of the selected node. First tab, General, shows general properties like name, path, type etc. The second and third tabs show the system and user attributes in a tabular way. Beware that data types shown in the General page are `PyTables` data types so we can deal with `enum`, `time64` and `pseudoatoms` (none of them are supported by ``numpy``). However data types shown in the System and User attributes pages are ``numpy`` data types because `PyTables` attributes are stored as ``numpy`` arrays. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the File Properties page.""" vtapp = vitables.utils.getVTApp() super(LeafPropPage, self).__init__(vtapp.gui) self.setupUi(self) # Customise the dialog's pages self.fillGeneralPage(info) def fillGeneralPage(self, info): """Make the General page of the Properties dialog. The page contains two groupboxes that are laid out vertically. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ self.nameLE.setText(info.nodename) self.pathLE.setText(info.nodepath) self.pathLE.setToolTip(info.nodepath) self.typeLE.setText(info.node_type) self.dimLE.setText(str(len(info.shape))) self.shapeLE.setText(str(info.shape)) self.dtypeLE.setText(info.type) if info.filters.complib is None: self.compressionLE.setText('uncompressed') else: self.compressionLE.setText(str(info.filters.complib)) # Information about the fields of Table instances if info.node_type == 'table': table = self.recordsTable # The Table's fields description table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) # QtGui.QPalette.Window constant is 10 bg_name = table.palette().brush(10).color().name() table.setStyleSheet("background-color: {0}".format(bg_name)) self.fields_model = QtGui.QStandardItemModel() self.fields_model.setHorizontalHeaderLabels([ translate('LeafPropPage', 'Field name', 'First column header of the table'), translate('LeafPropPage', 'Type', 'Second column header of the table'), translate('LeafPropPage', 'Shape', 'Third column header of the table')]) table.setModel(self.fields_model) # Fill the table. Nested fields will appear as (colname, nested, -) seen_paths = [] for pathname in info.columns_pathnames: if pathname.count('/'): field_name = pathname.split('/')[0] if field_name in seen_paths: continue else: seen_paths.append(field_name) pathname_item = QtGui.QStandardItem(field_name) type_item = QtGui.QStandardItem( translate('LeafPropPage', 'nested')) shape_item = QtGui.QStandardItem( translate('LeafPropPage', '-')) else: pathname_item = QtGui.QStandardItem(str(pathname)) type_item = QtGui.QStandardItem( str(info.columns_types[pathname])) shape_item = QtGui.QStandardItem( str(info.columns_shapes[pathname])) self.fields_model.appendRow([pathname_item, type_item, shape_item]) def arrayPage(self): """Remove widgets regarding root groups. """ # Remove the table of fields and datatypes self.dataspace_layout.removeWidget(self.recordsTable) self.recordsTable.deleteLater() ViTables-3.0.0/vitables/nodeprops/link_prop_dlg.ui000066400000000000000000000176741311223072700222440ustar00rootroot00000000000000 LinkPropDialog 0 0 472 160 Dialog General Name: 239 239 239 239 239 239 244 244 244 false true Path: 239 239 239 239 239 239 244 244 244 false true Type: 239 239 239 239 239 239 244 244 244 false Target: 239 239 239 239 239 239 244 244 244 false true Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() LinkPropDialog accept() 248 254 157 274 buttonBox rejected() LinkPropDialog reject() 316 260 286 274 ViTables-3.0.0/vitables/nodeprops/linkpropdlg.py000066400000000000000000000055271311223072700217530ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module displays in a dialog the link information collected by the :mod:`vitables.nodeprops.nodeinfo` module. """ __docformat__ = 'restructuredtext' import os.path from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_LinkPropDialog = \ loadUiType(os.path.join(os.path.dirname(__file__),'link_prop_dlg.ui'))[0] class LinkPropDlg(QtWidgets.QDialog, Ui_LinkPropDialog): """ Link properties dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This class displays a simple dialog that shows some properties of the selected link: name, path, type and target. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ def __init__(self, info): """Setup the Properties dialog.""" vtapp = vitables.utils.getVTApp() super(LinkPropDlg, self).__init__(vtapp.gui) self.setupUi(self) self.setWindowTitle(translate('LinkPropDlg', 'Link properties', 'Dlg caption')) # Customise the dialog's pages self.fillPage(info) self.resize(self.size().width(), self.minimumHeight()) # Show the dialog self.show() def fillPage(self, info): """Fill the dialog with info regarding the given link. :Parameter info: a :meth:`vitables.nodeprops.nodeinfo.NodeInfo` instance describing a given node """ self.nameLE.setText(info.nodename) self.pathLE.setText(info.nodepath) self.typeLE.setText(info.link_type) self.targetLE.setText(info.target) ViTables-3.0.0/vitables/nodeprops/nodeinfo.py000066400000000000000000000215571311223072700212300ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module collects information about a given node of a `PyTables` database. """ __docformat__ = 'restructuredtext' import os.path import vitables.utils class NodeInfo(object): """Collects information about a given node. The following data and metadata can be collected: * format of the database (generic `HDF5` or `PyTables`) * filename of the database * filepath of the database * opening mode of the database * size of the database * node type * node name * node path * for `tables.Group` nodes: - attributes set instance and related info - dictionary of nodes hanging from a group - dictionary of groups hanging from a group - dictionary of leaves hanging from a group * for `tables.Table` nodes: - columns names, datatypes and shapes - number of rows and columns - filters - shape - flavor * for `tables.XArray` nodes: - number of rows - datatype - filters - shape - flavor :Parameter node_item: an instance of :meth:`RootGroupNode`, :meth:`GroupNode` or :meth:`LeafNode`. """ def __init__(self, node_item): """Collects information about a given node. Some PyTables2.X string attributes are regular Python strings instead of unicode strings and have to be explicitely converted to unicode. """ self.node = node_item.node # The hosting File instance, filepath, filename and opening mode self.filepath = str(node_item.filepath) self.filename = os.path.basename(self.filepath) self.h5file = self.node._v_file mode = str(self.h5file.mode) if mode == 'a': self.mode = 'append' elif mode == 'r': self.mode = 'read-only' else: self.mode = 'read-write' # The node type is a string with one of the following values: # root group, group, table, vlarray, earray, carray, array # or unimplemented self.node_type = node_item.node_kind self.file_type = self.format + ', ' + self.size self.nodename = str(node_item.name) self.nodepath = str(node_item.nodepath) # The attributes set instance self.asi = self.node._v_attrs sysattrs_names = self.asi._v_attrnamessys self.system_attrs = \ dict((n, getattr(self.asi, n, None)) for n in sysattrs_names) userattrs_names = self.asi._v_attrnamesuser self.user_attrs = \ dict((n, getattr(self.asi, n, None)) for n in userattrs_names) # Properties for File instances def _format(self): """The format of the hosting `tables.File` instance""" if self.h5file._isPTFile: return 'PyTables file' else: return 'Generic HDF5 file' format = property(fget=_format) def _size(self): """The size of the hosting `tables.File` instance""" n_bytes = os.path.getsize(self.filepath) *1.0 kbytes = n_bytes/1024 mbytes = kbytes/1024 gbytes = mbytes/1024 tbytes = gbytes/1024 if kbytes < 1: size = '{0:.0f} bytes'.format(n_bytes) elif mbytes < 1: size = '{0:.1f} KB'.format(kbytes) elif gbytes < 1: size = '{0:.1f} MB'.format(mbytes) elif tbytes < 1: size = '{0:.1f} GB'.format(gbytes) else: size = '{0:.1f} TB'.format(tbytes) return size size = property(fget=_size) # Properties for Group instances def _hangingNodes(self): """The dictionary of nodes hanging from this node.""" try: return self.node._v_children except AttributeError: return {} hanging_nodes = property(fget=_hangingNodes) def _hangingGroups(self): """The dictionary of groups hanging from this node.""" try: return self.node._v_groups except AttributeError: return {} hanging_groups = property(fget=_hangingGroups) def _hangingLeaves(self): """The dictionary of leaves hanging from this node.""" try: return self.node._v_leaves except AttributeError: return {} hanging_leaves = property(fget=_hangingLeaves) def _hangingLinks(self): """The dictionary of links hanging from this node.""" try: return self.node._v_links except AttributeError: return {} hanging_links = property(fget=_hangingLinks) # Properties for Leaf instances def _type(self): """The `PyTables` data type of the atom for `tables.Leaf` nodes.""" if self.node_type.count('array'): try: return str(self.node.atom.type) except AttributeError: return None elif self.node_type == 'table': return 'record' type = property(fget=_type) def _nrows(self): """The current number of rows in the `tables.Leaf` node.""" try: return self.node.shape[0] except TypeError: # shape is None return 0 except IndexError: # numpy scalar arrays have shape = () return 1 nrows = property(fget=_nrows) def _shape(self): """The shape of data in the `tables.Leaf` node.""" try: return self.node.shape except AttributeError: return None shape = property(fget=_shape) def _flavor(self): """The type of data object read from the `tables.Leaf` node.""" try: return str(self.node.flavor) except AttributeError: return None flavor = property(fget=_flavor) def _filters(self): """Filters property for this `tables.Leaf` node.""" try: return self.node.filters except AttributeError: return None filters = property(fget=_filters) # Properties for Table instances def _colNames(self): """The list of names of top-level columns in a `tables.Table` node.""" try: return self.node.colnames except AttributeError: return [] columns_names = property(fget=_colNames) def _colPathNames(self): """The list of paths of top-level columns in a `tables.Table` node.""" try: return self.node.colpathnames except AttributeError: return [] columns_pathnames = property(fget=_colPathNames) def _colTypes(self): """ Mapping with `tables.Table` field names and their `PyTables` datatypes. """ try: return self.node.coltypes except AttributeError: return {} columns_types = property(fget=_colTypes) def _colShapes(self): """ Mapping with the `tables.Table` field names and their shapes. """ try: coldescrs = self.node.coldescrs return dict((k, v.shape) for (k, v) in coldescrs.items()) except AttributeError: return {} columns_shapes = property(fget=_colShapes) def _ncolumns(self): """The current number of columns in the `tables.Table` node.""" try: return len(self.node.columns_names) except AttributeError: return None ncolumns = property(fget=_ncolumns) def _target(self): """The target of a `tables.Link` node.""" try: return str(self.node.target) except AttributeError: return None target = property(fget=_target) def _link_type(self): """The kind of link (i.e. soft or external) of a `tables.Link` node.""" if self.target: try: link_type = 'external' self.node.extfile except AttributeError: link_type = 'soft' return link_type else: return None link_type = property(fget=_link_type) ViTables-3.0.0/vitables/plugins/000077500000000000000000000000001311223072700165135ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/__init__.py000066400000000000000000000015501311223072700206250ustar00rootroot00000000000000 # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ['csv', 'columnorg', 'dbstreesort', 'timeseries'] ViTables-3.0.0/vitables/plugins/about_page.ui000066400000000000000000000173231311223072700211660ustar00rootroot00000000000000 AboutPage 0 0 400 473 Form Plugin description Version: 239 239 239 239 239 239 244 244 244 true Module name: 239 239 239 239 239 239 244 244 244 true Folder: 239 239 239 239 239 239 244 244 244 true Author: 239 239 239 239 239 239 244 244 244 true Desription: 239 239 239 239 239 239 244 244 244 true ViTables-3.0.0/vitables/plugins/aboutpage.py000066400000000000000000000013241311223072700210340ustar00rootroot00000000000000"""Default plugin about page.""" import os from qtpy import QtGui from qtpy import QtWidgets from qtpy import uic Ui_AboutPage = uic.loadUiType(os.path.join(os.path.dirname( os.path.abspath(__file__)), 'about_page.ui'))[0] class AboutPage(QtWidgets.QWidget, Ui_AboutPage): def __init__(self, desc, parent=None): super(AboutPage, self).__init__(parent) self.setupUi(self) # fill gui elements self.version_text.setText(desc.get('version', '')) self.module_name_text.setText(desc.get('module_name', '')) self.folder_text.setText(desc.get('folder', '')) self.author_text.setText(desc.get('author', '')) self.desc_text.setText(desc.get('comment', '')) ViTables-3.0.0/vitables/plugins/columnorg/000077500000000000000000000000001311223072700205205ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/columnorg/__init__.py000066400000000000000000000015241311223072700226330ustar00rootroot00000000000000 # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ['aboutpage', 'columnar_org'] ViTables-3.0.0/vitables/plugins/columnorg/columnar_org.py000066400000000000000000000517151311223072700235720ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Plugin that provides columnar organizations for arrays The plugin let the users to mark several array views (all of them with the same number of rows) and then display those arrays using a unique widget, one array next to other. One can think that a set of arrays are displayed as a table. This seems quite strange to me but is a feature request so I assume that the plugin will be useful to some users. """ __docformat__ = 'restructuredtext' __version__ = '1.0' plugin_class = 'ArrayColsOrganizer' plugin_name = 'Columnar organization of arrays' comment = ('Rearrange several arrays with the same number of rows and ' 'displays them in a unique widget') import os.path import tables from qtpy import QtGui from qtpy import QtCore from qtpy import QtWidgets import vitables from vitables.vttables.datasheet import DataSheet from vitables.plugins.aboutpage import AboutPage translate = QtWidgets.QApplication.translate _PLUGIN_FOLDER = os.path.join(os.path.dirname(__file__)) class ArrayColsOrganizer(QtCore.QObject): """The class which defines the plugin for columnar organization of arrays. It is connected to the core program so that ever time a new view is created this class customizes the view if it is required. In addition the class triggers the update of the Node menu and includes a `helpAbout`method that is used in the Preferences dialog to show information about the plugin. """ UID = 'vitables.plugin.columnar_org' NAME = plugin_name COMMENT = comment def __init__(self, parent=None): """Class constructor. Dynamically finds new instances of :meth:`vitables.vttables.leaf_model.LeafModel` and customizes them if they are arrays that can be grouped in a unique view. """ super(ArrayColsOrganizer, self).__init__(parent) self.vtapp = vitables.utils.getVTApp() # An specialized object will deal with the Node menu changes self.menu_updater = MenuUpdater() self.menu_updater.addEntry() # Connect convenience signal defined in the vtapp module to slot self.vtapp.leaf_model_created.connect(self.customizeView) def customizeView(self, datasheet): """Add a checkbox in the bottom right corner of array views. Customization is twofold: add a checkbox to the LeafView and add a is_checked` attr to the view. In addition, the checkbox has a `source_array` attribute that points to the view containing it. In a regular array, if checkbox ticked, it means that the array is candidate to be added to other single/grouped arrays. In a group of arrays, if checkbox is ticked it means that the group can be group with other ticked single/grouped arrays. If the grouped array is the only ticked view then it means that it is a candidate for being ungrouped. This is a slot called every time a new view is created. """ # The tables.Node instance tied to that data structure pt_node = datasheet.dbt_leaf.node if hasattr(pt_node, 'target'): # The selected item is a link and must be dereferenced leaf = pt_node() else: leaf = pt_node if not isinstance(leaf, tables.Table): cb = QtWidgets.QCheckBox(datasheet) cb.setToolTip(translate('ArrayColsOrganizer', "Include this Array in the 'columnar Group'", 'Checkbox tooltip text')) datasheet.leaf_view.setCornerWidget(cb) # Attributes for retrieving the state of the checkbox from the # datasheet being customized cb.source_array = datasheet datasheet.is_checked = \ datasheet.leaf_view.cornerWidget().checkState() # Connect signals to slots cb.stateChanged.connect(self.cbStateChanged) def cbStateChanged(self, state): """Update the `is_checked` attribute of DataSheets and GroupedArrays. """ view = self.sender().source_array view.is_checked = state def helpAbout(self, parent): """Full description of the plugin. This is a convenience method which works as expected by :meth:preferences.preferences.Preferences.aboutPluginPage i.e. build a page which contains the full description of the plugin and, optionally, allows for its configuration. :Parameter about_page: the container widget for the page """ # Plugin full description desc = {'version': __version__, 'module_name': os.path.join(os.path.basename(__file__)), 'folder': os.path.join(os.path.dirname(__file__)), 'author': 'Vicent Mas ', 'comment': translate('ArrayColsOrganizer', """

Plugin that provides an alternative view for arrays with the same number of rows.

The user has to open all the arrays she whishes to see in a unique viewer, and tick their bottom-right corner checkbox. She may then click on the `Node -> Group Arrays` menu entry and these arrays will be grouped in a single sub-window.

Note that all ticked arrays must have the same dimensions for the `Group` menu item to enable. """, 'Text of an About plugin message box')} about_page = AboutPage(desc, parent) return about_page class MenuUpdater(QtCore.QObject): """Specialized class for modifying the Node menu. """ def __init__(self, parent=None): """The constructor method. """ super(MenuUpdater, self).__init__(parent) self.vtgui = vitables.utils.getGui() # Connect signals to slots self.vtgui.node_menu.aboutToShow.connect(self.updateNodeMenu) self.vtgui.leaf_node_cm.aboutToShow.connect(self.updateNodeMenu) def addEntry(self): """Add the `Group Arrays` and `Ungroup Arrays` entries to `Node` menu. """ object_group_icon = QtGui.QIcon() pixmap = QtGui.QPixmap(os.path.join(_PLUGIN_FOLDER, 'icons/object-group.png')) object_group_icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) self.group_action = QtWidgets.QAction( translate('MenuUpdater', "&Group Arrays", "Group separated arrays with the same number of rows"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.groupArrays, icon=object_group_icon, statusTip=translate('MenuUpdater', """ Use a unique widget to display Arrays as if they where columns of a Table""", "Status bar text for the Node -> Group Arrays action")) object_ungroup_icon = QtGui.QIcon() pixmap = QtGui.QPixmap(os.path.join(_PLUGIN_FOLDER, 'icons/object-ungroup.png')) object_ungroup_icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) self.ungroup_action = QtWidgets.QAction( translate('MenuUpdater', "&Ungroup Arrays", "Ungroup previously grouped arrays."), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.ungroupArrays, icon=object_ungroup_icon, statusTip=translate('MenuUpdater', """Ungroup previously grouped arrays.""", "Status bar text for the Node -> Ungroup Arrays action")) # Add the actions to the Node menu vitables.utils.addToMenu(self.vtgui.node_menu, (self.group_action, self.ungroup_action)) # Add the actions to the leaf context menu vitables.utils.addToLeafContextMenu( (self.group_action, self.ungroup_action)) def updateNodeMenu(self): """Update (un)group_action QActions if the Node menu is about to show. The `group_action` is disabled when there are less than two Arrays checked, and also when not all checked arrays have the same number of rows. The `ungroup_action` is enabled only if there are one array group selected. """ self.group_action.setEnabled(False) self.ungroup_action.setEnabled(False) checked_views = [] numrows = [] for view in self.vtgui.workspace.subWindowList(): # Both Datasheet and GroupedArray instances have an is_checked attr # but Table instances don't have it. if hasattr(view, 'is_checked') and (view.is_checked == QtCore.Qt.Checked): checked_views.append(view) if isinstance(view, GroupedArrays): numrows.append(view.grouped_arrays_nrows) elif isinstance(view, DataSheet): numrows.append(view.leaf_model.numrows[()]) self.checked_views = checked_views if len(checked_views) == 1: if isinstance(checked_views[0], GroupedArrays): self.ungroup_action.setEnabled(True) elif len(checked_views) > 1: if numrows.count(numrows[0]) == len(numrows): self.group_action.setEnabled(True) else: print(translate('MenuUpdater', """\nError: grouping arrays, operation cancelled. """ """Not all the selected arrays have the same number """ """of rows.""", 'An error message in the ArraysColsOrganizer plugin')) def groupArrays(self): """Group a set of individual arrays into the same view widget. """ GroupedArrays(views=self.checked_views) def ungroupArrays(self): """Break-up a grouped array into a set of views (one per component). """ GroupedArrays.ungroupArrays(self.checked_views[0]) class GroupedArrays(QtWidgets.QMdiSubWindow): """A widget that contains a group of Arrays. """ def __init__(self, parent=None, flags=QtCore.Qt.SubWindow, views=None): """The class constructor. """ self.vtgui = vitables.utils.getGui() super(GroupedArrays, self).__init__(self.vtgui.workspace, flags) # The components from which the GroupedArrays will be made. # We use sets instead of lists because there seems to be a # problem with my_list.pop(i) when i != -1 self.arrays = set(views) self.already_grouped = set([]) for i in self.arrays.copy(): if isinstance(i, GroupedArrays): self.already_grouped.add(i) self.arrays.remove(i) self.arrays = list(self.arrays) self.already_grouped = list(self.already_grouped) self.pindex = QtCore.QModelIndex() # Create a GroupedArrays object from the set of regular arrays if (len(self.arrays) > 1): self.combineArrays() # Combine regular arrays with GroupedArrays elif (len(self.arrays) == 1) and len(self.already_grouped): self.combineArrayAndGroupedArrays() # Combine GroupedArrays (no regular arrays in the way) elif len(self.already_grouped) > 1: self.combineGroupedArrays() # The following functions define the behavior of GroupedArrays objects: # - how they are created from several Datasheet objects # - how a single Datasheet object can be added to a GroupedArray object # - how they combine together to create a bigger GroupedArrays object # - how they are customized # - how they are closed # - how they are ungrouped def addVerticalLayout(self, container_layout, datasheet, title=None): """Add a vertical layout to the horizontal layout of a GroupArrays. This is a helper method. :Parameter: - `container_layout`: the horizontal layout of the ArraysGroup - `datasheet`: the datasheet being added """ if not title: title = QtWidgets.QLabel(datasheet.windowTitle()) datasheet.setWindowFlags(QtCore.Qt.FramelessWindowHint) vertical_layout = QtWidgets.QVBoxLayout() vertical_layout.addWidget(title) vertical_layout.addWidget(datasheet) container_layout.addLayout(vertical_layout) def convenienceAttrs(self, datasheet): """Helper method for setting some attributes """ self.is_checked = QtCore.Qt.Checked nrows = datasheet.leaf_model.numrows[()] self.grouped_arrays_nrows = nrows def combineArrays(self): """Convert a set of array views into a GroupedArray view. """ self.pindex = QtCore.QModelIndex() # The widget of this MdiSubWindow self.container = QtWidgets.QWidget() # Fill the widget with Datasheets arranged in the container layout container_layout = QtWidgets.QHBoxLayout() while self.arrays: # Extract the first datasheet and manipulate it conveniently: # get the title, remove the frame and put both of them in a # vertical layout datasheet = self.arrays.pop() self.addVerticalLayout(container_layout, datasheet) self.container.setLayout(container_layout) # Some convenient attributes self.convenienceAttrs(datasheet) # Create and customize the MdiSubWindow self.setWidget(self.container) self.show() self.customizeGroupedViews() def combineArrayAndGroupedArrays(self): """Add an Array to this GroupedArray instance. """ datasheet = self.arrays.pop() # Overwrite self with the last GroupedArray instance of the list # of grouped arrays but preserve the list of grouped arrays seen # by the self object. Calling self.show() won't be required because # the GroupedArray is already visible self.deleteLater() self.pindex = QtCore.QModelIndex() grouped_arrays = self.already_grouped[:] self = self.already_grouped.pop() self.already_grouped = grouped_arrays[:-1] self.container = self.widget() container_layout = self.container.layout() # The datasheet is manipulated conveniently: # get the title, remove the frame and put both of them in a # vertical layout self.addVerticalLayout(container_layout, datasheet) # Some convenient attributes self.convenienceAttrs(datasheet) self.customizeGroupedViews() def combineGroupedArrays(self): """Convert a set of GroupedArrays into a unique GroupedArrays view. :Parameter grouped_arrays: a set of GroupedArrays views """ # Overwrite self with the last GroupedArray instance of the list # of grouped arrays but preserve the list of grouped arrays seen # by the self object. Calling self.show() won't be required because # the GroupedArray is already visible self.deleteLater() self.pindex = QtCore.QModelIndex() grouped_arrays = self.already_grouped[:] self = self.already_grouped.pop() self.already_grouped = grouped_arrays[:-1] self.container = self.widget() container_layout = self.container.layout() while self.already_grouped: ga = self.already_grouped.pop(-1) hlayout = ga.widget().layout() first_datasheet = hlayout.itemAt(0).itemAt(1).widget() for i in range(hlayout.count()): vl = hlayout.itemAt(i) title = vl.itemAt(0).widget() datasheet = vl.itemAt(1).widget() self.addVerticalLayout(container_layout, datasheet, title) ga.deleteLater() # self.repaint() # Some convenient attributes self.convenienceAttrs(first_datasheet) self.customizeGroupedViews() def customizeGroupedViews(self): """Make the grouped view widget usable. - All but the leftmost horizontal header views are hidden - All but the rightmost verticals scrollbars are hidden and connected between them Beware that horizontal scrollbars cannot be connected easily if the number of columns differ for the grouped arrays so we recommend to group only arrays with the same number of columns. :Parameter sw: the viw (QMdiSubWindow instance) being customized """ # This instance will be the first GroupedArray instance of the set # Calling self.show() won't be required because the GroupedArray is # already visible self.container = self.widget() container_layout = self.container.layout() # The items contained in the container layout are QVBoxLAyout layout # boxes. These vertical layouts can contain labels and datasheets: # horizontal layout -> vertical layout -> widget item -> label # |-> widget item -> datasheet datasheets = [] for i in range(container_layout.count()): vl = container_layout.itemAt(i) datasheets.append(vl.itemAt(1).widget()) nd = len(datasheets) for i in range(nd): datasheets[nd-1].widget().verticalScrollBar().valueChanged.connect( datasheets[i].widget().verticalScrollBar().setValue) if i < (nd - 1): datasheets[i].widget().verticalScrollBar().hide() datasheets[i].widget().setCornerWidget(None) datasheets[i+1].widget().verticalHeader().hide() def closeEvent(self, event): """ Propagate the close event. In the process, self.widget().closeEvent will be called """ sw_layout = self.widget().layout() vl_count = sw_layout.count() for i in range(vl_count): layout = sw_layout.itemAt(i) datasheet = layout.itemAt(1).widget() datasheet.dbt_leaf.hasview = False self.vtgui.updateActions() datasheet.close() layout.deleteLater() self.deleteLater() QtWidgets.QMdiSubWindow.closeEvent(self, event) if self.vtgui.workspace.subWindowList() == []: self.vtgui.dbs_tree_view.setFocus(True) def ungroupArrays(self): """Break-up a GroupedArrays object into its individual components. """ for view in self.vtgui.workspace.subWindowList(): if isinstance(view, GroupedArrays): self = view break sw_layout = self.widget().layout() vl_count = sw_layout.count() for i in range(vl_count): layout = sw_layout.itemAt(i) title = layout.itemAt(0).widget().text() datasheet = layout.itemAt(1).widget() datasheet.setWindowFlags(QtCore.Qt.SubWindow) datasheet.setWindowTitle(title) datasheet.setParent(self.vtgui.workspace) datasheet.widget().verticalScrollBar().show() datasheet.widget().verticalHeader().show() cb = QtWidgets.QCheckBox(datasheet) cb.setToolTip(translate('GroupedArrays', "Group Arrays into a unique view", 'Checkbox tooltip')) datasheet.leaf_view.setCornerWidget(cb) # Attributes for retrieving the state of the checkbox from the # datasheet being customized cb.source_array = datasheet datasheet.leaf_view.cornerWidget().setCheckState(QtCore.Qt.Checked) datasheet.is_checked = \ datasheet.leaf_view.cornerWidget().checkState() datasheet.show() layout.deleteLater() self.deleteLater() self.vtgui.workspace.removeSubWindow(self) ViTables-3.0.0/vitables/plugins/columnorg/icons/000077500000000000000000000000001311223072700216335ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/columnorg/icons/object-group.png000066400000000000000000000003671311223072700247470ustar00rootroot00000000000000PNG  IHDR(-SKPLTEhgguw~xx{dtRNSgUIDATxڍI DQ •I%vnWflFAb}V̱E j80z=+/μIENDB`ViTables-3.0.0/vitables/plugins/columnorg/icons/object-ungroup.png000066400000000000000000000004231311223072700253030ustar00rootroot00000000000000PNG  IHDR(-STPLTEgeghghxx{xx{M tRNS%&"lJeIDATxmI YWO'8 NJm׆Cߵi Lv:n4{&KC"7$ HͱF&^͏PΕj- {IENDB`ViTables-3.0.0/vitables/plugins/csv/000077500000000000000000000000001311223072700173065ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/csv/__init__.py000066400000000000000000000015541311223072700214240ustar00rootroot00000000000000 # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ['aboutpage', 'csvutils', 'export_csv', 'import_csv'] ViTables-3.0.0/vitables/plugins/csv/aboutpage.py000066400000000000000000000050231311223072700216270ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a widget with the full description of the plugin. The module allows for configuring the plugin too. The widget is displayed when the plugin is selected in the Preferences dialog selector tree. """ __docformat__ = 'restructuredtext' import os.path from qtpy import QtGui from qtpy.uic import loadUiType from qtpy import QtWidgets from vitables.vtsite import PLUGINSDIR translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dynamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_AboutPage = \ loadUiType(os.path.join(PLUGINSDIR, 'about_page.ui'))[0] class AboutPage(QtWidgets.QWidget, Ui_AboutPage): """ Configure the About page for the csv plugin in the Preferences dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This widget is inserted as a page in the stacked widget of the Preferences dialog when the CVS import/export item is clicked in the selector tree. """ def __init__(self, desc, parent=None): """Fill the widget describing the CSV plugin. :Parameter desc: a dictionary with the plugin description """ # Makes the dialog and gives it a layout super(AboutPage, self).__init__(parent) self.setupUi(self) self.version_le.setText(desc['version']) self.module_name_le.setText(desc['module_name']) self.folder_le.setText(desc['folder']) self.author_le.setText(desc['author']) self.desc_te.setText(desc['about_text']) ViTables-3.0.0/vitables/plugins/csv/csvutils.py000066400000000000000000000341531311223072700215420ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # Plugin initial draft author: Jorge Ibanez jorge.ibannez@uam.es # """Convenience functions for the import_csv.py module. """ __docformat__ = 'restructuredtext' import os import tempfile import logging import traceback import re import tables import numpy from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate TYPE_ERROR = translate( 'ImportCSV', 'Please, make sure that you are importing a ' 'homogeneous dataset.', 'CSV file not imported error') def getArray(buf): """Fill an intermediate ``numpy`` array with data read from the `CSV` file. The lines read from the CSV file are stored in a temporary file which is passed to numpy.genfromtxt() in order to create a numpy array. The dtypes of the numpy array are determined by the contents of each column. Multidimensional columns will have string datatype. Warning: the temporary file is written in binary mode so lines are stored as bytearrays (encoded as UTF-8). It means that strings in the numpy array will also be bytes with UTF-8 encoding and not Python 3 strings. :Parameter buf: the data buffer is a list of lines of the CSV file """ with tempfile.TemporaryFile(mode='w+b') as temp_file: for line in buf: temp_file.write(bytearray(line, 'UTF-8')) temp_file.seek(0) data = numpy.genfromtxt(temp_file, delimiter=',', dtype=None) return data def tableInfo(input_handler): """Return useful information about the `tables.Table` being created. :Parameter input_handler: the file handler of the inspected CSV file """ # Inspect the CSV file reading its second line # (reading the first line is not safe as it could be a header) input_handler.seek(0) first_line = getArray(input_handler.readline()) try: second_line = getArray(input_handler.readline()) except IOError: # The second line cannot be read. We assume there is only on line second_line = first_line # Estimate the number of rows of the CSV file filesize = os.path.getsize(input_handler.name) # Record size = number of elements * element size record_size = second_line.size * second_line.itemsize nrows = filesize/record_size if second_line.dtype.fields is None: # second_line is a homogeneous array descr, has_header = \ homogeneousTableInfo(input_handler, first_line, second_line) else: # second_line is a heterogeneous array descr, has_header = \ heterogeneousTableInfo(input_handler, first_line, second_line) del second_line return (nrows, descr, has_header) def heterogeneousTableInfo(input_handler, first_line, second_line): """Return useful information about the `tables.Table` being created. The `data` array is heterogenous, i.e. not all fields have the same dtype. :Parameters: - `input_handler`: the file handler of the inspected `CSV` file - `first_line`: a ``numpy`` array which contains the first line of the `CSV` file - `second_line`: a ``numpy`` array which contains the second line of the `CSV` file """ has_header = False fl_dtype = first_line.dtype if (fl_dtype.fields is None) and (fl_dtype.char in('S', 'U')): has_header = True # Stuff used for finding out itemsizes of string fields itemsizes = {} for field in range(0, len(second_line.dtype)): if second_line.dtype[field].name.startswith('str') or \ second_line.dtype[field].name.startswith('bytes'): itemsizes[field] = 0 # If a dtype is a string, find out its biggest itemsize if itemsizes: buf_size = 1024 * 1024 input_handler.seek(0) if has_header: # Skip the header input_handler.readline() buf = input_handler.readlines(buf_size) while buf: temp_file = tempfile.TemporaryFile() for line in buf: temp_file.write(bytearray(line, 'UTF-8')) for field in itemsizes.keys(): temp_file.seek(0) idata = numpy.genfromtxt(temp_file, delimiter=',', usecols=(field,), dtype=None) itemsizes[field] = max(itemsizes[field], idata.dtype.itemsize) del idata temp_file.close() buf = input_handler.readlines(buf_size) if has_header: descr = {} for i in range(0, first_line.size): dtype = second_line.dtype.fields['f{0}'.format(i)][0] descr[first_line[i].decode('UTF-8')] = tables.Col.from_dtype(dtype, pos=i) for i in itemsizes: descr[first_line[i].decode('UTF-8')] = tables.StringCol(itemsizes[i] , pos=i) else: descr = dict([(f, tables.Col.from_dtype(t[0])) for f, t in second_line.dtype.fields.items()]) for i in itemsizes: descr['f{0}'.format(i)] = tables.StringCol(itemsizes[i]) return descr, has_header def homogeneousTableInfo(input_handler, first_line, second_line): """Return useful information about the `tables.Table` being created. The `second_line` array is homegenous, i.e. all fields have the same dtype. :Parameters: - `input_handler`: the file handler of the inspected `CSV` file - `first_line`: a ``numpy`` array which contains the first line of the `CSV` file - `second_line`: a ``numpy`` array which contains the second line of the `CSV` file """ # Find out if the table has a header or not. has_header = False fldn = first_line.dtype.name sldn = second_line.dtype.name if sldn.startswith('str') or sldn.startswith('bytes'): answer = askForHelp(first_line) if answer == 'Header': has_header = True elif fldn.startswith('str') or fldn.startswith('bytes'): has_header = True input_handler.seek(0) if has_header: # Skip the header input_handler.readline() # If the fields of the table are strings then find out the biggest itemsize if sldn.startswith('str') or sldn.startswith('bytes'): itemsize = 0 buf_size = 1024 * 1024 buf = input_handler.readlines(buf_size) if not buf: # If the CSV file contains just one line itemsize = first_line.dtype.itemsize while buf: idata = getArray(buf) itemsize = max(itemsize, idata.dtype.itemsize) del idata buf = input_handler.readlines(buf_size) # Iterate over the data fields and make the table description # If the CSV file contains just one field then first_line is a # scalar array and cannot be iterated so we reshape it if first_line.shape == (): first_line = first_line.reshape(1,) indices = list(range(0, first_line.shape[0])) if has_header: if sldn.startswith('str') or sldn.startswith('bytes'): descr = dict([(first_line[i].decode('UTF-8'), tables.StringCol(itemsize, pos=i)) for i in indices]) else: descr = dict([(first_line[i].decode('UTF-8'), tables.Col.from_dtype(second_line.dtype, pos=i)) for i in indices]) else: if sldn.startswith('str') or sldn.startswith('bytes'): descr = dict([('f{0}'.format(field), tables.StringCol(itemsize)) for field in indices]) else: descr = dict([('f{0}'.format(field), tables.Col.from_dtype(second_line.dtype)) for field in indices]) return descr, has_header def askForHelp(first_line): """Ask user if the first row is a header. :Parameter first_line: a ``numpy`` array which contains the first line of the `CSV` file """ title = translate('ImportCSV', 'Resolving first line role', 'Message box title') text = translate('ImportCSV', 'Does the first line of the file contain ' 'a table header or regular data?', 'Message box text') itext = '' try: from functools import reduce dtext = reduce(lambda x, y: '{0}, {1}'.format(x, y), first_line) except TypeError: # If first_line has only one field reduce raises a TypeError dtext = first_line.tostring() buttons = { 'Header': (translate('ImportCSV', 'Header', 'Button text'), QtWidgets.QMessageBox.YesRole), 'Data': (translate('ImportCSV', 'Data', 'Button text'), QtWidgets.QMessageBox.NoRole), } return vitables.utils.questionBox(title, text, itext, dtext, buttons) def earrayInfo(input_handler): """Return useful information about the `tables.EArray` being created. :Parameter input_handler: the file handler of the inspected file """ # Inspect the CSV file reading its first line # The dtypes are determined by the contents of each column # Multidimensional columns will have string datatype first_line = getArray(input_handler.readline()) # Estimate the number of rows of the file filesize = os.path.getsize(input_handler.name) record_size = first_line.size * first_line.itemsize nrows = filesize/record_size if first_line.dtype.name.startswith('str') or \ first_line.dtype.name.startswith('bytes'): # Find out the biggest itemsize itemsize = 0 buf_size = 1024 * 1024 input_handler.seek(0) buf = input_handler.readlines(buf_size) while buf: idata = getArray(buf) itemsize = max(itemsize, idata.dtype.itemsize) del idata buf = input_handler.readlines(buf_size) atom = tables.StringAtom(itemsize) else: # With compound dtypes this will raise a ValueError atom = tables.Atom.from_dtype(first_line.dtype) # Get the data shape if nrows < 2: # Corner case: the file only has one row array_shape = (0, ) elif first_line.shape == (): # Corner case: the file has just one column array_shape = (0, ) else: # General case: the file is a MxN array array_shape = (0, first_line.shape[0]) del first_line input_handler.seek(0) return nrows, atom, array_shape def carrayInfo(input_handler): """Return useful information about the `tables.CArray` being created. :Parameter input_handler: the file handler of the inspected file """ # Inspect the CSV file reading its first line # The dtypes are determined by the contents of each column # Multidimensional columns will have string datatype input_handler.seek(0) first_line = getArray(input_handler.readline()) # This counting algorithm is faster than looping over lines with # fh.readline and incrementing a counter at every step lines = 0 itemsize = 0 buf_size = 1024 * 1024 input_handler.seek(0) if first_line.dtype.name.startswith('str') or \ first_line.dtype.name.startswith('bytes'): # Count lines and find out the biggest itemsize buf = input_handler.readlines(buf_size) while buf: idata = getArray(buf) itemsize = max(itemsize, idata.dtype.itemsize) del idata lines += len(buf) buf = input_handler.readlines(buf_size) else: # Count lines buf = input_handler.readlines(buf_size) while buf: lines += len(buf) buf = input_handler.readlines(buf_size) if itemsize: atom = tables.StringAtom(itemsize) else: atom = tables.Atom.from_dtype(first_line.dtype) # Get the data shape if lines == 1: # Corner case: the file only has one row array_shape = first_line.shape lines = first_line.shape[0] elif first_line.shape == (): # Corner case: the file has just one column array_shape = (lines, ) else: # General case: the file is a MxN array array_shape = (lines, first_line.shape[0]) del first_line input_handler.seek(0) return atom, array_shape def isValidFilepath(filepath): """Check the filepath of the destination file. :Parameter filepath: the filepath where the imported dataset will live """ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) valid = True if os.path.exists(filepath): logger.error(translate( 'ImportCSV', 'CSV import failed because destination file already exists.', 'A file creation error')) valid = False elif os.path.isdir(filepath): logger.error(translate( 'ImportCSV', 'CSV import failed because destination container is a directory.', 'A file creation error')) valid = False return valid def checkFilenameExtension(filepath): """ Check the filename extension of the CSV file. If the filename has no extension this method adds .csv extension to it. :Parameter filepath: the full path of the file :Returns: the filepath with the proper extension """ if not re.search(r'\.(.+)$', os.path.basename(filepath)): ext = '.csv' filepath = filepath + ext return filepath ViTables-3.0.0/vitables/plugins/csv/examples/000077500000000000000000000000001311223072700211245ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/csv/examples/array.csv000066400000000000000000000000431311223072700227540ustar00rootroot000000000000001, 2, 3 4, 5, 6 7, 8, 9 10, 11, 12 ViTables-3.0.0/vitables/plugins/csv/examples/arrayND.csv000066400000000000000000000000711311223072700231770ustar00rootroot00000000000000[1 2], [3 4] [4 5], [6 7] [7 8], [9 10] [10 11], [12 13] ViTables-3.0.0/vitables/plugins/csv/examples/array_float.csv000066400000000000000000000000331311223072700241400ustar00rootroot000000000000001.0 2.71828182846 3.141592 ViTables-3.0.0/vitables/plugins/csv/examples/array_strings.csv000066400000000000000000000000511311223072700245240ustar00rootroot00000000000000a, b, c d, ee, f g, h, i jjj, pp, ll ViTables-3.0.0/vitables/plugins/csv/examples/column.csv000066400000000000000000000000151311223072700231320ustar00rootroot000000000000001 2 3 4 7 10 ViTables-3.0.0/vitables/plugins/csv/examples/columnND.csv000066400000000000000000000000231311223072700233530ustar00rootroot00000000000000[1 2] [3 4] [7 10] ViTables-3.0.0/vitables/plugins/csv/examples/row.csv000066400000000000000000000000221311223072700224420ustar00rootroot000000000000001, 2, 3, 4, 7, 10 ViTables-3.0.0/vitables/plugins/csv/examples/rowND.csv000066400000000000000000000000251311223072700226670ustar00rootroot00000000000000[1 2], [3 4], [7 10] ViTables-3.0.0/vitables/plugins/csv/examples/table.csv000066400000000000000000000014071311223072700227320ustar00rootroot00000000000000Particle: 10,10j, 0j,[ 90.+1.j 1.+0.j],[[ -0.10701348-0.99425757j 33.00000000+0.j ] [ -0.10701348-0.99425757j 33.00000000+0.j ]] Particle: 11,11j,-1+0j,[ 110.+2.j 2.+0.j],[[ 0.08330491-0.9965241j 30.00000000+0.j ] [ 0.08330491-0.9965241j 30.00000000+0.j ]] Particle: 12,12j,-2+0j,[ 132.+3.j 3.+0.j],[[ 0.25459059-0.96704893j 27.00000000+0.j ] [ 0.25459059-0.96704893j 27.00000000+0.j ]] Particle: 13,13j,-3+0j,[ 143.+4.j 4.+0.j],[[ 0.40548536-0.91410154j 24.00000000+0.j ] [ 0.40548536-0.91410154j 24.00000000+0.j ]] Particle: 14,14j,-4+0j,[ 154.+5.j 5.+0.j],[[ 0.53602858-0.84419984j 21.00000000+0.j ] [ 0.53602858-0.84419984j 21.00000000+0.j ]] ViTables-3.0.0/vitables/plugins/csv/examples/table_header.csv000066400000000000000000000014631311223072700242440ustar00rootroot00000000000000Field 0, Field 1, Field 2, Field 3, Field 4 Particle: 10,10j, 0j,[ 90.+1.j 1.+0.j],[[ -0.10701348-0.99425757j 33.00000000+0.j ] [ -0.10701348-0.99425757j 33.00000000+0.j ]] Particle: 11,11j,-1+0j,[ 110.+2.j 2.+0.j],[[ 0.08330491-0.9965241j 30.00000000+0.j ] [ 0.08330491-0.9965241j 30.00000000+0.j ]] Particle: 12,12j,-2+0j,[ 132.+3.j 3.+0.j],[[ 0.25459059-0.96704893j 27.00000000+0.j ] [ 0.25459059-0.96704893j 27.00000000+0.j ]] Particle: 13,13j,-3+0j,[ 143.+4.j 4.+0.j],[[ 0.40548536-0.91410154j 24.00000000+0.j ] [ 0.40548536-0.91410154j 24.00000000+0.j ]] Particle: 14,14j,-4+0j,[ 154.+5.j 5.+0.j],[[ 0.53602858-0.84419984j 21.00000000+0.j ] [ 0.53602858-0.84419984j 21.00000000+0.j ]] ViTables-3.0.0/vitables/plugins/csv/examples/table_integers.csv000066400000000000000000000000371311223072700246300ustar00rootroot000000000000001, 2, 3 11, 222, 3 1, 22, 3 ViTables-3.0.0/vitables/plugins/csv/examples/table_strings.csv000066400000000000000000000000341311223072700244760ustar00rootroot00000000000000a, b, c aa, bbb, c a, bb, c ViTables-3.0.0/vitables/plugins/csv/export_csv.py000066400000000000000000000276541311223072700220720ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Plugin that provides export of `tables.Leaf` nodes into `CSV` files. When exporting tables, a header with the field names can be inserted. In general, tables/arrays with Ndimensional fields are not exported because they are not written by np.savetxt() in a way compliant with the CSV format in which each line of the file is a data record. Neither numpy scalar arrays are exported. """ __docformat__ = 'restructuredtext' __version__ = '0.8' plugin_class = 'ExportToCSV' plugin_name = 'CSV exporter' comment = 'Export datasets to CSV files.' import os import re import tables import numpy import logging from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.plugins.aboutpage import AboutPage import vitables.plugins.csv.csvutils as csvutils translate = QtWidgets.QApplication.translate _PLUGIN_FOLDER = os.path.join(os.path.dirname(__file__)) class ExportToCSV(QtCore.QObject): """Provides `CSV` export capabilities for arrays. """ UID = 'vitables.plugin.export_csv' NAME = plugin_name COMMENT = comment def __init__(self): """The class constructor. """ super(ExportToCSV, self).__init__() self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # Get a reference to the application instance self.vtapp = vitables.utils.getVTApp() if self.vtapp is None: return self.vtgui = vitables.utils.getGui() # Add an entry under the Dataset menu self.addEntry() # Connect signals to slots self.vtgui.dataset_menu.aboutToShow.connect(self.updateDatasetMenu) self.vtgui.leaf_node_cm.aboutToShow.connect(self.updateDatasetMenu) def addEntry(self): """Add the `Export to CSV..`. entry to `Dataset` menu. """ export_icon = QtGui.QIcon() pixmap = QtGui.QPixmap(os.path.join(_PLUGIN_FOLDER, 'icons/document-export.png')) export_icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) self.export_action = QtWidgets.QAction( translate('ExportToCSV', "E&xport to CSV...", "Save dataset as CSV"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.export, icon=export_icon, statusTip=translate( 'ExportToCSV', "Save the dataset as a plain text with CSV format", "Status bar text for the Dataset -> Export to CSV... action")) # Add the action to the Dataset menu vitables.utils.addToMenu(self.vtgui.dataset_menu, self.export_action) # Add the action to the leaf context menu vitables.utils.addToLeafContextMenu(self.export_action) def updateDatasetMenu(self): """Update the `export` QAction when the Dataset menu is pulled down. This method is a slot. See class ctor for details. """ enabled = True current = self.vtgui.dbs_tree_view.currentIndex() if current: leaf = self.vtgui.dbs_tree_model.nodeFromIndex(current) if leaf.node_kind in ('group', 'root group'): enabled = False self.export_action.setEnabled(enabled) def getExportInfo(self, is_table): """Get info about the file where dataset will be stored. The info is retrieved from the FileSelector dialog. The returned info is the filepath and whether or not a header must be added. :Parameter is_table: True if the exported dataset is a tables.Table instance """ # Call the file selector (and, if needed, customise it) file_selector = vitables.utils.getFileSelector( self.vtgui, translate('ExportToCSV', 'Exporting dataset to CSV format', 'Caption of the Export to CSV dialog'), dfilter=translate('ExportToCSV', """CSV Files (*.csv);;""" """All Files (*)""", 'Filter for the Export to CSV dialog'), settings={'accept_mode': QtWidgets.QFileDialog.AcceptSave, 'file_mode': QtWidgets.QFileDialog.AnyFile, 'history': self.vtapp.file_selector_history, 'label': translate('ExportToCSV', 'Export', 'Accept button text for QFileDialog')} ) # Customise the file selector dialog for exporting to CSV files if is_table: # We can get the layout of Qt dialogs but not of native dialogs file_selector.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True) fs_layout = file_selector.layout() header_label = QtWidgets.QLabel('Add header:', file_selector) header_cb = QtWidgets.QCheckBox(file_selector) fs_layout.addWidget(header_label, 4, 0) fs_layout.addWidget(header_cb, 4, 1) # Execute the dialog try: if file_selector.exec_(): # OK clicked filepath = file_selector.selectedFiles()[0] # Make sure filepath contains no backslashes filepath = QtCore.QDir.fromNativeSeparators(filepath) filepath = csvutils.checkFilenameExtension(filepath) # Update the working directory working_dir = file_selector.directory().canonicalPath() else: # Cancel clicked filepath = working_dir = '' finally: add_header = False if is_table: add_header = header_cb.isChecked() del file_selector # Process the returned values if not filepath: # The user has canceled the dialog return # Update the history of the file selector widget self.vtapp.updateFSHistory(working_dir) # Check the returned path if os.path.exists(filepath): self.logger.error(translate( 'ExportToCSV', 'Export failed because destination file already exists.', 'A file creation error')) return if os.path.isdir(filepath): self.logger.error(translate( 'ExportToCSV', 'Export failed because destination container is a directory.', 'A file creation error')) return return filepath, add_header def export(self): """Export a given dataset to a `CSV` file. This method is a slot connected to the `export` QAction. See the :meth:`addEntry` method for details. """ # The PyTables node tied to the current leaf of the databases tree current = self.vtgui.dbs_tree_view.currentIndex() leaf = self.vtgui.dbs_tree_model.nodeFromIndex(current).node # Empty datasets aren't saved as CSV files if leaf.nrows == 0: self.logger.info(translate( 'ExportToCSV', 'Empty dataset. Nothing to export.')) return # Scalar arrays aren't saved as CSV files if leaf.shape == (): self.logger.info(translate( 'ExportToCSV', 'Scalar array. Nothing to export.')) return # Datasets with more than 3 dimensions aren't saved as CSV files # (see module's docstring) if len(leaf.shape) > 3: self.logger.info(translate( 'ExportToCSV', 'The selected node has more than ' '3 dimensions. I can\'t export it to CSV format.')) return # Variable lenght arrays aren't saved as CSV files if isinstance(leaf, tables.VLArray): self.logger.info(translate( 'ExportToCSV', 'The selected node is a VLArray. ' 'I can\'t export it to CSV format.')) return # Tables with Ndimensional fields aren't saved as CSV files is_table = isinstance(leaf, tables.Table) if is_table: first_row = leaf[0] for item in first_row: if item.shape != (): self.logger.info(translate( 'ExportToCSV', 'Some fields aren\'t scalars. ' 'I can\'t export the table to CSV format.')) return # Get the required info for exporting the dataset export_info = self.getExportInfo(is_table) if export_info is None: return else: filepath, add_header = export_info try: QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) with open(filepath, 'ab') as out_handler: if add_header: from functools import reduce header = reduce(lambda x, y: '{0}, {1}'.format(x, y), leaf.colnames) # To be consistent with numpy.savetxt use \n line breaks out_handler.write(bytearray(header + '\n', 'UTF-8')) chunk_size = 10000 nrows = leaf.nrows if chunk_size > nrows: chunk_size = nrows # Behavior of np.divide in Python 2 and Python 3 is different so # we must explicitly ensure we get an integer nchunks = numpy.floor_divide(nrows, chunk_size) for i in numpy.arange(0, nchunks+1): QtWidgets.qApp.processEvents() cstart = chunk_size*i if cstart >= nrows: break cstop = cstart + chunk_size if cstop > nrows: cstop = nrows numpy.savetxt(out_handler, leaf.read(cstart, cstop, 1), fmt='%s', delimiter=',') except OSError: vitables.utils.formatExceptionInfo() finally: QtWidgets.qApp.restoreOverrideCursor() def helpAbout(self, parent): """Full description of the plugin. This is a convenience method which works as expected by :meth:preferences.preferences.Preferences.aboutPluginPage i.e. build a page which contains the full description of the plugin and, optionally, allows for its configuration. :Parameter about_page: the container widget for the page """ # Plugin full description desc = {'version': __version__, 'module_name': os.path.join(os.path.basename(__file__)), 'folder': os.path.join(os.path.dirname(__file__)), 'author': 'Vicent Mas ', 'comment': translate( 'ExportToCSV', '

Plugin that provides export to CSV files ' 'capabilities.

Any kind of PyTables dataset can be ' 'exported. When exporting tables, a header with the ' 'field names can be inserted at top of the CSV file.', 'Text of an About plugin message box')} about_page = AboutPage(desc, parent) return about_page ViTables-3.0.0/vitables/plugins/csv/icons/000077500000000000000000000000001311223072700204215ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/csv/icons/document-export.png000066400000000000000000000011461311223072700242660ustar00rootroot00000000000000PNG  IHDR(-SsBITO pHYs:tEXtSoftwarewww.inkscape.org<PLTEdddmmm???dddՌ׃nnnxxxң=tRNS!$,-5PQRRIDATJPE}νɀr/;;A,u  $ŵ4<ͱ-;͘ 觛^`"̺-IlZxXEgwDmZÖAHLD,oIk}IdH/ㄑ$]-I :04iX6=P@] SAwGOIENDB`ViTables-3.0.0/vitables/plugins/csv/icons/document-import.png000066400000000000000000000011411311223072700242520ustar00rootroot00000000000000PNG  IHDR(-SsBITO pHYs:tEXtSoftwarewww.inkscape.org<PLTEddddddhhhrrr|||tRNS!$,5PQRsf"IDATJ@'⢈ji.D|xEA*]h.Z0d2AoޗY¤t?%a e?9p{޾[wMS^F ax o–Do?^Y@Dj^^I)$g:LP6CR#jf*9GO#|NIENDB`ViTables-3.0.0/vitables/plugins/csv/import_csv.py000066400000000000000000000455221311223072700220550ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # Plugin initial draft author: Jorge Ibanez jorge.ibannez@uam.es # """Plugin that provides import `CSV` files into `PyTables` arrays and tables. The pipeline for importing a `CSV` file is:: CSV file --> numpy array --> tables.Leaf The ``numpy`` array is created via `numpy.genfromtxt`. The `tables.Leaf` instance is created using the appropriate constructors. Beware that importing big files is a slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO. Other aspects to take into account: - creation of `tables.Array` datasets requires the ``numpy`` array containing the whole `CSV` file to be loaded in memory. If the file is large enough you can run out of memory. - creation of `tables.CArray` datasets requires an additional parsing of the whole `CSV` file in order to find out its number of rows (it is a required argument of the `tables.CArray` constructor). - there is a penalty performance when string dtypes are involved. The reason is that string fields use to have variable length so, before the ``numpy`` array is created, we need to find out the minimum itemsize required for storing those string fields with no lose of data. This step requires an additional parsing of the whole `CSV` file. - `CSV` files containing N-dimensional fields are always imported with `str` dtype. This is a limitation of `numpy.genfromtxt`. """ __docformat__ = 'restructuredtext' __version__ = '1.1' plugin_class = 'ImportCSV' plugin_name = 'CSV importer' comment = 'Import CSV files into datasets.' import os import tempfile import logging import traceback import tables import numpy from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.plugins.aboutpage import AboutPage import vitables.plugins.csv.csvutils as csvutils translate = QtWidgets.QApplication.translate TYPE_ERROR = translate( 'ImportCSV', 'Please, make sure that you are importing a ' 'homogeneous dataset.', 'CSV file not imported error') _PLUGIN_FOLDER = os.path.join(os.path.dirname(__file__)) class ImportCSV(QtCore.QObject): """Provides CSV import capabilities for tables and arrays. Some minor flaws: multidimensional fields are not well supported. They are imported as strings. """ UID = 'vitables.plugin.import_csv' NAME = plugin_name COMMENT = comment def __init__(self): """The class constructor. """ super(ImportCSV, self).__init__() self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # Get a reference to the application instance self.vtapp = vitables.utils.getVTApp() if self.vtapp is None: return self.vtgui = vitables.utils.getGui() self.dbt_model = self.vtgui.dbs_tree_model self.dbt_view = self.vtgui.dbs_tree_view # Add an entry under the File menu self.addEntry() def addEntry(self): """Add the `Import CSV...` entry to the `File` menu. """ icon = QtGui.QIcon() pixmap = QtGui.QPixmap(os.path.join(_PLUGIN_FOLDER, 'icons/document-import.png')) icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) self.import_submenu = QtWidgets.QMenu( translate('ImportCSV', 'I&mport from CSV...', 'File -> Import CSV')) self.import_submenu.setSeparatorsCollapsible(False) self.import_submenu.setIcon(icon) # Create the actions actions = {} actions['import_table'] = QtWidgets.QAction( translate('ImportCSV', "Import &Table...", "Import table from CSV file"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.csv2Table, statusTip=translate( 'ImportCSV', "Import Table from plain CSV file", "Status bar text for File -> Import CSV... -> Import Table")) actions['import_array'] = QtWidgets.QAction( translate('ImportCSV', "Import &Array...", "Import array from CSV file"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.csv2Array, statusTip=translate( 'ImportCSV', "Import Array from plain CSV file", "Status bar text for File -> Import CSV... -> Import Array")) actions['import_carray'] = QtWidgets.QAction( translate('ImportCSV', "Import &CArray...", "Import carray from CSV file"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.csv2CArray, statusTip=translate( 'ImportCSV', "Import CArray from plain CSV file", "Status bar text for File -> Import CSV... -> Import CArray")) actions['import_earray'] = QtWidgets.QAction( translate('ImportCSV', "Import &EArray...", "Import earray from CSV file"), self, shortcut=QtGui.QKeySequence.UnknownKey, triggered=self.csv2EArray, statusTip=translate( 'ImportCSV', "Import EArray from plain CSV file", "Status bar text for File -> Import CSV... -> Import EArray")) actions['separator'] = QtWidgets.QAction(self) actions['separator'].setSeparator(True) # Add actions to the Import submenu keys = ('import_table', 'import_array', 'import_carray', 'import_earray') vitables.utils.addActions(self.import_submenu, keys, actions) # Add submenu to file menu before the Close File action vitables.utils.insertInMenu( self.vtgui.file_menu, self.import_submenu, 'fileClose') sep = actions['separator'] vitables.utils.insertInMenu(self.vtgui.file_menu, sep, 'fileClose') # Add submenu to file context menu before the Close File action vitables.utils.insertInMenu(self.vtgui.view_cm, self.import_submenu, 'fileClose') vitables.utils.insertInMenu(self.vtgui.view_cm, sep, 'fileClose') def createDestFile(self, filepath): """Create the `PyTables` file where the `CSV` file will be imported. :Parameter filepath: the `PyTables` file filepath """ dbdoc = None try: dirname, filename = os.path.split(filepath) root = os.path.splitext(filename)[0] dest_filepath = vitables.utils.forwardPath(os.path.join(dirname, '{0}.h5'.format(root))) if csvutils.isValidFilepath(dest_filepath): dbdoc = self.dbt_model.createDBDoc(dest_filepath) except: self.logger.error( translate('ImportCSV', 'Import failed because destination ' 'file cannot be created.', 'A file creation error')) vitables.utils.formatExceptionInfo() return dbdoc def csvFilepath(self, leaf_kind): """Get the filepath of the source `CSV` file. :Parameter leaf_kind: the kind of container where data will be stored """ # Call the file selector (and, if needed, customise it) filepath, working_dir = vitables.utils.getFilepath( self.vtgui, translate( 'ImportCSV', 'Importing CSV file into {0}', 'Caption of the Import from CSV dialog').format(leaf_kind), dfilter=translate('ImportCSV', """CSV Files (*.csv);;""" """All Files (*)""", 'Filter for the Import from CSV dialog'), settings={'accept_mode': QtWidgets.QFileDialog.AcceptOpen, 'file_mode': QtWidgets.QFileDialog.ExistingFile, 'history': self.vtapp.file_selector_history, 'label': translate('ImportCSV', 'Import', 'Accept button text for QFileDialog')} ) if not filepath: # The user has canceled the dialog return # Update the history of the file selector widget self.vtapp.updateFSHistory(working_dir) return filepath def updateTree(self, filepath): """Update the databases tree once the `CSV` file has been imported. When the destination h5 file is created and added to the databases tree it has no nodes. Once the `CSV` file has been imported into a `PyTables` container we update the representation of the h5 file in the tree so that users can see that the file has a leaf. Eventually, the root node of the imported file is selected so that users can locate it immediately. :Parameter filepath: the filepath of the destination h5 file """ for row, child in enumerate(self.dbt_model.root.children): if child.filepath == filepath: index = self.dbt_model.index(row, 0, QtCore.QModelIndex()) self.dbt_model.lazyAddChildren(index) self.dbt_view.setCurrentIndex(index) def csv2Table(self): """Import a plain `CSV` file into a `tables.Array` object. """ kind = 'Table' filepath = self.csvFilepath(kind) if filepath is None: return # Import the CSV content try: QtWidgets.qApp.processEvents() QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) input_handler = open(filepath, 'r+') try: (nrows, descr, has_header) = csvutils.tableInfo(input_handler) except Exception as inst: print(traceback.format_exc()) # Create the dataset dbdoc = self.createDestFile(filepath) if dbdoc is None: return io_filters = tables.Filters(complevel=9, complib='lzo') dataset_name = "imported_{0}".format(kind) atitle = \ 'Source CSV file {0}'.format(os.path.basename(filepath)) dataset = dbdoc.h5file.create_table( '/', dataset_name, descr, title=atitle, filters=io_filters, expectedrows=nrows) # Fill the dataset in a memory efficient way input_handler.seek(0) if has_header: # Skip the header line input_handler.readline() chunk_size = 10000 buf_size = chunk_size*dataset.rowsize read_fh = input_handler.readlines buf = read_fh(buf_size) while buf: idata = csvutils.getArray(buf) # Append data to the dataset dataset.append(idata) dataset.flush() del idata buf = read_fh(buf_size) dbdoc.h5file.flush() self.updateTree(dbdoc.filepath) except: vitables.utils.formatExceptionInfo() finally: QtWidgets.qApp.restoreOverrideCursor() input_handler.close() def csv2EArray(self): """Import a plain `CSV` file into a `tables.EArray` object. This is a slot method. See :meth:`addEntry` method for details. """ kind = 'EArray' filepath = self.csvFilepath(kind) if filepath is None: return # Import the CSV content try: QtWidgets.qApp.processEvents() QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) chunk_size = 10000 input_handler = open(filepath, 'r+') (nrows, atom, array_shape) = csvutils.earrayInfo(input_handler) # Create the dataset dbdoc = self.createDestFile(filepath) if dbdoc is None: return io_filters = tables.Filters(complevel=9, complib='lzo') dataset_name = "imported_{0}".format(kind) atitle = 'Source CSV file {0}'.format(os.path.basename(filepath)) dataset = dbdoc.h5file.create_earray( '/', dataset_name, atom, array_shape, title=atitle, filters=io_filters, expectedrows=nrows) # Fill the dataset in a memory effcient way input_handler.seek(0) chunk_size = 10000 buf_size = chunk_size*dataset.rowsize read_fh = input_handler.readlines buf = read_fh(buf_size) while buf: idata = csvutils.getArray(buf) # Append data to the dataset dataset.append(idata) dataset.flush() del idata buf = read_fh(buf_size) dbdoc.h5file.flush() self.updateTree(dbdoc.filepath) except ValueError: self.logger.error(TYPE_ERROR) except: vitables.utils.formatExceptionInfo() finally: QtWidgets.qApp.restoreOverrideCursor() input_handler.close() def csv2CArray(self): """Import a plain `CSV` file into a `tables.CArray` object. This is a slot method. See :meth:`addEntry` method for details. """ kind = 'CArray' filepath = self.csvFilepath(kind) if filepath is None: return # Import the CSV content try: QtWidgets.qApp.processEvents() QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) chunk_size = 10000 input_handler = open(filepath, 'r+') (atom, array_shape) = csvutils.carrayInfo(input_handler) # Create the dataset dbdoc = self.createDestFile(filepath) if dbdoc is None: return io_filters = tables.Filters(complevel=9, complib='lzo') dataset_name = "imported_{0}".format(kind) atitle = 'Source CSV file {0}'.format(os.path.basename(filepath)) dataset = dbdoc.h5file.create_carray( '/', dataset_name, atom, array_shape, title=atitle, filters=io_filters) # Fill the dataset in a memory effcient way input_handler.seek(0) chunk_size = 10000 buf_size = chunk_size*dataset.rowsize read_fh = input_handler.readlines buf = read_fh(buf_size) start = 0 while buf: idata = csvutils.getArray(buf) stop = start + idata.shape[0] # Append data to the dataset dataset[start:stop] = idata dataset.flush() del idata start = stop buf = read_fh(buf_size) dbdoc.h5file.flush() self.updateTree(dbdoc.filepath) except ValueError: self.logger.error(TYPE_ERROR) except: vitables.utils.formatExceptionInfo() finally: QtWidgets.qApp.restoreOverrideCursor() input_handler.close() def csv2Array(self): """Import a plain `CSV` file into a `tables.Array` object. This is a slot method. See :meth:`addEntry` method for details. """ kind = 'Array' filepath = self.csvFilepath(kind) if filepath is None: return # Import the CSV content try: QtWidgets.qApp.processEvents() QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) # The dtypes are determined by the contents of each column # Multidimensional columns will have string datatype data = numpy.genfromtxt(filepath, delimiter=',', dtype=None) except TypeError: data = None dbdoc = None self.logger.error(TYPE_ERROR) else: try: # Create the array dbdoc = self.createDestFile(filepath) if dbdoc is None: return array_name = "imported_{0}".format(kind) title = 'Imported from CSV file {0}'.\ format(os.path.basename(filepath)) dbdoc.h5file.create_array('/', array_name, data, title=title) dbdoc.h5file.flush() self.updateTree(dbdoc.filepath) except TypeError: self.logger.error(TYPE_ERROR) except tables.NodeError: vitables.utils.formatExceptionInfo() finally: del data QtWidgets.qApp.restoreOverrideCursor() def helpAbout(self, parent): """Full description of the plugin. This is a convenience method which works as expected by :meth:preferences.preferences.Preferences.aboutPluginPage i.e. build a page which contains the full description of the plugin and, optionally, allows for its configuration. :Parameter about_page: the container widget for the page """ # Plugin full description desc = {'version': __version__, 'module_name': os.path.join(os.path.basename(__file__)), 'folder': os.path.join(os.path.dirname(__file__)), 'author': 'Vicent Mas ', 'comment': translate( 'ImportCSV', '

Plugin that provides import CSV files ' 'capabilities.

CSV files can be imported into any of ' 'the following PyTables containers: Array, EArray, CArray ' 'and Table.

When a file is imported into a Table ' 'automatic header detection is provided.

Beware that ' 'importing large files is a potentially slow process ' 'because the whole file has to be read from disk, ' 'transformed and write back to disk again so there is ' 'a lot of disk IO.', 'Text of an About plugin message box')} about_page = AboutPage(desc, parent) return about_page ViTables-3.0.0/vitables/plugins/dbstreesort/000077500000000000000000000000001311223072700210535ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/dbstreesort/__init__.py000066400000000000000000000015251311223072700231670ustar00rootroot00000000000000 # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ['aboutpage', 'dbs_tree_sort'] ViTables-3.0.0/vitables/plugins/dbstreesort/aboutpage.py000066400000000000000000000113671311223072700234040ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a widget with the full description of the plugin. The module allows for configuring the plugin too. The widget is displayed when the plugin is selected in the Preferences dialog selector pane. """ __docformat__ = 'restructuredtext' import os.path try: import configparser except ImportError: import ConfigParser as configparser from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType # This method of the PyQt4.uic module allows for dynamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_DBsTreeSortPage = \ loadUiType(os.path.join(os.path.dirname(__file__), 'dbs_tree_sort_page.ui'))[0] class AboutPage(QtWidgets.QWidget, Ui_DBsTreeSortPage): """ Widget for describing and customizing the Sorting of DBs Tree plugin. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This widget is inserted as a page in the stacked widget of the Preferences dialog when the sorting of DBs Tree item is clicked in the selector tree. """ def __init__(self, desc, parent=None): """Fill and customize the widget describing the DBs sorting plugin. :Parameters: -`desc` a dictionary with the plugin description -`parent` the stacked widget where this About page will be added """ # Makes the dialog and gives it a layout super(AboutPage, self).__init__(parent) self.setupUi(self) # The widget with the OK and Cancel buttons self.preferences_dlg = parent.parent() self.dlg_box_buttons = self.preferences_dlg.buttonsBox # The plugin description self.version_le.setText(desc['version']) self.module_name_le.setText(desc['module_name']) self.folder_le.setText(desc['folder']) self.author_le.setText(desc['author']) self.desc_te.setText(desc['about_text']) # The absolute path of the INI file self.ini_filename = \ os.path.join(os.path.dirname(__file__), 'sorting_algorithm.ini') # Read initial configuration from the INI file self.config = configparser.ConfigParser() default_sorting = 'human' try: self.config.read_file(open(self.ini_filename)) self.initial_sorting = self.config['DBsTreeSorting']['algorithm'] except (IOError, configparser.ParsingError): self.initial_sorting = default_sorting # Fill the combo with values and choose the current sorting algorithm self.algorithms_combobox.insertItems( 0, ['alphabetical', 'human']) current_index = self.algorithms_combobox.findText(self.initial_sorting) self.algorithms_combobox.setCurrentIndex(current_index) # Connect signals to slots self.dlg_box_buttons.button(QtWidgets.QDialogButtonBox.Cancel).clicked.\ connect(self.cancelAlgorithmChange) self.dlg_box_buttons.button(QtWidgets.QDialogButtonBox.Ok).clicked.\ connect(self.saveAlgorithmChange) def cancelAlgorithmChange(self): """Restore the initial sorting algorithm in the combobox. If the user press the Cancel button changes made in the combobox are lost. """ self.config['DBsTreeSorting']['algorithm'] = self.initial_sorting with open(self.ini_filename, 'w') as ini_file: self.config.write(ini_file) #self.preferences_dlg.reject() def saveAlgorithmChange(self): """Save the combobox current algorithm. """ self.config['DBsTreeSorting']['algorithm'] = \ self.algorithms_combobox.currentText() with open(self.ini_filename, 'w') as ini_file: self.config.write(ini_file) #self.parent().parent().accept() ViTables-3.0.0/vitables/plugins/dbstreesort/dbs_tree_sort.py000066400000000000000000000205051311223072700242650ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Plugin that provides sorting algorithms for the DBs tree. At the moment only two sorting algorithms are supported, alphabetical and human (a.k.a. natural sorting). In order to obtain the default ViTables random order of nodes just disable the plugin. Once the plugin is enabled it works on any file opened after the enabling. """ __docformat__ = 'restructuredtext' __version__ = '1.1' plugin_class = 'DBsTreeSort' plugin_name = 'Tree of DBs sorting' comment = 'Sorts the display of the databases tree' import os import re import logging try: import configparser except ImportError: import ConfigParser as configparser from qtpy import QtGui from qtpy import QtCore from qtpy import QtWidgets import vitables from vitables.plugins.dbstreesort.aboutpage import AboutPage from vitables.h5db import groupnode from vitables.h5db import leafnode from vitables.h5db import linknode from vitables.h5db import dbstreemodel translate = QtWidgets.QApplication.translate def customiseDBsTreeModel(): """Slot connected to the convenience dbtree_model_created signal. """ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # The absolute path of the INI file ini_filename = os.path.join(os.path.dirname(__file__), 'sorting_algorithm.ini') config = configparser.ConfigParser() try: config.read(ini_filename) initial_sorting = config.get('DBsTreeSorting', 'algorithm') except (IOError, configparser.ParsingError): logger.error( translate('DBsTreeSort', 'The configuration file of the ' 'dbs_tree_sort plugin cannot be read.', 'DBsTreeSort error message')) return # The essence of the plugin is pretty simple, just monkeypatch # the insertRows() method of the model to get the desired result. # TODO how can the nodes be chronologically sorted? if initial_sorting == 'human': dbstreemodel.DBsTreeModel.insertRows = humanSort elif initial_sorting == 'alphabetical': dbstreemodel.DBsTreeModel.insertRows = alphabeticalSort else: logger.warning( translate('DBsTreeSort', 'Unknown sorting algorithm: {}.', 'DBsTreeSort error message').format(initial_sorting)) def alphabeticalSort(self, position=0, count=1, parent=QtCore.QModelIndex()): """Sort nodes alphabetically. This method is called during nodes population and when files are opened/created. :Parameters: - `position`: the position of the first row being added. - `count`: the number of rows being added - `parent`: the index of the parent item. :Returns: True if the row is added. Otherwise it returns False. """ # Add rows to the model and update its underlaying data store self.layoutAboutToBeChanged.emit() first = position last = position + count - 1 self.beginInsertRows(parent, first, last) node = self.nodeFromIndex(parent) # Children are inserted at position 0, so inserted list must # be reversed if we want to preserve their original order for file_node in sorted(self.fdelta): self.root.insertChild(file_node, position) for name in sorted(self.gdelta, reverse=True): group = groupnode.GroupNode(self, node, name) node.insertChild(group, position) for name in sorted(self.ldelta, reverse=True): leaf = leafnode.LeafNode(self, node, name) node.insertChild(leaf, position) for name in sorted(self.links_delta, reverse=True): link = linknode.LinkNode(self, node, name) node.insertChild(link, position) self.dataChanged.emit(parent, parent) self.endInsertRows() self.layoutChanged.emit() # Report views about changes in data top_left = self.index(first, 0, parent) bottom_right = self.index(last, 0, parent) self.dataChanged.emit(top_left, bottom_right) return True def alphanum_key(key): """ Turn a string into a list of string and number chunks. "z23a" -> ["z", 23, "a"] """ convert = lambda text: int(text) if text.isdigit() else text return [convert(c) for c in re.split(r'(\d+)', key)] def humanSort(self, position=0, count=1, parent=QtCore.QModelIndex()): """Sort nodes using a human sort algorithm. This method is called during nodes population and when files are opened/created. :Parameters: - `position`: the position of the first row being added. - `count`: the number of rows being added - `parent`: the index of the parent item. :Returns: True if the row is added. Otherwise it returns False. """ # Add rows to the model and update its underlying data store self.layoutAboutToBeChanged.emit() first = position last = position + count - 1 self.beginInsertRows(parent, first, last) node = self.nodeFromIndex(parent) # Children are inserted at position 0, so inserted list must # be reversed if we want to preserve their original order for file_node in sorted(self.fdelta): self.root.insertChild(file_node, position) for name in sorted(self.gdelta, reverse=True, key=alphanum_key): group = groupnode.GroupNode(self, node, name) node.insertChild(group, position) for name in sorted(self.ldelta, reverse=True, key=alphanum_key): leaf = leafnode.LeafNode(self, node, name) node.insertChild(leaf, position) for name in sorted(self.links_delta, reverse=True, key=alphanum_key): link = linknode.LinkNode(self, node, name) node.insertChild(link, position) self.dataChanged.emit(parent, parent) self.endInsertRows() self.layoutChanged.emit() # Report views about changes in data top_left = self.index(first, 0, parent) bottom_right = self.index(last, 0, parent) self.dataChanged.emit(top_left, bottom_right) return True class DBsTreeSort(object): """Provides convenience methods and functions for sorting the tree of DBs. """ UID = 'vitables.plugin.dbs_tree_sort' NAME = plugin_name COMMENT = comment def __init__(self): """Class constructor. """ self.vtapp = vitables.utils.getVTApp() self.vtapp.dbtree_model_created.connect(customiseDBsTreeModel) def helpAbout(self, parent): """Full description of the plugin. This is a convenience method which works as expected by :meth:preferences.preferences.Preferences.aboutPluginPage i.e. build a page which contains the full description of the plugin and, optionally, allows for its configuration. :Parameter about_page: the container widget for the page """ # Plugin full description desc = {'version': __version__, 'module_name': os.path.join(os.path.basename(__file__)), 'folder': os.path.join(os.path.dirname(__file__)), 'author': 'Vicent Mas ', 'about_text': translate( 'DBsTreeSortingPage', '

Plugin that provides sorting capabilities to ' 'the tree of DBs.

For every open file, nodes (groups and' ' leaves) are sorted when the file is open. ' 'Nodes added at a later time are not sorted.

At the ' 'moment only two sorting ' 'algorithms are supported: human (a.k.a. natural sorting) ' 'and alphabetical.', 'Text of an About plugin message box')} self.about_page = AboutPage(desc, parent) return self.about_page ViTables-3.0.0/vitables/plugins/dbstreesort/dbs_tree_sort_page.ui000066400000000000000000000200551311223072700252460ustar00rootroot00000000000000 DBTreeSortPage 0 0 400 473 Form Plugin description Version: 239 239 239 239 239 239 244 244 244 true Module name: 239 239 239 239 239 239 244 244 244 true Folder: 239 239 239 239 239 239 244 244 244 true Author: 239 239 239 239 239 239 244 244 244 true Desription: 239 239 239 239 239 239 244 244 244 true Sorting algorithm ViTables-3.0.0/vitables/plugins/dbstreesort/sorting_algorithm.ini000066400000000000000000000000441311223072700253050ustar00rootroot00000000000000[DBsTreeSorting] algorithm = human ViTables-3.0.0/vitables/plugins/timeseries/000077500000000000000000000000001311223072700206645ustar00rootroot00000000000000ViTables-3.0.0/vitables/plugins/timeseries/__init__.py000066400000000000000000000015231311223072700227760ustar00rootroot00000000000000 # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ['aboutpage', 'time_series'] ViTables-3.0.0/vitables/plugins/timeseries/aboutpage.py000066400000000000000000000112731311223072700232110ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a widget with the full description of the plugin. The module allows for configuring the plugin too. The widget is displayed when the plugin is selected in the Preferences dialog selector tree. """ __docformat__ = 'restructuredtext' import os.path import datetime try: import configparser except ImportError: import ConfigParser as configparser from qtpy import QtGui from qtpy import QtCore from qtpy import QtWidgets from qtpy.uic import loadUiType # This method of the PyQt4.uic module allows for dynamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_TimeFormatterPage = \ loadUiType(os.path.join(os.path.dirname(__file__), 'timeformatter_page.ui'))[0] class AboutPage(QtWidgets.QWidget, Ui_TimeFormatterPage): """ Widget for describing and customizing the Time series plugin. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This widget is inserted as a page in the stacked widget of the Preferences dialog when the Time series item is clicked in the selector tree. """ def __init__(self, desc, parent=None): """Widget for describing and customizing the Timeseries plugin. :Parameters: - `desc`: a dictionary with the plugin description -`parent`: the stacked widget of the Preferences dialog """ # Makes the dialog and gives it a layout super(AboutPage, self).__init__(parent) self.setupUi(self) self.version_le.setText(desc['version']) self.module_name_le.setText(desc['module_name']) self.folder_le.setText(desc['folder']) self.author_le.setText(desc['author']) self.desc_te.setText(desc['about_text']) # Configuration section of the page self.save_button = self.buttons_box.button(QtWidgets.QDialogButtonBox.Save) self.save_button.setText('Save format') # The absolute path of the INI file self.ini_filename = \ os.path.join(os.path.dirname(__file__), 'time_format.ini') # Setup initial configuration self.config = configparser.ConfigParser(interpolation=None) def_tformat = '%c' try: self.config.read_file(open(self.ini_filename)) self.tformat = self.config['Timeseries']['strftime'] except (IOError, configparser.ParsingError): self.tformat = def_tformat self.tformat_editor.setText(self.tformat) today = datetime.datetime.today().strftime(self.tformat) self.today_label.setText(today) self.save_button.clicked.connect(self.saveFormat) def eventFilter(self, w, e): """Event filter for the dialog. """ if self.tformat_editor.hasFocus(): if e.type() == 6: if e.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): self.applyFormat() return True return QtWidgets.QWidget.eventFilter(self, w, e) def applyFormat(self): """ Check the current time format. The time format currently entered in the line editor is applied to the sample label showing the today date. If the result is that expected by user then she can click safely the OK button. Otherwise she should try another time format. """ today = datetime.datetime.today().strftime(self.tformat_editor.text()) self.today_label.clear() self.today_label.setText(today) def saveFormat(self): """Slot for saving the entered time format. """ self.config['Timeseries']['strftime'] = self.tformat_editor.text() with open(self.ini_filename, 'w') as ini_file: self.config.write(ini_file) ViTables-3.0.0/vitables/plugins/timeseries/time_format.ini000066400000000000000000000000341311223072700236700ustar00rootroot00000000000000[Timeseries] strftime = %c ViTables-3.0.0/vitables/plugins/timeseries/time_series.py000066400000000000000000000341741311223072700235570ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Plugin that provides nice string formatting for time fields. It supports not only native `PyTables` time datatypes but also the time series contained in `PyTables` tables generated via ``scikits.timeseries`` and ``Pandas``. """ __docformat__ = 'restructuredtext' __version__ = '2.0' plugin_class = 'TSFormatter' plugin_name = 'Time series formatter' comment = 'Display time series in a human friendly format' import time import os try: import configparser except ImportError: import ConfigParser as configparser import tables try: import scikits.timeseries as ts except ImportError: ts = None try: import pandas as pd except ImportError: pd = None from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils from vitables.plugins.timeseries.aboutpage import AboutPage translate = QtWidgets.QApplication.translate def findTS(leaf, node_kind): """Find out if the inspected leaf contains a time field. **Existing time fields that cannot be formatted are skipped**: - time series created via ``pandas`` module are ignored if that module is not available - time series created via ``scikits.timeseries`` module are ignored if that module is not available - time fields that are displayed in a multidimensional cell are ignored The last restriction includes the following cases: - time fields that are part of a nested field - time fields in `VLArrays` - time fields in arrays with more than 2 dimensions - time fields in arrays with atom shape other than () :Parameters: - `leaf`: the tables.Leaf instance being inspected. - `node_kind`: a LeafNode attribute that indicates the kind of dataset :Return ts_kind: a flag indicating the kind of time series found """ time_types = ['time32', 'time64'] if isinstance(leaf, tables.Table): attrs = leaf._v_attrs coltypes = leaf.coltypes # Check for Pandas timeseries if pd and hasattr(attrs, 'index_kind') and \ (attrs.index_kind in ('datetime64', 'datetime32')): return 'pandas_ts' # Check for scikits.timeseries timeseries if ts and hasattr(attrs, 'CLASS') and \ (attrs.CLASS == 'TimeSeriesTable'): return 'scikits_ts' # Check for PyTables timeseries for name in leaf.colnames: if (name in coltypes) and (coltypes[name] in time_types): return 'pytables_ts' elif (leaf.atom.type in time_types) and \ (len(leaf.shape) < 3) and \ (leaf.atom.shape == ()) and \ (node_kind != 'vlarray'): return 'pytables_ts' else: return None def tsPositions(ts_kind, leaf): """Return the position of the time field going to be formatted. The following cases can occur: - scikits_ts: leaf is a `TimeSeriesTable` instance. It contains just one time field, in a column labeled as `_dates`. - pandas_ts: leaf is a regular `tables.Table` instance with a column named `index`. - pytables_ts and leaf is a regular `tables.Table` instance. Every column can contain a time data type so we must inspect every column - pytables_ts and leaf is a `tables.Array` instance. As it is a homogeneous data container if a column contains a time data type then every column contains a time data type. Specific positions are not required. """ positions = [] if (ts_kind == 'scikits_ts'): positions.append(leaf.coldescrs['_dates']._v_pos) elif (ts_kind == 'pandas_ts'): positions.append(leaf.coldescrs['index']._v_pos) elif ts_kind == 'pytables_ts': if isinstance(leaf, tables.Table): for name in leaf.colnames: if leaf.coltypes[name] in ['time32', 'time64']: positions.append(leaf.coldescrs[name]._v_pos) else: positions = [-1] return positions def tsFrequency(ts_kind, leaf): """Return the frequency (if any) of the time series. Only time series created via ``scikits.timeseries`` module have this attribute. """ ts_freq = None if ts_kind == 'scikits_ts': # The frequency of the time serie. Default is 6000 (daily) special_attrs = getattr(leaf._v_attrs, 'special_attrs', {'freq': 6000}) ts_freq = special_attrs['freq'] return ts_freq def datetimeFormat(): """The format string to be used when rendering the time series. """ config = configparser.ConfigParser(interpolation=None) ini_filename = os.path.join(os.path.dirname(__file__), 'time_format.ini') def_dtformat = '%c' try: config.read_file(open(ini_filename)) datetime_format = config['Timeseries']['strftime'] except (IOError, configparser.ParsingError): datetime_format = def_dtformat return datetime_format class TSFormatter(object): """Human friendly formatting of time series in a dataset. An inspector class intended for finding out if a `tables.Leaf` instance contains a time series suitable to be formatted in a user friendly way. """ UID = 'vitables.plugin.time_series' NAME = plugin_name COMMENT = comment def __init__(self): """Class constructor. Dynamically finds new instances of :meth:`vitables.vttables.leaf_model.LeafModel` and customises them if they contain time fields. """ self.vtapp = vitables.utils.getVTApp() self.vtapp.leaf_model_created.connect(self.customiseModel) def customiseModel(self, datasheet): """Inspect a leaf model and customise it if a time series is found. :Parameter subwindow: the :meth:`vitables.vttables.datasheet.DataSheet` instance being inspected """ # If the node is a soft/external link then dereference it leaf = datasheet.dbt_leaf.node if isinstance(leaf, tables.link.Link): leaf = leaf.__call__() # Look for formattable time fields in the dataset node_kind = datasheet.dbt_leaf.node_kind ts_kind = findTS(leaf, node_kind) if ts_kind is None: return # Get the positions of the time fields time_cols = tsPositions(ts_kind, leaf) if time_cols == []: return # Customise the leaf model model = datasheet.widget().model() ts_info = { 'ts_kind': ts_kind, 'ts_cols': time_cols, 'ts_freq': tsFrequency(ts_kind, leaf), 'ts_format': datetimeFormat(), } if isinstance(leaf, tables.Table): leaf_kind = 'table' else: leaf_kind = 'array' model_info = { 'leaf_kind': leaf_kind, 'rbuffer': model.rbuffer, 'numrows': model.rowCount(), 'formatContent': model.formatContent, } # Add required attributes to model for k in ts_info: setattr(model, k, ts_info[k]) # Add/customise required methods to model ts_model = TSLeafModel(model_info, ts_info) model.tsFormatter = ts_model.tsFormatter model.data = ts_model.data def helpAbout(self, parent): """Full description of the plugin. This is a convenience method which works as expected by :meth:preferences.preferences.Preferences.aboutPluginPage i.e. build a page which contains the full description of the plugin and, optionally, allows for its configuration. :Parameter about_page: the container widget for the page """ # Plugin full description desc = {'version': __version__, 'module_name': os.path.join(os.path.basename(__file__)), 'folder': os.path.join(os.path.dirname(__file__)), 'author': 'Vicent Mas ', 'about_text': translate('TimeFormatterPage', """

Plugin that provides nice string formatting for time fields.

It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. """, 'Text of an About plugin message box')} self.about_page = AboutPage(desc, parent) # We need to install the event filter because the Preferences dialog # eats all Return key presses even if the time format editor widget # has the keyboard focus (so connecting the returnPressed signal # of this widget to the AboutPage.applyFormat is useless) parent.parent().installEventFilter(self.about_page) return self.about_page class TSLeafModel(object): """Provides a `data()` method to leaf models that contains time series. Formatting a table is more difficult than formatting an array because tables content is not homogeneous and columns with time series have to be formatted in a different way to the rest of columns. """ def __init__(self, model_info, ts_info, parent=None): """The constructor method. All required attributes are set in this method. """ # Attributes required by the tsFormatter() method self.ts_kind = ts_info['ts_kind'] self.ts_freq = ts_info['ts_freq'] self.ts_format = ts_info['ts_format'] # Attributes required by the data() method self.rbuffer = model_info['rbuffer'] self.numrows = model_info['numrows'] self.ts_cols = ts_info['ts_cols'] self.formatContent = model_info['formatContent'] self.tsFormatter = self.timeFormatter() leaf_kind = model_info['leaf_kind'] if leaf_kind == 'table': self.data = self.table_data else: self.data = self.array_data def table_data(self, index, role=QtCore.Qt.DisplayRole): """Returns the data stored under the given role for the item referred to by the index. This is an overwritten method. :Parameters: - `index`: the index of a data item - `role`: the role being returned """ if not index.isValid() or \ not (0 <= index.row() < self.numrows): return None cell = self.rbuffer.getCell(self.rbuffer.start + index.row(), index.column()) if role == QtCore.Qt.DisplayRole: if index.column() in self.ts_cols: return self.tsFormatter(cell) return self.formatContent(cell) elif role == QtCore.Qt.TextAlignmentRole: return int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) else: return None def array_data(self, index, role=QtCore.Qt.DisplayRole): """Returns the data stored under the given role for the item referred to by the index. This is an overwritten method. :Parameters: - `index`: the index of a data item - `role`: the role being returned """ if not index.isValid() or \ not (0 <= index.row() < self.numrows): return None cell = self.rbuffer.getCell(self.rbuffer.start + index.row(), index.column()) if role == QtCore.Qt.DisplayRole: return self.tsFormatter(cell) elif role == QtCore.Qt.TextAlignmentRole: return int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) else: return None def timeFormatter(self): """Return the function to be used for formatting time series. """ time_formatter = None ts_kind = self.ts_kind if ts_kind == 'pandas_ts': time_formatter = self.formatPandasTS elif ts_kind == 'scikits_ts': time_formatter = self.formatScikitsTS elif ts_kind == 'pytables_ts': time_formatter = self.formatPyTablesTS return time_formatter def formatPyTablesTS(self, content): """ Format a given date in a user friendly way. The textual representation of the date index is converted to a UTC time that can be easily formatted. This method is called when the timeseries has not been created using a third party library (i.e; Pandas, scikits.timeseries packages). """ try: return time.strftime(self.ts_format, time.gmtime(content)) except ValueError: return content def formatPandasTS(self, content): """Format a given date in a user friendly way. The textual representation of the date index is converted to a Timestamp instance that can be easily formatted. :Parameter content: the content of the table cell being formatted """ date = pd.Timestamp(int(content)) try: return date.strftime(self.ts_format) except ValueError: return content def formatScikitsTS(self, content): """Format a given date in a user friendly way. The textual representation of the date index is converted to a Date instance that can be easily formatted. :Parameter content: the content of the table cell being formatted """ date = ts.Date(self.ts_freq, value=int(content)) try: return date.datetime.strftime(self.ts_format) except ValueError: return content ViTables-3.0.0/vitables/plugins/timeseries/timeformatter_page.ui000066400000000000000000000250421311223072700251040ustar00rootroot00000000000000 TimeFormatterPage 0 0 400 473 Form Plugin description Version: 239 239 239 239 239 239 244 244 244 true Module name: 239 239 239 239 239 239 244 244 244 true Folder: 239 239 239 239 239 239 244 244 244 true Author: 239 239 239 239 239 239 244 244 244 true Desription: 239 239 239 239 239 239 244 244 244 true Configure time format Time format: Sample date: Qt::Horizontal 81 43 Today Qt::Horizontal 117 43 Qt::Horizontal 114 20 QDialogButtonBox::Save Qt::Horizontal 117 20 ViTables-3.0.0/vitables/preferences/000077500000000000000000000000001311223072700173335ustar00rootroot00000000000000ViTables-3.0.0/vitables/preferences/__init__.py000066400000000000000000000016701311223072700214500ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["cfgexception", "pluginsloader", "preferences", "vtconfig"] ViTables-3.0.0/vitables/preferences/cfgexception.py000066400000000000000000000043171311223072700223700ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines an Exception to be used when there is a problem reading/writting the ``ViTables`` configuration. """ __docformat__ = 'restructuredtext' from qtpy import QtGui from qtpy import QtWidgets translate = QtWidgets.QApplication.translate class ConfigFileIOException(Exception): """Exception class for IO errors in the configuration file. :Parameter key: the configuration file key that cannot be read/written """ def __init__(self, key): """Setup the configuration error messages that will be shown to user. """ Exception.__init__(self) # If key looks like /path/to/property=value a write exception is # raised. If not a read exception is raised if '=' in key: setting = key.split('=')[0] self.error_message = translate('ConfigFileIOException', \ """\nConfiguration error: the application setting """\ """{0} cannot be saved.""", 'A logger error message').format(setting) else: self.error_message = translate('ConfigFileIOException', \ """\nConfiguration warning: the application setting """\ """{0} cannot be read. Its default value will be used.""", 'A logger error message').format(key) ViTables-3.0.0/vitables/preferences/pluginsloader.py000066400000000000000000000076461311223072700225720ustar00rootroot00000000000000# Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """The plugins loader module. """ __docformat__ = 'restructuredtext' import pkg_resources import logging import traceback from qtpy import QtGui from qtpy import QtWidgets translate = QtWidgets.QApplication.translate PLUGIN_GROUP = 'vitables.plugins' def _add_plugin_translator(module_name, plugin_class, logger): """Try to load plugin translator.""" app = QtWidgets.QApplication.instance() if hasattr(plugin_class, 'translator'): try: app.installTranslator(plugin_class.translator) except Exception as e: logger.error('Failed to install {0} plugin ' 'translator'.format(module_name)) logger.error(e) def _load_entrypoint(entrypoint, logger): plugin_class = None try: plugin_class = entrypoint.load() except Exception as e: logger.error('Failed to load plugin: {0}'.format( entrypoint.module_name)) logger.error(e) logger.info(traceback.format_exc()) return plugin_class def _create_instance(plugin_class, logger): instance = None try: instance = plugin_class() except Exception as e: logger.error('Failed to create plugin instance') logger.error(e) logger.info(traceback.format_exc()) return instance class PluginsLoader(object): """Plugins loader class. The class loads enabled plugins and their translations and stores info about them. """ def __init__(self, enabled_plugins): """Assign default values to members. """ self._logger = logging.getLogger(__name__) # list of UID of enabled plugins, stored in configuration self.enabled_plugins = enabled_plugins # dictionary that contains all available plugins self.all_plugins = {} # instances of loaded plugins self.loaded_plugins = {} def _disable_not_loaded(self): self.enabled_plugins = list(self.loaded_plugins.keys()) def loadAll(self): """Find plugins in the system and crete instances of enabled ones.""" self._logger.debug('Enabled plugins: {0}'.format( str(self.enabled_plugins))) for entrypoint in pkg_resources.iter_entry_points(PLUGIN_GROUP): # @UndefinedVariable plugin_class = _load_entrypoint(entrypoint, self._logger) if plugin_class is None: continue self._logger.debug('Found plugin: {0}'.format( entrypoint.module_name)) self.all_plugins[plugin_class.UID] = { 'UID': plugin_class.UID, 'name': plugin_class.NAME, 'comment': plugin_class.COMMENT} if plugin_class.UID in self.enabled_plugins: self._logger.debug('Loading plugin: {0}'.format( entrypoint.name)) _add_plugin_translator(entrypoint.module_name, plugin_class, self._logger) instance = _create_instance(plugin_class, self._logger) if instance is not None: self.loaded_plugins[plugin_class.UID] = instance self._disable_not_loaded() ViTables-3.0.0/vitables/preferences/preferences.py000066400000000000000000000403611311223072700222120ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a dialog for changing ``ViTables`` settings at runtime. The dialog has 3 pages managed via QtGui.QStackedWidget: General settings page, Look&Feel settings page and Plugins settings page. """ __docformat__ = 'restructuredtext' import os from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType from vitables.vtsite import ICONDIR import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dynamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_SettingsDialog = \ loadUiType(os.path.join(os.path.dirname(__file__),'settings_dlg.ui'))[0] class Preferences(QtWidgets.QDialog, Ui_SettingsDialog): """ Create the Settings dialog. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) """ def __init__(self): """ Initialize the preferences dialog. * initializes the dialog appearance according to current preferences * connects dialog widgets to slots that provide them functionality """ self.vtapp = vitables.utils.getVTApp() self.vtgui = self.vtapp.gui # Create the Settings dialog and customize it super(Preferences, self).__init__(self.vtgui) self.setupUi(self) self.config = self.vtapp.config self.pg_loader = self.vtapp.plugins_mgr self.all_plugins = \ dict(item for item in self.pg_loader.all_plugins.items()) self.enabled_plugins = self.pg_loader.enabled_plugins[:] # Setup the Plugins page self.setupPluginsPage() # Setup the page selector widget self.setupSelector() # Style names can be retrieved with qt.QStyleFactory.keys() styles = QtWidgets.QStyleFactory.keys() self.stylesCB.insertItems(0, styles) # The dictionary of current ViTables preferences self.initial_prefs = {} style_sheet = self.vtgui.logger.styleSheet() paper = style_sheet[-7:] self.initial_prefs['Logger/Paper'] = QtGui.QColor(paper) self.initial_prefs['Logger/Text'] = self.vtgui.logger.textColor() self.initial_prefs['Logger/Font'] = self.vtgui.logger.font() self.initial_prefs['Workspace/Background'] = \ self.vtgui.workspace.background() self.initial_prefs['Look/currentStyle'] = self.config.current_style self.initial_prefs['Startup/startupWorkingDir'] = \ self.config.startup_working_directory self.initial_prefs['Startup/restoreLastSession'] = \ self.config.restore_last_session # The dictionary used to update the preferences self.new_prefs = {} # Apply the current ViTables configuration to the Preferences dialog self.resetPreferences() # Connect SIGNALS to SLOTS self.buttonsBox.helpRequested.connect( QtWidgets.QWhatsThis.enterWhatsThisMode) def setupPluginsPage(self): """Populate the tree of plugins. """ nrows = len(self.all_plugins) self.plugins_model = QtGui.QStandardItemModel(nrows, 2, self) self.pluginsTV.setModel(self.plugins_model) header = QtWidgets.QHeaderView(QtCore.Qt.Horizontal, self.pluginsTV) header.setStretchLastSection(True) self.pluginsTV.setHeader(header) self.plugins_model.setHorizontalHeaderLabels(['Name', 'Comment']) # Populate the model row = 0 for UID, desc in self.all_plugins.items(): name = desc['name'] comment = desc['comment'] nitem = QtGui.QStandardItem(name) nitem.setData(UID) nitem.setCheckable(True) if UID in self.enabled_plugins: nitem.setCheckState(QtCore.Qt.Checked) citem = QtGui.QStandardItem(comment) self.plugins_model.setItem(row, 0, nitem) self.plugins_model.setItem(row, 1, citem) row = row + 1 def setupSelector(self): """Setup the page selector widget of the Preferences dialog. """ iconsdir = os.path.join(ICONDIR, '64x64') self.selector_model = QtGui.QStandardItemModel(self) self.pageSelector.setModel(self.selector_model) # Populate the model with top level items alignment = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled general_item = QtGui.QStandardItem() general_item.setIcon(QtGui.QIcon(os.path.join(iconsdir, 'preferences-other.png'))) general_item.setText(translate('Preferences', " General ", "Text for page selector icon")) general_item.setTextAlignment(alignment) general_item.setFlags(flags) style_item = QtGui.QStandardItem() style_item.setIcon(QtGui.QIcon(os.path.join(iconsdir, 'preferences-desktop-theme.png'))) style_item.setText(translate('Preferences', "Look & Feel", "Text for page selector icon")) style_item.setTextAlignment(alignment) style_item.setFlags(flags) self.plugins_item = QtGui.QStandardItem() self.plugins_item.setIcon(QtGui.QIcon(os.path.join(iconsdir, 'preferences-plugin.png'))) self.plugins_item.setText(translate('Preferences', " Plugins ", "Text for page selector icon")) self.plugins_item.setTextAlignment(alignment) self.plugins_item.setFlags(flags) for item in (general_item, style_item, self.plugins_item): self.selector_model.appendRow(item) # Add items for *loaded* plugins to the Plugins item index = self.selector_model.indexFromItem(self.plugins_item) self.pageSelector.setExpanded(index, True) for UID in self.vtapp.plugins_mgr.loaded_plugins.keys(): name = UID.split('#@#')[0] item = QtGui.QStandardItem(name) item.setData(UID) self.plugins_item.appendRow(item) @QtCore.Slot("QModelIndex", name="on_pageSelector_clicked") def changeSettingsPage(self, index): """Slot for changing the selected page in the Settings dialog. :Parameter index: the index clicked by the user """ # If top level item is clicked if not index.parent().isValid(): self.stackedPages.setCurrentIndex(index.row()) # If a plugin item is clicked elif index.parent() == self.plugins_item.index(): pluginID = self.selector_model.itemFromIndex(index).data() self.aboutPluginPage(pluginID) @QtCore.Slot("QAbstractButton *", name="on_buttonsBox_clicked") def executeButtonAction(self, button): """Slot that manages button box clicks in the Preferences dialog. Whenever one of the `Help`, `Reset`, `Cancel` or `OK` buttons is clicked in the Preferences dialog this slot is called. :Parameter button: the clicked button. """ if button == self.buttonsBox.button(QtWidgets.QDialogButtonBox.Reset): self.resetPreferences() elif button == self.buttonsBox.button(QtWidgets.QDialogButtonBox.Help): pass elif button == self.buttonsBox.button(QtWidgets.QDialogButtonBox.Cancel): self.reject() else: self.applySettings() def resetPreferences(self): """ Apply the current ``ViTables`` configuration to the Preferences dialog. """ # Startup page if self.initial_prefs['Startup/startupWorkingDir'] == 'last': self.lastDirCB.setChecked(True) else: self.lastDirCB.setChecked(False) self.restoreCB.setChecked( self.initial_prefs['Startup/restoreLastSession']) # Style page self.sampleTE.selectAll() self.sampleTE.setCurrentFont(self.initial_prefs['Logger/Font']) self.sampleTE.setTextColor(self.initial_prefs['Logger/Text']) self.sampleTE.moveCursor(QtGui.QTextCursor.End) # Unselect text self.sampleTE.setStyleSheet("background-color: {0}". format(self.initial_prefs['Logger/Paper'].name())) self.workspaceLabel.setStyleSheet('background-color: {0}'. format(self.initial_prefs['Workspace/Background'].color().name())) index = self.stylesCB.findText(self.initial_prefs['Look/currentStyle']) self.stylesCB.setCurrentIndex(index) # The visual update done above is not enough, we must reset the # new preferences dictionary and the list of enabled plugins self.new_prefs.clear() self.new_prefs.update(self.initial_prefs) self.enabled_plugins = self.pg_loader.enabled_plugins[:] self.all_plugins = \ dict(item for item in self.pg_loader.all_plugins.items()) # UIDs = self.all_plugins.keys() for row in range(0, self.plugins_model.rowCount()): item = self.plugins_model.item(row, 0) if item.data() in self.enabled_plugins: item.setCheckState(2) else: item.setCheckState(0) def applySettings(self): """ Apply the current preferences to the application and close the dialog. This method is a slot connected to the `accepted` signal. See ctor for details. """ # Update the plugins manager self.updatePluginsManager() # Update the rest of settings for key, value in self.new_prefs.items(): self.new_prefs[key] = value self.accept() @QtCore.Slot("bool", name="on_lastDirCB_toggled") def setInitialWorkingDirectory(self, cb_on): """ Configure startup behavior of the application. If the `Start in last opened directory` check box is checked then when the user opens a file *for the very first time* the current directory of the file selector dialog (CDFSD) will be the last directory accessed in the previous ``ViTables session``. If it is not checked then ``ViTables`` follows the standard behavior: if it has been started from a console session then the CDFSD will be the current working directory of the session, if it has been started from a menu/desktop-icon/run-command-applet the CDFSD will be the users' home. This is a slot method. :Parameter cb_on: a boolean indicator of the checkbox state. """ if cb_on: self.new_prefs['Startup/startupWorkingDir'] = 'last' else: self.new_prefs['Startup/startupWorkingDir'] = 'home' @QtCore.Slot("bool", name="on_restoreCB_toggled") def setRestoreSession(self, cb_on): """ Configure startup behavior of the application. If the `Restore last session` checkbox is checked then, at the next startup, the application will atempt to restore the last working session. This is a slot method. :Parameter cb_on: a boolean indicator of the checkbox state. """ if cb_on: self.new_prefs['Startup/restoreLastSession'] = 1 else: self.new_prefs['Startup/restoreLastSession'] = 0 @QtCore.Slot(name="on_fontPB_clicked") def setLoggerFont(self): """Slot for setting the logger font.""" new_font, is_ok = \ QtWidgets.QFontDialog.getFont(self.sampleTE.currentFont()) # The selected font is applied to the sample text if is_ok: self.new_prefs['Logger/Font'] = new_font self.sampleTE.selectAll() self.sampleTE.setCurrentFont(new_font) self.sampleTE.moveCursor(QtGui.QTextCursor.End) # Unselect text @QtCore.Slot(name="on_foregroundPB_clicked") def setLoggerTextColor(self): """Slot for setting the logger foreground color.""" text_color = self.sampleTE.textColor() color = QtWidgets.QColorDialog.getColor(text_color) # The selected text color is applied to the sample text if color.isValid(): self.new_prefs['Logger/Text'] = color self.sampleTE.selectAll() self.sampleTE.setTextColor(color) self.sampleTE.moveCursor(QtGui.QTextCursor.End) @QtCore.Slot(name="on_backgroundPB_clicked") def setLoggerBackgroundColor(self): """Slot for setting the logger background color.""" stylesheet = self.sampleTE.styleSheet() background = stylesheet[-7:] color = QtWidgets.QColorDialog.getColor(QtGui.QColor(background)) # The selected paper color is applied to the sample text window if color.isValid(): self.new_prefs['Logger/Paper'] = color new_stylesheet = stylesheet.replace(background, color.name()) self.sampleTE.setStyleSheet(new_stylesheet) @QtCore.Slot(name="on_workspacePB_clicked") def setWorkspaceColor(self): """Slot for setting the workspace background color.""" stylesheet = self.workspaceLabel.styleSheet() background = stylesheet[-7:] color = QtWidgets.QColorDialog.getColor(QtGui.QColor(background)) # The selected color is applied to the sample label besides the button if color.isValid(): self.new_prefs['Workspace/Background'] = QtGui.QBrush(color) new_stylesheet = stylesheet.replace(background, color.name()) self.workspaceLabel.setStyleSheet(new_stylesheet) @QtCore.Slot("QString", name="on_stylesCB_activated") def setGlobalStyle(self, style_name): """ Slot for setting the application style. :Parameter style_name: the style to be applied """ self.new_prefs['Look/currentStyle'] = style_name def updatePluginsManager(self): """Update the plugins manager before closing the dialog. When the Apply button is clicked the list of enabled plugins is refreshed. """ self.enabled_plugins = [] for row in range(self.plugins_model.rowCount()): item = self.plugins_model.item(row, 0) if item.checkState() == 2: self.enabled_plugins.append(item.data()) self.pg_loader.enabled_plugins = self.enabled_plugins[:] def aboutPluginPage(self, pluginID): """A page with info about the plugin clicked in the selector widget. :Parameter pluginID: a unique ID for getting the proper plugin """ # Refresh the Preferences dialog pages. There is at most one # About Plugin page at any given time while self.stackedPages.count() > 3: about_page = self.stackedPages.widget(3) self.stackedPages.removeWidget(about_page) del about_page pg_instance = self.vtapp.plugins_mgr.loaded_plugins[pluginID] try: about_page = pg_instance.helpAbout(self.stackedPages) except AttributeError: about_page = QtWidgets.QWidget(self.stackedPages) label = QtWidgets.QLabel(translate( 'Preferences', 'Sorry, there are no info available for this plugin', 'A text label'), about_page) layout = QtWidgets.QVBoxLayout(about_page) layout.addWidget(label) self.stackedPages.addWidget(about_page) self.stackedPages.setCurrentIndex(3) ViTables-3.0.0/vitables/preferences/settings_dlg.ui000066400000000000000000000336261311223072700223720ustar00rootroot00000000000000 SettingsDialog 0 0 542 419 ViTables settings 0 0 161 380 200 16777215 Click an item in this tree to select the settings you want to change. Beware that the listed plugins are *loaded* plugins (i.e. the are working in the current ViTables session) not just enabled plugins. QAbstractItemView::NoEditTriggers 22 22 false 100 100 false 0 0 2 0 0 Configure the startup behavior of ViTables. 4 4 351 351 0 0 Startup If checked, the last working session -i.e. open files and views- will be restored. If not, ViTables will start with an empty session. Restore last session The working directory used when opening the very first file. It defaults to the current directory if ViTables has been launched from the command line or to the user's home directory if ViTables started from a menu or a desktop icon. If the checkbox is checked then the last entered directory will be used. Start in last working directory 0 0 Configure the look and feel of ViTables. Customise font and colors of the Logger. Logger false You can preview your Font settings here. true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html> Qt::NoTextInteraction Setup the text color. F&oreground Qt::Vertical 20 40 Qt::Vertical 20 40 Setup the background color. &Background Here you can choose the font used in the Logger. &Font Setup the background color of the workspace. Workspace &Background true Background color sample Choose the global style of ViTables here. Style 0 0 Available plugins 0 0 The list of all available plugins. If a plugin is checked then it is enabled (but not necessarely loaded), if it is unchecked then it is disabled (but not necessarely unloaded). Please, note that changes in the check state of plugins will take effect the next time you start ViTables. QAbstractItemView::NoEditTriggers false false Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset ViTables-3.0.0/vitables/preferences/vtconfig.py000066400000000000000000000514251311223072700215330ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module manages the ``ViTables`` configuration. The module provides methods for reading and writing settings. Whether the settings are stored in a plain text file or in a Windows registry is transparent for this module because it deals with settings via `QtCore.QSettings`. Every access to the config settings is done via a `QSettings` instance that, in turn, will access the config file and return the read setting to the application. Saving settings works in a similar way, the application passes the setting to the `QSetting` instance and it (the instance) will write the setting into the config file. .. Note:: *About the config file location*. If format is NativeFormat then the default search path will be: - Unix - UserScope - ``$HOME/.config/MyCompany/ViTables-version.conf`` - ``$HOME/.config/MyCompany.conf`` - SystemScope - ``/etc/xdg/MyCompany/ViTables-version.conf`` - ``/etc/xdg/MyCompany.conf`` - MacOSX - UserScope - ``$HOME/Library/Preferences/org.vitables.ViTables-version.plist`` - ``$HOME/Library/Preferences/org.vitables.plist`` - SystemScope - ``/Library/Preferences/org.vitables.ViTables-version.plist`` - ``/Library/Preferences/org.vitables.plist`` - Windows - UserScope - ``HKEY_CURRENT_USER/Software/MyCompany/ViTables/version`` - ``HKEY_CURRENT_USER/Software/MyCompany/`` - SystemScope - ``HKEY_LOCAL_MACHINE/Software/MyCompany/ViTables/version`` - ``HKEY_LOCAL_MACHINE/Software/MyCompany/`` If format is NativeFormat and platform is Unix the path can be set via QSettings.setPath static method. .. Note:: *About the config file name*. If format is NativeFormat: - under Unix, Product Name -> Product Name.conf so the product name ``ViTables`` will match a configuration file named ``ViTables.conf`` - under MacOSX, Internet Domain and Product Name -> reversed Internet Domain.Product Name.plist so the domain ``vitables.org`` and the product ``ViTables`` become ``org.vitables.ViTables.plist`` """ __docformat__ = 'restructuredtext' __version__ = '3.0.0' import sys import logging from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from vitables.preferences import cfgexception import vitables.utils import vitables.vttables.datasheet as datasheet translate = QtWidgets.QApplication.translate def getVersion(): """The application version.""" return __version__ class Config(QtCore.QSettings): """ Manages the application configuration dynamically. This class defines accessor methods that allow the application (a :meth:`vitables.vtapp.VTApp` instance) to read the configuration in file/registry/plist. The class also provides a method to save the current configuration in the configuration file/registry/plist. """ def __init__(self): """ Setup the application configurator. On Windows systems settings will be stored in the registry under the HKCU\Software\ViTables\__version__ key Mac OS X saves settings in a properties list stored in a standard location, either on a global or user basis (see docstring for more information). In all platforms QSettings format is NativeFormat and scope is UserScope. """ self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) organization = QtWidgets.qApp.organizationName() product = QtWidgets.qApp.applicationName() version = QtWidgets.qApp.applicationVersion() if sys.platform.startswith('win'): path = 'HKEY_CURRENT_USER\\Software\\{0}\\{1}' rpath = path.format(product, version) super(Config, self).__init__(rpath, QtCore.QSettings.NativeFormat) elif sys.platform.startswith('darwin'): super(Config, self).__init__(product, version) else: arg1 = organization arg2 = '-'.join((product, version)) super(Config, self).__init__(arg1, arg2) # System-wide settings will not be searched as a fallback # Setting the NativeFormat paths on MacOSX has no effect self.setFallbacksEnabled(False) # The application default style depends on the platform styles = QtWidgets.QStyleFactory.keys() self.default_style = styles[0] self.vtapp = vitables.utils.getVTApp() if not (self.vtapp is None): style_name = self.vtapp.gui.style().objectName() for item in styles: if item.lower() == style_name: self.default_style = item break def loggerPaper(self): """ Returns the logger background color. """ key = 'Logger/Paper' default_value = QtGui.QColor("#ffffff") setting_value = self.value(key) if isinstance(setting_value, QtGui.QColor): return setting_value else: return default_value def loggerText(self): """ Returns the logger text color. """ key = 'Logger/Text' default_value = QtGui.QColor("#000000") setting_value = self.value(key) if isinstance(setting_value, QtGui.QColor): return setting_value else: return default_value def loggerFont(self): """ Returns the logger font. """ key = 'Logger/Font' default_value = QtWidgets.qApp.font() setting_value = self.value(key) if isinstance(setting_value, QtGui.QFont): return setting_value else: return default_value def workspaceBackground(self): """ Returns the workspace background color. """ key = 'Workspace/Background' default_value = QtGui.QBrush(QtGui.QColor("#ffffff")) setting_value = self.value(key) if isinstance(setting_value, QtGui.QBrush): return setting_value else: return default_value def readStyle(self): """Returns the current application style.""" # The property key and its default value key = 'Look/currentStyle' default_value = self.default_style # Read the entry from the configuration file/registry setting_value = self.value(key) # Check the entry format and value styles = QtWidgets.QStyleFactory.keys() if not isinstance(setting_value, str): return default_value elif setting_value not in styles: return default_value else: return setting_value def windowPosition(self): """ Returns the main window geometry setting. """ key = 'Geometry/Position' default_value = None setting_value = self.value(key) if isinstance(setting_value, QtCore.QByteArray): return setting_value else: return default_value def windowLayout(self): """ Returns the main window layout setting. This setting stores the position and size of toolbars and dockwidgets. """ key = 'Geometry/Layout' default_value = None setting_value = self.value(key) if isinstance(setting_value, QtCore.QByteArray): return setting_value else: return default_value def hsplitterPosition(self): """ Returns the horizontal splitter geometry setting. """ key = 'Geometry/HSplitter' default_value = None setting_value = self.value(key) if isinstance(setting_value, QtCore.QByteArray): return setting_value else: return default_value def startupLastSession(self): """ Returns the `Restore last session` setting. """ key = 'Startup/restoreLastSession' default_value = False # Warning! # If the application settings have not yet been saved # in the registry then self.value(key) returns a Null # QVariant (its type is None) and self.value(key, type=bool) # raises an exception because None cannot be converted # to a boolean value try: setting_value = self.value(key, type=bool) except TypeError: setting_value = default_value if setting_value in (False, True): return setting_value else: return default_value #TODO: remove this setting def startupWorkingDir(self): """ Returns the `Startup working directory` setting. """ key = 'Startup/startupWorkingDir' default_value = 'home' setting_value = self.value(key) if isinstance(setting_value, str): return setting_value else: return default_value def lastWorkingDir(self): """ Returns the `Last working directory` setting. """ key = 'Startup/lastWorkingDir' default_value = vitables.utils.getHomeDir() setting_value = self.value(key) if isinstance(setting_value, str): return setting_value else: return default_value def recentFiles(self): """ Returns the list of most recently opened files setting. """ key = 'Recent/Files' default_value = [] setting_value = self.value(key) if isinstance(setting_value, list): return setting_value else: return default_value def sessionFiles(self): """ Returns the list of files and nodes opened when the last session quit. """ key = 'Session/Files' default_value = [] setting_value = self.value(key) if isinstance(setting_value, list): return setting_value else: return default_value def helpHistory(self): """ Returns the navigation history of the docs browser. """ key = 'HelpBrowser/History' default_value = [] setting_value = self.value(key) if isinstance(setting_value, list): return setting_value else: return default_value def helpBookmarks(self): """ Returns the bookmarks of the docs browser. """ key = 'HelpBrowser/Bookmarks' default_value = [] setting_value = self.value(key) if isinstance(setting_value, list): return setting_value else: return default_value def enabledPlugins(self): """Returns the list of enabled plugins. """ key = 'Plugins/Enabled' default_value = [] setting_value = self.value(key) if isinstance(setting_value, list): return setting_value else: return default_value def writeValue(self, key, value): """ Write an entry to the configuration file. :Parameters: - `key`: the name of the property we want to set. - `value`: the value we want to assign to the property """ try: self.setValue(key, value) if self.status(): raise cfgexception.ConfigFileIOException( '{0}={1}'.format(key, value)) except cfgexception.ConfigFileIOException as inst: self.logger.error(inst.error_message) def readConfiguration(self): """ Get the application configuration currently stored on disk. Read the configuration from the stored settings. If a setting cannot be read (as it happens when the package is just installed) then its default value is returned. Geometry and Recent settings are returned as lists, color settings as QColor instances. The rest of settings are returned as strings or integers. :Returns: a dictionary with the configuration stored on disk """ config = {} config['Logger/Paper'] = self.loggerPaper() config['Logger/Text'] = self.loggerText() config['Logger/Font'] = self.loggerFont() config['Workspace/Background'] = self.workspaceBackground() config['Startup/restoreLastSession'] = self.startupLastSession() config['Startup/startupWorkingDir'] = self.startupWorkingDir() config['Startup/lastWorkingDir'] = self.lastWorkingDir() config['Geometry/Position'] = self.windowPosition() config['Geometry/Layout'] = self.windowLayout() config['Geometry/HSplitter'] = self.hsplitterPosition() config['Recent/Files'] = self.recentFiles() config['Session/Files'] = self.sessionFiles() config['HelpBrowser/History'] = self.helpHistory() config['HelpBrowser/Bookmarks'] = self.helpBookmarks() config['Look/currentStyle'] = self.readStyle() config['Plugins/Enabled'] = self.enabledPlugins() return config def saveConfiguration(self): """ Store current application settings on disk. Note that we are using ``QSettings`` for writing to the config file, so we **must** rely on its searching algorithms in order to find that file. """ vtgui = self.vtapp.gui # Logger paper style_sheet = vtgui.logger.styleSheet() paper = style_sheet[-7:] self.writeValue('Logger/Paper', QtGui.QColor(paper)) # Logger text color self.writeValue('Logger/Text', vtgui.logger.textColor()) # Logger text font self.writeValue('Logger/Font', vtgui.logger.font()) # Workspace self.writeValue('Workspace/Background', vtgui.workspace.background()) # Style self.writeValue('Look/currentStyle', self.current_style) # Startup working directory self.writeValue('Startup/startupWorkingDir', self.startup_working_directory) # Startup restore last session self.writeValue('Startup/restoreLastSession', self.restore_last_session) # Startup last working directory self.writeValue('Startup/lastWorkingDir', self.last_working_directory) # Window geometry self.writeValue('Geometry/Position', vtgui.saveGeometry()) # Window layout self.writeValue('Geometry/Layout', vtgui.saveState()) # Horizontal splitter geometry self.writeValue('Geometry/HSplitter', vtgui.hsplitter.saveState()) # The list of recent files self.writeValue('Recent/Files', self.recent_files) # The list of session files and nodes self.session_files_nodes = self.getSessionFilesNodes() self.writeValue('Session/Files', self.session_files_nodes) # The Help Browser history self.writeValue('HelpBrowser/History', self.hb_history) # The Help Browser bookmarks self.writeValue('HelpBrowser/Bookmarks', self.hb_bookmarks) # The list of enabled plugins self.writeValue('Plugins/Enabled', self.vtapp.plugins_mgr.enabled_plugins) self.sync() def getSessionFilesNodes(self): """ The list of files and nodes currently open. The list looks like:: ['mode#@#filepath1#@#nodepath1#@#nodepath2, ...', 'mode#@#filepath2#@#nodepath1#@#nodepath2, ...', ...] """ # Get the list of views workspace = self.vtapp.gui.workspace node_views = [window for window in workspace.subWindowList() \ if isinstance(window, datasheet.DataSheet)] # Get the list of open files (temporary database is not included) dbt_model = self.vtapp.gui.dbs_tree_model session_files_nodes = [] filepaths = dbt_model.getDBList() for path in filepaths: mode = dbt_model.getDBDoc(path).mode # If a new file has been created during the current session # then write mode must be replaced by append mode or the file # will be created from scratch in the next ViTables session if mode == 'w': mode = 'a' item_path = mode + '#@#' + path for view in node_views: if view.dbt_leaf.filepath == path: item_path = item_path + '#@#' + view.dbt_leaf.nodepath session_files_nodes.append(item_path) # Format the list in a handy way to store it on disk return session_files_nodes def loadConfiguration(self, config): """ Configure the application with the given settings. We call `user settings` to those settings that can be setup via Settings dialog and `internal settings` to the rest of settings. At startup all settings will be loaded. At any time later the `users settings` can be explicitly changed via Settings dialog. :Parameter config: a dictionary with the settings to be (re)loaded """ # Load the user settings self.userSettings(config) # Load the internal settings (if any) gui = self.vtapp.gui try: key = 'Geometry/Position' value = config[key] if isinstance(value, QtCore.QByteArray): # Default position is provided by the underlying window manager gui.restoreGeometry(value) key = 'Geometry/Layout' value = config[key] if isinstance(value, QtCore.QByteArray): # Default layout is provided by the underlying Qt installation gui.restoreState(value) key = 'Geometry/HSplitter' value = config[key] if isinstance(value, QtCore.QByteArray): # Default geometry provided by the underlying Qt installation gui.hsplitter.restoreState(value) key = 'Startup/lastWorkingDir' self.last_working_directory = config[key] key = 'Recent/Files' self.recent_files = config[key] key = 'Session/Files' self.session_files_nodes = config[key] key = 'HelpBrowser/History' self.hb_history = config[key] key = 'HelpBrowser/Bookmarks' self.hb_bookmarks = config[key] except KeyError: pass def userSettings(self, config): """Load settings that can be setup via Settings dialog. :Parameter config: a dictionary with the settings to be (re)loaded """ # Usually after calling the Settings dialog only some user # settings will need to be reloaded. So for every user setting # we have to check if it needs to be reloaded or not key = 'Startup/restoreLastSession' if key in config: self.restore_last_session = config[key] key = 'Startup/startupWorkingDir' if key in config: self.startup_working_directory = config[key] key = 'Logger/Paper' logger = self.vtapp.gui.logger if key in config: value = config[key] paper = value.name() stylesheet = logger.styleSheet() old_paper = stylesheet[-7:] new_stylesheet = stylesheet.replace(old_paper, paper) logger.setStyleSheet(new_stylesheet) key = 'Logger/Text' if key in config: logger.moveCursor(QtGui.QTextCursor.End) logger.setTextColor(config[key]) key = 'Logger/Font' if key in config: logger.setFont(config[key]) key = 'Workspace/Background' workspace = self.vtapp.gui.workspace if key in config: workspace.setBackground(config[key]) workspace.viewport().update() key = 'Look/currentStyle' if key in config: self.current_style = config[key] # Default style is provided by the underlying window manager QtWidgets.qApp.setStyle(self.current_style) key = 'Plugins/Enabled' if key in config: self.enabled_plugins = config[key] ViTables-3.0.0/vitables/queries/000077500000000000000000000000001311223072700165075ustar00rootroot00000000000000ViTables-3.0.0/vitables/queries/__init__.py000066400000000000000000000016351311223072700206250ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["query", "querydlg", "querymgr"] ViTables-3.0.0/vitables/queries/query.py000066400000000000000000000177271311223072700202440ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module executes `tables.Table` queries at low level. It collects information from the `New Query` dialog, processes it and then executes the query. """ __docformat__ = 'restructuredtext' import tables import numpy from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils translate = QtWidgets.QApplication.translate class Query(QtCore.QObject): """Class implementing a tables.Table query. Ideally queries SHOULD be sequentially executed in a secondary thread for keeping the GUI responsive (i.e. not frozen) while a query (a potentially long-running operation) is taking place. Unfortunately this goal has proven difficult to achieve because `PyTables` is not thread-safe. So one more task to the TO DO list :-) The query is implemented in a clever way that doesn't interfer with the lazy population of the tree of databases view: the query results table is stored under a hidden group of the temporary database until the query finishes. Then it is moved to the root node and becomes visible to the world. This way, while the query results table is partially filled it is not seen by the lazy population algorithm so it is not added to the tree of databases view and neither the user nor ViTables will try to read it. So no problems can occur trying to read a partially filled table. :Parameters: - `table_uid`: UID of the tables.Table instance being queried - `table`: the table being queried - `qdescr`: dictionary description of the query """ query_completed = QtCore.Signal(bool, str, name="queryCompleted") def __init__(self, tmp_h5file, table_uid, table, qdescr): """Initialises the query.""" super(Query, self).__init__() self.completed = False self.tmp_h5file = tmp_h5file self.table_uid = table_uid self.table = table self.qdescr = qdescr def run(self): """ Query a table and add a the result to the temporary database. """ self.queryTable() self.query_completed.emit(self.completed, self.table_uid) def flushTable(self, ftable): """Flush the filtered table and setup some user attributes. :Parameters: - `ftable`: the filtered table being flushed """ ftable.flush() # Set some user attributes that define this filtered table asi = ftable.attrs asi.query_path = self.qdescr['src_filepath'] asi.query_table = self.qdescr['src_path'] asi.query_condition = self.qdescr['title'] def queryWithIndex(self, src_dict): """Do the query (`PyTables` level). """ # The query range is made of numpy scalars with dtype int64 (start, stop, step) = self.qdescr['rows_range'] chunk_size = 10000 div = int((stop - start) // chunk_size) # Create the destination table: its first column will contain # the indices of the rows selected in the source table so a new # description dictionary is needed. Int64 values are necessary # to keep full 64-bit indices ft_dict = {self.qdescr['indices_field_name']: tables.Int64Col(pos=-1)} ft_dict.update(src_dict) f_table = self.tmp_h5file.create_table( '/_p_query_results', self.qdescr['ft_name'], ft_dict, self.qdescr['title']) # Get the array of rows that fulfill the condition # Selection is done in several steps. It saves a *huge* # amount of memory when querying large tables for i in numpy.arange(0, div+1): QtWidgets.qApp.processEvents() lstart = start + chunk_size*i if lstart > stop: lstart = stop lstop = lstart + chunk_size if lstop > stop: lstop = stop coordinates = self.table.get_where_list( self.qdescr['condition'], self.qdescr['condvars'], start=lstart, stop=lstop, step=step) selection = self.table.read_coordinates(coordinates) if selection.shape == (0, ): continue coord_dtype = numpy.dtype( [(str(self.qdescr['indices_field_name']), ' stop: lstart = stop lstop = lstart + chunk_size if lstop > stop: lstop = stop selection = self.table.read_where( self.qdescr['condition'], self.qdescr['condvars'], start=lstart, stop=lstop, step=step) f_table.append(selection) self.flushTable(f_table) # Move the intermediate table to its final destination self.tmp_h5file.move_node( '/_p_query_results/' + self.qdescr['ft_name'], '/', newname=self.qdescr['ft_name'], overwrite=True) self.completed = True def queryTable(self): """Do the query (`PyTables` level). """ try: src_dict = self.table.description._v_colobjects # Add an `indexes` column to the result table if self.qdescr['indices_field_name']: self.queryWithIndex(src_dict) # Do no add an `indexes` column to the result table else: self.queryWithNoIndex(src_dict) except KeyError: vitables.utils.formatExceptionInfo() self.tmp_h5file.remove_node( '/_p_query_results/' + self.qdescr['ft_name']) else: self.tmp_h5file.flush() ViTables-3.0.0/vitables/queries/query_dlg.ui000066400000000000000000000276561311223072700210610ustar00rootroot00000000000000 QueryDialog Qt::WindowModal 0 0 435 545 Dialog 6 11 0 0 Global options 6 11 6 11 Name: <qt> The name of the table where the query results will be added. </qt> 6 11 Original indices into column: <qt> The name of the column where the indices of the selected rows will be added. </qt> Orig_idx Query condition 6 11 <qt> <h3>Conditions syntax</h3> A condition on a table is just a <em>string</em> containing a Python expression that involves <em>at least one column</em> , and maybe some constants and external variables, all combined with algebraic operators or functions. Beware that <tt>&</tt>, <tt>|</tt> and <tt>~</tt> operators are used for logical comparisons. They have higher precedence than logical operators so we recommend to <em>always use parenthesis around logical operators</em>.</p> <p>The following table shows some examples of conditions and their equivalent Python expressions.</p> <div align='center'><table border='1'> <tr><th>Condition</th><th>Python expression</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>You can find detailed information about conditions in the Appendix B of the PyTables users guide.</p> </qt> 6 11 Qt::Horizontal 40 20 <qt> The names of the searchable columns. They must fulfill the following requirements: <ul><li>must be not nested</li> <li>must have a scalar data type</li> <li>their data type cannot be <code>complex</code></li></ul> Columns whose names contains blanks are automatically mapped to variables whose names contain no blanks. For querying those columns the mapped variables will be used. </qt> <qt> The operators that can be used in a given condition. Operators can be logical, comparison and arithmetic.<br>Not all operators are available for every data type. </qt> <qt> The set of functions that can appear in a condition. It includes functions for doing selections, trigonometric functions and functions on complex numbers. For ease of use, arguments are automatically included when a function is inserted. The arguments meaning is: <ul><li>N: number</li><li>B: boolean</li> <li>F: float</li><li>C: complex</li></ul> </qt> Qt::Horizontal 40 20 The range of rows included in the query. Range of rows 11 6 Start: 1 Stop: Qt::Horizontal 40 20 Step: 1 QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok true buttonBox rejected() QueryDialog reject() 217 517 217 272 ViTables-3.0.0/vitables/queries/querydlg.py000066400000000000000000000365651311223072700207340ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a dialog for querying (filtering) `tables.Table` nodes. The result of the query is stored in other `tables.Table` node, referred as a filtered table, which will live in the temporary database (labeled as `Query results` in the databases tree). """ __docformat__ = 'restructuredtext' import os.path import logging import numpy from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_QueryDialog = \ loadUiType(os.path.join(os.path.dirname(__file__), 'query_dlg.ui'))[0] class QueryDlg(QtWidgets.QDialog, Ui_QueryDialog): """ A dialog for filtering `tables.Table` nodes. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) The dialog layout looks like this:: root label + textbox checkbox + label + textbox text box combobox + combobox + combobox label + textbox label + textbox label + textbox Ok + Cancel A text box is used to enter the condition to be applied. Combos are used to enter operators, functions and field names. Textboxes are used to enter the range of the query. :Parameters: - `info`: a dictionary with information about the table being queried - `ft_names`: the list of filtered tables names currently in use - `counter`: a counter used to give a unique ID to the query - `initial_query`: the dialog will be setup with this query (if any) - `table`: the table being queried """ def __init__(self, info, ft_names, counter, initial_query, table): """ Initialise the dialog. """ self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # # Attributes used by slot updateOKState # self.used_names = ft_names self.col_names = info['col_names'] self.condvars = info['condvars'] self.source_table = table self.num_rows = info['nrows'] # # Attributes used by slot composeQuery # # If the dialog is cancelled these initial values will be returned to # the caller. If the dialog is accepted then these values will be # updated (in the slotAccept method) and returned to the caller self.query_info = {} self.query_info['condition'] = '' self.query_info['rows_range'] = () self.query_info['ft_name'] = '' self.query_info['indices_field_name'] = '' self.query_info['condvars'] = self.condvars self.query_info['src_filepath'] = info['src_filepath'] self.query_info['src_path'] = info['src_path'] # # Create the dialog and customise the content of some widgets # super(QueryDlg, self).__init__(QtWidgets.qApp.activeWindow()) self.setupUi(self) self.setWindowTitle(translate('QueryDlg', 'New query on table: {0}', 'A dialog caption').format(info['name'])) self.nameLE.setText('FilteredTable_{0}'.format(counter)) self.indicesColumnLE.setEnabled(0) # Use the values of the last query done on this table (if any) if initial_query != '': self.queryLE.setText(initial_query) # Fill the combos operators = ['&', '|', '~', '<', '<=', '==', '!=', '>', '>=', '+', '-', '*', '/', '**', '%'] self.operatorsComboBox.insertItems(0, operators) functions = ['where', 'sin', 'cos', 'tan', 'arcsin', 'arccos', 'arctan', 'arctan2', 'sinh', 'cosh', 'tanh', 'arcsinh', 'arccosh', 'arctanh', 'log', 'log10', 'log1p', 'exp', 'expm1', 'sqrt', 'real', 'imag', 'complex'] self.functionsComboBox.insertItems(0, functions) sorted_fields = [field for field in info['valid_fields']] sorted_fields.sort() self.columnsComboBox.insertItems(0, sorted_fields) self.rstartLE.setText('0') self.rstopLE.setText('{0}'.format(info['nrows'])) whatsthis_button = self.buttonBox.button(QtWidgets.QDialogButtonBox.Help) whatsthis_button.setText("&What's this") # # Setup a validator for Range selectors section # validator = QtGui.QRegExpValidator(QtCore.QRegExp("\\d*"), self) self.rstartLE.setValidator(validator) self.rstopLE.setValidator(validator) self.rstep.setValidator(validator) # # Connect signals to slots # self.buttonBox.helpRequested.connect( QtWidgets.QWhatsThis.enterWhatsThisMode) # Ensure that if the condition line edit is initialised with an # initial condition then the OK button will be enabled self.nameLE.textChanged.emit(self.nameLE.text()) @QtCore.Slot(bool, name="on_indicesCheckBox_toggled") def enableIndicesColumn(self, cb_on): """ Enable/disable the indices column name field. If the checkbox in the global options groupbox is checked then a column with the indices of the filtered rows will be added to the table produced by the filtering process. Moreover the user can set the name of this column. :Parameter cb_on: a boolean that indicates if the checkbox is down or not. """ if cb_on: self.indicesColumnLE.setEnabled(1) else: self.indicesColumnLE.setEnabled(0) @QtCore.Slot("QString", name="on_operatorsComboBox_activated") def insertOperator(self, operator): """ Insert an operator in the query line editor. :Parameter operator: is the operator in the combobox current item """ self.queryLE.insert(' {0} '.format(operator)) @QtCore.Slot("QString", name="on_columnsComboBox_activated") def insertField(self, field_id): """ Insert a fieldname in the query line editor. When the fields combobox is activated the selected field_id is inserted in the query line editor. Fields whose names contain blanks have a field id with the format 'condvar (fieldname)'. In this case only the condvar name will be inserted in the query line editor. :Parameter field_id: is the field identifier in the combobox current item """ self.queryLE.insert(field_id.split(' ')[0]) @QtCore.Slot("QString", name="on_functionsComboBox_activated") def insertFunction(self, text): """ Insert a function in the query line editor. When the functions combobox is activated the selected value is inserted in the query line editor. :Parameter text: is the text of the combobox current item """ name2call = {'where': 'where(B, N, N)', 'sin': 'sin(F|C)', 'cos': 'cos(F|C)', 'tan': 'tan(F|C)', 'arcsin': 'arcsin(F|C)', 'arccos': 'arccos(F|C)', 'arctan': 'arctan(F|C)', 'arctan2': 'arctan2(F, F)', 'sinh': 'sinh(F|C)', 'cosh': 'cosh(F|C)', 'tanh': 'tanh(F|C)', 'arcsinh': 'arcsinh(F|C)', 'arccosh': 'arccosh(F|C)', 'arctanh': 'arctanh(F|C)', 'log': 'log(F|C)', 'log10': 'log10(F|C)', 'log1p': 'log1p(F|C)', 'exp': 'exp(F|C)', 'expm1': 'expm1(F|C)', 'sqrt': 'sqrt(F|C)', 'real': 'real(C)', 'imag': 'imag(C)', 'complex': 'complex(F, F)'} self.queryLE.insert(name2call[text]) @QtCore.Slot("QString", name="on_nameLE_textChanged") @QtCore.Slot("QString", name="on_indicesColumnLE_textChanged") @QtCore.Slot("QString", name="on_queryLE_textChanged") @QtCore.Slot("QString", name="on_rstartLE_textChanged") @QtCore.Slot("QString", name="on_rstopLE_textChanged") def updateOKState(self): """ Update the activation state of the `OK` button. Every time that the table name text box changes the new content is checked. If it is empty, then the `OK` button is disabled. If the indices checkbox is checked, every time that the indices column name text box changes the new content is checked. If it is empty, then the `OK` button is disabled. Every time that the lower/upper limit text box change the new content is checked. If the new values don't make a legal condition, then the `OK` button is disabled. Every time the column name combobox changes the datatype of limit values is checked. If there is a mismatch, then the `OK` button is disabled. Every time that the spinboxes content change the new content is checked. If the combination of the start/stop/step boxes makes a not legal selection range, then the `OK` button is disabled. """ status_ok = True # Check the table name ft_name = self.nameLE.text() if not ft_name: status_ok = False elif ft_name in self.used_names: status_ok = False self.logger.error( translate('QueryDlg', """The chosen name is already in use. Please,""" """ choose another one.""", 'A logger info message')) # Check the indices column name indices_colname = self.indicesColumnLE.text() if self.indicesColumnLE.isEnabled(): if indices_colname == '': status_ok = False self.logger.error( translate('QueryDlg', "Enter a name for the column of indices, please", 'A logger info message')) elif indices_colname.count('/'): status_ok = False self.logger.error( translate('QueryDlg', """The chosen name for the column of indices""" """is not valid. It contains '/' characters""", 'A logger info message')) elif indices_colname in self.col_names: status_ok = False self.logger.error( translate('QueryDlg', """The chosen name for the column of indices""" """ is already in use. """ """"Please, choose another one.""", 'A logger info message')) # Check the condition. # If it is an empty string the OK button is not enabled condition = self.queryLE.text() if condition.isspace() or (condition in [None, '']): status_ok = False # Check the range values start_str = self.rstartLE.text() stop_str = self.rstopLE.text() if not (start_str and stop_str): status_ok = False else: start = numpy.array(start_str).astype(numpy.int64) stop = numpy.array(stop_str).astype(numpy.int64) if stop > self.num_rows: status_ok = False self.logger.error( translate('QueryDlg', """The stop value cannot be greater than """ """the number of rows.""", 'A logger info message')) elif start > stop: status_ok = False self.logger.error( translate('QueryDlg', """The start value cannot be greater than the """ """stop value.""", 'A logger info message')) # Enable/disable the OK button ok_button = self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok) if status_ok: ok_button.setEnabled(1) else: ok_button.setEnabled(0) def checkConditionSyntax(self, condition): """Check the condition syntax. :Parameter condition: the query condition used for filtering the table """ syntax_ok = True try: self.source_table.will_query_use_indexing(condition, self.condvars) except SyntaxError as error: syntax_ok = False self.logger.error(error.__doc__) vitables.utils.formatExceptionInfo() except NameError as error: syntax_ok = False self.logger.error(error.__doc__) vitables.utils.formatExceptionInfo() except ValueError as error: syntax_ok = False self.logger.error(error.__doc__) vitables.utils.formatExceptionInfo() except TypeError as error: syntax_ok = False self.logger.error(error.__doc__) vitables.utils.formatExceptionInfo() except: syntax_ok = False vitables.utils.formatExceptionInfo() return syntax_ok @QtCore.Slot(name="on_buttonBox_accepted") def composeQuery(self): """Slot for composing the query and accept the dialog.""" # Get the query condition = self.queryLE.text() # Blanks at the begining of condition raise a SyntaxError condition = condition.strip() if not self.checkConditionSyntax(condition): return self.query_info['condition'] = condition # Get the table name and the name of the column with indices (if any) self.query_info['ft_name'] = self.nameLE.text() if self.indicesColumnLE.isEnabled(): self.query_info['indices_field_name'] = \ self.indicesColumnLE.text() # Get the range and convert it into a Python range self.query_info['rows_range'] = ( numpy.array(self.rstartLE.text()).astype(numpy.int64), numpy.array(self.rstopLE.text()).astype(numpy.int64), numpy.array(self.rstep.text()).astype(numpy.int64)) # Exit self.accept() ViTables-3.0.0/vitables/queries/querymgr.py000066400000000000000000000304731311223072700207430ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module implements a controller for managing the queries. The manager tracks the existing filtered tables and their names, launches the Query dialog and executes the queries at low level (i.e. `PyTables` level). It also keeps a description of the last executed query and tracks the tables currently being queried, in order to ensure that no more than 1 query at a time is executed on a given table. """ __docformat__ = 'restructuredtext' import logging from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils import vitables.queries.querydlg as querydlg import vitables.queries.query as query translate = QtWidgets.QApplication.translate def getTableInfo(table): """Retrieves table info required for querying it. :Parameter table: the `tables.Table` instance being queried. """ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) info = {} info['nrows'] = table.nrows info['src_filepath'] = table._v_file.filename info['src_path'] = table._v_pathname info['name'] = table._v_name # Fields info: top level fields names, flat fields shapes and types info['col_names'] = frozenset(table.colnames) info['col_shapes'] = \ dict((k, v.shape) for (k, v) in table.coldescrs.items()) info['col_types'] = table.coltypes # Fields that can be queried info['condvars'] = {} info['valid_fields'] = [] if info['nrows'] <= 0: logger.info( translate('QueriesManager', "Table {0} is empty. Nothing to query.", 'Info message for users').format(info['name'])) return None # Find out the valid (i.e. searchable) fields and condition variables. # First discard nested fields. # Beware that order matters in binary operations that mix set instances # with frozensets: set & frozenset returns a set but frozenset & set # returns a frozenset valid_fields = set(info['col_shapes'].keys()).intersection( info['col_names']) # info['col_names'].intersection(info['col_shapes'].keys()) # Then discard fields that aren't scalar and those that are complex for name in valid_fields.copy(): if (info['col_shapes'][name] != ()) or \ info['col_types'][name].count('complex'): valid_fields.remove(name) # Among the remaining fields, those whose names contain blanks # cannot be used in conditions unless they are mapped to # variables with valid names index = 0 for name in valid_fields.copy(): if name.count(' '): while ('col{0}'.format(index)) in valid_fields: index = index + 1 info['condvars']['col{0}'.format(index)] = \ table.cols._f_col(name) valid_fields.remove(name) valid_fields.add('col{0} ({1})'.format(index, name)) index = index + 1 info['valid_fields'] = valid_fields # If table has not columns suitable to be filtered does nothing if not info['valid_fields']: logger.info( translate('QueriesManager', """Table {0} has no columns suitable to be """ """queried. All columns are nested, multidimensional """ """or have a Complex data type.""", 'Info when trying to query a table').format( info['name'])) return None elif len(info['valid_fields']) != len(info['col_names']): # Log a message if non selectable fields exist logger.warning( translate('QueriesManager', """Some table columns contain multidimensional, """ """nested or Complex data. They cannot be queried so """ """are not included in the Column selector of the """ """query dialog.""", 'An informational note for users')) return info class QueriesManager(QtCore.QObject): """This is the class in charge of the execution of queries. `PyTables` doesn't support threaded queries. So when several queries are requested to ``ViTables`` they will be executed sequentially. Also no more than one query can be made at the same time on a given table. This goal is achieved in a very simple way: tracking the tables currently being queried in a data structure (a dictionary at present). :Parameter parent: the parent of the `QueriesManager` object """ def __init__(self, parent=None): """Setup the queries manager. The last query description has three components: the filepath of the file where the queried table lives, the nodepath of the queried table and the query condition. A query name is the name of the table where the query results are stored. By default it has the format "Filtered_TableUID" where UID is an integer automatically generated. User can customise the query name in the New Query dialog. """ super(QueriesManager, self).__init__(parent) self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # Description of the last query made self.last_query = [None, None, None] # UID for automatically generating query names self.counter = 0 # The list of query names currently in use self.ft_names = [] self.vtapp = vitables.utils.getVTApp() self.vtgui = self.vtapp.gui self.dbt_view = self.vtgui.dbs_tree_view self.dbt_model = self.vtgui.dbs_tree_model def newQuery(self): """Process the query requests launched by users. """ # The VTApp.updateQueryActions method ensures that the current node is # tied to a tables.Table instance so we can query it without # further checking current = self.dbt_view.currentIndex() node = self.dbt_model.nodeFromIndex(current) table_uid = node.as_record table = node.node table_info = getTableInfo(table) if table_info is None: return # Update the suggested name sufix self.counter = self.counter + 1 query_description = self.getQueryInfo(table_info, table) if query_description is None: self.counter = self.counter - 1 return # Update the list of names in use for filtered tables self.ft_names.append(query_description['ft_name']) self.last_query = [query_description['src_filepath'], query_description['src_path'], query_description['condition']] # Run the query tmp_h5file = self.dbt_model.tmp_dbdoc.h5file new_query = query.Query(tmp_h5file, table_uid, table, query_description) new_query.query_completed.connect(self.addQueryResult) QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) new_query.run() def getQueryInfo(self, info, table): """Retrieves useful info about the query. :Parameters: - `info`: dictionary with info about the queried table - `table`: the tables.Table instance being queried """ # Information about table # Setup the initial condition last_query = self.last_query if (last_query[0], last_query[1]) == (info['src_filepath'], info['src_path']): initial_condition = last_query[2] else: initial_condition = '' # GET THE QUERY COMPONENTS # Get a complete query description from user input: condition to # be applied, involved range of rows, name of the # filtered table and name of the column of returned indices query_dlg = querydlg.QueryDlg(info, self.ft_names, self.counter, initial_condition, table) try: query_dlg.exec_() finally: query_description = dict(query_dlg.query_info) del query_dlg QtWidgets.qApp.processEvents() if not query_description['condition']: return None # SET THE TITLE OF THE RESULT TABLE title = query_description['condition'] for name in info['valid_fields']: # Valid fields can have the format 'fieldname' or # 'varname (name with blanks)' so a single blank shouldn't # be used as separator components = name.split(' (') if len(components) > 1: fieldname = '({0}'.format(components[-1]) title = title.replace(components[0], fieldname) query_description['title'] = title return query_description def deleteAllQueries(self): """ Delete all nodes under the `Query results` node of the databases tree. """ title = translate('QueriesManager', 'Cleaning the Query results file', 'Caption of the QueryDeleteAll dialog') text = translate('QueriesManager', ('\n\nYou are about to delete all ' 'nodes under Query results\n\n'), 'Ask for confirmation') itext = '' dtext = '' buttons = { 'Delete': (translate('QueriesManager', 'Delete', 'Button text'), QtWidgets.QMessageBox.YesRole), 'Cancel': (translate('QueriesManager', 'Cancel', 'Button text'), QtWidgets.QMessageBox.NoRole)} # Ask for confirmation answer = vitables.utils.questionBox(title, text, itext, dtext, buttons) if answer == 'Cancel': return # Remove every filtered table from the tree of databases model/view model_rows = self.dbt_model.rowCount(QtCore.QModelIndex()) tmp_index = self.dbt_model.index(model_rows - 1, 0, QtCore.QModelIndex()) rows_range = list( range(0, self.dbt_model.rowCount(tmp_index)).__reversed__()) for row in rows_range: index = self.dbt_model.index(row, 0, tmp_index) self.vtapp.nodeDelete(index, force=True) # Reset the queries manager self.counter = 0 self.ft_names = [] def addQueryResult(self, completed, table_uid): """Update the GUI once the query has finished. Add the result of the query to the tree of databases view and open the new filtered table. :Parameters: - `completed`: whether the query has been succesful or not - `table_uid`: the UID of the table just queried """ QtWidgets.qApp.restoreOverrideCursor() if not completed: self.logger.error(translate('QueriesManager', 'Query on table {0} failed!', 'Warning log message about a failed ' 'query').format(table_uid)) return # Update temporary database view i.e. call lazyAddChildren model_rows = self.dbt_model.rowCount(QtCore.QModelIndex()) tmp_index = self.dbt_model.index(model_rows - 1, 0, QtCore.QModelIndex()) self.dbt_model.lazyAddChildren(tmp_index) # The new filtered table is inserted in first position under # the Query results node and opened index = self.dbt_model.index(0, 0, tmp_index) self.vtapp.nodeOpen(index) ViTables-3.0.0/vitables/start.py000077500000000000000000000147661311223072700165620ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """This is the launcher script for the ViTables application.""" __docformat__ = 'restructuredtext' import sys import locale import argparse import os.path import logging import traceback import sip sip.setapi('QString', 2) sip.setapi('QVariant', 2) from qtpy import QtGui import qtpy.QtCore as qtcore from qtpy import QtWidgets from vitables.vtapp import VTApp from vitables.preferences import vtconfig # Map number of -v's on command line to logging error level. _VERBOSITY_LOGLEVEL_DICT = {0: logging.ERROR, 1: logging.WARNING, 2: logging.INFO, 3: logging.DEBUG} # Default log format used by logger. _FILE_LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' # Folder with vitables translations. _I18N_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'i18n') _uncaught_exception_logger = logging.getLogger('vitables') def _uncaught_exception_hook(type_, value, tb): _uncaught_exception_logger.error(''.join(traceback.format_tb(tb)) + str(value)) sys.__excepthook__(type_, value, tb) sys.excepthook = _uncaught_exception_hook def _check_versions(): """Check that tables are at least version 3.0""" import tables if tables.__version__ < '3.0': sys.exit('FATAL: PyTables version 3.0 or above is required, ' 'installed version is {}'.format(tables.__version__)) def _set_credentials(app): """Specify the organization's Internet domain. When the Internet domain is set, it is used on Mac OS X instead of the organization name, since Mac OS X applications conventionally use Internet domains to identify themselves """ app.setOrganizationDomain('vitables.org') app.setOrganizationName('ViTables') app.setApplicationName('ViTables') app.setApplicationVersion(vtconfig.getVersion()) def _set_locale(app): """Set locale and load translation if available. Localize the application using the system locale numpy seems to have problems with decimal separator in some locales (catalan, german...) so C locale is always used for numbers. """ locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_NUMERIC, 'C') locale_name = qtcore.QLocale.system().name() translator = qtcore.QTranslator() if translator.load('vitables_' + locale_name, _I18N_PATH): app.installTranslator(translator) return translator def _parse_command_line(): """Create parser and parse command line.""" # Parse the command line optional arguments parser = argparse.ArgumentParser(usage='%(prog)s [option]... [h5file]...') h5files_group = parser.add_argument_group('h5files') logging_group = parser.add_argument_group('logging') # Options for the default group parser.add_argument( '--version', action='version', version='%(prog)s {}'.format(vtconfig.getVersion())) # Options for opening files h5files_group.add_argument( '-m', '--mode', choices=['r', 'a'], metavar='MODE', help='mode access for a database. Can be r(ead) or a(ppend)') h5files_group.add_argument('-d', '--dblist', help=('a file with the list of HDF5 ' 'filepaths to be open')) # Logging options logging_group.add_argument('-l', '--log-file', help='log file path') logging_group.add_argument('-v', '--verbose', action='count', default=0, help='log verbosity level') # Allow an optional list of input filepaths parser.add_argument('h5file', nargs='*') # Set sensible option defaults parser.set_defaults(mode='a', dblist='', h5file=[]) # parse and process arguments args = parser.parse_args() if args.dblist: # Other options and positional arguments are silently ignored args.mode = '' args.h5file = [] return args def _setup_logger(args): """Setup logger output format, level and output file. Stderr logger is added to handle error that raise before the gui is launched. It better be removed before event loop starts. """ logger = logging.getLogger() file_formatter = logging.Formatter(_FILE_LOG_FORMAT) temporary_stderr_handler = logging.StreamHandler() temporary_stderr_handler.setFormatter(file_formatter) logger.addHandler(temporary_stderr_handler) if args.log_file is not None: try: log_filename = os.path.expandvars( os.path.expanduser(args.log_file)) file_handler = logging.FileHandler(log_filename) file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) except Exception as e: logger.error('Failed to open log file') logger.error(e) if args.verbose in _VERBOSITY_LOGLEVEL_DICT: logger.setLevel(_VERBOSITY_LOGLEVEL_DICT[args.verbose]) else: logger.setLevel(logging.ERROR) logger.error('Invalid verbosity level: {}, error level ' 'set to ERROR'.format(args.verbose)) return logger, temporary_stderr_handler def gui(): """The application launcher. First of all, translators are loaded. Then the GUI is shown and the events loop is started. """ _check_versions() app = QtWidgets.QApplication(sys.argv) _set_credentials(app) translator = _set_locale(app) # must not be destroyed before app quits args = _parse_command_line() logger, console_log_handler = _setup_logger(args) vtapp = VTApp(mode=args.mode, dblist=args.dblist, h5files=args.h5file) vtapp.gui.show() logger.removeHandler(console_log_handler) app.exec_() if __name__ == '__main__': gui() ViTables-3.0.0/vitables/test/000077500000000000000000000000001311223072700160115ustar00rootroot00000000000000ViTables-3.0.0/vitables/test/test_samples.py000066400000000000000000000165131311223072700210740ustar00rootroot00000000000000import sys import os.path import nose.tools as nt import sip sip.setapi('QString', 2) sip.setapi('QVariant', 2) from qtpy import QtWidgets from qtpy import QtCore import qtpy.QtTest as qtest import vitables.start as vtstart from vitables.vtapp import VTApp from vitables.preferences import vtconfig TABLES_PATH = os.path.join('examples', 'tables') def get_index(model, node_name, start_index=None): """Return index of the node with the given name or None.""" start_index = start_index if start_index else QtCore.QModelIndex() for c in range(model.columnCount(start_index)): for r in range(model.rowCount(start_index)): index = model.index(r, c, start_index) if index.data(QtCore.Qt.DisplayRole) == node_name: return index child_search_result = get_index(model, node_name, index) if child_search_result: return child_search_result return None def assert_path(test, path): """Activate and check that node at given path exist. If the last node is a leaf then subwindow will be created. """ if not path: return index = get_index(test.model, path[0]) nt.assert_false(index is None) test.view.activateNode(index) assert_path(test, path[1:]) def get_leaf_model_with_assert(test, filepath, leaf_path): """Open view for given leaf and return its model. filepath is a valid system path, node_path is a slash separated leaf path inside file without preceding slash. """ leaf_path = leaf_path.split('/') _, filename = os.path.split(filepath) test.vtapp.fileOpen(filepath) assert_path(test, [filename] + leaf_path) return test.vtgui.workspace.subWindowList()[0].leaf_model class TestTableOpening: """Open files and read all cell values.""" TEST_NODES = { 'examples/arrays/array_samples.h5': [ 'array_b', 'array_f', 'array_f3D', 'array_int16', 'array_int8', 'group1/array_B', 'group2/array_h', 'group3/array_l', 'group4/array_f', 'group5/array_d', 'scalar_array', ], 'examples/arrays/carray_sample.h5': [ 'carray', ], 'examples/arrays/earray_samples.h5': [ 'array_b', 'array_c', 'array_char', 'array_e', ], 'examples/arrays/vlarray_samples.h5': [ 'vlarray1', 'vlarray11', 'vlarray2', 'vlarray3', 'vlarray5', 'vlarray6', 'vlarray8', 'vlarray10', 'vlarray9', # 'vlarray7', ], 'examples/misc/external_file.h5': [ 'a1', ], # modified on open !!! # 'examples/misc/fnode.h5': [ # 'fnode_test', # ], # modified on open !!! # 'examples/misc/genericHDF5.h5': [ # 'A note', 'arrays/2D float array', 'arrays/2D int array', # 'arrays/3D int array', # 'arrays/Vdata table: PerBlockMetadataCommon', # 'arrays/external', # # 'images/iceberg_palette', # # 'images/Iceberg', # # 'images/landcover.umd.199906.jpg', # # 'images/pixel interlace', # # 'images/plane interlace', # ], 'examples/misc/links_examples.h5': [ 'arrays/a1', 'links/ht1', 'tables/t1', ], # modified on open !!! # 'examples/misc/nonalphanum.h5': [ # 'array_1', 'array_f', 'array_f_Numeric', 'array_s', # ], 'examples/misc/objecttree.h5': [ 'array1', 'group1/array2', 'group1/table1', 'group2/table2', ], 'examples/misc/szip_compressor.h5': [ # 'datasetF32', ], 'examples/tables/nested_samples.h5': [ 'table', ], 'examples/tables/table_samples.h5': [ 'columns/TDC', 'columns/name', 'columns/pressure', 'detector/recarray', 'detector/recarray2', 'detector/table', 'newgroup/table', 'table1', ], 'examples/timeseries/carray_ts.h5': [ 'test_carray_1', 'test_carray_2', ], 'examples/timeseries/pandas_test1.hdf5': [ # 'one_column_ts/_i_table/index/abounds', # 'one_column_ts/_i_table/index/bounds', # 'one_column_ts/_i_table/index/indices', # 'one_column_ts/_i_table/index/indicesLR', # 'one_column_ts/_i_table/index/mbounds', # 'one_column_ts/_i_table/index/mranges', # 'one_column_ts/_i_table/index/ranges', # 'one_column_ts/_i_table/index/sorted', # 'one_column_ts/_i_table/index/sortedLR', # 'one_column_ts/_i_table/index/zbounds', # 'one_column_ts/table', ], 'examples/timeseries/pandas_test2.hdf5': [ # 'intc/_i_table/index/abounds', 'intc/_i_table/index/bounds', # 'intc/_i_table/index/indices', 'intc/_i_table/index/indicesLR', # 'intc/_i_table/index/mbounds', 'intc/_i_table/index/mranges', # 'intc/_i_table/index/ranges', 'intc/_i_table/index/sorted', # 'intc/_i_table/index/sortedLR', 'intc/_i_table/index/zbounds', # 'intc/table', ], 'examples/timeseries/pandas_test3.hdf5': [ # 'df/axis0', 'df/axis1', 'df/block0_items', 'df/block0_values', # 'df_table/_i_table/index/abounds', # 'df_table/_i_table/index/bounds', # 'df_table/_i_table/index/indices', # 'df_table/_i_table/index/indicesLR', # 'df_table/_i_table/index/mbounds', # 'df_table/_i_table/index/mranges', # 'df_table/_i_table/index/ranges', # 'df_table/_i_table/index/sorted', # 'df_table/_i_table/index/sortedLR', # 'df_table/_i_table/index/zbounds', 'df_table/table', ], # modified on open !!! # 'examples/timeseries/scikits_test1.hdf5': [ # 'examples/Example_1', # ], # modified on open !!! # 'examples/timeseries/scikits_test2.hdf5': [ # 'examples/Example_2', # ], # modified on open !!! # 'examples/timeseries/scikits_test3.hdf5': [ # 'examples/Example_3', # ], 'examples/timeseries/table_ts.h5': [ 'Particles/TParticle', ], } @classmethod def setup_class(cls): """Create app and store shortcuts to the application objects.""" cls.app = QtWidgets.QApplication(sys.argv) cls.vtapp = VTApp(keep_splash=False) cls.vtgui = cls.vtapp.gui cls.model = cls.vtgui.dbs_tree_model cls.view = cls.vtgui.dbs_tree_view def test_opening_files(self): """Generate tests for given data files.""" for filepath, nodes in self.TEST_NODES.items(): for node in nodes: yield self.check_node_open, filepath, node def check_node_open(self, filepath, nodepath): """Open file get access to a node and read all cells.""" try: leaf_model = get_leaf_model_with_assert(self, filepath, nodepath) for row in range(leaf_model.rowCount()): for column in range(leaf_model.columnCount()): cell_index = leaf_model.index(row, column, QtCore.QModelIndex()) cell_data = leaf_model.data(cell_index) finally: self.vtapp.fileClose() ViTables-3.0.0/vitables/utils.py000066400000000000000000000470161311223072700165540ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org from qtpy.QtWidgets import QFileDialog """ This is the utilities module. It contains functions that perform tasks that are required at several parts of the application. """ __docformat__ = 'restructuredtext' import sys import os import traceback import locale import re import logging import collections import functools import numpy from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.vtwidgets.renamedlg as renamedlg from vitables.vtsite import ICONDIR, DOCDIR ICONS_DICT = {} HB_ICONS_DICT = {} DEFAULT_ENCODING = locale.getdefaultlocale()[1] def getVTApp(): """Get a reference to the `VTApp` instance. This is useful namely for plugins. """ vtapp = None for widget in QtWidgets.qApp.topLevelWidgets(): if widget.objectName() == 'VTGUI': vtapp = widget.vtapp break return vtapp def getApp(): """Return getVTApp.""" return getVTApp() def getGui(): """Small wrapper to hide the fact that vtapp object contains gui. :return: main window object """ return getApp().gui def getModel(): """Small wrapper to hide that vtapp.gui object contains dbs_tree_model. :return: the DBs tree model """ return getGui().dbs_tree_model def getView(): """Small wrapper to hide that vtapp.gui object contains dbs_tree_view. :return: the DBs tree view """ return getGui().dbs_tree_view def getSelectedIndexes(): """Return the list of selected indices.""" return getView().selectedIndexes() def getSelectedNodes(): """Return list of selected nodes.""" return [getModel().nodeFromIndex(index).node for index in getSelectedIndexes()] def long_action(message=None): """Decorator that changes the cursor to the wait cursor. Used with functions that take some time finish. The provided message is displayed in the status bar while the function is running (the status bar is cleaned afterwards). If the message is not provided then the status bar is not updated. :parameter message: string to display in status bar """ def _long_action(f): @functools.wraps(f) def __long_action(*args, **kwargs): status_bar = getGui().statusBar() if message is not None: status_bar.showMessage(message) QtWidgets.QApplication.setOverrideCursor( QtGui.QCursor(QtCore.Qt.WaitCursor)) try: res = f(*args, **kwargs) finally: QtWidgets.QApplication.restoreOverrideCursor() if message is not None: status_bar.clearMessage() return res return __long_action return _long_action def addToMenuBar(menu, enable_function=None): """Add menu to the menu bar into one before last position. Basically insert a menu before Help menu. Actions can be enabled or disabled by enable_function which is connected to aboutToShow signal of the submenu. :parameter menu: QMenu object :parameter enable_function: is connected to aboutToShow for menu :return: None """ menu_bar = getGui().menuBar() last_action = menu_bar.actions()[-1] menu_bar.insertMenu(last_action, menu) if enable_function is not None: menu.aboutToShow.connect(enable_function) def insertInMenu(menu, entries, uid): """Insert entries to the given menu before the action named uid. The function accept a QAction/QMenu or an iterable. The entries will be added before the action whose name is uid. :Parameters: - `menu`: the menu or context menu being updated - `entries`: QAction/Qmenu object or a list of such objects - `uid`: indicates the insertion position for the new entries :return: None """ if not isinstance(entries, collections.Iterable): entries = [entries] if isinstance(entries[0], QtWidgets.QAction): menu.insertEntry = menu.insertAction elif isinstance(entries[0], QtWidgets.QMenu): menu.insertEntry = menu.insertMenu for item in menu.actions(): if item.objectName() == uid: for a in entries: menu.insertEntry(item, a) def addToMenu(menu, entries): """Add entries at the end of the given menu. The function accept a QAction/QMenu or an iterable. Entries will be preceded with a separator and added at the end of the menu. :Parameters: - `menu`: the menu or context menu being updated - `entries`: QAction/QMenu object or a list of such objects :return: None """ if not isinstance(entries, collections.Iterable): entries = [entries] if isinstance(entries[0], QtWidgets.QAction): menu.addEntry = menu.addAction elif isinstance(entries[0], QtWidgets.QMenu): menu.addEntry = menu.addMenu menu.addSeparator() for a in entries: menu.addEntry(a) def addToLeafContextMenu(actions, enable_function=None): """Add entries at the end of the leaf context menu. The function accept a QAction/QMenu or an iterable. Entries will be preceded with a separator and added at the end of the menu. Actions can be enabled or disabled by enable_function which is connected to aboutToShow signal of the context menu. :parameter actions: QAction/QMenu object or a list of such objects :parameter enable_function: is connected to aboutToShow for menu :return: None """ context_menu = getGui().leaf_node_cm addToMenu(context_menu, actions) if enable_function is not None: context_menu.aboutToShow.connect(enable_function) def addToGroupContextMenu(actions): """Add entries at the end of the group context menu. The function accept a QAction/QMenu or an iterable. Entries will be preceded with a separator and added at the end of the menu. :parameter actions: QAction/QMenu object or a list of such objects :return: None """ context_menu = getGui().group_node_cm addToMenu(context_menu, actions) def getFileSelector(parent, caption, dfilter, filepath='', settings=None): """Raise a customised file selector dialog. :Parameters: - `parent`: the parent widget - `caption`: the dialog caption - `dfilter`: filters used to display files and folders - `filepath`: the filepath initially selected - `settings`: dictionary with keys `label` (Accept button text), `history` (file selector history) , `accept_mode` and `file_mode` """ file_selector = QtWidgets.QFileDialog(parent, caption, '', dfilter) # Misc. setup file_selector.setDirectory(settings['history'][-1]) file_selector.setAcceptMode(settings['accept_mode']) if settings['accept_mode'] == QtWidgets.QFileDialog.AcceptSave: file_selector.setOption(QFileDialog.DontConfirmOverwrite) file_selector.setFileMode(settings['file_mode']) file_selector.setHistory(settings['history']) if filepath: file_selector.selectFile(filepath) if settings['label'] != '': file_selector.setLabelText( QtWidgets.QFileDialog.Accept, settings['label']) # Uncomment next line if you want native dialogs. Removing the comment # comes at the price of an annoying KDE warning in your console. See the # thread "A dire warning message" (July, 2011) in the pyQt4 mailing list # for details. #file_selector.setOption(QtWidgets.QFileDialog.DontUseNativeDialog) return file_selector def getFilepath(parent, caption, dfilter, filepath='', settings=None): """Raise a file selector dialog and get a filepath. :Parameters: - `parent`: the parent widget - `caption`: the dialog caption - `dfilter`: filters used to display files and folders - `filepath`: the filepath initially selected - `settings`: dictionary with keys `label` (Accept button text), `history` (file selector history) , `accept_mode` and `file_mode` """ working_dir = None file_selector = \ getFileSelector(parent, caption, dfilter, filepath, settings) # Execute the dialog try: if file_selector.exec_(): # OK clicked filepath = file_selector.selectedFiles()[0] # Make sure filepath uses Unix-like separators filepath = forwardPath(filepath) # Update the working directory working_dir = file_selector.directory().canonicalPath() else: # Cancel clicked filepath = working_dir = '' finally: del file_selector return filepath, working_dir def checkFileExtension(filepath): """ Check the filename extension of a given file. If the filename has no extension this method adds `.h5` extension to it. This is useful when a file is being created or saved. :Parameter filepath: the full path of the file. :Returns: the filepath with the proper extension. """ if not re.search('\.(.+)$', os.path.basename(filepath)): ext = '.h5' filepath = filepath + ext return filepath # # Icons related functions # def createIcons(large_icons, small_icons, icons_dict): """ Create icons for different components of the GUI. The method creates sets of icons for the popup menus and the toolbar. It also creates icons for the tree of databases view and for the windows displaying leaves. :Parameters: - `large_icons`: the list of names of icons with size 22x22 - `small_icons`: the list of names of icons with size 16x16 - `icons_dict`: the icons dictionary to be updated """ all_icons = large_icons.union(small_icons) for name in all_icons: icon = QtGui.QIcon() if name in large_icons: pixmap = QtGui.QPixmap( os.path.join(ICONDIR, '22x22', '{0}.png').format(name)) pixmap.scaled(QtCore.QSize(22, 22), QtCore.Qt.KeepAspectRatio) icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) if name in small_icons: pixmap = QtGui.QPixmap( os.path.join(ICONDIR,'16x16', '{0}.png').format(name)) icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.On) icons_dict[name] = icon # Add an empty iconSet for the Default button of some dialogs icons_dict[''] = QtGui.QIcon() # Application icon icons_dict['vitables_wm'] = QtGui.QIcon( os.path.join(ICONDIR, 'vitables_wm.png')) def getIcons(): """Return the icons dictionary to be used by the main window.""" if not ICONS_DICT: large_icons = frozenset([ # Icons for toolbars 'document-close', 'document-new', 'document-open', 'document-save-as', 'application-exit', 'folder-new', 'edit-copy', 'edit-cut', 'edit-delete','edit-paste', 'help-contents', 'view-filter', 'delete_filters', # Icons for tree pane items 'file_ro', 'file_rw', 'dbfilters', 'folder', 'document-open-folder']) small_icons = frozenset([ # Icons for menu items 'document-close', 'document-new', 'document-open', 'document-save-as', 'document-open-recent', 'application-exit', 'edit-cut', 'edit-copy','edit-delete','edit-paste', 'edit-rename', 'folder-new', 'view-filter', 'delete_filters', 'configure', 'help-about', 'help-contents', # Icons for tree pane items 'image-missing', 'object', 'vlstring', 'array', 'link_array', 'carray', 'link_carray', 'earray', 'link_earray', 'vlarray','link_vlarray', 'table', 'link_table', # Icons for node views 'zoom-in', # Icons for buttons 'dialog-cancel', 'dialog-ok']) createIcons(large_icons, small_icons, ICONS_DICT) return ICONS_DICT def getHBIcons(): """Return the icons dictionary to be used by the `Help Browser`.""" if not HB_ICONS_DICT: large_icons = frozenset([ # Icons for toolbar 'go-first-view', 'go-previous-view', 'go-next-view', 'view-refresh', 'bookmarks', 'bookmark_add', 'zoom-in', 'zoom-out', 'edit-clear-history']) small_icons = frozenset([ # Icons for menu items 'document-open', 'application-exit', 'zoom-in', 'zoom-out', 'go-first-view', 'go-previous-view', 'go-next-view', 'view-refresh', 'bookmarks', 'bookmark_add', # Icons for buttons 'dialog-ok', 'dialog-cancel', 'list-remove']) createIcons(large_icons, small_icons, HB_ICONS_DICT) return HB_ICONS_DICT def addActions(target, actions, actions_dict): """Add a list of QActions to a menu or a toolbar. This is a helper function which make easier to add QActions to a menu or a toolbar. Separators and submenus are also handled by this method. :Parameters: - `target`: the menu or toolbar where actions will be added - `actions`: a sequence of keywords used to get actions from a mapping - `actions_dict`: a mapping of actions """ for action in actions: if action is None: target.addSeparator() elif isinstance(action, QtWidgets.QMenu): target.addMenu(action) else: target.addAction(actions_dict[action]) def formatArrayContent(content): """ Nicely format the contents of a view (table widget) cell. Used when the cell contains a ``numpy`` array. :Parameter content: the ``numpy`` array contained in the view cell """ if isinstance(content, numpy.string_): try: return content.decode(DEFAULT_ENCODING) except UnicodeDecodeError: pass ret = numpy.array2string(content, separator=',') return ret def formatObjectContent(content): """ Nicely format the contents of a view (table widget) cell. Used in `VLArrays` with `object` pseudo atoms. Reading a `VLArray` with `object` pseudo atom returns a list of Python objects. This method formats that objects as unicode strings via str(content). :Parameter content: the Python list contained in the view cell """ try: text = str(content) except UnicodeEncodeError: text = content return text def formatStringContent(content): """ Nicely format the contents of a view (table widget) cell. Used in `VLArrays` with `vlstring` or `vlunicode` pseudo atoms. If the pseudo atom is `vlstring` the method return a encoded string. If the pseudo atom is `vlunicode` then a unicode string is returned. :Parameter content: the Python list contained in the view cell """ # Content is a encoded string i.e. a sequence of raw bytes if isinstance(content, bytes): try: fcontent = content.decode(encoding=DEFAULT_ENCODING) return fcontent except UnicodeDecodeError: logger = logging.getLogger(__name__) logger.error('UnicodeDecodeError exception') return content def formatExceptionInfo(limit=1): """ Format conveniently the catched exceptions. Takes the three-element tuple returned by ``sys.exc_info()`` and transforms each element into a more convenient form. :Parameter limit: the number of stack trace entries to be printed """ logger = logging.getLogger(__name__) logger.error('{0}'.format(traceback.format_exc(limit))) # # Path related functions # def getHomeDir(): """ Get the user's home directory. How the directory is obtained depends on the platform. The returned path is used in QFileDialog calls. """ if sys.platform.startswith('win'): home = os.getenv('HOMEDRIVE') + os.getenv('HOMEPATH') home = forwardPath(home) else: home = os.getenv('HOME') return home def forwardPath(path): """Replace backslashes with slashes in a given path. :Parameter path: the path being transformed """ while path.count(chr(92)): path = path.replace(chr(92), '/') return path def questionBox(title='', text='', info='', detail='', buttons_def=''): """The value returned by a question message box with customised buttons. :Parameters: - `title`: the window title - `text`: the primary text - `info`: additional informative text - `detail`: a detailed text - `buttons_def`: mapping with buttons definitions """ qmbox = QtWidgets.QMessageBox() qmbox.setIcon(QtWidgets.QMessageBox.Question) qmbox.setWindowTitle(title) qmbox.setText(text) if info: qmbox.setInformativeText(info) if detail: qmbox.setDetailedText(detail) qmbox.setDefaultButton(QtWidgets.QMessageBox.NoButton) buttons = {} for name, (text, role) in buttons_def.items(): buttons[name] = qmbox.addButton(text, role) qmbox.exec_() # Find out which button has been returned for name in buttons.keys(): if buttons[name] == qmbox.clickedButton(): return name return def getFinalName(nodename, sibling, pattern, info): """Return the node name to be used when editing a node. Some node editing operations may raise naming issues because the name wanted for the edited node is already being used by a sibling node. These operations are: - paste - drop - rename - group creation If such naming issue arises, a dialog is displayed, and the user is required to decide what to do: choose a new name for the node being edited, overwrite the node which is currently using the troubled name or cancel the node editing. :Parameters: - `nodename`: the troubled name - `sibling`: a sequence with the sibling nodenames of the edited node - `pattern`: a regular expression pattern the nodename must match - `info`: the information to be displayed in the dialog """ overwrite = False # Bad nodename condition nodename_in_sibling = nodename in sibling # If repeated, ask for a new nodename while nodename_in_sibling: dialog = renamedlg.RenameDlg(nodename, pattern, info) if dialog.exec_(): nodename = dialog.action['new_name'] overwrite = dialog.action['overwrite'] del dialog if overwrite == True: break # Update the bad nodename condition nodename_in_sibling = nodename in sibling else: del dialog return None, None return nodename, overwrite def getLicense(): """The ``ViTables`` license in Rich Text format.""" # From: http://stackoverflow.com/a/20885799/548792 import pkg_resources resource_package = __name__ resource_path = 'LICENSE.html' license_text = pkg_resources.resource_string(resource_package, resource_path) # @UndefinedVariable return license_text.decode('UTF-8') ViTables-3.0.0/vitables/vtapp.py000066400000000000000000001461131311223072700165440ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module is the core of the application: it controls the managers for specific tasks and contains the logic for reacting to user's input i.e. the slots connected to every menu entry are defined here. """ __docformat__ = 'restructuredtext' import os import time import sys import logging import tables from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils import vitables.vtsplash from vitables.vtsite import ICONDIR from vitables.preferences import vtconfig import vitables.preferences.pluginsloader as pluginsloader from vitables.preferences import preferences import vitables.h5db.dbstreemodel as dbstreemodel import vitables.h5db.dbstreeview as dbstreeview import vitables.queries.querymgr as qmgr import vitables.vtwidgets.nodenamedlg as nodenamedlg import vitables.vtwidgets.renamedlg as renamedlg from vitables.docbrowser import helpbrowser import vitables.vttables.buffer as rbuffer import vitables.vttables.datasheet as datasheet import vitables.vtgui as vtgui translate = QtWidgets.QApplication.translate def makePage(content): """Create a page for the About ViTables dialog. :Parameter content: the text displayed on the page """ widget = QtWidgets.QWidget() widget.setLayout(QtWidgets.QVBoxLayout()) text_edit = QtWidgets.QTextEdit(widget) text_edit.setReadOnly(1) text_edit.setAcceptRichText(True) text_edit.setText(content) widget.layout().addWidget(text_edit) return widget class VTApp(QtCore.QObject): """ The application core. :Parameters: - `mode`: the opening mode for files passed in the command line - `h5files`: a list of files to be open at startup - `dblist`: a file that contains a list of files to be open at startup """ # Convenience signals for the plugins. Usually new signals are added # when a new plugin is added to ViTables. They are the link between # the plugins and the core of the program leaf_model_created = QtCore.Signal(QtWidgets.QMdiSubWindow, name="leafModelCreated") dbtree_model_created = QtCore.Signal() pluginsLoaded = QtCore.Signal() def __init__(self, mode='', dblist='', h5files=None, keep_splash=True): """ Initialize the application. This method starts the application: makes the GUI, configure the app, instantiates managers needed to control the app. and connect signals to slots. """ super(VTApp, self).__init__() self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # Make the main window easily accessible for external modules self.setObjectName('VTApp') self.is_first_opening = True # for Open file dialogs # Show a splash screen logo = QtGui.QPixmap(os.path.join(ICONDIR, "vitables_logo.png")) splash = vitables.vtsplash.VTSplash(logo) splash.show() t_i = time.time() # Instantiate a configurator object for the application self.config = vtconfig.Config() # Create the GUI. This is done in 3 steps: # - create the main window # - create the model/view for the tree of databases # - setup the main window splash.drawMessage(translate('VTApp', 'Creating the GUI...', 'A splash screen message')) self.gui = vtgui.VTGUI(self, vtconfig.getVersion()) # Apply the configuration stored on disk splash.drawMessage(translate('VTApp', 'Configuration setup...', 'A splash screen message')) # Reset the configuration object. I don't know why this is necessary # but it is del self.config self.config = vtconfig.Config() self.config.loadConfiguration(self.config.readConfiguration()) # Load plugins. # Some plugins modify existing menus so plugins must be loaded after # creating the user interface. # Some plugins modify the tree of databases or datasets displaying so # plugins must be loaded before opening any file. self.plugins_mgr = \ pluginsloader.PluginsLoader(self.config.enabled_plugins) self.plugins_mgr.loadAll() self.pluginsLoaded.emit() self.dbtree_model_created.emit() # The queries manager self.queries_mgr = qmgr.QueriesManager() # Print the welcome message self.gui.logger.write( translate('VTApp', """ViTables {0}\nCopyright (c) 2008-2017 Vicent Mas.""" """\nAll rights reserved.""", 'Application startup message').format( vtconfig.getVersion())) # The list of most recently open DBs self.number_of_recent_files = 10 while len(self.config.recent_files) > self.number_of_recent_files: del self.config.recent_files[-1] # The File Selector History self.file_selector_history = [] if self.config.startup_working_directory != 'last': self.config.last_working_directory = os.getcwd() self.file_selector_history.append(self.config.last_working_directory) # List of HelpBrowser instances in memory self.doc_browser = None # Restore last session if self.config.restore_last_session: splash.drawMessage(translate('VTApp', 'Recovering last session...', 'A splash screen message')) self.recoverLastSession() # Process the command line if h5files: splash.drawMessage(translate('VTApp', 'Opening files...', 'A splash screen message')) self.processCommandLineArgs(mode=mode, h5files=h5files) elif dblist: splash.drawMessage(translate('VTApp', 'Opening the list of files...', 'A splash screen message')) self.processCommandLineArgs(dblist=dblist) # Make sure that the splash screen is shown at least for two seconds if keep_splash: t_f = time.time() while t_f - t_i < 2: t_f = time.time() splash.finish(self.gui) del splash # Ensure that QActions have a consistent state self.gui.updateActions() self.gui.dbs_tree_model.rowsRemoved.connect(self.gui.updateActions) self.gui.dbs_tree_model.rowsInserted.connect(self.gui.updateActions) self.gui.updateWindowMenu() # Databases are automatically opened at startup when: # # * application is configured for recovering last session # * ViTables is started from the command line with some args # def recoverLastSession(self): """ Recover the last session. This method will attempt to open those files and leaf views that were opened the last time the user closed ``ViTables``. The lists of files and leaves is read from the configuration file. The format is:: ['mode#@#filepath1#@#nodepath1#@#nodepath2, ...', 'mode#@#filepath2#@#nodepath1#@#nodepath2, ...', ...] """ # Get the list of open files (temporary database is not included) for file_data in self.config.session_files_nodes: item = file_data.split('#@#') # item looks like [mode, filepath1, nodepath1, nodepath2, ...] mode = item.pop(0) filepath = item.pop(0) filepath = vitables.utils.forwardPath(filepath) # Open the database --> add the root group to the tree view. if self.gui.dbs_tree_model.openDBDoc(filepath, mode): self.gui.dbs_tree_view.setCurrentIndex( self.gui.dbs_tree_model.index(0, 0, QtCore.QModelIndex())) db_doc = self.gui.dbs_tree_model.getDBDoc(filepath) if db_doc is None: continue # Update the history file self.updateRecentFiles(filepath, mode) # For opening a node the groups in the nodepath are expanded # left to right letting the lazy population feature to work for nodepath in item: # '/group1/group2/...groupN/leaf' # Check if the node still exists because the database # could have changed since last ViTables session node = db_doc.get_node(nodepath) if node is None: continue # groups is ['', 'group1', 'group2', ..., 'groupN'] groups = nodepath.split('/')[:-1] # Expands the top level group, i.e., the root group. # It happens to be the last root node added to model # so its row is 0 group = self.gui.dbs_tree_model.root.childAtRow(0) index = self.gui.dbs_tree_model.index(0, 0, QtCore.QModelIndex()) self.gui.dbs_tree_view.expanded.emit(index) groups.pop(0) # Expand the rest of groups of the nodepath while groups != []: parent_group = group parent_index = index group = parent_group.findChild(groups[0]) row = group.row() index = self.gui.dbs_tree_model.index(row, 0, parent_index) self.gui.dbs_tree_view.expanded.emit(index) groups.pop(0) # Finally we open the leaf leaf_name = nodepath.split('/')[-1] leaf = group.findChild(leaf_name) row = leaf.row() leaf_index = self.gui.dbs_tree_model.index(row, 0, index) self.gui.dbs_tree_view.setCurrentIndex(leaf_index) self.nodeOpen(leaf_index) def processCommandLineArgs(self, mode='', h5files=None, dblist=''): """ Open files passed in the command line. :Parameters: - `mode`: the opening mode for files passed in the command line - `h5files`: a list of files to be open at startup - `dblist`: a file that contains a list of files to be open at startup """ bad_line = translate('VTApp', 'Opening failed: wrong {0} in line {1} of {2}', 'Bad line format') # The database manager opens the files (if any) if isinstance(h5files, list): for filepath in h5files: filepath = vitables.utils.forwardPath(filepath) if self.gui.dbs_tree_model.openDBDoc(filepath, mode): self.gui.dbs_tree_view.setCurrentIndex( self.gui.dbs_tree_model.index(0, 0, QtCore.QModelIndex())) self.updateRecentFiles(filepath, mode) # If a list of files is passed then parse the list and open the files if dblist: try: input_file = open(dblist, 'r') lines = [i[:-1].split('#@#') for i in input_file.readlines()] input_file.close() for line in lines: if line == ['']: continue if len(line) != 2: self.logger.error(bad_line.format('format', line, dblist)) continue [mode, filepath] = line filepath = vitables.utils.forwardPath(filepath) if not mode in ['r', 'a']: self.logger.error(bad_line.format('mode', line, dblist)) continue if self.gui.dbs_tree_model.openDBDoc(filepath, mode): self.gui.dbs_tree_view.setCurrentIndex( self.gui.dbs_tree_model.index( 0, 0, QtCore.QModelIndex())) self.updateRecentFiles(filepath, mode) except IOError: self.logger.error( translate('VTApp', 'List of HDF5 files not read', 'File not updated error')) def updateRecentFiles(self, filepath, mode): """ Add a new path to the list of most recently open files. :meth:`processCommandLineArgs`, :meth:`recoverLastSession`, :meth:`fileNew` and :meth:`fileOpen` call this method. :Parameters: - `filepath`: the last opened/created file - `mode`: the opening mode of the file """ item = mode + '#@#' + filepath recent_files = self.config.recent_files # Updates the list of recently open files. Most recent goes first. if item not in recent_files: recent_files.insert(0, item) else: recent_files.remove(item) recent_files.insert(0, item) while len(recent_files) > self.number_of_recent_files: del recent_files[-1] def updateFSHistory(self, working_dir): """Update the navigation history of the file selector widget. :Parameter working_dir: the last visited directory """ self.config.last_working_directory = working_dir if working_dir not in self.file_selector_history: self.file_selector_history.append(working_dir) else: while working_dir in self.file_selector_history: self.file_selector_history.remove(working_dir) self.file_selector_history.append(working_dir) def fileNew(self): """Create a new file.""" # Launch the file selector fs_args = {'accept_mode': QtWidgets.QFileDialog.AcceptOpen, 'file_mode': QtWidgets.QFileDialog.AnyFile, 'history': self.file_selector_history, 'label': translate('VTApp', 'Create', 'Accept button text for QFileDialog')} filepath, working_dir = vitables.utils.getFilepath( self.gui, translate('VTApp', 'Creating a new file...', 'Caption of the File New... dialog'), dfilter=translate('VTApp', """HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;""" """All Files (*)""", 'Filter for the Open New dialog'), settings=fs_args) if not filepath: # The user has canceled the dialog return # Update the history of the file selector widget self.updateFSHistory(working_dir) # Check the file extension filepath = vitables.utils.checkFileExtension(filepath) # Check the returned path if os.path.exists(filepath): self.logger.error( translate('VTApp', 'New file creation failed because file ' 'already exists.', 'A file creation error')) return # Open the database and select it in the tree view db_doc = self.gui.dbs_tree_model.createDBDoc(filepath) if db_doc: # The write mode must be replaced by append mode or the file # will be created from scratch in the next ViTables session self.gui.dbs_tree_view.setCurrentIndex( self.gui.dbs_tree_model.index(0, 0, QtCore.QModelIndex())) self.updateRecentFiles(filepath, 'a') def fileSaveAs(self): """ Save a renamed copy of a file. This method exhibits the typical behavior: copied file is closed and the fresh renamed copy is opened. """ overwrite = False current_index = self.gui.dbs_tree_view.currentIndex() # The file being saved initial_filepath = \ self.gui.dbs_tree_model.nodeFromIndex(current_index).filepath # Launch the file selector fs_args = {'accept_mode': QtWidgets.QFileDialog.AcceptSave, 'file_mode': QtWidgets.QFileDialog.AnyFile, 'history': self.file_selector_history, 'label': translate('VTApp', 'Create', 'Accept button text for QFileDialog')} trier_filepath, working_dir = vitables.utils.getFilepath( self.gui, translate('VTApp', 'Copying a file...', 'Caption of the File Save as... dialog'), dfilter=translate('VTApp', """HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;""" """All Files (*)""", 'Filter for the Save As... dialog'), filepath=initial_filepath, settings=fs_args) if not trier_filepath: # The user has canceled the dialog return # Update the history of the file selector widget self.updateFSHistory(working_dir) trier_filepath = vitables.utils.checkFileExtension(trier_filepath) # # Check if the chosen name is valid # info = [translate('VTApp', 'File Save as: file already exists', 'A dialog caption'), None] # Bad filepath conditions trier_dirname, trier_filename = os.path.split(trier_filepath) sibling = os.listdir(trier_dirname) filename_in_sibling = trier_filename in sibling is_tmp_filepath = \ trier_filepath == self.gui.dbs_tree_model.tmp_filepath is_initial_filepath = trier_filepath == initial_filepath # If the suggested filepath is not valid ask for a new filepath # The loop is necessary because the file being saved as and the # temporary database can be in the same directory. In this case # we must check all error conditions every time a new name is tried while is_tmp_filepath or is_initial_filepath or filename_in_sibling: if is_tmp_filepath: info[1] = translate('VTApp', """Target directory: {0}\n\nThe Query results""" """ database cannot be overwritten.""", 'Overwrite file dialog label').format(trier_dirname) template = \ "(^{0}$)|[a-zA-Z_]+[0-9a-zA-Z_]*(?:\.[0-9a-zA-Z_]+)?$" pattern = template.format(trier_filename) elif is_initial_filepath: info[1] = translate('VTApp', """Target directory: {0}\n\nThe file being """ """saved cannot overwrite itself.""", 'Overwrite file dialog label').format(trier_dirname) template = \ "(^{0}$)|[a-zA-Z_]+[0-9a-zA-Z_]*(?:\.[0-9a-zA-Z_]+)?$" pattern = template.format(trier_filename) elif filename_in_sibling: info[1] = translate('VTApp', """Target directory: {0}\n\nFile name {1}""" """ already in use in that directory.\n""", 'Overwrite file dialog label').format(trier_dirname, trier_filename) pattern = "[a-zA-Z_]+[0-9a-zA-Z_]*(?:\.[0-9a-zA-Z_]+)?$" dialog = renamedlg.RenameDlg(trier_filename, pattern, info) if dialog.exec_(): trier_filename = dialog.action['new_name'] trier_filepath = os.path.join(trier_dirname, trier_filename) trier_filepath = \ QtCore.QDir.fromNativeSeparators(trier_filepath) overwrite = dialog.action['overwrite'] # Update the error conditions is_initial_filepath = trier_filepath == initial_filepath is_tmp_filepath = \ trier_filepath == self.gui.dbs_tree_model.tmp_filepath filename_in_sibling = trier_filename in sibling del dialog if (overwrite == True) and (not is_initial_filepath) and \ (not is_tmp_filepath): break else: del dialog return filepath = vitables.utils.checkFileExtension(trier_filepath) # If an open file is overwritten then close it if overwrite and self.gui.dbs_tree_model.getDBDoc(filepath): for row, child in enumerate(self.gui.dbs_tree_model.root.children): if child.filepath == filepath: self.fileClose(self.gui.dbs_tree_model.index(row, 0, QtCore.QModelIndex())) # The current index could have changed when overwriting # so we update it for row in range(0, self.gui.dbs_tree_model.rowCount(QtCore.QModelIndex())): index = QtCore.QModelIndex().child(row, 0) node = self.gui.dbs_tree_model.nodeFromIndex(index) if node.filepath == initial_filepath: current_index = index self.gui.dbs_tree_view.setCurrentIndex(current_index) # Make a copy of the selected file try: QtWidgets.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) dbdoc = self.gui.dbs_tree_model.getDBDoc(initial_filepath) dbdoc.copy_file(filepath) finally: QtWidgets.qApp.restoreOverrideCursor() # Close the copied file (which is not necessarely selected in # the tree view because closing an overwritten file can change # the selected item) and open the new copy in read-write mode. # The position in the tree is kept for row, child in enumerate(self.gui.dbs_tree_model.root.children): if child.filepath == initial_filepath: self.fileClose(self.gui.dbs_tree_model.index( row, 0, QtCore.QModelIndex())) self.fileOpen(filepath, 'a', row) def fileOpenRO(self, filepath=None): """ Open a file that contains a ``PyTables`` database in read-only mode. :Parameters filepath: the full path of the file to be open """ self.fileOpen(filepath, mode='r') def openRecentFile(self): """ Open the file selected in the `Open Recent...` submenu. """ action = self.sender() item = action.data() (mode, filepath) = item.split('#@#') self.fileOpen(filepath, mode) def clearRecentFiles(self): """ Clear the list of recently opened files and delete the corresponding historical file. """ self.config.recent_files = [] def fileOpen(self, filepath=None, mode='a', position=0): """ Open a file that contains a ``PyTables`` database. If this method is invoqued via ``File -> Open`` then no filepath is passed and a dialog is raised. When the method is invoqued passing arguments to the command line or via :meth:`openRecentFile` or :meth:`fileSaveAs` methods then filepath is passed and the dialog is not raised. :Parameters: - `filepath`: the full path of the file to be open - `mode`: the file opening mode. It can be read-write or read-only - `position`: position in the tree view of the new file """ if not filepath: # Launch the file selector fs_args = {'accept_mode': QtWidgets.QFileDialog.AcceptOpen, 'file_mode': QtWidgets.QFileDialog.ExistingFile, 'history': self.file_selector_history, 'label': translate('VTApp', 'Open', 'Accept text for QFileDialog')} filepath, working_dir = vitables.utils.getFilepath( self.gui, translate('VTApp', 'Select a file for opening', 'Caption of the File Open... dialog'), dfilter = translate('VTApp', """HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;""" """All Files (*)""", 'Filter for the Open New dialog'), settings=fs_args) if not filepath: # The user has canceled the dialog return # Update the history of the file selector widget self.updateFSHistory(working_dir) else: # Make sure filepath uses Unix-like separators filepath = vitables.utils.forwardPath(filepath) # Open the database and select it in the tree view if self.gui.dbs_tree_model.openDBDoc(filepath, mode, position): self.gui.dbs_tree_view.setCurrentIndex( self.gui.dbs_tree_model.index( position, 0, QtCore.QModelIndex())) self.updateRecentFiles(filepath, mode) def fileClose(self, current=False): """ Close a file. First of all this method finds out which database has to be closed. Afterwards all views belonging to that database are closed, then the object tree is removed from the databases tree and, finally, the database is closed. :Parameter current: the index in the databases tree of a node living in the file being closed """ if current is False: current = self.gui.dbs_tree_view.currentIndex() node = self.gui.dbs_tree_model.nodeFromIndex(current) filepath = node.filepath # The position of this database in the tree view last_row = len(self.gui.dbs_tree_model.root.children) - 1 for row, child in enumerate(self.gui.dbs_tree_model.root.children): if child.filepath == filepath: position = row break # If some leaf of this database has an open view then close it for window in self.gui.workspace.subWindowList(): if window.dbt_leaf.filepath == filepath: window.close() # The tree model closes the file and delete its root item # from the tree view self.gui.dbs_tree_model.closeDBDoc(filepath) # The root node immediately below the closed node becomes selected if position <= last_row: index = self.gui.dbs_tree_model.index(position, 0, QtCore.QModelIndex()) self.gui.dbs_tree_view.setCurrentIndex(index) def fileCloseAll(self): """Close every open file.""" # The list of top level items to be removed. # The temporary database should be closed at quit time only open_files = len(self.gui.dbs_tree_model.root.children) - 1 rows_range = list(range(0, open_files).__reversed__()) # Reversing is a must because, if we start from 0, row positions # change as we delete rows for row in rows_range: index = self.gui.dbs_tree_model.index(row, 0, QtCore.QModelIndex()) self.fileClose(index) def fileExit(self): """ Safely close the application. Saves current configuration on disk, closes opened files and exits. """ # Because configuration is always restored from the previous session # we have to be careful with the Logger and make sure that it is neither # closed nor floated if not self.gui.logger_dock.isVisible(): self.gui.logger_dock.setVisible(True) if self.gui.logger_dock.isFloating(): self.gui.logger_dock.setFloating(False) # Close all browsers if self.doc_browser: self.doc_browser.exitBrowser() # Save current configuration self.config.saveConfiguration() # Close every user opened file self.fileCloseAll() # Close the temporary database index = self.gui.dbs_tree_model.index(0, 0, QtCore.QModelIndex()) self.fileClose(index) def tablesNode(self, index): """The tables.Leaf instance tied to the given index. :Parameter index: the tree of databases model index being retrieved """ # The leaf (data structure) of the databases tree view tied to index leaf = self.gui.dbs_tree_model.nodeFromIndex(index) # The tables.Leaf instance referenced by that data structure pt_node = leaf.node if hasattr(pt_node, 'target'): return pt_node() return pt_node def nodeOpen(self, current=False): """ Open a leaf node for viewing. :Parameter current: the index in the databases tree of the node being opened """ if current is False: # Open the node currently selected in the tree of databases index = self.gui.dbs_tree_view.currentIndex() else: # When restoring the previous session explicit indexes are passed index = current leaf = self.tablesNode(index) # tables.UnImplemented datasets cannot be read so are not opened if isinstance(leaf, tables.UnImplemented): QtWidgets.QMessageBox.information(self.gui, translate('VTApp', 'About UnImplemented nodes', 'A dialog caption'), translate('VTApp', """Actual data for this node are not accesible.
""" """The combination of datatypes and/or dataspaces in this """ """node is not yet supported by PyTables.
""" """If you want to see this kind of dataset implemented in """ """PyTables, please, contact the developers.""", 'Text of the Unimplemented node dialog')) return # The buffer tied to this node in order to optimize the read access leaf_buffer = rbuffer.Buffer(leaf) # Leaves that cannot be read are not opened if not leaf_buffer.isDataSourceReadable(): return # Create a view subwindow = datasheet.DataSheet(index) subwindow.show() # For unknown reasons sometimes views cannot be resized. This strange # problem is fixed by hiding the view and immediately showing it again subwindow.hide() subwindow.show() # Announcing the new view is potentially helpful for plugins in charge # of datasets customizations (for instance, additional formatting) self.leaf_model_created.emit(subwindow) def nodeClose(self, current=False): """ Close the view of the selected node. The method is called by activating ``Node --> Close`` (what passes no argument) or programatically by the :meth:`fileClose` method (what does pass argument). If the target is an open leaf this method closes its view, delete its model and updates the controller tracking system. If the target node is a root group the method looks for opened children and closes them as described above. :Parameter current: the index in the databases tree of the node being closed """ if not current: current = self.gui.dbs_tree_view.currentIndex() pcurrent = QtCore.QPersistentModelIndex(current) # Find out the subwindow tied to the selected node and close it for data_sheet in self.gui.workspace.subWindowList(): if pcurrent == data_sheet.pindex: data_sheet.close() break def nodeNewGroup(self): """Create a new group node.""" current = self.gui.dbs_tree_view.currentIndex() parent = self.gui.dbs_tree_model.nodeFromIndex(current) # Get the new group name dialog = nodenamedlg.InputNodeName( translate('VTApp', 'Creating a new group', 'A dialog caption'), translate('VTApp', 'Source file: {0}\nParent group: {1}\n\n ', 'A dialog label').format(parent.filepath, parent.nodepath), translate('VTApp', 'Create', 'A button label')) self.gui.editing_dlg = True if dialog.exec_(): suggested_nodename = dialog.node_name self.gui.dbs_tree_view.setFocus(True) del dialog else: self.gui.dbs_tree_view.setFocus(True) del dialog return # # Check if the entered nodename is already in use # sibling = getattr(parent.node, '_v_children').keys() pattern = "[a-zA-Z_]+[0-9a-zA-Z_ ]*" info = [translate('VTApp', 'Creating a new group: name already in use', 'A dialog caption'), translate('VTApp', """Source file: {0}\nParent group: {1}\n\nThere is """ """already a node named '{2}' in that parent group.\n""", 'A dialog label').format\ (parent.filepath, parent.nodepath, suggested_nodename)] nodename, overwrite = vitables.utils.getFinalName(suggested_nodename, sibling, pattern, info) if nodename is None: return # If the creation overwrites a group with attached views then these # views are closed before the renaming is done if overwrite: nodepath = tables.path.join_path(parent.nodepath, nodename) self.gui.closeChildrenViews(nodepath, parent.filepath) self.gui.dbs_tree_model.create_group(current, nodename, overwrite) def nodeRename(self): """ Rename the selected node. - ask for the node name - check the node name. If it is already in use ask what to do (possibilities are rename, overwrite and cancel creation) - rename the node """ index = self.gui.dbs_tree_view.currentIndex() child = self.gui.dbs_tree_model.nodeFromIndex(index) parent = child.parent # Get the new nodename dialog = nodenamedlg.InputNodeName( translate('VTApp', 'Renaming a node', 'A dialog caption'), translate('VTApp', 'Source file: {0}\nParent group: {1}\n\n', 'A dialog label').format(parent.filepath, parent.nodepath), translate('VTApp', 'Rename', 'A button label'), child.name) self.gui.editing_dlg = True if dialog.exec_(): suggested_nodename = dialog.node_name del dialog else: del dialog return # # Check if the nodename is already in use # sibling = getattr(parent.node, '_v_children').keys() # Note that current nodename is not allowed as new nodename. # Embedding it in the pattern makes unnecessary to pass it to the # rename dialog via method argument and simplifies the code pattern = """(^{0}$)|""" \ """(^[a-zA-Z_]+[0-9a-zA-Z_ ]*)""".format(child.name) info = [translate('VTApp', 'Renaming a node: name already in use', 'A dialog caption'), translate('VTApp', """Source file: {0}\nParent group: {1}\n\nThere is """ """already a node named '{2}' in that parent """ """group.\n""", 'A dialog label').format\ (parent.filepath, parent.nodepath, suggested_nodename)] nodename, overwrite = vitables.utils.getFinalName(suggested_nodename, sibling, pattern, info) self.gui.editing_dlg = True if nodename is None: return # If the renaming overwrites a node with attached views then these # views are closed before the renaming is done if overwrite: nodepath = tables.path.join_path(parent.nodepath, nodename) self.gui.closeChildrenViews(nodepath, child.filepath) # Rename the node self.gui.dbs_tree_model.rename_node(index, nodename, overwrite) # Update the Selected node indicator of the status bar self.gui.updateStatusBar() def nodeCut(self): """Cut the selected node.""" current = self.gui.dbs_tree_view.currentIndex() # If the cut node has attached views then these views are closed # before the cutting is done. This behavior can be inconvenient # for users but get rid of potential problems that arise if, for # any reason, the user doesn't paste the cut node. node = self.gui.dbs_tree_model.nodeFromIndex(current) self.gui.closeChildrenViews(node.nodepath, node.filepath) # Cut the node self.gui.dbs_tree_model.cutNode(current) def nodeCopy(self): """ Copy the selected node. """ current = self.gui.dbs_tree_view.currentIndex() # Non readable leaves should not be copied dbs_tree_node = self.gui.dbs_tree_model.nodeFromIndex(current) if not (dbs_tree_node.node_kind in ('root group', 'group')): leaf = dbs_tree_node.node # tables.Leaf instances must be readable in order to be copied if not hasattr(leaf, 'target'): leaf_buffer = rbuffer.Buffer(leaf) if not leaf_buffer.isDataSourceReadable(): QtWidgets.QMessageBox.information(self, translate('VTApp', 'About unreadable datasets', 'Dialog caption'), translate('VTApp', """Sorry, actual data for this node are not """ """accesible.
The node will not be copied.""", 'Text of the Unimplemented node dialog')) return # Copy the node self.gui.dbs_tree_model.copy_node(current) def nodePaste(self): """ Paste the currently copied/cut node under the selected node. """ current = self.gui.dbs_tree_view.currentIndex() parent = self.gui.dbs_tree_model.nodeFromIndex(current) cni = self.gui.dbs_tree_model.ccni if cni == {}: return nodename = cni['nodename'] if cni['nodepath'] == '/': nodename = \ 'root_group_of_{0}'.format(os.path.basename(cni['filepath'])) if cni['is_copied']: # Check if pasting a copied node is allowed (pasting a cut # node has no restrictions). It is not when # - source and target are the same node # - target is the source's parent if (cni['filepath'] == parent.filepath): if (cni['nodepath'] == parent.nodepath) or \ (parent.nodepath == os.path.dirname(cni['nodepath'])): return # Soft links cannot be pasted in external files if cni['target']: link = self.gui.dbs_tree_model.copiedNode() try: getattr(link, 'extfile') except AttributeError: if (parent.filepath != cni['filepath']): return # # Check if the nodename is already in use # sibling = getattr(parent.node, '_v_children').keys() # Nodename pattern pattern = "[a-zA-Z_]+[0-9a-zA-Z_ ]*" # Bad nodename conditions info = [translate('VTApp', 'Node paste: nodename already exists', 'A dialog caption'), translate('VTApp', """Source file: {0}\nCopied node: {1}\n""" """Destination file: {2}\nParent group: {3}\n\n""" """Node name '{4}' already in use in that group.\n""", 'A dialog label').format\ (cni['filepath'], cni['nodepath'], parent.filepath, parent.nodepath, nodename), translate('VTApp', 'Paste', 'A button label')] # Validate the nodename nodename, overwrite = vitables.utils.getFinalName(nodename, sibling, pattern, info) self.gui.editing_dlg = True if nodename is None: # Node editing dialog is not displayed return # If the pasting overwrites a node with attached views then these # views are closed before the pasting is done if overwrite: nodepath = tables.path.join_path(parent.nodepath, nodename) self.gui.closeChildrenViews(nodepath, parent.filepath) # Paste the node self.gui.dbs_tree_model.pasteNode(current, nodename, overwrite) def nodeDelete(self, current=False, force=None): """ Delete a given node. :Parameters: - `current`: the index in the databases tree of the node being deleted - `force`: ask/do not ask for confirmation before deletion """ if current is False: current = self.gui.dbs_tree_view.currentIndex() node = self.gui.dbs_tree_model.nodeFromIndex(current) # Confirm deletion dialog if not force: title = translate('VTApp', 'Node deletion', 'Caption of the node deletion dialog') text = translate('VTApp', """\nYou are about to delete the node:\n{0}\n""", 'Ask for confirmation').format(node.nodepath) itext = '' dtext = '' buttons = { 'Delete': (translate('VTApp', 'Delete', 'Button text'), QtWidgets.QMessageBox.YesRole), 'Cancel': (translate('VTApp', 'Cancel', 'Button text'), QtWidgets.QMessageBox.NoRole), } # Ask for confirmation answer = \ vitables.utils.questionBox(title, text, itext, dtext, buttons) self.gui.editing_dlg = True if answer == 'Cancel': return # If item is a filtered table then update the list of used names if hasattr(node.node._v_attrs, 'query_condition'): self.queries_mgr.ft_names.remove(node.name) # If the deletion involves a node with attached views then these # views are closed before the deletion is done self.gui.closeChildrenViews(node.nodepath, node.filepath) # Delete the node self.gui.dbs_tree_model.deleteNode(current) # Ensure that the new current node (if any) gets selected select_model = self.gui.dbs_tree_view.selectionModel() new_current = self.gui.dbs_tree_view.currentIndex() select_model.select(new_current, QtCore.QItemSelectionModel.Select) def nodeProperties(self): """ Display the properties dialog for the currently selected node. The method is called by activating ``Node --> Properties``. """ current = self.gui.dbs_tree_view.currentIndex() node = self.gui.dbs_tree_model.nodeFromIndex(current) node.properties() self.gui.editing_dlg = True def newQuery(self): """Slot for querying tables.""" self.queries_mgr.newQuery() def deleteAllQueries(self): """Slot for emptying the `Query results` node.""" self.queries_mgr.deleteAllQueries() def settingsPreferences(self): """ Launch the Preferences dialog. Clicking the ``OK`` button applies the configuration set in the Preferences dialog. """ prefs = preferences.Preferences() try: if prefs.exec_() == QtWidgets.QDialog.Accepted: self.config.loadConfiguration(prefs.new_prefs) finally: del prefs def windowClose(self): """Close the window currently active in the workspace.""" self.gui.workspace.activeSubWindow().close() if self.gui.workspace.subWindowList() == []: self.gui.dbs_tree_view.setFocus(True) def windowCloseAll(self): """Close all open windows.""" for window in self.gui.workspace.subWindowList(): window.close() self.gui.dbs_tree_view.setFocus(True) def windowRestoreAll(self): """Restore every window in the workspace to its normal size.""" for window in self.gui.workspace.subWindowList(): window.showNormal() def windowMinimizeAll(self): """Restore every window in the workspace to its normal size.""" for window in self.gui.workspace.subWindowList(): window.showMinimized() def helpBrowser(self): """ Open the documentation browser. """ self.doc_browser = helpbrowser.HelpBrowser() def helpAbout(self): """ Show a tabbed dialog with the application About and License info. """ # Text to be displayed about_text = translate('VTApp', """

ViTables {0}

ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.

For more information see http://www.vitables.org.

Please send bug reports or feature requests to the ViTables Users Group.

ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. """, 'Text of the About ViTables dialog').format(vtconfig.getVersion()) thanks_text = translate('VTApp', """ Kostis Anagnostopoulos, Arne de Laat and Christoph Gohlke for helping to revive ViTables with his great contributions.

Santi Villalba for the conda environment.

Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.

Robert Meyer, jaminsore, kprussing, Gaetan de Menten, Kamil Kisiel and Max Bohnet for fixing bugs.

Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.

Oxygen team for a wonderful icons set.

All the people who reported bugs and made suggestions. """, 'Text of the About ViTables dialog (Thanks to page)') license_text = vitables.utils.getLicense() # Construct the dialog about_dlg = QtWidgets.QDialog(self.gui) about_dlg.setWindowTitle( translate('VTApp', 'About ViTables {0}', 'Caption of the About ViTables dialog').\ format(vtconfig.getVersion())) layout = QtWidgets.QVBoxLayout(about_dlg) tab_widget = QtWidgets.QTabWidget(about_dlg) buttons_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok) layout.addWidget(tab_widget) layout.addWidget(buttons_box) buttons_box.accepted.connect(about_dlg.accept) # Make About page content = [about_text, thanks_text, license_text] tabs = [translate('VTApp', '&About', 'Title of the first tab of the About dialog'), translate('VTApp', '&Thanks To', 'Title of the second tab of the About dialog'), translate('VTApp', '&License', 'Title of the third tab of the About dialog')] for index in range(0, 3): widget = makePage(content[index]) tab_widget.addTab(widget, tabs[index]) # Show the dialog about_dlg.exec_() def helpAboutQt(self): """ Show a message box with the Qt About info. """ QtWidgets.QMessageBox.aboutQt(self.gui, translate('VTApp', 'About Qt', 'Caption of the About Qt dialog')) def helpVersions(self): """ Message box with info about versions of libraries used by ``ViTables``. """ svi = sys.version_info pyversion = '.'.join((str(svi.major), str(svi.minor), str(svi.micro))) # The libraries versions dictionary libs_versions = { 'title': translate('VTApp', 'Version Numbers', 'Caption of the Versions dialog'), 'Python': pyversion, 'PyTables': tables.__version__ , 'NumPy': tables.numpy.__version__, 'Qt': QtCore.qVersion(), 'PyQt': QtCore.PYQT_VERSION_STR, 'ViTables': vtconfig.getVersion() } # Add new items to the dictionary libraries = ('HDF5', 'Zlib', 'LZO', 'BZIP2') for lib in libraries: lversion = tables.which_lib_version(lib.lower()) if lversion: libs_versions[lib] = lversion[1] else: libs_versions[lib] = translate('VTApp', 'not available', 'Part of the library not found text') # Construct the dialog versions_dlg = QtWidgets.QDialog(self.gui) versions_dlg.setWindowTitle(translate('VTApp', 'Version Numbers', 'Caption of the Versions dialog')) layout = QtWidgets.QVBoxLayout(versions_dlg) versions_edit = QtWidgets.QTextEdit(versions_dlg) buttons_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok) layout.addWidget(versions_edit) layout.addWidget(buttons_box) buttons_box.accepted.connect(versions_dlg.accept) versions_edit.setReadOnly(1) versions_edit.setText( """

{title}

Python{Python}
PyTables{PyTables}
NumPy{NumPy}
HDF5{HDF5}
Zlib{Zlib}
LZO{LZO}
BZIP2{BZIP2}
Qt{Qt}
PyQt{PyQt}
ViTables{ViTables}
""".format( title=libs_versions['title'], Python=libs_versions['Python'], PyTables=libs_versions['PyTables'], NumPy=libs_versions['NumPy'], Qt=libs_versions['Qt'], PyQt=libs_versions['PyQt'], ViTables=libs_versions['ViTables'], HDF5=libs_versions['HDF5'], Zlib=libs_versions['Zlib'], LZO=libs_versions['LZO'], BZIP2=libs_versions['BZIP2'], )) # Show the dialog versions_dlg.exec_() ViTables-3.0.0/vitables/vtgui.py000066400000000000000000001221631311223072700165470ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides de `ViTables` GUI: main window, menus, context menus, toolbars, statusbars and `QActions` bound to both menus and toolbars. """ __docformat__ = 'restructuredtext' import sys import logging from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils import vitables.logger as logger from vitables.calculator import calculator import vitables.h5db.dbstreemodel as dbstreemodel import vitables.h5db.dbstreeview as dbstreeview translate = QtWidgets.QApplication.translate _GUI_LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' class VTGUI(QtWidgets.QMainWindow): """ The application GUI. :Parameters: - `vtapp`: an instance of the :meth:`vitables.vtapp.VTApp` class - `version`: the `ViTables` version """ def __init__(self, vtapp, version): """Initialize the application main window.""" super(VTGUI, self).__init__(None) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setWindowTitle(translate('VTGUI', 'ViTables {0}', 'Main window title').format(version)) self.vtapp = vtapp # Make the main window easily accessible for external modules self.setObjectName('VTGUI') self.icons_dictionary = vitables.utils.getIcons() # After a node editing the workspace and the databases tree view # should not been sync because keyboard focus should remain on # the tree view. However, if editing dialogs are raised, when # they are closed the focus goes temporarily to the workspace, # resulting in spurious syncs. The editing_dlg flag prevents # this behavior self.editing_dlg = None self.logger_dock = None self.logger = None self.setup_logger_window() self.setup(vtapp) def setup(self, vtapp): """Add widgets, actions, menus and toolbars to the GUI. :Parameter tree_view: The databases tree view """ self.dbs_tree_model = dbstreemodel.DBsTreeModel(self, vtapp) self.dbs_tree_view = dbstreeview.DBsTreeView(vtapp, self, self.dbs_tree_model, self) self.addComponents() self.gui_actions = self.setupActions() self.setupToolBars() self.setupMenus() self.initStatusBar() self.logger.nodeCopyAction = self.gui_actions['nodeCopy'] def setup_logger_window(self): # Put the logging console in the bottom region of the window self.logger_dock = QtWidgets.QDockWidget('Log') self.logger_dock.setObjectName('LoggerDockWindow') self.logger_dock.setFeatures( QtWidgets.QDockWidget.DockWidgetClosable | QtWidgets.QDockWidget.DockWidgetMovable | QtWidgets.QDockWidget.DockWidgetFloatable) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.logger_dock) self.logger = logger.Logger() self.logger_dock.setWidget(self.logger) # add self.logger as handler of main logger object vitables_logger = logging.getLogger('vitables') stream_handler = logging.StreamHandler(self.logger) stream_handler.setFormatter(logging.Formatter(_GUI_LOG_FORMAT)) vitables_logger.addHandler(stream_handler) def addComponents(self): """Add widgets to the main window. The main window contains a databases tree view, a workspace and a console. """ self.setIconSize(QtCore.QSize(22, 22)) self.setWindowIcon(self.icons_dictionary['vitables_wm']) central_widget = QtWidgets.QWidget(self) central_layout = QtWidgets.QVBoxLayout(central_widget) # Divide the top region of the window into 2 regions and put there # the workspace. The tree of databases will be added later on self.hsplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal, central_widget) central_layout.addWidget(self.hsplitter) self.setCentralWidget(central_widget) self.hsplitter.addWidget(self.dbs_tree_view) self.workspace = QtWidgets.QMdiArea(self.hsplitter) sb_as_needed = QtCore.Qt.ScrollBarAsNeeded self.workspace.setHorizontalScrollBarPolicy(sb_as_needed) self.workspace.setVerticalScrollBarPolicy(sb_as_needed) self.workspace.setWhatsThis( translate('VTGUI', """

The Workspace

This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously.

The diferent views can be tiled as a mosaic or stacked as a cascade. """, 'WhatsThis help for the workspace')) # The signal mapper used to keep the the Window menu updated self.window_mapper = QtCore.QSignalMapper(self) self.window_mapper.mapped[QtWidgets.QWidget].connect( self.workspace.setActiveSubWindow) self.workspace.installEventFilter(self) self.dbs_tree_view.clicked.connect(self.selection_changed) def selection_changed(self, index): self.updateActions() self.updateStatusBar() def setupActions(self): """Provide actions to the menubar and the toolbars. """ # Setting action names makes it easier to acces these actions # from plugins actions = {} actions['fileNew'] = QtWidgets.QAction( translate('VTGUI', '&New...', 'File -> New'), self, shortcut=QtGui.QKeySequence.New, triggered=self.vtapp.fileNew, icon=self.icons_dictionary['document-new'], statusTip=translate( 'VTGUI', 'Create a new file', 'Status bar text for the File -> New action')) actions['fileNew'].setObjectName('fileNew') actions['fileOpen'] = QtWidgets.QAction( translate('VTGUI', '&Open...', 'File -> Open'), self, shortcut=QtGui.QKeySequence.Open, triggered=self.vtapp.fileOpen, icon=self.icons_dictionary['document-open'], statusTip=translate( 'VTGUI', 'Open an existing file', 'Status bar text for the File -> Open action')) actions['fileOpen'].setObjectName('fileOpen') actions['fileOpenRO'] = QtWidgets.QAction( translate('VTGUI', 'Read-only open...', 'File -> Open'), self, triggered=self.vtapp.fileOpenRO, icon=self.icons_dictionary['document-open'], statusTip=translate( 'VTGUI', 'Open an existing file in read-only mode', 'Status bar text for the File -> Open action')) actions['fileOpenRO'].setObjectName('fileOpenRO') actions['fileClose'] = QtWidgets.QAction( translate('VTGUI', '&Close', 'File -> Close'), self, shortcut=QtGui.QKeySequence('Shift+F4'), triggered=self.vtapp.fileClose, icon=self.icons_dictionary['document-close'], statusTip=translate( 'VTGUI', 'Close the selected file', 'Status bar text for the File -> Close action')) actions['fileClose'].setObjectName('fileClose') actions['fileCloseAll'] = QtWidgets.QAction( translate('VTGUI', 'Close &All', 'File -> Close All'), self, triggered=self.vtapp.fileCloseAll, statusTip=translate( 'VTGUI', 'Close all files', 'Status bar text for the File -> Close All action')) actions['fileCloseAll'].setObjectName('fileCloseAll') actions['fileSaveAs'] = QtWidgets.QAction( translate('VTGUI', '&Save as...', 'File -> Save As'), self, shortcut=QtGui.QKeySequence.SaveAs, triggered=self.vtapp.fileSaveAs, icon=self.icons_dictionary['document-save-as'], statusTip=translate( 'VTGUI', 'Save a renamed copy of the selected file', 'Status bar text for the File -> Save As action')) actions['fileSaveAs'].setObjectName('fileSaveAs') actions['fileExit'] = QtWidgets.QAction( translate('VTGUI', 'E&xit', 'File -> Exit'), self, shortcut=QtGui.QKeySequence.Quit, triggered=self.close, icon=self.icons_dictionary['application-exit'], statusTip=translate( 'VTGUI', 'Quit ViTables', 'Status bar text for the File -> Exit action')) actions['fileExit'].setObjectName('fileExit') actions['nodeOpen'] = QtWidgets.QAction( translate('VTGUI', '&Open view', 'Node -> Open View'), self, shortcut=QtGui.QKeySequence('Alt+Ctrl+O'), triggered=self.vtapp.nodeOpen, statusTip=translate( 'VTGUI', 'Display the contents of the selected node', 'Status bar text for the Node -> Open View action')) actions['nodeOpen'].setObjectName('nodeOpen') actions['nodeClose'] = QtWidgets.QAction( translate('VTGUI', 'C&lose view', 'Node -> Close View'), self, shortcut=QtGui.QKeySequence('Alt+Shift+F4'), triggered=self.vtapp.nodeClose, statusTip=translate( 'VTGUI', 'Close the view of the selected node', 'Status bar text for the Node -> Close View action')) actions['nodeClose'].setObjectName('nodeClose') actions['nodeProperties'] = QtWidgets.QAction( translate('VTGUI', 'Prop&erties...', 'Node -> Properties'), self, shortcut=QtGui.QKeySequence('Ctrl+I'), triggered=self.vtapp.nodeProperties, icon=self.icons_dictionary['help-about'], statusTip=translate( 'VTGUI', 'Show the properties dialog for the selected node', 'Status bar text for the Node -> Properties action')) actions['nodeProperties'].setObjectName('nodeProperties') actions['nodeNew'] = QtWidgets.QAction( translate('VTGUI', '&New group...', 'Node -> New group'), self, shortcut=QtGui.QKeySequence('Alt+Ctrl+N'), triggered=self.vtapp.nodeNewGroup, icon=self.icons_dictionary['folder-new'], statusTip=translate( 'VTGUI', 'Create a new group under the selected node', 'Status bar text for the Node -> New group action')) actions['nodeNew'].setObjectName('nodeNew') actions['nodeRename'] = QtWidgets.QAction( translate('VTGUI', '&Rename...', 'Node -> Rename'), self, shortcut=QtGui.QKeySequence('Ctrl+R'), triggered=self.vtapp.nodeRename, icon=self.icons_dictionary['edit-rename'], statusTip=translate( 'VTGUI', 'Rename the selected node', 'Status bar text for the Node -> Rename action')) actions['nodeRename'].setObjectName('nodeRename') actions['nodeCut'] = QtWidgets.QAction( translate('VTGUI', 'Cu&t', 'Node -> Cut'), self, shortcut=QtGui.QKeySequence.Cut, triggered=self.vtapp.nodeCut, icon=self.icons_dictionary['edit-cut'], statusTip=translate('VTGUI', 'Cut the selected node', 'Status bar text for the Node -> Cut action')) actions['nodeCut'].setObjectName('nodeCut') actions['nodeCopy'] = QtWidgets.QAction( translate('VTGUI', '&Copy', 'Node -> Copy'), self, shortcut=QtGui.QKeySequence.Copy, triggered=self.makeCopy, icon=self.icons_dictionary['edit-copy'], statusTip=translate('VTGUI', 'Copy the selected node', 'Status bar text for the Node -> Copy action')) actions['nodeCopy'].setObjectName('nodeCopy') actions['nodePaste'] = QtWidgets.QAction( translate('VTGUI', '&Paste', 'Node -> Paste'), self, shortcut=QtGui.QKeySequence.Paste, triggered=self.vtapp.nodePaste, icon=self.icons_dictionary['edit-paste'], statusTip=translate('VTGUI', 'Paste the last copied/cut node', 'Status bar text for the Node -> Copy action')) actions['nodePaste'].setObjectName('nodePaste') actions['nodeDelete'] = QtWidgets.QAction( translate('VTGUI', '&Delete', 'Node -> Delete'), self, shortcut=QtGui.QKeySequence.Delete, triggered=self.vtapp.nodeDelete, icon=self.icons_dictionary['edit-delete'], statusTip=translate('VTGUI', 'Delete the selected node', 'Status bar text for the Node -> Copy action')) actions['nodeDelete'].setObjectName('nodeDelete') actions['queryNew'] = QtWidgets.QAction( translate('VTGUI', '&Query...', 'Query -> New...'), self, triggered=self.vtapp.newQuery, icon=self.icons_dictionary['view-filter'], statusTip=translate( 'VTGUI', 'Create a new filter for the selected table', 'Status bar text for the Query -> New... action')) actions['queryNew'].setObjectName('queryNew') actions['queryDeleteAll'] = QtWidgets.QAction( translate('VTGUI', 'Delete &All', 'Query -> Delete All'), self, triggered=self.vtapp.deleteAllQueries, icon=self.icons_dictionary['delete_filters'], statusTip=translate( 'VTGUI', 'Remove all filters', 'Status bar text for the Query -> Delete All action')) actions['queryDeleteAll'].setObjectName('queryDeleteAll') actions['settingsPreferences'] = QtWidgets.QAction( translate('VTGUI', '&Preferences...', 'Settings -> Preferences'), self, shortcut=QtGui.QKeySequence.Preferences, triggered=self.vtapp.settingsPreferences, icon=self.icons_dictionary['configure'], statusTip=translate( 'VTGUI', 'Configure ViTables', 'Status bar text for the Settings -> Preferences action')) actions['settingsPreferences'].setObjectName('settingsPreferences') actions['windowCascade'] = QtWidgets.QAction( translate('VTGUI', '&Cascade', 'Windows -> Cascade'), self, triggered=self.workspace.cascadeSubWindows, statusTip=translate( 'VTGUI', 'Arranges open windows in a cascade pattern', 'Status bar text for the Windows -> Cascade action')) actions['windowCascade'].setObjectName('windowCascade') actions['windowTile'] = QtWidgets.QAction( translate('VTGUI', '&Tile', 'Windows -> Tile'), self, triggered=self.workspace.tileSubWindows, statusTip=translate( 'VTGUI', 'Arranges open windows in a tile pattern', 'Status bar text for the Windows -> Tile action')) actions['windowTile'].setObjectName('windowTile') actions['windowRestoreAll'] = QtWidgets.QAction( translate('VTGUI', '&Restore All', 'Windows -> Restore All'), self, triggered=self.vtapp.windowRestoreAll, statusTip=translate( 'VTGUI', 'Restore all minimized windows on the workspace', 'Status bar text for the Windows -> Restore All action')) actions['windowRestoreAll'].setObjectName('windowRestoreAll') actions['windowMinimizeAll'] = QtWidgets.QAction( translate('VTGUI', '&Minimize All', 'Windows -> Minimize All'), self, triggered=self.vtapp.windowMinimizeAll, statusTip=translate( 'VTGUI', 'Minimize all windows on the workspace', 'Status bar text for the Windows -> Restore All action')) actions['windowMinimizeAll'].setObjectName('windowMinimizeAll') actions['windowClose'] = QtWidgets.QAction( translate('VTGUI', 'C&lose', 'Windows -> Close'), self, triggered=self.vtapp.windowClose, statusTip=translate( 'VTGUI', 'Close the active view', 'Status bar text for the Windows -> Close action')) actions['windowClose'].setObjectName('windowClose') actions['windowCloseAll'] = QtWidgets.QAction( translate('VTGUI', 'Close &All', 'Windows -> Close All'), self, triggered=self.vtapp.windowCloseAll, statusTip=translate( 'VTGUI', 'Close all views', 'Status bar text for the Windows -> Close All action')) actions['windowCloseAll'].setObjectName('windowCloseAll') actions['windowSeparator'] = QtWidgets.QAction( translate('VTGUI', 'Current View', 'Windows -> separator'), self) actions['windowSeparator'].setSeparator(True) actions['windowSeparator'].setObjectName('windowSeparator') actions['mdiTabbed'] = QtWidgets.QAction( translate('VTGUI', 'Toggle MDI/Tabs', 'MDI -> Tabbed'), self, triggered=self.changeMDIViewMode, statusTip=translate( 'VTGUI', 'Toggle workspace view mode between Tabs <--> Multi Document Interface', 'Status bar text for the MDI -> Tabbed action')) actions['mdiTabbed'].setObjectName('mdiTabbed') actions['helpUsersGuide'] = QtWidgets.QAction( translate('VTGUI', "&User's Guide", 'Help -> Users Guide'), self, shortcut=QtGui.QKeySequence.HelpContents, triggered=self.vtapp.helpBrowser, icon=self.icons_dictionary['help-contents'], statusTip=translate( 'VTGUI', "Open the ViTables User's Guide", 'Status bar text for the Help -> Users Guide action')) actions['helpUsersGuide'].setObjectName('helpUsersGuide') actions['helpAbout'] = QtWidgets.QAction( translate('VTGUI', '&About ViTables', 'Help -> About'), self, triggered=self.vtapp.helpAbout, icon=self.icons_dictionary['vitables_wm'], statusTip=translate( 'VTGUI', 'Display information about ViTables', 'Status bar text for the Help -> About action')) actions['helpAbout'].setObjectName('helpAbout') actions['helpAboutQt'] = QtWidgets.QAction( translate('VTGUI', 'About &Qt', 'Help -> About Qt'), self, triggered=self.vtapp.helpAboutQt, statusTip=translate( 'VTGUI', 'Display information about the Qt library', 'Status bar text for the Help -> About Qt action')) actions['helpAboutQt'].setObjectName('helpAboutQt') actions['helpVersions'] = QtWidgets.QAction( translate('VTGUI', 'Show &Versions', 'Help -> Show Versions'), self, triggered=self.vtapp.helpVersions, statusTip=translate( 'VTGUI', 'Show the versions of the libraries used by ViTables', 'Status bar text for the Help -> Show Versions action')) actions['helpVersions'].setObjectName('helpVersions') actions['calculate'] = QtWidgets.QAction( translate('VTGUI', 'Calculate...', 'Calculate action'), self, triggered=calculator.run, statusTip=translate( 'VTGUI', 'Run calculation on opened tables.', 'Action tip')) actions['calculate'].setObjectName('calculate') return actions def setupToolBars(self): """ Set up the main window toolbars. Toolbars are made of actions. """ # File toolbar self.file_toolbar = self.addToolBar( translate('VTGUI', 'File operations', 'Toolbar title')) # Warning! Do NOT use 'File toolbar' as a object name or it will # show an strange behaviour (a Qt bug I think): it will always # be added to the left and will expand the whole top area self.file_toolbar.setObjectName('File') actions = ['fileNew', 'fileOpen', 'fileClose', 'fileSaveAs'] vitables.utils.addActions(self.file_toolbar, actions, self.gui_actions) # Reset the tooltip of the File -> Open... button file_open_button = self.file_toolbar.widgetForAction( self.gui_actions['fileOpen']) file_open_button.setToolTip(translate( 'VTGUI', """Click to open a """ """file\nClick and hold to open a recent file""", 'File toolbar -> Open Recent Files')) # Node toolbar self.node_toolbar = self.addToolBar( translate('VTGUI', 'Node operations', 'Toolbar title')) self.node_toolbar.setObjectName('Node toolbar') actions = ['nodeNew', 'nodeCut', 'nodeCopy', 'nodePaste', 'nodeDelete'] vitables.utils.addActions(self.node_toolbar, actions, self.gui_actions) # Query toolbar self.query_toolbar = self.addToolBar( translate('VTGUI', 'Queries on tables', 'Toolbar title')) self.query_toolbar.setObjectName('Query toolbar') actions = ['queryNew', 'queryDeleteAll'] vitables.utils.addActions(self.query_toolbar, actions, self.gui_actions) # Help toolbar self.help_toolbar = self.addToolBar(translate('VTGUI', 'Help system', 'Toolbar title')) self.help_toolbar.setObjectName('Help toolbar') actions = ['helpUsersGuide'] vitables.utils.addActions(self.help_toolbar, actions, self.gui_actions) whatis = QtWidgets.QWhatsThis.createAction(self.help_toolbar) whatis.setStatusTip(translate( 'VTGUI', 'Whats this? help for a widget', 'Status bar text for the Help -> Whats This action')) whatis.setShortcut(QtGui.QKeySequence()) self.help_toolbar.addAction(whatis) def initStatusBar(self): """Initialise the status bar.""" status_bar = self.statusBar() self.sb_node_info = QtWidgets.QLabel(status_bar) self.sb_node_info.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum) status_bar.addPermanentWidget(self.sb_node_info) self.sb_node_info.setToolTip(translate( 'VTGUI', 'The node currently selected in the Tree of ' 'databases pane', 'The Selected node box startup message')) status_bar.showMessage(translate('VTGUI', 'Ready...', 'The status bar startup message')) def setupMenus(self): """ Set up the main window menus. Popus are made of actions, items and separators. The `Window` menu is a special case due to its dynamic nature. Its contents depend on the number of existing views. In order to track changes and keep updated the menu, it is reloaded every time it is about to be displayed. """ # Create the File menu and add actions/submenus/separators to it self.file_menu = self.menuBar().addMenu(translate( 'VTGUI', "&File", 'The File menu entry')) self.file_menu.setObjectName('file_menu') self.open_recent_submenu = QtWidgets.QMenu( translate('VTGUI', 'Open R&ecent Files', 'File -> Open Recent Files')) self.open_recent_submenu.setObjectName('open_recent_submenu') self.open_recent_submenu.setSeparatorsCollapsible(False) self.open_recent_submenu.setIcon( self.icons_dictionary['document-open-recent']) file_actions = ['fileNew', 'fileOpen', 'fileOpenRO', self.open_recent_submenu, None, 'fileClose', 'fileCloseAll', None, 'fileSaveAs', None, 'fileExit'] vitables.utils.addActions(self.file_menu, file_actions, self.gui_actions) file_open_button = self.file_toolbar.widgetForAction( self.gui_actions['fileOpen']) file_open_button.setMenu(self.open_recent_submenu) self.open_recent_submenu.aboutToShow.connect(self.updateRecentSubmenu) # Create the Node menu and add actions/submenus/separators to it self.node_menu = self.menuBar().addMenu( translate('VTGUI', "&Node", 'The Node menu entry')) self.node_menu.setObjectName('node_menu') node_actions = ['nodeOpen', 'nodeClose', 'nodeProperties', None, 'nodeNew', 'nodeRename', 'nodeCut', 'nodeCopy', 'nodePaste', 'nodeDelete'] vitables.utils.addActions(self.node_menu, node_actions, self.gui_actions) # Create the Dataset menu and add actions/submenus/separators to it self.dataset_menu = self.menuBar().addMenu( translate('VTGUI', "&Dataset", 'The Dataset menu entry')) self.dataset_menu.setObjectName('dataset_menu') dataset_actions = ['queryNew', 'calculate', None] vitables.utils.addActions(self.dataset_menu, dataset_actions, self.gui_actions) # Create the Settings menu and add actions/submenus/separators to it settings_menu = self.menuBar().addMenu( translate('VTGUI', "&Settings", 'The Settings menu entry')) settings_menu.setObjectName('settings-menu') self.toolbars_submenu = self.createPopupMenu() self.toolbars_submenu.menuAction().setText( translate('VTGUI', 'ToolBars', 'Tools -> ToolBars action')) settings_actions = ['settingsPreferences', None, self.toolbars_submenu] vitables.utils.addActions(settings_menu, settings_actions, self.gui_actions) # Create the Window menu and add actions/menus/separators to it self.window_menu = self.menuBar().addMenu( translate('VTGUI', "&Window", 'The Windows menu entry')) self.window_menu.setObjectName('window_menu') windows_actions = ['windowCascade', 'windowTile', 'windowRestoreAll', 'windowMinimizeAll', 'windowClose', 'windowCloseAll', None, 'mdiTabbed', 'windowSeparator'] vitables.utils.addActions(self.window_menu, windows_actions, self.gui_actions) self.window_menu.setSeparatorsCollapsible(True) self.window_menu.aboutToShow.connect(self.updateWindowMenu) # Create the Help menu and add actions/menus/separators to it help_menu = self.menuBar().addMenu( translate('VTGUI', "&Help", 'The Help menu entry')) help_menu.setObjectName('help_menu') help_actions = ['helpUsersGuide', None, 'helpAbout', 'helpAboutQt', 'helpVersions', None] vitables.utils.addActions(help_menu, help_actions, self.gui_actions) whatis = QtWidgets.QWhatsThis.createAction(help_menu) whatis.setStatusTip( translate('VTGUI', 'Context help', 'Status bar text for the Help -> Whats This action')) help_menu.addAction(whatis) ######################################################### # # Context menus # ######################################################### self.view_cm = QtWidgets.QMenu() actions = ['fileNew', 'fileOpen', 'fileOpenRO', self.open_recent_submenu, None, 'fileClose', 'fileCloseAll', None, 'fileSaveAs', None, 'fileExit'] vitables.utils.addActions(self.view_cm, actions, self.gui_actions) self.root_node_cm = QtWidgets.QMenu() actions = ['fileClose', 'fileSaveAs', None, 'nodeProperties', None, 'nodeNew', 'nodeCopy', 'nodePaste', None, 'queryDeleteAll'] vitables.utils.addActions(self.root_node_cm, actions, self.gui_actions) self.group_node_cm = QtWidgets.QMenu() actions = ['nodeProperties', None, 'nodeNew', 'nodeRename', 'nodeCut', 'nodeCopy', 'nodePaste', 'nodeDelete'] vitables.utils.addActions(self.group_node_cm, actions, self.gui_actions) self.leaf_node_cm = QtWidgets.QMenu() actions = ['nodeOpen', 'nodeClose', None, 'nodeProperties', None, 'nodeRename', 'nodeCut', 'nodeCopy', 'nodePaste', 'nodeDelete', None, 'queryNew'] vitables.utils.addActions(self.leaf_node_cm, actions, self.gui_actions) self.mdi_cm = QtWidgets.QMenu() actions = [self.window_menu] vitables.utils.addActions(self.mdi_cm, actions, self.gui_actions) def closeEvent(self, event): """ Handle close events. Clicking the close button of the main window titlebar causes the application quitting immediately, leaving things in a non consistent state. This event handler ensures that the needed tidy up is done before quitting. :Parameter event: the close event being handled """ # Do the required tidy up self.vtapp.fileExit() # Quit event.accept() # Explicit deletion is required here as a workaround of a PyQt4 # v4.8.2 bug. See thread in # the PyQt4 mailing list for details del self.toolbars_submenu QtWidgets.qApp.quit() def makeCopy(self): """Copy text/leaf depending on which widget has focus. This methos disambiguates the ``Ctrl+C`` shortcut. If the console has focus then ``Ctrl+C`` will copy the console selected text. If the databases tree view has focus then the selected node (if any) will be copied. """ if self.dbs_tree_view.hasFocus(): self.vtapp.nodeCopy() elif self.logger.hasFocus(): self.logger.copy() # Updating appearance means: # # * changing the toolbar buttons look when their tied QActions are # enabled/disabled # * updating content of menus and submenus # # Updating state means: # # * toggling state of QActions i.e. enabling/disabling QActions # def updateActions(self): """ Update the state of the actions tied to menu items and toolbars. Every time that the selected item changes in the tree viewer the state of the actions must be updated because it depends on the type of selected item (leaf or group, opening mode etc.). The following events trigger a call to this slot: * insertion/deletion of rows in the tree of databases model * changes in the selection state of the tree of databases view The slot should be manually called when a new view is activated in the workspace (for instance by methods :meth:`vitables.vtapp.VTApp.nodeOpen`, :meth:`vitables.vtapp.VTApp.nodeClose`). .. _Warning: Warning! Don\'t call this method until the GUI initialisation finishes. """ # The following actions are always active: # fileNew, fileOpen, fileOpenRO, fileExit and the Help menu actions # The set of actions that can be enabled or disabled actions = frozenset(['fileClose', 'fileCloseAll', 'fileSaveAs', 'nodeOpen', 'nodeClose', 'nodeProperties', 'nodeNew', 'nodeRename', 'nodeCut', 'nodeCopy', 'nodePaste', 'nodeDelete', 'queryNew', 'queryDeleteAll']) enabled = set([]) model_rows = self.dbs_tree_model.rowCount(QtCore.QModelIndex()) if model_rows <= 0: return # If there are open files aside the temporary DB if model_rows > 1: enabled = enabled.union(['fileCloseAll']) # if there are filtered tables --> queryDeleteAll is enabled tmp_index = self.dbs_tree_model.index(model_rows - 1, 0, QtCore.QModelIndex()) ftables = self.dbs_tree_model.rowCount(tmp_index) if ftables > 0: enabled = enabled.union(['queryDeleteAll']) current = self.dbs_tree_view.currentIndex() node = self.dbs_tree_model.nodeFromIndex(current) if node != self.dbs_tree_model.root: # Actions always enabled for every node enabled = enabled.union(['nodeProperties', 'nodeCopy']) # If the selected file is not the temporary DB if node.filepath != self.dbs_tree_model.tmp_filepath: enabled = enabled.union(['fileSaveAs', 'fileClose']) kind = node.node_kind # If the node is a table --> queryNew is enabled if kind == 'table': enabled = enabled.union(['queryNew']) # If the file is not open in read-only mode mode = self.dbs_tree_model.getDBDoc(node.filepath).mode if mode != 'r': if kind == 'root group': enabled = enabled.union(['nodeNew', 'nodePaste']) elif kind == 'group': enabled = enabled.union(['nodeNew', 'nodeRename', 'nodeCut', 'nodePaste', 'nodeDelete']) elif kind == 'table': enabled = enabled.union(['nodeRename', 'nodeCut', 'nodeDelete']) else: enabled = enabled.union(['nodeRename', 'nodeCut', 'nodeDelete']) if kind not in ('group', 'root group'): if node.has_view: enabled = enabled.union(['nodeClose']) else: enabled = enabled.union(['nodeOpen']) disabled = actions.difference(enabled) for action in enabled: self.gui_actions[action].setEnabled(True) for action in disabled: self.gui_actions[action].setDisabled(True) def updateRecentSubmenu(self): """Update the content of the `Open Recent File...` submenu.""" index = 0 self.open_recent_submenu.clear() iconset = vitables.utils.getIcons() for item in self.vtapp.config.recent_files: index += 1 (mode, filepath) = item.split('#@#') action = QtWidgets.QAction('{0:>2} {1}.'.format(index, filepath), self, triggered=self.vtapp.openRecentFile) action.setData(item) if mode == 'r': action.setIcon(iconset['file_ro']) else: action.setIcon(iconset['file_rw']) self.open_recent_submenu.addAction(action) # Always add a separator and a clear QAction. So if the menu is empty # the user still will know what's going on self.open_recent_submenu.addSeparator() action = QtWidgets.QAction( translate('VTGUI', '&Clear', 'Recent File submenu entry'), self, triggered=self.vtapp.clearRecentFiles) self.open_recent_submenu.addAction(action) def updateWindowMenu(self): """ Update the `Window` menu. The `Window` menu is dynamic because its content is determined by the currently open views. Because the number of these views or its contents may vary at any moment we must update the `Window` menu every time it is open. For simplicity we don't keep track of changes in the menu content. Instead, we clean and create it from scratch every time it is about to show. """ # Clear the menu and rebuild it from scratch wmenu = self.window_menu wmenu.clear() window_actions = ['windowCascade', 'windowTile', 'windowRestoreAll', 'windowMinimizeAll', 'windowClose', 'windowCloseAll', None, 'mdiTabbed', 'windowSeparator'] vitables.utils.addActions(wmenu, window_actions, self.gui_actions) windows_list = self.workspace.subWindowList() if not windows_list: return # Create actions for the existing views action_group = QtWidgets.QActionGroup(wmenu) wmenu.action_group = action_group counter = 1 for window in windows_list: title = window.windowTitle() if counter < 10: action = wmenu.addAction("&{0:d} {1}".format(counter, title)) wmenu.action_group.addAction(action) elif counter == 10: wmenu.addSeparator() submenu = wmenu.addMenu( translate('VTGUI', "&More...", 'A Windows submenu')) action_subgroup = QtWidgets.QActionGroup(submenu) elif counter < 36: atext = "&{0} {1}".format(chr(counter + ord("@") - 10), title) action = submenu.addAction(atext) action_subgroup.addAction(action) self.window_mapper.setMapping(action, window) action.triggered.connect(self.window_mapper.map) action.setCheckable(True) if self.workspace.activeSubWindow() == window: action.setChecked(True) counter = counter + 1 def updateStatusBar(self): """Update the permanent message of the status bar. """ current = self.dbs_tree_view.currentIndex() if current.isValid(): tip = self.dbs_tree_model.data(current, QtCore.Qt.StatusTipRole) message = tip else: message = '' self.sb_node_info.setText(message) def popupContextMenu(self, kind, pos): """ Popup a context menu in the tree of databases view. When a point of the tree view is right clicked, a context popup is displayed. The content of the popup depends on the kind of node pointed: no node, root group, group or leaf. :Parameters: - `kind`: defines the content of the menu - `pos`: the clicked point in global coordinates """ if kind == 'view': menu = self.view_cm elif kind == 'root group': menu = self.root_node_cm elif kind == 'group': menu = self.group_node_cm else: menu = self.leaf_node_cm menu.popup(pos) def closeChildrenViews(self, nodepath, filepath): """Close views being overwritten during node editing. :Parameters: - `nodepath`: the full path of the node that is overwrting other nodes - `filepath`: the full path of the file where that node lives """ for window in self.workspace.subWindowList(): wnodepath = window.dbt_leaf.nodepath wfilepath = window.dbt_leaf.filepath if not wfilepath == filepath: continue if wnodepath[0:len(nodepath)] == nodepath: window.close() def changeMDIViewMode(self): """Toggle the view mode of the workspace. """ if self.workspace.viewMode() == QtWidgets.QMdiArea.SubWindowView: self.workspace.setViewMode(QtWidgets.QMdiArea.TabbedView) else: self.workspace.setViewMode(QtWidgets.QMdiArea.SubWindowView) def eventFilter(self, widget, event): """Event filter used to provide the workspace with a context menu. :Parameters: - `widget`: the widget that receives the event - `event`: the event being processed """ if widget == self.workspace: if event.type() == QtCore.QEvent.ContextMenu: # If active mdi subwindow can handle context menu # pass the event to it active_window = self.workspace.activeSubWindow() if active_window is not None and \ hasattr(active_window, 'is_context_menu_custom'): is_cm_custom = active_window.is_context_menu_custom else: is_cm_custom = False if not is_cm_custom: pos = event.globalPos() self.mdi_cm.popup(pos) return QtWidgets.QMdiArea.eventFilter(widget, widget, event) else: return QtWidgets.QMainWindow.eventFilter(self, widget, event) ViTables-3.0.0/vitables/vtsite.py000066400000000000000000000026371311223072700167320ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Site configuration module. This module indicates the full install path of the ``ViTables`` package to the running :meth:`vitables.vtapp.VTApp` instance. Mac OS X boxes use the module as is. Misc variables: * __docformat__ * INSTALLDIR * ICONDIR * DOCDIR * PLUGINSDIR """ __docformat__ = 'restructuredtext' import os.path INSTALLDIR = os.path.dirname(__file__) ICONDIR = os.path.join(INSTALLDIR, "icons") DOCDIR = os.path.join(INSTALLDIR, "htmldocs") PLUGINSDIR = os.path.join(INSTALLDIR, "plugins") ViTables-3.0.0/vitables/vtsplash.py000066400000000000000000000045751311223072700172630ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Here is defined the VTSplash class. It displays the splash screen during the ``ViTables`` startup and shows the advance of the startup sequence. """ __docformat__ = 'restructuredtext' import time from qtpy import QtCore, QtGui, QtWidgets class VTSplash(QtWidgets.QSplashScreen): """ The application splash screen. :Parameter png: the pixmap image displayed as a splash screen. """ def __init__(self, png): """ Initialize the application. Create a splash screen and ties it to a painter which will be in charge of displaying the needed messages. """ super(VTSplash, self).__init__(png) self.msg = '' def drawContents(self, painter): """Draw the contents of the splash screen using the given painter. This is an overloaded method. It draws contents with the origin translated by a certain offset. :Parameter painter: the painter used to draw the splash screen """ painter.setPen(QtGui.QColor(QtCore.Qt.white)) font = painter.font() font.setBold(True) painter.setFont(font) painter.drawText(10, 215, self.msg) def drawMessage(self, msg): """ Draw the message text onto the splash screen. :Parameter msg: the message to be displayed """ QtWidgets.qApp.processEvents() self.msg = msg self.showMessage(self.msg) time.sleep(0.500) self.clearMessage() ViTables-3.0.0/vitables/vttables/000077500000000000000000000000001311223072700166565ustar00rootroot00000000000000ViTables-3.0.0/vitables/vttables/__init__.py000066400000000000000000000017141311223072700207720ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["buffer", "datasheet", "leaf_delegate", "leaf_model", "leaf_view", "scrollbar"] ViTables-3.0.0/vitables/vttables/buffer.py000066400000000000000000000344541311223072700205130ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module implements a buffer used to access the real data contained in `PyTables` datasets. By using this buffer we speed up the access to the stored data. As a consequence, views (widgets showing a tabular representation of the dataset) are painted much faster too. """ __docformat__ = 'restructuredtext' import warnings import logging from qtpy import QtGui from qtpy import QtWidgets import numpy import tables import vitables.utils translate = QtWidgets.QApplication.translate # Restrict the available flavors to 'numpy' so that reading a leaf # always return a numpy array instead of an object of the kind indicated # by the leaf flavor. For VLArrays the read data is returned as a list whose # elements will be numpy arrays. tables.restrict_flavors(keep=['numpy']) warnings.filterwarnings('ignore', category=tables.FlavorWarning) warnings.filterwarnings('ignore', category=tables.NaturalNameWarning) class Buffer(object): """Buffer used to access the real data contained in `PyTables` datasets. Note that the buffer number of rows **must** be at least equal to the number of rows of the table widget it is going to fill. This way we avoid to have partially filled tables. Also note that rows in buffer are numbered from 0 to N (as it happens with the data source). Leaves are displayed in MxN table widgets: - scalar arrays are displayed in a 1x1 table. - 1D arrays are displayed in a Mx1 table. - KD arrays are displayed in a MxN table. - tables are displayed in a MxN table with one field per column Implementing a reader method for each case allows us to choose at document creation time which method will be used. It works *much* faster than a global reader method that has to decide which block of code must be executed at every cell painting time. :Parameter leaf: the data source (`tables.Leaf` instance) from which data are going to be read. """ def __init__(self, leaf): """ Initializes the buffer. """ self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) self.data_source = leaf # The maximum number of rows to be read from the data source self.chunk_size = 10000 # The length of the dimension that is going to be read. It # is an int64. self.leaf_numrows = self.leafNumberOfRows() if self.leaf_numrows <= self.chunk_size: self.chunk_size = self.leaf_numrows # The numpy array where read data will be stored self.chunk = numpy.array([]) # The document row where the current chunk of data starts. # It must be an int64 in order to address spaces bigger than 2**32 self.start = numpy.array(0, dtype=numpy.int64) # The method used for reading data depends on the kind of node. # Setting the reader method at initialization time increases the # speed of reading several orders of magnitude shape = leaf.shape if isinstance(leaf, tables.Table): # Dataset elements will be read like a[row][column] self.getCell = self.arrayCell elif isinstance(leaf, tables.EArray): self.getCell = self.EArrayCell elif isinstance(leaf, tables.VLArray): # Array elements will be read like a[row] self.getCell = self.vectorCell elif shape == (): # Array element will be read like a[()] self.getCell = self.scalarCell elif (len(shape) == 1): # Array elements will be read like a[row] self.getCell = self.vectorCell elif len(shape) > 1: # Dataset elements will be read like a[row][column] self.getCell = self.arrayCell def __del__(self): """Release resources before destroying the buffer. """ self.chunk = None def leafNumberOfRows(self): """The number of rows of the dataset being read. We don't use the `Leaf.nrows` attribute because it is not always suitable for displaying the data in a 2D grid. Instead we use the `Leaf.shape` attribute and map it to a number of rows useful for our purposes. The returned number of rows may differ from that returned by the `nrows` attribute in scalar arrays and `EArrays`. :Returns: the size of the first dimension of the document """ shape = self.data_source.shape if shape is None: # Node is not a Leaf or there was problems getting the shape nrows = 0 elif shape == (): # Node is a rank 0 array (e.g. numpy.array(5)) nrows = 1 elif isinstance(self.data_source, tables.EArray): # Warning: the number of rows of an EArray, ea, can be different # from the number of rows of the numpy array ea.read() nrows = self.data_source.shape[0] else: nrows = self.data_source.nrows return numpy.array(nrows, dtype=numpy.int64) def getReadParameters(self, start, buffer_size): """ Returns acceptable parameters for the read method. :Parameters: - `start`: the document row that is the first row of the chunk. It *must* be a 64 bits integer. - `buffer_size`: the buffer size, i.e. the number of rows to be read. :Returns: a tuple with tested values for the parameters of the read method """ first_row = numpy.array(0, dtype=numpy.int64) last_row = self.leaf_numrows # When scrolling up we must keep start value >= first_row if start < first_row: start = first_row # When scrolling down we must keep stop value <= last_row stop = start + buffer_size if stop > last_row: stop = last_row # Ensure that the whole buffer will be filled if stop - start < self.chunk_size: start = stop - self.chunk_size return start, stop def isDataSourceReadable(self): """Find out if the dataset can be read or not. This is not a complex test. It simply try to read a small chunk of data at the beginning of the dataset. If it cannot then the dataset is considered unreadable. """ readable = True start, stop = self.getReadParameters(numpy.array(0, dtype=numpy.int64), self.chunk_size) try: self.data_source.read(start, stop) except tables.HDF5ExtError: readable = False self.logger.error( translate('Buffer', """Problems reading records. The dataset """ """seems to be compressed with the {0} library. """ """Check that it is installed in your system, """ """please.""", 'A dataset readability error').format( self.data_source.filters.complib)) except ValueError as e: readable = False self.logger.error( translate('Buffer', 'Data read error: {}', 'A dataset read error').format(e.message)) return readable def readBuffer(self, start, buffer_size): """ Read a chunk from the data source. The size of the chunk is given in number of rows, and might be smaller than the requested one if the beginning/end of the document is reached when reading. Data read from `VLArrays` are returned as a Python list of objects of the current flavor (usually ``numpy`` arrays). Any other kind of `tables.Leaf` returns a ``numpy`` array (see comments on restricted_flavors above) :Parameters: - `start`: the document row that is the first row of the chunk. It *must* be a 64 bits integer. - `buffer_size`: the buffer size, i.e. the number of rows to be read. """ start, stop = self.getReadParameters(start, buffer_size) try: # data_source is a tables.Table or a tables.XArray # but data is a numpy array # Warning: in a EArray with shape (2,3,3) and extdim attribute # being 1, the read method will have 3 rows. However, the numpy # array returned by EArray.read() will have only 2 rows data = self.data_source.read(start, stop) except tables.HDF5ExtError: self.logger.error( translate('Buffer', """\nError: problems reading records. """ """The dataset maybe corrupted.""", 'A dataset readability error')) except: vitables.utils.formatExceptionInfo() else: # Update the buffer contents and its start position self.chunk = data self.start = start def scalarCell(self, row, col): """ Returns a cell of a scalar array view. The indices values are not checked (and could not be in the buffer) so they should be checked by the caller methods. :Parameters: - `row`: the row to which the cell belongs. It is a 64 bits integer - `col`: the column to wich the cell belongs :Returns: the cell at position `(row, col)` of the document """ try: return self.chunk[()] except IndexError: self.logger.error('IndexError! buffer start: {0} row, column: ' '{1}, {2}'.format(self.start, row, col)) def vectorCell(self, row, col): """ Returns a cell of a 1D-array view. VLArrays, for instance, always are read with this method. If no pseudo atoms are used then a list of arrays is returned. If vlstring is used then a list of raw bytes is returned. If vlunicode is used then a list of unicode strings is returned. If object is used then a list of Python objects is returned. The indices values are not checked (and could not be in the buffer) so they should be checked by the caller methods. :Parameters: - `row`: the row to which the cell belongs. It is a 64 bits integer - `col`: the column to wich the cell belongs :Returns: the cell at position `(row, col)` of the document """ # We must shift the row value by self.start units in order to # get the right chunk element. Note that indices of chunk # needn't to be int64 because they are indexing a fixed size, # small chunk of data (see ctor docstring). # chunk = [row0, row1, row2, ..., rowN] # and columns can be read from a given row using indexing notation try: return self.chunk[int(row - self.start)] except IndexError: self.logger.error('IndexError! buffer start: {0} row, column: ' '{1}, {2}'.format(self.start, row, col)) def EArrayCell(self, row, col): """ Returns a cell of a EArray view. The indices values are not checked (and could not be in the buffer) so they should be checked by the caller methods. :Parameters: - `row`: the row to which the cell belongs. It is a 64 bits integer - `col`: the column to wich the cell belongs :Returns: the cell at position `(row, col)` of the document """ # We must shift the row value by self.start units in order to # get the right chunk element. Note that indices of chunk # needn't to be int64 because they are indexing a fixed size, # small chunk of data (see ctor docstring). # chunk = [row0, row1, row2, ..., rowN] # and columns can be read from a given row using indexing notation # TODO: this method should be improved as it requires to read the # whola array keeping the read data in memory try: return self.data_source.read()[int(row - self.start)] except IndexError: self.logger.error('IndexError! buffer start: {0} row, column: ' '{1}, {2}'.format(self.start, row, col)) def arrayCell(self, row, col): """ Returns a cell of a ND-array view or a table view. The indices values are not checked (and could not be in the buffer) so they should be checked by the caller methods. :Parameters: - `row`: the row to which the cell belongs. It is a 64 bits integer - `col`: the column to wich the cell belongs :Returns: the cell at position `(row, col)` of the document """ # We must shift the row value by self.start units in order to get the # right chunk element. Note that indices of chunk needn't to be # int64 because they are indexing a fixed size, small chunk of # data (see ctor docstring). # For arrays we have # chunk = [row0, row1, row2, ..., rowN] # and columns can be read from a given row using indexing notation # For tables we have # chunk = [nestedrecord0, nestedrecord1, ..., nestedrecordN] # and fields can be read from nestedrecordJ using indexing notation try: return self.chunk[int(row - self.start)][col] except IndexError: self.logger.error('IndexError! buffer start: {0} row, column: ' '{1}, {2}'.format(self.start, row, col)) ViTables-3.0.0/vitables/vttables/datasheet.py000066400000000000000000000134351311223072700212000ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a widget that wraps the view widget of leaves. When a leaf node is opened in the tree of databases view the data stored in that leaf will be displayed in the workspace using this wrapper widget. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils import vitables.nodeprops.nodeinfo as nodeinfo import vitables.vtwidgets.zoom_cell as zoom_cell import vitables.vttables.leaf_model as leaf_model import vitables.vttables.leaf_view as leaf_view import vitables.vttables.buffer as readBuffer class DataSheet(QtWidgets.QMdiSubWindow): """ The widget containing the displayed data of a given dataset. :Parameter index: the index (in the tree of databases model) of the leaf whose data will be displayed """ def __init__(self, index): """Display a given dataset in the MDI area. """ # The main application window self.vtgui = vitables.utils.getVTApp().gui # The data structure (LeafNode/LinkNode instance) whose dataset # is being displayed dbt_model = self.vtgui.dbs_tree_model self.dbt_leaf = dbt_model.nodeFromIndex(index) # The tables.Node instance tied to that data structure pt_node = self.dbt_leaf.node if hasattr(pt_node, 'target'): # The selected item is a link and must be dereferenced leaf = pt_node() else: leaf = pt_node rbuffer = readBuffer.Buffer(leaf) self.leaf_model = leaf_model.LeafModel(rbuffer) self.leaf_view = leaf_view.LeafView(self.leaf_model) super(DataSheet, self).__init__(self.vtgui.workspace, QtCore.Qt.SubWindow) self.setWidget(self.leaf_view) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) # Customize the title bar if not isinstance(leaf.title, str): title = str(leaf.title) else: title = leaf.title wtitle = "{0}\t{1}".format(self.dbt_leaf.name, title) self.setWindowTitle(wtitle) self.setWindowIcon(self.dbt_leaf.icon) # Eventually update the Node menu actions self.dbt_leaf.has_view = True self.vtgui.updateActions() self.pindex = QtCore.QPersistentModelIndex(index) # Connect signals to slots self.aboutToActivate.connect(self.syncTreeView) self.leaf_view.doubleClicked.connect(self.zoomCell) def closeEvent(self, event): """Close the window cleanly with the close button of the title bar. :Parameter event: the event being processed """ # Ensure that Node menu actions are properly updated self.dbt_leaf.has_view = False self.vtgui.updateActions() # Propagate the event. In the process, self.widget().closeEvent # will be called QtWidgets.QMdiSubWindow.closeEvent(self, event) if self.vtgui.workspace.subWindowList() == []: self.vtgui.dbs_tree_view.setFocus(True) def focusInEvent(self, event): """Specialised handler for focus events. Synchronize with the tree view when the view gets keyboard focus. :Parameter event: the event being processed """ # Sync the workspace with the tree view (if needed) but keep the # focus (giving focus to the tree view when a given view is # clicked is counter intuitive) QtWidgets.QMdiSubWindow.focusInEvent(self, event) self.syncTreeView() self.setFocus(True) def syncTreeView(self): """ If the view is activated select its leaf in the tree of databases view. """ if self.vtgui.editing_dlg is not None: self.vtgui.editing_dlg = None return # Locate the tree view leaf tied to this data sheet. Persistent # indices are used to get direct access to the leaf so we don't # have to walk the tree self.vtgui.dbs_tree_view.setCurrentIndex( QtCore.QModelIndex(self.pindex)) def zoomCell(self, index): """Display the inner dimensions of a cell. :Parameter index: the index (in the leaf model) of the cell being zoomed """ row = index.row() column = index.column() tmodel = index.model() data = tmodel.rbuffer.getCell(tmodel.rbuffer.start + row, column) # The title of the zoomed view node = self.dbt_leaf info = nodeinfo.NodeInfo(node) if node.node_kind == 'table': col = info.columns_names[column] title = '{0}: {1}[{2}]'.format(node.name, col, tmodel.rbuffer.start + row) else: title = '{0}: ({1},{2})'.format(node.name, tmodel.rbuffer.start + row, column) zoom_cell.ZoomCell(data, title, self.vtgui.workspace, self.dbt_leaf) ViTables-3.0.0/vitables/vttables/leaf_delegate.py000066400000000000000000000072711311223072700220000ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ A custom delegate for rendering selected cells. As explained in the leaf_view module the current cell must be rendered differently depending on the buffer being displayed. If the dataset row of the current/selected cell is in the range of rows being displayed then the cell should be rendered in the standard way. If it is not then it should always be rendered unselected. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets class LeafDelegate(QtWidgets.QStyledItemDelegate): """ A delegate for rendering selected cells. :Parameter parent: the parent of this widget """ def paint(self, painter, option, index): """Renders the delegate for the item specified by index. This method handles specially the result returned by the model data() method for the Qt.BackgroundRole role. Typically, if the cell being rendered is selected then the data() returned value is ignored and the value set by the desktop (KDE, Gnome...) is used. We need to change that behavior as explained in the module docstring. The following properties of the style option are used for customising the painting: state (which holds the state flags), rect (which holds the area that should be used for painting) and palette (which holds the palette that should be used when painting) :Parameters: - `painter`: the painter used for rendering - `option`: the style option used for rendering - `index`: the index of the rendered item """ # option.state is an ORed combination of flags if (option.state & QtWidgets.QStyle.State_Selected): model = index.model() buffer_start = model.rbuffer.start cell = index.model().selected_cell if ((index == cell['index']) and \ (buffer_start != cell['buffer_start'])): painter.save() self.initStyleOption(option, index) background = option.palette.color(QtGui.QPalette.Base) foreground = option.palette.color(QtGui.QPalette.Text) painter.setBrush(QtGui.QBrush(background)) painter.fillRect(option.rect, painter.brush()) painter.translate(option.rect.x() + 3, option.rect.y()) painter.setBrush(QtGui.QBrush(foreground)) painter.drawText( option.rect, QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop, model.data(index)) painter.restore() else: QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) else: QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) ViTables-3.0.0/vitables/vttables/leaf_model.py000066400000000000000000000166641311223072700213340ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module implements a model (in the `MVC` sense) for the real data stored in a `tables.Leaf`. """ __docformat__ = 'restructuredtext' import collections import tables import numpy as np from qtpy import QtCore import vitables.utils class LeafModel(QtCore.QAbstractTableModel): """ The model for real data contained in leaves. The data is read from data sources (i.e., `HDF5/PyTables` nodes) by the model. :Parameters: - `rbuffer`: a buffer used for optimizing read access to data - `parent`: the parent of the model """ def __init__(self, rbuffer, parent=None): """Create the model. """ # The model data source (a PyTables/HDF5 leaf) and its access buffer self.data_source = rbuffer.data_source self.rbuffer = rbuffer # The number of digits of the last row self.last_row_width = len(str(self.rbuffer.leaf_numrows)) # # The table dimensions # # The dataset number of rows is potentially huge but tables are # kept small: just the data returned by a read operation of the # buffer are displayed self.numrows = self.rbuffer.leafNumberOfRows() if self.numrows > self.rbuffer.chunk_size: self.numrows = self.rbuffer.chunk_size # The dataset number of columns doesn't use to be large so, we don't # need set a maximum as we did with rows. The whole set of columns # are displayed if isinstance(self.data_source, tables.Table): # Leaf is a PyTables table self.numcols = len(self.data_source.colnames) elif isinstance(self.data_source, tables.EArray): self.numcols = 1 else: # Leaf is some kind of PyTables array shape = self.data_source.shape if len(shape) > 1: # The leaf will be displayed as a bidimensional matrix self.numcols = shape[1] else: # The leaf will be displayed as a column vector self.numcols = 1 # # Choose a format for cells # self.formatContent = vitables.utils.formatArrayContent # Time series (if they are found) are formatted transparently # via the time_series.py plugin if not isinstance(self.data_source, tables.Table): # Leaf is some kind of PyTables array atom_type = self.data_source.atom.type if atom_type == 'object': self.formatContent = vitables.utils.formatObjectContent elif atom_type in ('vlstring', 'vlunicode'): self.formatContent = vitables.utils.formatStringContent # Track selected cell self.selected_cell = {'index': QtCore.QModelIndex(), 'buffer_start': 0} # Populate the model with the first chunk of data self.loadData(self.rbuffer.start, self.rbuffer.chunk_size) super(LeafModel, self).__init__(parent) def _collect_enum_indices(self): """Initialize structures required to properly display enum columns.""" def headerData(self, section, orientation, role): """Returns the data for the given role and section in the header with the specified orientation. This is an overwritten method. :Parameters: - `section`: the header section being inspected - `orientation`: the header orientation (horizontal or vertical) - `role`: the role of the header section being inspected """ # The section alignment if role == QtCore.Qt.TextAlignmentRole: if orientation == QtCore.Qt.Horizontal: return int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) return int(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) if role != QtCore.Qt.DisplayRole: return None # The section label for horizontal header if orientation == QtCore.Qt.Horizontal: # For tables horizontal labels are column names, for arrays # the section numbers are used as horizontal labels if hasattr(self.data_source, 'description'): return str(self.data_source.colnames[section]) return str(section) # The section label for vertical header. This is a 64 bits integer return str(self.rbuffer.start + section) def data(self, index, role=QtCore.Qt.DisplayRole): """Returns the data stored under the given role for the item referred to by the index. This is an overwritten method. :Parameters: - `index`: the index of a data item - `role`: the role being returned """ if not index.isValid() or not (0 <= index.row() < self.numrows): return None cell = self.rbuffer.getCell(self.rbuffer.start + index.row(), index.column()) if role == QtCore.Qt.DisplayRole: return self.formatContent(cell) elif role == QtCore.Qt.TextAlignmentRole: return int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) else: return None def columnCount(self, index=QtCore.QModelIndex()): """The number of columns of the given model index. When implementing a table based model this method has to be overriden -because it is an abstract method- and should return 0 for valid indices (because they have no children). If the index is not valid the method should return the number of columns exposed by the model. :Parameter index: the model index being inspected. """ if not index.isValid(): return self.numcols else: return 0 def rowCount(self, index=QtCore.QModelIndex()): """The number of columns for the children of the given index. When implementing a table based model this method has to be overriden -because it is an abstract method- and should return 0 for valid indices (because they have no children). If the index is not valid the method should return the number of rows exposed by the model. :Parameter index: the model index being inspected. """ if not index.isValid(): return self.numrows else: return 0 def loadData(self, start, chunk_size): """Load the model with fresh data from the buffer. :Parameters: - `start`: the row where the buffer starts - `chunk_size`: the size of the buffer """ self.rbuffer.readBuffer(start, chunk_size) ViTables-3.0.0/vitables/vttables/leaf_view.py000066400000000000000000000764521311223072700212070ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module defines a view for the model bound to a `tables.Leaf` node. This view is used to display the real data stored in a `tables.Leaf` node in a tabular way: - scalar arrays are displayed in a 1x1 table. - 1D arrays are displayed in a Mx1 table. - KD arrays are displayed in a MxN table. - tables are displayed in a MxN table with one field per column """ __docformat__ = 'restructuredtext' import numpy from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.vttables.scrollbar as scrollbar import vitables.vttables.leaf_delegate as leaf_delegate class LeafView(QtWidgets.QTableView): """ A view for real data contained in leaves. This is a customised view intended to deal with huge datasets. :Parameters: - `tmodel`: the leaf model to be tied to this view - `parent`: the parent of this widget """ def __init__(self, tmodel, parent=None): """Create the view. """ super(LeafView, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.tmodel = tmodel # This is a MUST self.leaf_numrows = self.tmodel.rbuffer.leaf_numrows self.selection_model = self.selectionModel() self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems) # Setup the actual vertical scrollbar self.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) self.vscrollbar = self.verticalScrollBar() self.setModel(tmodel) # For potentially huge datasets use a customised scrollbar if self.leaf_numrows > self.tmodel.numrows: self.setItemDelegate(leaf_delegate.LeafDelegate()) self.rbuffer_fault = False self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.tricky_vscrollbar = scrollbar.ScrollBar(self) self.max_value = self.tvsMaxValue() self.tricky_vscrollbar.setMaximum(self.max_value) self.tricky_vscrollbar.setMinimum(0) self.interval_size = self.mapSlider2Leaf() # Setup the vertical header width self.vheader = QtWidgets.QHeaderView(QtCore.Qt.Vertical) self.setVerticalHeader(self.vheader) font = self.vheader.font() font.setBold(True) fmetrics = QtGui.QFontMetrics(font) max_width = fmetrics.width(" {0} ".format(str(self.leaf_numrows))) self.vheader.setMinimumWidth(max_width) self.vheader.setSectionsClickable(True) # Setup the headers' resize mode rmode = QtWidgets.QHeaderView.Stretch if self.tmodel.columnCount() == 1: self.horizontalHeader().setSectionResizeMode(rmode) if self.tmodel.rowCount() == 1: self.vheader.setSectionResizeMode(rmode) # Setup the text elide mode self.setTextElideMode(QtCore.Qt.ElideRight) # Connect signals to slots if self.leaf_numrows > self.tmodel.numrows: self.tricky_vscrollbar.actionTriggered.connect( self.navigateWithMouse) def tvsMaxValue(self): """Calulate the maximum range value of the tricky vertical scrollbar. """ # The scrollbar range must be a signed 32 bits integer so its # largest range is [0, 2**31 - 1] top_value = 2**31 - 1 if self.leaf_numrows <= top_value: top_value = self.leaf_numrows return top_value def mapSlider2Leaf(self): """Setup the interval size. Get the number of rows we move up/down on the dataset every time the slider's value moves up/down by 1 unit. The interval size is given by the formula:: int(self.leaf_numrows/self.max_value) Note that the larger is the number of rows the worse is this approach. In the worst case we would have an interval size of (2**64 - 1)/(2**31 - 1) = 2**33. Nevertheless the approach is quite good for number of rows about 2**33 (eight thousand million rows). In this case the interval size is about 4. """ # If the slider range equals to the number of rows of the dataset # then there is a 1:1 mapping between range values and dataset # rows and row equals to value interval_size = 1 if self.max_value < self.leaf_numrows: interval_size = numpy.rint(numpy.array( self.leaf_numrows/self.max_value, dtype=numpy.int64)) return interval_size def syncView(self): """Update the tricky scrollbar value after a data navigation. This method every time we navigate on the table (except when we press the Home/End keys). Unless we are at top/bottom of the dataset the update is done using the first visible row as a reference. """ offset = self.tmodel.rbuffer.start + 1 fv_label = self.vheader.logicalIndexAt(0) + offset lv_label = self.vheader.logicalIndexAt( self.vheader.viewport().height() - 1) + offset if lv_label == self.leaf_numrows : self.tricky_vscrollbar.setValue(self.max_value) elif fv_label == 1 : self.tricky_vscrollbar.setValue(0) else : value = numpy.rint(numpy.array(fv_label/self.interval_size, dtype=numpy.float64)) self.tricky_vscrollbar.setValue(value) def updateView(self): """Update the view contents after a buffer fault. """ self.vheader.headerDataChanged( QtCore.Qt.Vertical, 0, self.tmodel.numrows - 1) top_left = self.tmodel.index(0, 0) bottom_right = self.tmodel.index(self.tmodel.numrows - 1, self.tmodel.numcols - 1) self.dataChanged(top_left, bottom_right) def navigateWithMouse(self, slider_action): """Navigate the view with the mouse. On a regular table (with the scrollbar connected to the table view) this slot is called after the `action` has set the slider position but before the display has been updated (see documentation of the QAbstractSlider.actionTriggered signal in the Qt4 docs) so in this method we can safely do any action before that display update happens. In our case the slot is connected to the tricky scrollbar and its main functionality is to refresh model data if needed i.e, to detect buffer fault conditions and update the data display accordingly. If a buffer fault doesn't occur then the slider action is passed to the hidden scrollbar (which is connected to the table view) so that it can update the data display. :Parameter slider_action: the triggered slider action i.e., a member of the QAbstractSlider.SliderAction enum """ # The QAbstractSlider.SliderAction enum values used in this method # QtGui.QAbstractSlider.SliderSingleStepAdd -> 1 # QtGui.QAbstractSlider.SliderSingleStepSub -> 2 # QtGui.QAbstractSlider.SliderPageStepAdd -> 3 # QtGui.QAbstractSlider.SliderPageStepSub -> 4 # QtGui.QAbstractSlider.SliderMove -> 7 actions = { 1: self.addSingleStep, 2: self.subSingleStep, 3: self.addPageStep, 4: self.subPageStep, 7: self.dragSlider } if not slider_action in actions.keys(): return # Navigate the data dealing with buffer faults actions[slider_action]() # Eventually synchronize the position of the visible scrollbar # with the displayed data using the first visible cell as # reference self.syncView() def mouseNavInfo(self, direction): """Gives information about model, vertical header and viewport. This is a helper method used by methods that browse the data via mouse. :Parameter direction: the data browsing direction (upwards/downwards) """ model = self.tmodel vh = self.vheader # About the table table_rows = model.numrows buffer_start = model.rbuffer.start # The viewport BEFORE navigating the data if (direction == 'u'): row = vh.visualIndexAt(0) elif (direction == 'd'): row = vh.visualIndexAt(self.viewport().height()) page_step = self.vscrollbar.pageStep() return (model, vh, table_rows, buffer_start, row, page_step) def addSingleStep(self): """Setup data for moving towards the last section line by line. """ model, vh, table_rows, buffer_start, last_vp_row, page_step = \ self.mouseNavInfo('d') # If we are at the last row of the buffer but not at the last # row of the dataset we still can go downwards so we have to # read the next contiguous buffer if (last_vp_row + 1 == table_rows) and \ (buffer_start + table_rows < self.leaf_numrows): # Buffer fault. The new buffer starts just after the current # first row of the viewport. new_start = buffer_start + last_vp_row - page_step + 1 model.loadData(new_start, table_rows) self.updateView() self.scrollTo( model.index(new_start - model.rbuffer.start, 0), QtWidgets.QAbstractItemView.PositionAtTop) else: self.vscrollbar.triggerAction(1) def addPageStep(self): """Setup data for moving towards the last section page by page. """ model, vh, table_rows, buffer_start, last_vp_row, page_step = \ self.mouseNavInfo('d') # If we are at the last page of the buffer but not at the last # row of the dataset we still can go downwards so we have to # read the next contiguous buffer if (last_vp_row + page_step + 1 > table_rows) and \ (buffer_start + table_rows < self.leaf_numrows): # Buffer fault. The new buffer starts at the current last # row of the viewport. new_start = buffer_start + last_vp_row model.loadData(new_start, table_rows) self.updateView() self.scrollTo( model.index(new_start - model.rbuffer.start, 0), QtWidgets.QAbstractItemView.PositionAtTop) else: self.vscrollbar.triggerAction(3) def subSingleStep(self): """Setup data for moving towards the first section line by line. """ model, vh, table_rows, buffer_start, first_vp_row, page_step = \ self.mouseNavInfo('u') # If we are at the first row of the buffer but not at the first # row of the dataset we still can go upwards so we have to # read the previous contiguous buffer if (first_vp_row == 0) and (buffer_start > 0): # Buffer fault. The new buffer ends just before the current # last row of the viewport. model.loadData( buffer_start + page_step - table_rows, table_rows) self.scrollTo( model.index( buffer_start + page_step - model.rbuffer.start - 1, 0), QtWidgets.QAbstractItemView.PositionAtBottom) self.updateView() else: self.vscrollbar.triggerAction(2) def subPageStep(self): """Setup data for moving towards the first section page by page. """ model, vh, table_rows, buffer_start, first_vp_row, page_step = \ self.mouseNavInfo('u') # If we are at the first page of the buffer but not at the first # row of the dataset we still can go upwards so we have to # read the previous contiguous buffer if (first_vp_row < page_step + 1) and (buffer_start > 0): # Buffer fault. The new buffer ends just at the current # first row of the viewport. model.loadData( buffer_start + first_vp_row - table_rows + 1, table_rows) self.updateView() self.scrollTo( model.index( buffer_start + first_vp_row - model.rbuffer.start, 0), QtWidgets.QAbstractItemView.PositionAtBottom) else: self.vscrollbar.triggerAction(4) def dragSlider(self): """Move the slider by dragging it. When navigating large datasets we must beware that the number of rows of the dataset (int64) is greater than the number of values in the range of values (int32) of the scrollbar. It means that there are rows that cannot be reached with the scrollbar. Note:: QScrollBar.sliderPosition and QScrollBar.value not always return the same value. When we reach the top of the dataset: - wheeling: value() returns 0, sliderPosition() returns a negative number - dragging: value() returns a number greater than 0, sliderPosition() returns 0 """ model = self.tmodel table_rows = model.numrows value = self.tricky_vscrollbar.sliderPosition() if value < 0: value = 0 row = 0 elif value >= self.max_value: value = self.max_value row = self.leaf_numrows - 1 else : row = numpy.array(self.interval_size*value, dtype=numpy.int64) # top buffer fault condition if row < model.rbuffer.start: self.topBF(value, row) # bottom buffer fault condition elif (row >= model.rbuffer.start + table_rows): self.bottomBF(value, row) # We are at top of the dataset elif value == self.tricky_vscrollbar.minimum(): self.vscrollbar.triggerAction( QtWidgets.QAbstractSlider.SliderToMinimum) # We are at bottom of the dataset elif value == self.tricky_vscrollbar.maximum(): self.vscrollbar.triggerAction( QtWidgets.QAbstractSlider.SliderToMaximum) # we are somewhere in the middle of the dataset else : self.scrollTo( model.index(row - model.rbuffer.start, 0), QtWidgets.QAbstractItemView.PositionAtTop) def topBF(self, value, row): """Going out of buffer when browsing upwards. Buffer fault condition: row < rbuffer.start :Parameters: - `value`: the current value of the tricky scrollbar - `row`: the estimated dataset row mapped to that value """ table_rows = self.tmodel.numrows if value == self.tricky_vscrollbar.minimum(): start = 0 position = 0 hint = QtWidgets.QAbstractItemView.PositionAtTop self.vscrollbar.triggerAction( QtWidgets.QAbstractSlider.SliderToMinimum) else: start = row - table_rows position = table_rows - 1 hint = QtWidgets.QAbstractItemView.PositionAtBottom self.tmodel.loadData(start, table_rows) self.updateView() self.scrollTo(self.tmodel.index(position, 0), hint) def bottomBF(self, value, row): """Going out of buffer when browsing downwards. Buffer fault condition: row > self.tmodel.rbuffer.start + table_rows - 1 :Parameters: - `value`: the current value of the tricky scrollbar - `row`: the estimated dataset row mapped to that value """ table_rows = self.tmodel.numrows if value == self.tricky_vscrollbar.maximum(): row = self.leaf_numrows - 1 start = self.leaf_numrows - table_rows position = table_rows - 1 hint = QtWidgets.QAbstractItemView.PositionAtBottom self.vscrollbar.triggerAction( QtWidgets.QAbstractSlider.SliderToMinimum) else: start = row position = 0 hint = QtWidgets.QAbstractItemView.PositionAtTop self.tmodel.loadData(start, table_rows) self.updateView() self.scrollTo(self.tmodel.index(position, 0), hint) def wheelEvent(self, event): """Specialized handler for the wheel events received by the *viewport*. :Parameter event: the QWheelEvent being processed """ if self.leaf_numrows > self.tmodel.numrows: height = self.vheader.sectionSize(0) # The distance the wheel is rotated in eights of a degree. # For example: 120/8 = 15 so if delta is 120 then the wheel # has been rotated by 15 degrees. It *seems* that every eight of # degree corresponds to a distance of 1 pixel. delta = event.angleDelta().y() self.wheel_step = \ numpy.rint(abs(delta)/height).astype(numpy.int64) - 1 if delta < 0: self.wheelDown(event) else: self.wheelUp(event) self.syncView() # Filter the event so it will not be passed to the parent widget event.accept() else: QtWidgets.QTableView.wheelEvent(self, event) def wheelDown(self, event): """Setup data for wheeling with the mouse towards the last section. """ model, vh, table_rows, buffer_start, last_vp_row, page_step = \ self.mouseNavInfo('d') vp_rows = last_vp_row - vh.visualIndexAt(0) # If we are at the last page of the buffer but not at the last # row of the dataset we still can go downwards so we have to # read the next contiguous buffer if (last_vp_row + self.wheel_step + 1 > table_rows) and \ (buffer_start + table_rows < self.leaf_numrows): # Buffer fault. The new buffer and the old one overlap to ensure # that no jumps occur. new_start = \ buffer_start + last_vp_row + self.wheel_step - page_step model.loadData(new_start, table_rows) self.updateView() self.scrollTo( model.index(new_start - model.rbuffer.start, 0), QtWidgets.QAbstractItemView.PositionAtTop) else: QtCore.QCoreApplication.sendEvent(self.vscrollbar, event) def wheelUp(self, event): """Setup data for wheeling with the mouse towards the first section. """ model, vh, table_rows, buffer_start, first_vp_row, page_step = \ self.mouseNavInfo('u') vp_rows = vh.visualIndexAt(self.viewport().height()) - first_vp_row # If we are at the first page of the buffer but not at the first # row of the dataset we still can go upwards so we have to # read the previous contiguous buffer if (first_vp_row < page_step + 1) and (buffer_start > 0): # Buffer fault. The new buffer and the old one overlap to ensure # that no jumps occur. new_start = buffer_start + first_vp_row + page_step - \ self.wheel_step - table_rows + 1 model.loadData(new_start, table_rows) self.updateView() self.scrollTo( model.index( new_start + table_rows - model.rbuffer.start - 1, 0), QtWidgets.QAbstractItemView.PositionAtBottom) else: QtCore.QCoreApplication.sendEvent(self.vscrollbar, event) def keyPressEvent(self, event): """Handle basic cursor movement for key events. :Parameter event: the key event being processed """ if self.tmodel.numrows < self.leaf_numrows: key = event.key() if key == QtCore.Qt.Key_Home: event.accept() self.homeKeyPressEvent() elif key == QtCore.Qt.Key_End: event.accept() self.endKeyPressEvent() elif key == QtCore.Qt.Key_Up: event.accept() self.upKeyPressEvent(event) elif key == QtCore.Qt.Key_Down: event.accept() self.downKeyPressEvent(event) elif key == QtCore.Qt.Key_PageUp: event.accept() self.pageUpKeyPressEvent(event) elif key == QtCore.Qt.Key_PageDown: event.accept() self.pageDownKeyPressEvent(event) else: QtWidgets.QTableView.keyPressEvent(self, event) else: QtWidgets.QTableView.keyPressEvent(self, event) def homeKeyPressEvent(self): """Specialised handler for the `Home` key press event. See enum QAbstractitemView.CursorAction for reference. """ model = self.tmodel table_rows = model.numrows index = model.index(0, 0) # Update buffer if needed if model.rbuffer.start > 0 : model.loadData(0, table_rows) self.updateView() self.setCurrentIndex(index) self.scrollToTop() # Eventually synchronize the position of the visible scrollbar # the displayed data self.tricky_vscrollbar.setValue(0) def endKeyPressEvent(self): """Specialised handler for the `End` key press event. See enum QAbstractitemView.CursorAction for reference. """ model = self.tmodel table_rows = model.numrows index = model.index(table_rows - 1, model.numcols - 1) # Update buffer if needed last_row = model.rbuffer.start + table_rows if last_row < self.leaf_numrows: self.tmodel.loadData(self.leaf_numrows - table_rows, table_rows) self.updateView() self.setCurrentIndex(index) self.scrollToBottom() # Eventually synchronize the position of the visible scrollbar # the displayed data self.tricky_vscrollbar.setValue(self.max_value) def keyboardNavInfo(self): """Gives information about model, and current cell. This is a helper method used by methods that browse the data via keyboard. :Parameter direction: the data browsing direction (upwards/downwards) """ model = self.tmodel # Load the buffer where the valid current cell lives self.validCurrentCellBuffer() # About the table table_rows = model.numrows buffer_start = model.rbuffer.start page_step = self.vscrollbar.pageStep() # About the current cell current_index = self.currentIndex() buffer_row = current_index.row() buffer_column = current_index.column() dataset_row = buffer_start + buffer_row return (model, table_rows, buffer_start, page_step, current_index, buffer_row, buffer_column, dataset_row) def upKeyPressEvent(self, event): """Specialised handler for the cursor up key press event. :Parameter event: the key event being processed """ (model, table_rows, buffer_start, page_step, current_index, buffer_row, buffer_column, dataset_row) = self.keyboardNavInfo() # If we are at the first row of the buffer but not at the first # row of the dataset we still can go upwards so we have to read # the previous contiguous buffer if (buffer_row == 0) and (buffer_start > 0): model.loadData(dataset_row - table_rows + page_step, table_rows) self.updateView() # The position of the new current row row = dataset_row - model.rbuffer.start - 1 if row < 0: row = 0 index = model.index(row, buffer_column) self.setCurrentIndex(index) self.scrollTo(index, QtWidgets.QAbstractItemView.PositionAtTop) else: QtWidgets.QTableView.keyPressEvent(self, event) # Eventually synchronize the position of the visible scrollbar # with the displayed data using the first visible cell as # reference self.syncView() def pageUpKeyPressEvent(self, event): """Specialised handler for the `PageUp` key press event. :Parameter event: the key event being processed """ (model, table_rows, buffer_start, page_step, current_index, buffer_row, buffer_column, dataset_row) = self.keyboardNavInfo() # If we are at the first page of the buffer but not at the first # page of the dataset we still can go upwards so we have to read # the previous contiguous buffer if (buffer_row - page_step < 0) and (buffer_start > 0): model.loadData(dataset_row - table_rows, table_rows) self.updateView() # The position of the new current row row = dataset_row - model.rbuffer.start - page_step - 1 if row < 0: row = 0 index = model.index(row, buffer_column) self.setCurrentIndex(index) self.scrollTo(index, QtWidgets.QAbstractItemView.PositionAtTop) else: QtWidgets.QTableView.keyPressEvent(self, event) # Eventually synchronize the position of the visible scrollbar # with the displayed data using the first visible cell as # reference self.syncView() def downKeyPressEvent(self, event): """Specialised handler for the cursor down key press event. :Parameter event: the key event being processed """ (model, table_rows, buffer_start, page_step, current_index, buffer_row, buffer_column, dataset_row) = self.keyboardNavInfo() # If we are at the last row of the buffer but not at the last # row of the dataset we still can go downwards so we have to # read the next contiguous buffer if (buffer_row == table_rows - 1) and \ (buffer_start + table_rows < self.leaf_numrows): model.loadData(dataset_row - page_step + 1, table_rows) self.updateView() # The position of the new current row row = dataset_row - model.rbuffer.start + 1 if row > table_rows - 1: row = table_rows - 1 index = model.index(row, buffer_column) self.setCurrentIndex(index) self.scrollTo(index, QtWidgets.QAbstractItemView.PositionAtBottom) else: QtWidgets.QTableView.keyPressEvent(self, event) # Eventually synchronize the position of the visible scrollbar # with the displayed data using the first visible cell as # reference self.syncView() def pageDownKeyPressEvent(self, event): """Specialised handler for the `PageDown` key press event. :Parameter event: the key event being processed """ (model, table_rows, buffer_start, page_step, current_index, buffer_row, buffer_column, dataset_row) = self.keyboardNavInfo() # If we are at the last page of the buffer but not at the last # row of the dataset we still can go downwards so we have to # read the next contiguous buffer if (buffer_row + page_step > table_rows - 1) and \ (buffer_start + table_rows < self.leaf_numrows): model.loadData(dataset_row + 1, table_rows) self.updateView() # The position of the new current row row = dataset_row - model.rbuffer.start + page_step + 1 if row > table_rows - 1: row = table_rows - 1 index = model.index(row, buffer_column) self.setCurrentIndex(index) self.scrollTo(index, QtWidgets.QAbstractItemView.PositionAtBottom) else: QtWidgets.QTableView.keyPressEvent(self, event) # Eventually synchronize the position of the visible scrollbar # with the displayed data using the first visible cell as # reference self.syncView() # For large datasets the number of rows of the dataset is greater than # the number of rows of the table used for displaying data. It means # that if a table cell is activated (made selected by clicking, double # cliking or pressing the arrow keys. We call this cell *valid current # cell*) we must take care for keeping it updated. For instance, if # the table contains the first 10000 rows of the dataset and the user # clicks the cell (52, 1) it becomes the valid current cell. If now the # user draggs the slider and goes down let say 30000 rows then the row # 52 of the table will still be the current one but its section number # will be 30052 which is wrong (the current cell can only be changed by # activating other cell, not by dragging the scrollbar). We call this # cell *fake current cell*. This would be a bug. def currentChanged(self, current, previous): """Track the dataset current cell. This SLOT is automatically called when the current cell changes. :Parameters: - `current`: the new current index - `previous`: the previous current index """ QtWidgets.QTableView.currentChanged(self, current, previous) if self.tmodel.numrows < self.leaf_numrows: self.valid_current_buffer = self.tmodel.rbuffer.start # This method has been renamed from loadDatasetCurrentCell to # validCurrentCellBuffer. The method has been debugged too def validCurrentCellBuffer(self): """Load the buffer in which the valid current cell lives. """ table_rows = self.tmodel.numrows valid_current = self.currentIndex().row() + self.valid_current_buffer if not (self.tmodel.rbuffer.start <= valid_current <= self.tmodel.rbuffer.start + table_rows - 1): self.tmodel.loadData(self.valid_current_buffer, table_rows) self.updateView() def selectionChanged(self, selected, deselected): """Track the dataset selected cells. This method is automatically called when the selected range changes. :Parameters: - `selected`: the new selection - `deselected`: the previous selection (maybe empty) """ model = self.tmodel if model.numrows < self.leaf_numrows: # Get the selected indexes from the QItemSelection object selection = selected.indexes() if len(selection): model.selected_cell = { 'index': selection[0], 'buffer_start': model.rbuffer.start, } else: QtWidgets.QTableView.selectionChanged(self, selected, deselected) ViTables-3.0.0/vitables/vttables/scrollbar.py000066400000000000000000000054531311223072700212220ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This minimal module makes a QScrollBar for browsing huge datasets. The use of this scrollbar is very tricky. It will be painted over the scrollbar of views bound to huge datasets so the view will look as usual but will have 2 scrollbars. The hidden scrollbar is not useful for browsing huge datasets (it is tightly bound to the dimensions (number of rows) of the view widget. But the visible scrollbar is independent of the dimensions of the view widget and can be used for customising the view in a way that makes it useful for browsing datasets with a larger number of rows than that provided by the view widget. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets class ScrollBar(QtWidgets.QScrollBar): """ A specialised scrollbar for views of huge datasets. :Parameter scrollbar: the scrollbar being hidden """ def __init__(self, view): """Replace a vertical scrollbar with other one. After replacing, the ancestor widgets of `scrollbar` looks exactly the same, but the visible scrollbar is not currently useful for navigating the data displayed in the ancestor widgets because it is not tied to that data in anyway. """ self.view = view # Cheat the user hidding a scrollbar and displaying other one # that looks exactly the same parent = view.vscrollbar.parent() super(ScrollBar, self).__init__(parent) view.vscrollbar.setVisible(False) parent.layout().addWidget(self) self.setOrientation(QtCore.Qt.Vertical) self.setObjectName('tricky_vscrollbar') def event(self, e): """Filter wheel events and send them to the table viewport. """ if (e.type() == QtCore.QEvent.Wheel): self.view.wheelEvent(e) return True return QtWidgets.QScrollBar.event(self, e) ViTables-3.0.0/vitables/vtwidgets/000077500000000000000000000000001311223072700170525ustar00rootroot00000000000000ViTables-3.0.0/vitables/vtwidgets/__init__.py000066400000000000000000000016451311223072700211710ustar00rootroot00000000000000 # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org __all__ = ["nodenamedlg", "renamedlg", "zoom_cell"] ViTables-3.0.0/vitables/vtwidgets/nodename_dlg.ui000066400000000000000000000034151311223072700220300ustar00rootroot00000000000000 InputNodeNameDlg Qt::WindowModal 0 0 400 128 Dialog InfoLabel Node name: Qt::Horizontal QDialogButtonBox::Cancel buttonsBox rejected() InputNodeNameDlg reject() 316 260 286 274 ViTables-3.0.0/vitables/vtwidgets/nodenamedlg.py000066400000000000000000000077761311223072700217220ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a dialog for renaming nodes of the tree of databases view. The dialog is raised when a new group node is created and when an existing node is being renamed. """ __docformat__ = 'restructuredtext' import os.path from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_InputNodenameDialog = \ loadUiType(os.path.join(os.path.dirname(__file__),'nodename_dlg.ui'))[0] class InputNodeName(QtWidgets.QDialog, Ui_InputNodenameDialog): """ Dialog for interactively entering a name for a given node. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) This dialog is called when a new group is being created and also when a node of any kind is being renamed. Regular Qt class QInputDialog is not used because, at least apparently, it doesn't provide a way for customizing buttons text. :Parameters: - `title`: the dialog title - `info`: information to be displayed in the dialog - `action`: string with the editing action to be done, Create or Rename """ def __init__(self, title, info, action, default_value=None): """A customised `QInputDialog`. """ vtapp = vitables.utils.getVTApp() # Makes the dialog and gives it a layout super(InputNodeName, self).__init__(vtapp.gui) self.setupUi(self) # Set dialog caption and label with general info self.setWindowTitle(title) self.generalInfo.setText(info) # The Create/Rename button self.edit_button = self.buttonsBox.addButton(action, QtWidgets.QDialogButtonBox.AcceptRole) # Setup a validator for checking the entered node name validator = QtGui.QRegExpValidator(self) pattern = QtCore.QRegExp("[a-zA-Z_]+[0-9a-zA-Z_ ]*") validator.setRegExp(pattern) self.valueLE.setValidator(validator) if default_value: self.valueLE.setText(default_value) # Make sure that buttons are in the proper activation state self.valueLE.textChanged.emit(self.valueLE.text()) @QtCore.Slot("QString", name="on_valueLE_textChanged") def checkName(self, current): """ Check the current name value. The state of the `Create` button depends on the passed string. If it is empty then the button is disabled. Otherwise it is enabled. :Parameter current: the value currently displayed in the text box """ if current == '': self.edit_button.setEnabled(0) else: self.edit_button.setEnabled(1) @QtCore.Slot(name="on_buttonsBox_accepted") def saveName(self): """Slot for saving the entered name and closing the dialog. """ self.node_name = self.valueLE.text() self.accept() ViTables-3.0.0/vitables/vtwidgets/rename_dlg.ui000066400000000000000000000034031311223072700215060ustar00rootroot00000000000000 RenameNodeDlg Qt::WindowModal 0 0 400 128 Dialog InfoLabel New name: Qt::Horizontal QDialogButtonBox::Cancel buttonsBox rejected() RenameNodeDlg reject() 316 260 286 274 ViTables-3.0.0/vitables/vtwidgets/renamedlg.py000066400000000000000000000172201311223072700213640ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This module provides a dialog for solving node renaming issues on the tree of databases view. Some times naming problems appear when the tree is being edited: - when a file is being saved as a different one and its name is already being used by another file in the same directory - when a new group is being created and its name is already being used by other node in the destination group - when a node is being renamed and its new name is already being used by other node in the same group - when a node is being pasted/dropped and its name is already being used by other node in the destination group This dialog allows the user to solve the problem. Available options are: - rename the object in trouble - overwrite the existing object - cancel the editing action """ __docformat__ = 'restructuredtext' import os.path import re from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.uic import loadUiType import vitables.utils translate = QtWidgets.QApplication.translate # This method of the PyQt4.uic module allows for dinamically loading user # interfaces created by QtDesigner. See the PyQt4 Reference Guide for more # info. Ui_RenameNodeDialog = \ loadUiType(os.path.join(os.path.dirname(__file__),'rename_dlg.ui'))[0] class RenameDlg(QtWidgets.QDialog, Ui_RenameNodeDialog): """ Ask user for help when a name issue raises. By loading UI files at runtime we can: - create user interfaces at runtime (without using pyuic) - use multiple inheritance, MyParentClass(BaseClass, FormClass) Regular Qt class `QInputDialog` is not used because, at least apparently, it doesn't provide a way for customizing buttons text. This dialog allows the user to solve naming issues. Available options are: - rename the object in trouble - overwrite the existing object - cancel the editing action :Parameters: - `name`: the troubled name - `pattern`: a regular expression pattern that the name must match - `info`: dialog title and label """ def __init__(self, name, pattern, info): """A customised `QInputDialog`. """ vtapp = vitables.utils.getVTApp() # Makes the dialog and gives it a layout super(RenameDlg, self).__init__(vtapp.gui) self.setupUi(self) # Sets dialog caption self.setWindowTitle(info[0]) self.generalInfo.setText(info[1]) self.troubled_name = name self.cpattern = re.compile(pattern) # The result returned by this dialog will be contained in the # action dictionary. Its values can be: # If Overwrite --> True, troubled_name # If Rename --> False, new_name # If Cancel --> False, '' self.action = {'overwrite': False, 'new_name': ''} # The dialog buttons: Rename, Overwrite and Cancel self.overwrite_button = self.buttonsBox.addButton( translate('RenameDlg', 'Overwrite', 'A button label'), QtWidgets.QDialogButtonBox.AcceptRole) self.rename_button = self.buttonsBox.addButton( translate('RenameDlg', 'Rename', 'A button label'), QtWidgets.QDialogButtonBox.AcceptRole) self.rename_button.setDefault(1) self.cancel_button = self.buttonsBox.button( QtWidgets.QDialogButtonBox.Cancel) # Setup a validator for checking the entered node name validator = QtGui.QRegExpValidator(self) qt_pattern = QtCore.QRegExp(pattern) validator.setRegExp(qt_pattern) self.valueLE.setValidator(validator) self.valueLE.setText(self.troubled_name) self.valueLE.selectAll() # Make sure that buttons are in the proper activation state self.valueLE.textChanged.emit(self.valueLE.text()) @QtCore.Slot('QString', name="on_valueLE_textChanged") def checkName(self, new_name): """ Check the new name value. Every time that the text box content changes, this method is asked to check if the new name and the original name differ. Four cases can occur: 1) the new name is empty 2) the new name and the current nodename are the same 3) the new name and the current name differ and the new name is not being used by a sibling node 4) the new name and the current name differ and the new name is being used by a sibling node In cases 1) and 2) the new name is not valid, the `Rename` and `Overwrite` buttons are both disabled. In case 3) the `Rename` button is enabled and the `Overwrite` one is not. In case 4) the `Overwrite` button is enabled but the `Rename` one is not. Beware that case 2) can appear only during a node renaming operation or during a file `Save As...` operation (not when creating a new group or pasting/dropping a node) :Parameter new_name: the value currently displayed in the text box """ # If the new name and the current nodename are the same then the # group 1 of the pattern is matched result = self.cpattern.search(new_name) if (result == None) or \ ((result != None) and (result.lastindex == 1)) or \ (not new_name): self.rename_button.setEnabled(0) self.overwrite_button.setEnabled(0) elif new_name == self.troubled_name: self.rename_button.setEnabled(0) if self.troubled_name == '/': self.overwrite_button.setEnabled(0) else: self.overwrite_button.setEnabled(1) else: self.rename_button.setEnabled(1) self.overwrite_button.setEnabled(0) @QtCore.Slot("QAbstractButton *", name="on_buttonsBox_clicked") def executeAction(self, button): """Execute the action specified by the clicked button. :Parameter button: the clicked button (`Rename` or `Overwrite`) """ if button == self.rename_button: self.rename_node() elif button == self.overwrite_button: self.overwriteNode() def overwriteNode(self): """ Set the new name and exit. When the `Overwrite` button is clicked the new name is saved and the dialog finishes. """ self.action['overwrite'] = True self.action['new_name'] = self.troubled_name self.accept() def rename_node(self): """ Set the new name and exit. When the `Rename` button is clicked the new name is saved and the dialog finishes. """ new_name = self.valueLE.text() self.action['overwrite'] = False self.action['new_name'] = new_name self.accept() ViTables-3.0.0/vitables/vtwidgets/zoom_cell.py000066400000000000000000000262231311223072700214140ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Display recursively the content of a given cell of a view. """ __docformat__ = 'restructuredtext' from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets import vitables.utils def getArrayDimensions(shape): """ Get the dimensions of the grid where the cell will be zoomed. The zoomed cell contains a `numpy` array and will be displayed in a table with the same shape than it. :Parameter shape: the cell shape :Returns: a tuple (rows, columns) """ # Numpy scalars are special a case if shape == (): nrows = ncols = 1 # 1-D arrays are displayed as a 1-column vector with nrows elif len(shape) == 1: nrows = shape[0] ncols = 1 # N-D arrays are displayed as a matrix (nrowsXncols) which # elements are (N-2)-D arrays else: nrows = shape[0] ncols = shape[1] return (nrows, ncols) class ZoomCell(QtWidgets.QMdiSubWindow): """ Display an array/table cell on its own view (table widget). When a leaf is displayed in a view, is quite usual that the content of some cells is not fully visible because it doesn't fit into the cell. To alleviate this problem this class provides a way to, recursively, display the content of any cell on its own view. The cell content depends on the kind of leaf and the shape of its atom. Cells of `Table` views and `E/C/Array` views can be: - a ``numpy`` scalar. `Atom` shape is () - a ``numpy`` array. `Atom` shape is not () In addition, cells of `VLArray` views can be: - a serialized `Python` object. `Atom` kind is `object`, shape is () - a `Python` string. `Atom` kind is `vlstring`, shape is () Finally, cells of `Table` views also can be: - a `numpy.void` object when the cell corresponds to nested field of the record :Parameters: - `data`: the value stored in the cell being zoomed - `title`: the base string for the zoomed view title - `workspace`: the parent of the zoomed view - `leaf`: a LeafNode instance """ def __init__(self, data, title, workspace, leaf): """ Creates a zoom view for a given cell. The passed cell is an element of a given dataset. It is always a (potentially nested) `numpy` array. See cell accessor methods in the `Buffer` class for details. """ self.data = data self.title = title self.workspace = workspace self.data_shape = self.hasShape() self.field_names = [] # Create and customise the widget that will display the zoomed cell # The pindex attribute is required to keep working the code for # synchronising workspace and tree of databases view. # The leaf attribute is required to keep working the code for # cleaning the workspace when a file is closed. # The WA_DeleteOnClose flag makes that when the widget is # closed either programatically (see VTAPP.windowClose) # or by the user (clicking the close button in the titlebar) # the widget is hidden AND destroyed --> the workspace # updates automatically its list of open windows --> the # Windows menu content is automatically updated super(ZoomCell, self).__init__(workspace) self.pindex = None self.dbt_leaf = leaf self.setAttribute(QtCore.Qt.WA_DeleteOnClose) # The internal widget self.grid = QtWidgets.QTableWidget() self.setWidget(self.grid) # Configure the titlebar self.setWindowTitle(self.title) icons_dictionary = vitables.utils.getIcons() self.setWindowIcon(icons_dictionary['zoom-in']) # Decide how the cell content will be formatted. Content can be: # - a numpy array # - either a string or a unicode string # - other Python object if self.data_shape: self.formatContent = vitables.utils.formatArrayContent elif isinstance(self.data, str): self.formatContent = vitables.utils.formatStringContent else: self.formatContent = vitables.utils.formatObjectContent # Setup grid dimensions (nrows, ncols) = self.getGridDimensions() self.grid.setColumnCount(ncols) self.grid.setRowCount(nrows) # Setup grid editing self.grid.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) # Setup grid horizontal header if self.field_names: for section in range(0, ncols): item = QtWidgets.QTableWidgetItem() item.setText(self.field_names[section]) self.grid.setHorizontalHeaderItem(section, item) else: for section in range(0, ncols): item = QtWidgets.QTableWidgetItem() item.setText('{0}'.format(section)) self.grid.setHorizontalHeaderItem(section, item) # Setup grid vertical header for section in range(0,nrows): item = QtWidgets.QTableWidgetItem() item.setText('{0}'.format(section)) self.grid.setVerticalHeaderItem(section, item) # Fill the grid if self.field_names: self.zoomTable() else: self.zoomArray() self.show() rmode = QtWidgets.QHeaderView.Stretch if self.grid.columnCount() == 1: self.grid.horizontalHeader().setSectionResizeMode(rmode) if self.grid.rowCount() == 1: self.grid.verticalHeader().setSectionResizeMode(rmode) # Connect signals to slots self.grid.cellDoubleClicked.connect(self.zoomView) def hasShape(self): """Find out if the zoomed cell has a shape attribute.""" return hasattr(self.data, 'shape') def getGridDimensions(self): """ Get the dimensions of the grid where the zoomed cell will be displayed. :Returns: a tuple (rows, columns) """ if self.data_shape: # The cell contains a numpy object shape = self.data.shape dtype = self.data.dtype if dtype.fields is None: # Arrays with nested fields come here return getArrayDimensions(shape) else: # Table nested fields come here return self.getNestedFieldDimensions() else: # The cell contains a Python object return self.getPyObjectDimensions() def getPyObjectDimensions(self): """ Get the dimensions of the grid where the cell will be zoomed. The zoomed cell contains a `Python` object. :Returns: a tuple (rows, columns) """ if isinstance(self.data, list) or isinstance(self.data, tuple): return (len(self.data), 1) else: return (1, 1) def getNestedFieldDimensions(self): """ Get the dimensions of the grid where the cell will be zoomed. The zoomed cell contains a nested field (a field made of inner fields, than can be nested or not) and will be displayed in a table with only one row and one column per (top - 1) level field. The dtype.descr attribute describes the inner fields. A field description is a tuple with one of the following formats: - (field_name, format) field is not nested, shape=() - (field_name, format, shape) field is not nested, shape!=() - (field_name, descr) field is nested :Returns: a tuple (rows, columns) """ self.field_names = [item[0] for item in self.data.dtype.descr] ncols = len(self.field_names) nrows = 1 return (nrows, ncols) def zoomTable(self): """Fill the zoom view with the content of the clicked nested field.""" for column in range(0, self.grid.columnCount()): content = self.data[self.field_names[column]] text = self.formatContent(content) item = QtWidgets.QTableWidgetItem(text) self.grid.setItem(0, column, item) def zoomArray(self): """Fill the zoom view with the content of the clicked cell.""" num_rows = self.grid.rowCount() num_cols = self.grid.columnCount() # Numpy scalars are displayed in a 1x1 grid if num_rows == num_cols == 1: content = self.data text = self.formatContent(content) item = QtWidgets.QTableWidgetItem(text) self.grid.setItem(0, 0, item) # 1-D arrays elif num_cols == 1: for row in range(0, num_rows): content = self.data[row] text = self.formatContent(content) item = QtWidgets.QTableWidgetItem(text) self.grid.setItem(row, 0, item) # N-D arrays else: for row in range(0, num_rows): for column in range(0, num_cols): content = self.data[row][column] text = self.formatContent(content) item = QtWidgets.QTableWidgetItem(text) self.grid.setItem(row, column, item) def zoomView(self, row, col): """Makes the content of the clicked cell fully visible. :Parameters: - `row`: the row of the clicked cell - `col`: the column of the clicked cell """ # Check if the zoom has to be done if self.data_shape: if not (self.data.shape !=() or self.field_names): return elif not (isinstance(self.data, list) or isinstance(self.data, tuple)): return # Get data if self.data_shape: # Arrays and table nested fields if self.field_names: cell = self.data[self.field_names[col]] elif len(self.data.shape) > 1: cell = self.data[row][col] elif len(self.data.shape) == 1: cell = self.data[row] else: # Python lists and tuples cell = self.data[row] # Get caption if self.field_names: caption = '{0}: {1}[{2}]'.format(self.title, self.field_names[col], row) else: caption = '{0}: ({1}, {2})'.format(self.title, row, col) ZoomCell(cell, caption, self.workspace, self.dbt_leaf) ViTables-3.0.0/vitables_ca_ES.ts000066400000000000000000003606131311223072700164450ustar00rootroot00000000000000 AboutPage Form Plugin description Version: Module name: Folder: Author: Desription: ArrayColsOrganizer Group Arrays into a unique view Checkbox tooltip text <qt><p>Plugin that provides an alternative view for arrays with the same number of rows. <p>The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.</qt> Text of an About plugin message box AttrEditor Error: "{0}" value mismatches its data type. User attributes table editing error Error: "{0}" value is out of range. User attributes table editing error Error: "{0}" value is out of range or mismatches its data type. User attributes table editing error Error: "{0}" cannot be converted to a Python object. User attributes table editing error Error: empty field Name in the row {0:d} User attrs editing error Error: attribute name "{0}" is repeated. User attrs table editing error AttrPropDialog Dialog &System attributes System attributes: &User Attributes User attributes: <qt> <h3>User's attributes editing table</h3> Here you can perform the editing of user's attributes for this node. It is quite straightforward. <p>For adding an attribute click the <b>Add</b> button. A new row will be added to the table. Enter the attribute name and its value in the corresponding cells. Finally, select the attribute datatype in the combobox of the DataType column. In order to delete an attribute just select it by clicking any of its cells, then click the <b>Delete</b> button.</p> <p>Beware that PyTables stores scalar attributes as numpy scalar arrays so you will be unable to save them as Python objects even if you choose the Python datatype in the combobox selector. Also note that multidimensional attributes other than Python lists and tuples are not supported.</p> </qt> Help text for the User Attributes page &Add &Delete &What's this AttrPropDlg Name First column header of the table Value Second column header of the table Datatype Third column header of the table Please, select the attribute to be deleted. A usage text User attribute deletion Caption of the attr deletion dialog You are about to delete the attribute: {0} Ask for confirmation Delete Button text Cancel Button text BookmarksDlg Bookmarks editor Dialog caption Bookmark First column header of the bookmarks table URL Second column header of the bookmarks table &OK Button label &Delete Button label &Cancel Button label Buffer Problems reading records. The dataset seems to be compressed with the {0} library. Check that it is installed in your system, please. A dataset readability error Data read error: {} A dataset read error Error: problems reading records. The dataset maybe corrupted. A dataset readability error Calculator No group is selected. Relative references are disabled. Continue? Multiple groups are selected. Relative references are disabled. Continue? Relative references are disabled Save expression as Name: Node not found Node type Result name The location to store results is not specified Create group Evaluation error An exception was raised during evaluation, see log for details. Result save error An exception was raised while trying to store results, see log for details. CalculatorDialog Evaluate expression Saved expressions: Save Remove Statements: Expression: Result table: <html><head/><body><p>Saved expressions.</p></body></html> <html><head/><body><p>Store expression for future use.</p></body></html> <html><head/><body><p>Remove the selected expression from the saved expressions list.</p></body></html> <html><head/><body> <p>Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.</p> </body></html> <html><head/><body> <p>The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.</p> <p>The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.mydata&quot;. If &quot;sub_group&quot; is the current group then the string &quot;mydata&quot; can be used as reference.</p> </body></html> <html><head/><body> <p>Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.myresult&quot;. If &quot;sub_group&quot; is the current group then the string &quot;myresult&quot; can be used as reference.</p> <p>The result table must not exitst.</p> </body></html> ConfigFileIOException Configuration error: the application setting {0} cannot be saved. A logger error message Configuration warning: the application setting {0} cannot be read. Its default value will be used. A logger error message DBDoc Warning: file access in read-write mode is denied. It will be opened in read-only mode. A logger error message {0} A logger error message Please, if you think it is a bug, report it to developers. A logger error message Error: cannot open node {0} in file {1} Error message Unable to save the file {0} as {1}. Beware that only closed files can be safely overwritten via Save As... A logger error message DBTreeSortPage Form Plugin description Version: Module name: Folder: Author: Desription: Sorting algorithm DBsTreeModel Openning cancelled: {0} is a folder. A logger error message Opening failed: file {0} cannot be found. A logger error message Opening cancelled: file {0} already open. A logger error message Opening cancelled: file {0} has not HDF5 format. A logger error message Opening failed: I cannot find out if file {0} has HDF5 format. A logger error message File creation failed due to unknownreasons! Please, have a look to the last error displayed in the logger. If you think it's a bug, please report it to developers. A file creation error Creating the Query results file... A logger info message Node move: nodename already exists A dialog caption Source file: {0} Moved node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Rename A button label Tree of databases Header of the only column of the tree of databases view DBsTreeSortingPage <qt><p>Plugin that provides sorting capabilities to the tree of DBs.<p>At the moment only two sorting algorithms are supported: human (a.k.a. natural sorting) and alphabetical.</qt> Text of an About plugin message box DBsTreeView <qt> <h3>The Tree of databases</h3> For every open database this widget shows the object tree, a graphical representation<br>of the data hierarchy stored in the database.</qt> WhatsThis help for the tree pane ExportToCSV E&xport to CSV... Save dataset as CSV Save the dataset as a plain text with CSV format Status bar text for the Dataset -> Export to CSV... action Exporting dataset to CSV format Caption of the Export to CSV dialog CSV Files (*.csv);;All Files (*) Filter for the Export to CSV dialog Export Accept button text for QFileDialog Export failed because destination file already exists. A file creation error Export failed because destination container is a directory. A file creation error Empty dataset. Nothing to export. Scalar array. Nothing to export. The selected node has more than 2 dimensions. I can't export it to CSV format. The selected node is a VLArray. I can't export it to CSV format. Some fields aren't scalars. I can't export the table to CSV format. <qt><p>Plugin that provides export to CSV files capabilities.<p>Any kind of PyTables dataset can be exported. When exporting tables, a header with the field names can be inserted at top of the CSV file.</qt> Text of an About plugin message box FilePropPage Form Database Name: Path: Type: Access mode: Root group Number of children: GroupPropDlg File properties Dlg caption Group properties Dlg caption GroupPropPage Child name First column header of the table Type Second column header of the table group leaf link Group Title of the group box GroupedArrays Group Arrays into a unique view Checkbox tooltip HelpBrowser About HelpBrowser A dialog caption <html><h3>HelpBrowser</h3> HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs. <p>Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit.</html> About Help browser text About Qt A dialog caption HelpBrowserGUI Documentation browser The window title Ready... Status bar startup message E&xit File --> Exit Close Help Browser Status bar text for the File --> Exit action Zoom &in View --> Zoom in Increases the font size Status bar text for the View --> Zoom in action Zoom &out View --> Zoom out Decreases the font size Status bar text for the View --> Zoom out action &Home Go --> Home Go to the first visited page Status bar text for the Go --> Home action &Backward Go --> Backward Go to previous page Status bar text for the Go --> Backward action &Forward Go --> Forward Go to next page Status bar text for the Go --> Forward action &Reload Go --> Reload Reload the current page Status bar text for the Go --> Reload action &Add bookmark Bookmarks --> Add bookmark Bookmark the current page Status bar text for Bookmarks --> Add bookmark action &Edit bookmarks... Bookmarks --> Edit bookmarks Edit bookmarks Status bar text for Bookmarks --> Edit bookmarks action &Clear All Bookmarks --> Clear bookmark Clear all existing bookmarks Status bar text for Bookmarks --> Add bookmark action &About HelpBrowser Help --> About HelpBrowser About HelpBrowser Status bar text for Help --> About HelpBrowser action About &Qt Help --> About Qt About Qt Status bar text for the Help --> About Qt action Clear history Clear the content of the history combobox &File The File menu entry &View The View menu entry View operations Toolbar title &Go The Go menu entry Go operations Toolbar title &Bookmarks Bookmarks menu entry Bookmarks operations Toolbar title &Help The Help menu entry History operations Toolbar title Go: Text of the Go: label <qt> <h3>Page selector</h3>Select the page you want to visit. </qt> WhatsThis text for the combobox of visited pages ImportCSV Resolving first line role Message box title Does the first line of the file contain a table header or regular data? Message box text Header Button text Data Button text I&mport from CSV... File -> Import CSV Import &Table... Import table from CSV file Import Table from plain CSV file Status bar text for File -> Import CSV... -> Import Table Import &Array... Import array from CSV file Import Array from plain CSV file Status bar text for File -> Import CSV... -> Import Array Import &CArray... Import carray from CSV file Import CArray from plain CSV file Status bar text for File -> Import CSV... -> Import CArray Import &EArray... Import earray from CSV file Import EArray from plain CSV file Status bar text for File -> Import CSV... -> Import EArray Importing CSV file into {0} Caption of the Import from CSV dialog CSV Files (*.csv);;All Files (*) Filter for the Import from CSV dialog Import Accept button text for QFileDialog Please, make sure that you are importing a homogeneous dataset. CSV file not imported error Import failed because destination file already exists. A file creation error Import failed because destination container is a directory. A file creation error Import failed because destination file cannot be created. A file creation error <qt><p>Plugin that provides import CSV files capabilities.<p>CSV files can be imported into any of the following PyTables containers: Array, EArray, CArray and Table.<p>When a file is imported into a Table automatic header detection is provided. <p>Beware that importing large files is a potentially slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO.</qt> Text of an About plugin message box InputNodeNameDlg Dialog InfoLabel Node name: LeafPropDlg Table properties Dlg caption Array properties Dlg caption LeafPropPage Field name First column header of the table Type Second column header of the table Shape Third column header of the table nested - Form Database Name: Path: Type: Dataspace Dimensions: Shape: Data Type: Compression: LinkPropDialog Dialog General Name: Path: Type: Target: LinkPropDlg Link properties Dlg caption Logger <qt> <h3>The Logger</h3> This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user. <p>Also execution errors and exceptions are logged in the console. </qt> WhatsThis help for the logger &Copy Logger menu entry Copy selected text to clipboard Status bar text for the logger context menu -> Copy action Cl&ear All Logger menu entry Empty the Logger Status bar text for the logger context menu -> Clear action Select &All Logger menu entry Select the whole Logger contents Status bar text for the logger context menu -> Select All MenuUpdater Use a unique widget to display Arrays as if they where columns of a Table Status bar text for the Node -> Group Arrays action &Ungroup Arrays Ungroup previously grouped arrays. Ungroup previously grouped arrays. Status bar text for the Node -> Ungroup Arrays action &Group Arrays Group separated arrays with the same number of rows Error: grouping arrays, operation cancelled. Not all the selected arrays have the same number of rows. An error message in the ArraysColsOrganizer plugin NodeItemDelegate Renaming a node: name already in use A dialog caption Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Preferences General Text for page selector icon Look & Feel Text for page selector icon Plugins Text for page selector icon Sorry, there are no info available for this plugin A text label QueriesManager Table {0} is empty. Nothing to query. Warning message for users Table {0} has no columns suitable to be queried. All columns are nested, multidimensional or have a Complex data type. An error when trying to query a table Some table columns contain multidimensional, nested or Complex data. They cannot be queried so are not included in the Column selector of the query dialog. An informational note for users Cleaning the Query results file Caption of the QueryDeleteAll dialog Delete Button text Cancel Button text Query on table {0} failed! Warning log message about a failed query QueryDialog Dialog Global options Name: <qt> The name of the table where the query results will be added. </qt> Original indices into column: <qt> The name of the column where the indices of the selected rows will be added. </qt> Orig_idx Query condition <qt> <h3>Conditions syntax</h3> A condition on a table is just a <em>string</em> containing a Python expression that involves <em>at least one column</em> , and maybe some constants and external variables, all combined with algebraic operators or functions. Beware that <tt>&</tt>, <tt>|</tt> and <tt>~</tt> operators are used for logical comparisons. They have higher precedence than logical operators so we recommend to <em>always use parenthesis around logical operators</em>.</p> <p>The following table shows some examples of conditions and their equivalent Python expressions.</p> <div align='center'><table border='1'> <tr><th>Condition</th><th>Python expression</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>You can find detailed information about conditions in the Appendix B of the PyTables users guide.</p> </qt> <qt> The names of the searchable columns. They must fulfill the following requirements: <ul><li>must be not nested</li> <li>must have a scalar data type</li> <li>their data type cannot be <code>complex</code></li></ul> Columns whose names contains blanks are automatically mapped to variables whose names contain no blanks. For querying those columns the mapped variables will be used. </qt> <qt> The operators that can be used in a given condition. Operators can be logical, comparison and arithmetic.<br>Not all operators are available for every data type. </qt> <qt> The set of functions that can appear in a condition. It includes functions for doing selections, trigonometric functions and functions on complex numbers. For ease of use, arguments are automatically included when a function is inserted. The arguments meaning is: <ul><li>N: number</li><li>B: boolean</li> <li>F: float</li><li>C: complex</li></ul> </qt> The range of rows included in the query. Range of rows Start: 1 A range selector label Stop: Step: QueryDlg New query on table: {0} A dialog caption The chosen name is already in use. Please, choose another one. A logger info message Enter a name for the column of indices, please A logger info message The chosen name for the column of indicesis not valid. It contains '/' characters A logger info message The chosen name for the column of indices is already in use. "Please, choose another one. A logger info message The stop value is greater than the number of rows. Please, choose another one. A logger info message The start value is greater than the stop value. Please, choose another one. A logger info message The start value must be greater than 0. A logger info message RenameDlg Overwrite A button label Rename A button label RenameNodeDlg Dialog InfoLabel New name: SettingsDialog ViTables settings Click an item in this tree to select the settings you want to change. Beware that the listed plugins are *loaded* plugins (i.e. the are working in the current ViTables session) not just enabled plugins. Configure the startup behavior of ViTables. Startup The name of the groupbox where startup is configured If checked, the last working session -i.e. open files and views- will be restored. If not, ViTables will start with an empty session. Restore last session Label of the restore last session check button The working directory used when opening the very first file. It defaults to the current directory if ViTables has been launched from the command line or to the user's home directory if ViTables started from a menu or a desktop icon. If the checkbox is checked then the last entered directory will be used. Start in last working directory Label of the startup in the last open directory check box Configure the look and feel of ViTables. Customise font and colors of the Logger. Logger The title of the logger groubox You can preview your Font settings here. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html> Setup the text color. F&oreground The label of the logger text color button Setup the background color. &Background The label of the logger color button Here you can choose the font used in the Logger. &Font The label of the logger font chooser button Setup the background color of the workspace. Workspace The title of the workspace groupbox &Background The label of the workspace color button Background color sample A label for the workspace color sample Choose the global style of ViTables here. Style The title of the global aspect groupbox Available plugins The list of all available plugins. If a plugin is checked then it is enabled (but not necessarely loaded), if it is unchecked then it is disabled (but not necessarely unloaded). Please, note that changes in the check state of plugins will take effect the next time you start ViTables. TimeFormatterPage <qt> <p>Plugin that provides nice string formatting for time fields. <p>It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. </qt> Text of an About plugin message box Form Plugin description Version: Module name: Folder: Author: Desription: Configure time format Time format: Sample date: Today VTApp Node deletion Caption of the node deletion dialog About Qt Caption of the About Qt dialog Version Numbers Caption of the Versions dialog not available Part of the library not found text Configuration setup... A splash screen message Creating the GUI... A splash screen message ViTables {0} Copyright (c) 2008-2017 Vicent Mas. All rights reserved. Application startup message Recovering last session... A splash screen message Opening files... A splash screen message Opening the list of files... A splash screen message Opening failed: wrong {0} in line {1} of {2} Bad line format List of HDF5 files not read File not updated error Create Accept button text for QFileDialog Creating a new file... Caption of the File New... dialog HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Open New dialog New file creation failed because file already exists. A file creation error Copying a file... Caption of the File Save as... dialog HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Save As... dialog File Save as: file already exists A dialog caption Target directory: {0} The Query results database cannot be overwritten. Overwrite file dialog label Target directory: {0} The file being saved cannot overwrite itself. Overwrite file dialog label Target directory: {0} File name {1} already in use in that directory. Overwrite file dialog label Open Accept text for QFileDialog Select a file for opening Caption of the File Open... dialog About UnImplemented nodes A dialog caption Actual data for this node are not accesible.<br> The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.<br>If you want to see this kind of dataset implemented in PyTables, please, contact the developers. Text of the Unimplemented node dialog Creating a new group A dialog caption Source file: {0} Parent group: {1} A dialog label Create A button label Creating a new group: name already in use A dialog caption Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Renaming a node A dialog caption Source file: {0} Parent group: {1} A dialog label Rename A button label Renaming a node: name already in use A dialog caption About unreadable datasets Dialog caption Sorry, actual data for this node are not accesible.<br>The node will not be copied. Text of the Unimplemented node dialog Node paste: nodename already exists A dialog caption Source file: {0} Copied node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Paste A button label You are about to delete the node: {0} Ask for confirmation Delete Button text Cancel Button text <qt> <h3>ViTables {0}</h3> ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.<p> For more information see <b>http://www.vitables.org</b>.<p> Please send bug reports or feature requests to the <em>ViTables Users Group</em>.<p> ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. </qt> Text of the About ViTables dialog <qt> Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.<p> Kamil Kisiel and Max Bohnet for fixing bugs.<p> Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.<p> Oxygen team for a wonderful icons set.<p> All the people who reported bugs and made suggestions. </qt> Text of the About ViTables dialog (Thanks to page) About ViTables {0} Caption of the About ViTables dialog &About Title of the first tab of the About dialog &Thanks To Title of the second tab of the About dialog &License Title of the third tab of the About dialog VTGUI Ready... The status bar startup message ViTables {0} Main window title <qt> <h3>The Workspace</h3> This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously. <p>The diferent views can be tiled as a mosaic or stacked as a cascade. </qt> WhatsThis help for the workspace &New... File -> New Create a new file Status bar text for the File -> New action &Open... File -> Open Open an existing file Status bar text for the File -> Open action Read-only open... File -> Open Open an existing file in read-only mode Status bar text for the File -> Open action &Close File -> Close Close the selected file Status bar text for the File -> Close action Close &All File -> Close All Close all files Status bar text for the File -> Close All action &Save as... File -> Save As Save a renamed copy of the selected file Status bar text for the File -> Save As action E&xit File -> Exit Quit ViTables Status bar text for the File -> Exit action &Open view Node -> Open View Display the contents of the selected node Status bar text for the Node -> Open View action C&lose view Node -> Close View Close the view of the selected node Status bar text for the Node -> Close View action Prop&erties... Node -> Properties Show the properties dialog for the selected node Status bar text for the Node -> Properties action &New group... Node -> New group Create a new group under the selected node Status bar text for the Node -> New group action &Rename... Node -> Rename Rename the selected node Status bar text for the Node -> Rename action Cu&t Node -> Cut Cut the selected node Status bar text for the Node -> Cut action &Copy Node -> Copy Copy the selected node Status bar text for the Node -> Copy action &Paste Node -> Paste Paste the last copied/cut node Status bar text for the Node -> Copy action &Delete Node -> Delete Delete the selected node Status bar text for the Node -> Copy action &Query... Query -> New... Create a new filter for the selected table Status bar text for the Query -> New... action Delete &All Query -> Delete All Remove all filters Status bar text for the Query -> Delete All action &Preferences... Settings -> Preferences Configure ViTables Status bar text for the Settings -> Preferences action &Cascade Windows -> Cascade Arranges open windows in a cascade pattern Status bar text for the Windows -> Cascade action &Tile Windows -> Tile Arranges open windows in a tile pattern Status bar text for the Windows -> Tile action &Restore All Windows -> Restore All Restore all minimized windows on the workspace Status bar text for the Windows -> Restore All action &Minimize All Windows -> Minimize All Minimize all windows on the workspace Status bar text for the Windows -> Restore All action C&lose Windows -> Close Close the active view Status bar text for the Windows -> Close action Close &All Windows -> Close All Close all views Status bar text for the Windows -> Close All action Current View Windows -> separator Change view mode MDI -> Tabbed Change the workspace view mode Status bar text for the MDI -> Tabbed action &User's Guide Help -> Users Guide Open the ViTables User's Guide Status bar text for the Help -> Users Guide action &About ViTables Help -> About Display information about ViTables Status bar text for the Help -> About action About &Qt Help -> About Qt Display information about the Qt library Status bar text for the Help -> About Qt action Show &Versions Help -> Show Versions Show the versions of the libraries used by ViTables Status bar text for the Help -> Show Versions action File operations Toolbar title Click to open a file Click and hold to open a recent file File toolbar -> Open Recent Files Node operations Toolbar title Queries on tables Toolbar title Help system Toolbar title Whats this? help for a widget Status bar text for the Help -> Whats This action The node currently selected in the Tree of databases pane The Selected node box startup message &File The File menu entry Open R&ecent Files File -> Open Recent Files &Node The Node menu entry &Dataset The Dataset menu entry &Settings The Settings menu entry ToolBars Tools -> ToolBars action &Window The Windows menu entry &Help The Help menu entry Context help Status bar text for the Help -> Whats This action &Clear Recent File submenu entry &More... A Windows submenu Calculate... Calculate action Run calculation on opened tables. Action tip ViTables-3.0.0/vitables_es_ES.ts000066400000000000000000004264551311223072700165000ustar00rootroot00000000000000 AboutPage Form Plugin description Descripción del plugin Version: Versión: Module name: Nombre del módulo: Folder: Carpeta: Author: Autor: Desription: Descripción: ArrayColsOrganizer &Group Arrays Group separated arrays with the same number of rows A&grupa arrays Group Arrays into a unique view Checkbox tooltip text Agrupa arrays en una vista única <qt><p>Plugin that provides an alternative view for arrays with the same number of rows. <p>The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.</qt> Text of an About plugin message box <qt><p>Plugin que proporciona una vista alternativa para arrays con el mismo número de filas. <p>El usuario selecciona los arrays que desea ver agrupados. Entonces selecciona la entrada de menú Nodo -> Agrupa arrays y los arrays se visualizan de la forma esperada por el usuario.</qt> ArraysColsOrganizer <qt><p>Plugin that provides an alternative view for arrays with the same number of rows. <p>The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.</qt> Text of an About plugin message box <qt><p>Plugin que proporciona una vista alternativa para arrays con el mismo número de filas. <p>El usuario selecciona los arrays que desea ver agrupados. Entonces selecciona la entrada de menú Nodo -> Agrupa arrays y los arrays se visualizan de la forma esperada por el usuario.</qt> AttrEditor Error: "{0}" value mismatches its data type. User attributes table editing error Error: el valor "{0}" no concuerda con su tipo de datos. Error: "{0}" value is out of range. User attributes table editing error Error: el valor "{0}" está fuera de rango. Error: "{0}" value is out of range or mismatches its data type. User attributes table editing error Error: el valor "{0}" esta fuera de rango o no concuerda con su tipo de datos. Error: "{0}" cannot be converted to a Python object. User attributes table editing error Error: "{0}" no puede convertirse a un objeto Python. Error: empty field Name in the row {0:d} User attrs editing error Error: el campo Nombre está vacío en la fila {0:d} Error: attribute name "{0}" is repeated. User attrs table editing error Error: el nombre de atributo "{0}" está repetido. AttrPropDialog Dialog &System attributes Atributos de &Sistema System attributes: Atributos de sistema: &User Attributes Atributos de &Usuario User attributes: Atributos de usuario: <qt> <h3>User's attributes editing table</h3> Here you can perform the editing of user's attributes for this node. It is quite straightforward. <p>For adding an attribute click the <b>Add</b> button. A new row will be added to the table. Enter the attribute name and its value in the corresponding cells. Finally, select the attribute datatype in the combobox of the DataType column. In order to delete an attribute just select it by clicking any of its cells, then click the <b>Delete</b> button.</p> <p>Beware that PyTables stores scalar attributes as numpy scalar arrays so you will be unable to save them as Python objects even if you choose the Python datatype in the combobox selector. Also note that multidimensional attributes other than Python lists and tuples are not supported.</p> </qt> Help text for the User Attributes page <qt> <h3>Tabla de edición de atributos de usuario</h3> Aquí puedes editar los atributos de usuario para este nodo. Es bastante fácil. <p>Para añadir un atributo pulsa el botón <b>Añadir</b>. En la tabla se insertará una nueva fila. Introduce el nombre del atributo y su valor en las celdas correspondientes. Por último, selecciona el tipo de dato del atributo en el combobox de la columna Tipo de Dato. Para borrar un atributo seleccionalo pulsando en cualquiera de sus celdas y pulsa el botón <b>Borrar</b>.</p> <p>Ten en cuenta que PyTables almacena los atributos escalares como arrays escalares de Numpy, por eso no pueden guardarse como objetos Python, ni siquiera si eliges el tipo de dato Python en el combobox. Ten en cuenta también que los atributos multidimensionales (aparte de listas y tuplas de Python) no están soportados.</p> </qt> &Add &Añadir &Delete &Borrar &What's this &Qué es esto AttrPropDlg Name First column header of the table Nombre Value Second column header of the table Valor Datatype Third column header of the table Tipo de dato Please, select the attribute to be deleted. A usage text Por favor, selecciona el atributo que quieres borrar. User attribute deletion Caption of the attr deletion dialog Borrar atributo de usuario You are about to delete the attribute: {0} Ask for confirmation Estás a punto de borrar el atributo: {0} Delete Button text Borrar Cancel Button text Cancelar BookmarksDlg Bookmarks editor Dialog caption Editor de marcadores &OK Button label &Aceptar &Delete Button label &Borrar &Cancel Button label &Cancelar Bookmark First column header of the bookmarks table Marcador URL Second column header of the bookmarks table URL Buffer Problems reading records. The dataset seems to be compressed with the {0} library. Check that it is installed in your system, please. A dataset readability error Problemas leyendo los registros. El conjunto de datos parece estar comprimido con la librería {0}. Comprueba que esta librería está instalada, por favor. Data read error: {} A dataset read error Error de lectura de datos: {} Error: problems reading records. The dataset maybe corrupted. A dataset readability error Error: se han detectado problemas durante la lectura de registros. El conjunto de datos podría estar corrompido. Calculator No group is selected. Relative references are disabled. Continue? No se ha seleccionado ningún grupo. Las referencias relativas están desactivadas.¿Continuar? Multiple groups are selected. Relative references are disabled. Continue? Se han seleccionado varios grupos. Las referencias relativas están desactivadas ¿Continuar? Relative references are disabled Referencias relativas desactivadas Save expression as Guardar expresión como Name: Nombre: Node not found Nodo no encontrado Node type Tipo de nodo Result name Nombre del resultado The location to store results is not specified No se ha especificado ningún lugar para almacenar los resultados Create group Crear grupo Evaluation error Error de evaluación An exception was raised during evaluation, see log for details. Se lanzó una excepción durante la evaluación, consulta el fichero de log para ver los detalles. Result save error Error al guardar el resultado An exception was raised while trying to store results, see log for details. Se lanzó una excepción mientras se intentaba almacenar los resultados, consulta el fichero de log para ver los detalles. CalculatorDialog Evaluate expression Evaluar la expresión Saved expressions: Expresiones guardadas: Save Guardar Remove Borrar Statements: Sentencias: Expression: Expresión: Result table: Tabla de resultados: <html><head/><body><p>Saved expressions.</p></body></html> <html><head/><body><p>Expresiones guardadas.</p></body></html> <html><head/><body><p>Store expression for future use.</p></body></html> <html><head/><body><p>Almacenar la expresión para su uso futuro.</p></body></html> <html><head/><body><p>Remove the selected expression from the saved expressions list.</p></body></html> <html><head/><body><p>Borra la expresión seleccionada de la lista de expresiones guardadas.</p></body></html> <html><head/><body> <p>Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.</p> </body></html> <html><head/><body> <p>Conjunto de sentencias de Python que se ejecutarán antes de evaluar la expresión. Puede usarse para importar módulos adicionales o realizar cálculos preliminares para simplificar la expresión.</p> </body></html> <html><head/><body> <p>The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.</p> <p>The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.mydata&quot;. If &quot;sub_group&quot; is the current group then the string &quot;mydata&quot; can be used as reference.</p> </body></html> <html><head/><body> <p>Los resultados de la expresión se guardarán en la tabla de resultados. Este campo debe contener una expresión válida que devuelva un array de PyTables, una lista o un escalar.</p> <p>La expresión puede contener referencias a nodos abiertos. Una referencia puede ser absoluta y empezar con un nombre de fichero o relativa al grupo actual. Una referencia es un string construido mediante la unión de nombres de grupos que lleva a los datos por puntos. Por ejemplo: &quot;filename.h5.some_group.sub_group.mydata&quot;. Si &quot;sub_group&quot; es el grupo actual entonces la cadena &quot;mydata&quot; puede usarse como referencia.</p> </body></html> <html><head/><body> <p>Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.myresult&quot;. If &quot;sub_group&quot; is the current group then the string &quot;myresult&quot; can be used as reference.</p> <p>The result table must not exitst.</p> </body></html> <html><head/><body> <p>Referencia al destino para la expresión resultante. Una referencia es un string construido mediante la unión de nombres de grupos que lleva a los datos por puntos. Por ejemplo: &quot;filename.h5.some_group.sub_group.myresult&quot;. Si &quot;sub_group&quot; es el grupo actual entonces la cadena &quot;myresult&quot; puede usarse como referencia.</p> <p>La tabla de resultados no debe exisitir.</p> </body></html> ConfigFileIOException Configuration error: the application setting {0} cannot be saved. A logger error message Error de configuración: la configuración {0} de la aplicación no puede guardarse. Configuration warning: the application setting {0} cannot be read. Its default value will be used. A logger error message Aviso de configuración: la configuración {0} de la aplicación no puede leerse. Se utilizará su valor por defecto. DBDoc Warning: file access in read-write mode is denied. It will be opened in read-only mode. A logger error message Aviso: se ha denegado el acceso al fichero en modo lectura-escritura. El fichero se abrirá en modo solo lectura. {0} A logger error message {0} Please, if you think it is a bug, report it to developers. A logger error message Por favor, si crees que esto es un bug, informa de ello a los desarrolladores. Error: cannot open node {0} in file {1} Error message Error: no puede abrirse el nodo {0} del fichero {1} Unable to save the file {0} as {1}. Beware that only closed files can be safely overwritten via Save As... A logger error message No se puede guardar el fichero {0} como {1}. Ten en cuenta que solamente los ficheros cerrados se pueden sobreescribir con garantías via Guardar como... DBTreeSortPage Form Plugin description Descripción del plugin Version: Versión: Module name: Nombre del módulo: Folder: Carpeta: Author: Autor: Desription: Descripción: Sorting algorithm Algoritmo de ordenación DBsTreeModel Openning cancelled: {0} is a folder. A logger error message Apertura cancelada: {0} es una carpeta. Opening failed: file {0} cannot be found. A logger error message Fallo de apertura: no se encuentra el fichero {0}. Opening cancelled: file {0} already open. A logger error message Apertura cancelada: el fichero {0} ya está abierto. Opening cancelled: file {0} has not HDF5 format. A logger error message Apertura cancelada: el fichero {0} no tiene formato HDF5. Opening failed: I cannot find out if file {0} has HDF5 format. A logger error message Fallo de apertura: no se puede averiguar si el fichero {0} tiene formato HDF5. File creation failed due to unknownreasons! Please, have a look to the last error displayed in the logger. If you think it's a bug, please report it to developers. A file creation error La creación del fichero falló debido a razones desconocidas! Por favor, consulta el último error mostrado en el panel de log. Si crees que es un bug, por favor informa de ello a los desarrolladores. Creating the Query results file... A logger info message Creando el fichero Query results... Node move: nodename already exists A dialog caption Mover nodo: el nombre de nodo ya existe Source file: {0} Moved node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Fichero fuente: {0} Nodo movido: {1} Fichero destino: {2} Grupo padre: {3} Nombre de node '{4}' ya existe en ese grupo. Rename A button label Renombrar Tree of databases Header of the only column of the tree of databases view Árbol de bases de datos DBsTreeSortingPage <qt><p>Plugin that provides sorting capabilities to the tree of DBs.<p>At the moment only two sorting algorithms are supported: human (a.k.a. natural sorting) and alphabetical.</qt> Text of an About plugin message box <qt><p>Plugin que proporciona capacidades de ordenación al árbol de DBs.<p>Por el momento solo dos algoritmos están soportados: ordenación humana (o natural) y alfabética.</qt> DBsTreeView <qt> <h3>The Tree of databases</h3> For every open database this widget shows the object tree, a graphical representation<br>of the data hierarchy stored in the database.</qt> WhatsThis help for the tree pane <qt> <h3>El árbol de bases de datos</h3> Para cada base de datos abierta este panel muestra el árbol de objetos, una representación gráfica<br> de la jerarquía de datos almacenada en esa base de datos.</qt> ExportToCSV E&xport to CSV... Save dataset as CSV E&xportar a CSV... Save the dataset as a plain text with CSV format Status bar text for the Dataset -> Export to CSV... action Salvar el conjunto de datos como texto plano con formato CSV Exporting dataset to CSV format Caption of the Export to CSV dialog Exportando conjunto de datos a formato CSV CSV Files (*.csv);;All Files (*) Filter for the Export to CSV dialog Ficheros CSV (**.csv);; Todos los ficheros (*) Export Accept button text for QFileDialog Exportar Export failed because destination file already exists. A file creation error Exportar ha fallado porque el fichero de destino ya existe. Export failed because destination container is a directory. A file creation error Exportar ha fallado porque el contenedor de destino es una carpeta. Empty dataset. Nothing to export. El conjunto de datos está vacío. No hay nada que exportar. Scalar array. Nothing to export. Array escalar. No hay nada que exportar. The selected node has more than 2 dimensions. I can't export it to CSV format. El nodo seleccionado tiene más de 2 dimensiones. No puede ser exportado a formato CSV. The selected node is a VLArray. I can't export it to CSV format. El nodo seleccionado es un VLArray. No puede ser exportado a formato CSV. Some fields aren't scalars. I can't export the table to CSV format. Algunos campos no son escalares. No se puede exportar la tabla a formato CSV. <qt><p>Plugin that provides export to CSV files capabilities.<p>Any kind of PyTables dataset can be exported. When exporting tables, a header with the field names can be inserted at top of the CSV file.</qt> Text of an About plugin message box <qt><p>plugin que ofrece la posibilidad de exportar a formato CSV.<p>Casi cualquier conjunto de datos de PyTables puede ser exportado. Cuando se exportan tablas, una cabecera con el nombre de los campos puede insertarse en la primera línea del fichero CSV.</qt> FilePropPage Form Database Base de datos Name: Nombre: Path: Ruta: Type: Tipo: Access mode: Modo de acceso: Root group Grupo raíz Number of children: Número de hijos: GroupPropDlg File properties Dlg caption Propiedades del fichero Group properties Dlg caption Propiedades del grupo GroupPropPage Child name First column header of the table Nombre del hijo Type Second column header of the table Tipo group grupo leaf hoja link enlace Group Title of the group box Grupo GroupedArrays Group Arrays into a unique view Checkbox tooltip Agrupa Arrays en una única vista HelpBrowser About HelpBrowser A dialog caption Acerca del Navegador de Ayuda About Qt A dialog caption Acerca de Qt <html><h3>HelpBrowser</h3> HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs. <p>Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit.</html> About Help browser text <html><h3>Navegador de Ayuda</h3> El Navegador de Ayuda es un instrumento muy simple para mostrar la versión HTML de la Guía del Usuario sin necesidad de usar programas externos. <p>Y lo mejor de todo... está escrita en PyQt, el binding de Python para Qt. </html> HelpBrowserGUI Documentation browser The window title Navegador de documentación Ready... Status bar startup message Listo... Close Help Browser Status bar text for the File --> Exit action Cerrar Navegador de Ayuda E&xit File --> Exit &Salir Increases the font size Status bar text for the View --> Zoom in action Aumenta el tamaño de la fuente Zoom &in View --> Zoom in &Aumentar Decreases the font size Status bar text for the View --> Zoom out action Reduce el tamaño de la fuente Zoom &out View --> Zoom out &Reducir Go to the first visited page Status bar text for the Go --> Home action Ir a la primera página visitada &Home Go --> Home &Inicio Go to previous page Status bar text for the Go --> Backward action Ir a la página anterior &Backward Go --> Backward &Atrás Go to next page Status bar text for the Go --> Forward action Ir a la página siguiente Reload the current page Status bar text for the Go --> Reload action Recargar esta página &Reload Go --> Reload &Recargar Bookmark the current page Status bar text for Bookmarks --> Add bookmark action Marcar esta página &Add bookmark Bookmarks --> Add bookmark &Añadir marcador Edit bookmarks Status bar text for Bookmarks --> Edit bookmarks action Editar los marcadores del documento Clear all existing bookmarks Status bar text for Bookmarks --> Add bookmark action Borrar todos los marcadores About HelpBrowser Status bar text for Help --> About HelpBrowser action Acerca del Navegador de Ayuda &About HelpBrowser Help --> About HelpBrowser &Acerca del Navegador de Ayuda About Qt Status bar text for the Help --> About Qt action Acerca de Qt About &Qt Help --> About Qt Acerca de &Qt Go: Text of the Go: label Ir a: &Edit bookmarks... Bookmarks --> Edit bookmarks &Editar marcadores... <qt> <h3>Page selector</h3>Select the page you want to visit. </qt> WhatsThis text for the combobox of visited pages <qt><h3>Selector de página</h3>Selecciona la página que quieres visitar.</qt> &Forward Go --> Forward A&delante &Clear All Bookmarks --> Clear bookmark &Borrar Todos Clear history Borrar el historial de navegación Clear the content of the history combobox Borra el contenido del combobox del historial de navegación &File The File menu entry &Fichero &View The View menu entry &Tamaño View operations Toolbar title Operaciones con el tamaño &Go The Go menu entry &Ir Go operations Toolbar title Operaciones de navegación &Bookmarks Bookmarks menu entry &Marcadores Bookmarks operations Toolbar title Operaciones con marcadores &Help The Help menu entry &Ayuda History operations Toolbar title Operaciones con el historial de navegación ImportCSV Resolving first line role Message box title Resolviendo el rol de la primera línea Does the first line of the file contain a table header or regular data? Message box text ¿La primera línea contiene una cabecera de tabla o contiene datos? Header Button text Cabecera Data Button text Datos I&mport from CSV... File -> Import CSV I&mportar desde CSV... Import &Table... Import table from CSV file Importar &Tabla... Import Table from plain CSV file Status bar text for File -> Import CSV... -> Import Table Importar una tabla desde un fichero CSV Import &Array... Import array from CSV file Importar &Array... Import Array from plain CSV file Status bar text for File -> Import CSV... -> Import Array Importar un Array desde un fichero CSV Import &CArray... Import carray from CSV file Importar &CArray... Import CArray from plain CSV file Status bar text for File -> Import CSV... -> Import CArray Importar un CArray desde un fichero CSV Import &EArray... Import earray from CSV file Importar &EArray... Import EArray from plain CSV file Status bar text for File -> Import CSV... -> Import EArray Importar un EArray desde un fichero CSV Importing CSV file into {0} Caption of the Import from CSV dialog Importando fichero CSV en {0} CSV Files (*.csv);;All Files (*) Filter for the Import from CSV dialog Ficheros CSV (*.csv);; Todos los Ficheros (*) Import Accept button text for QFileDialog Importar Please, make sure that you are importing a homogeneous dataset. CSV file not imported error Por favor, asegúrate de que estás importando un conjunto de datos homogéneo. Import failed because destination file already exists. A file creation error Importar ha fallado porque el fichero de destino ya existe. Import failed because destination container is a directory. A file creation error Importar ha fallado porque el contenedor de destino es una carpeta. Import failed because destination file cannot be created. A file creation error Importar ha fallado porque no puede crearse el fichero de destino. <qt><p>Plugin that provides import CSV files capabilities.<p>CSV files can be imported into any of the following PyTables containers: Array, EArray, CArray and Table.<p>When a file is imported into a Table automatic header detection is provided. <p>Beware that importing large files is a potentially slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO.</qt> Text of an About plugin message box <qt><p>Plugin que proporciona la capacidad para importar ficheros CSV.<p>Los ficheros CSV pueden importarse en cualquiera de los siguientes contenedores de PyTables: Array, EArray, CArray y Table.<p>Cuando se importa el fichero a una tabla se dispone de detección automática de cabeceras <p>Hay que tener en cuenta que importar ficheros grandes es una operación potencialmente lenta porque el fichero completo tiene que leerse del disco, transformarse y almacenarse nuevamente en el disco, por tanto hay una gran cantidad de lectura/escritura al disco.</qt> InputNodeNameDlg Dialog InfoLabel Etiqueta informativa Node name: Nombre del nodo: LeafPropDlg Table properties Dlg caption Propiedades de la tabla Array properties Dlg caption Propiedades del array LeafPropPage Field name First column header of the table Campo Type Second column header of the table Tipo Shape Third column header of the table Forma nested anidado - - Form Database Base de datos Name: Nombre: Path: Ruta: Type: Tipo: Dataspace Espacio de datos Dimensions: Dimensiones: Shape: Forma: Data Type: Tipo de dato: Compression: Compresión: LinkPropDialog Dialog General General Name: Nombre: Path: Ruta: Type: Tipo: Target: Destino: LinkPropDlg Link properties Dlg caption Propiedades del enlace Logger &Copy Logger menu entry &Copiar Select &All Logger menu entry Seleccionar &Todo Cl&ear All Logger menu entry &Borrar Todo <qt> <h3>The Logger</h3> This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user. <p>Also execution errors and exceptions are logged in the console. </qt> WhatsThis help for the logger <qt><h3>La Consola</h3>Es el panel en el que queda registrado el resultado de determinadas operaciones ejecutadas por el usuario.<p>Los errores de ejecución y las excepciones también se registran en la consola.</qt> Copy selected text to clipboard Status bar text for the logger context menu -> Copy action Copia el texto seleccionado al Portapapeles Empty the Logger Status bar text for the logger context menu -> Clear action Borra la consola Select the whole Logger contents Status bar text for the logger context menu -> Select All Selecciona todo el contenido de la consola MenuUpdater Use a unique widget to display Arrays as if they where columns of a Table Status bar text for the Node -> Group Arrays action Usa un único widget para mostrar Arrays como si fueran columnas de una Table &Ungroup Arrays Ungroup previously grouped arrays. &Desagrupa Arrays Ungroup previously grouped arrays. Status bar text for the Node -> Ungroup Arrays action Desagrupa arrays agrupados anteriormente. &Group Arrays Group separated arrays with the same number of rows A&grupa arrays Error: grouping arrays, operation cancelled. Not all the selected arrays have the same number of rows. An error message in the ArraysColsOrganizer plugin Error: agrupamiento de Arrays cancelado. No todos los arrays seleccionados tienen el mismo número de filas. NodeItemDelegate Renaming a node: name already in use A dialog caption Renombrar un nodo: el nombre ya está en uso Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Fichero fuente: {0} Grupo padre: {1} Ya hay un nodo llamado '{2}' en el grupo padre. Preferences General Text for page selector icon General Look & Feel Text for page selector icon Apariencia Plugins Text for page selector icon Plugins Sorry, there are no info available for this plugin A text label Lo sentimos, no hay disponible información acerca de este plugin QueriesManager Table {0} is empty. Nothing to query. Warning message for users La tabla {0} está vacía. No hay nada que consultar. Table {0} has no columns suitable to be queried. All columns are nested, multidimensional or have a Complex data type. An error when trying to query a table La tabla {0} no contiene columnas que puedan ser consultadas. Todas las columnas están anidadas, son multidimensionales o tienen el tipo de datos Complex. Some table columns contain multidimensional, nested or Complex data. They cannot be queried so are not included in the Column selector of the query dialog. An informational note for users Algunas columnas de la tabla contienen datos multidimensionales, anidados o de tipo Complex. Estos campos no pueden consultarse y no se han incluído en el selector Columna del diálogo de consultas. Cleaning the Query results file Caption of the QueryDeleteAll dialog Limpiando el fichero Query results Delete Button text Borrar Cancel Button text Cancelar Query on table {0} failed! Warning log message about a failed query La consulta a la tabla {0} ha fallado! QueryDialog Dialog Global options Opciones globales Name: Nombre: <qt> The name of the table where the query results will be added. </qt> <qt> Nombre de la tabla a la que se añadirán los resultados de la consulta. </qt> Original indices into column: Índices originales en la columna: <qt> The name of the column where the indices of the selected rows will be added. </qt> <qt> El nombre de la columna en la que se añadirán los índices de las filas seleccionadas. </qt> Orig_idx Orig_índices Query condition Consulta <qt> <h3>Conditions syntax</h3> A condition on a table is just a <em>string</em> containing a Python expression that involves <em>at least one column</em> , and maybe some constants and external variables, all combined with algebraic operators or functions. Beware that <tt>&</tt>, <tt>|</tt> and <tt>~</tt> operators are used for logical comparisons. They have higher precedence than logical operators so we recommend to <em>always use parenthesis around logical operators</em>.</p> <p>The following table shows some examples of conditions and their equivalent Python expressions.</p> <div align='center'><table border='1'> <tr><th>Condition</th><th>Python expression</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>You can find detailed information about conditions in the Appendix B of the PyTables users guide.</p> </qt> <qt> <h3>Sintaxis de las consultas</h3> Una consulta en una tabla es simplemente una <em>cadena</em> que contiene una expresión Python que implica <em>como mínimo una columna</em> , y quizás algunas constantes y variables externas, todo ello combinado con operadores algebraicos o funciones. Ten en cuenta que los operadores <tt>&</tt>, <tt>|</tt> and <tt>~</tt> se usan para las comparaciones lógicas y tienen mayor precedencia que los operadores lógicos, así que recomendamos <em>usar siempre paréntesis con los operadores lógicos</em>.</p> <p>La siguiente tabla muestra algunas consultas y sus expresiones equivalentes en Python.</p> <div align='center'><table border='1'> <tr><th>Consulta</th><th>Expresión Python</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>Puedes encontrar información detallada acerca de las consultas en el Apéndice B de la guía de usuarios de PyTables.</p> </qt> <qt> The names of the searchable columns. They must fulfill the following requirements: <ul><li>must be not nested</li> <li>must have a scalar data type</li> <li>their data type cannot be <code>complex</code></li></ul> Columns whose names contains blanks are automatically mapped to variables whose names contain no blanks. For querying those columns the mapped variables will be used. </qt> <qt> Los nombres de las columnas que pueden ser consultadas. Deben cumplir los siguientes requerimientos: <ul><li>no deben estar anidados</li> <li>deben tener un tipo de datos escalar</li> <li>su tipo de datos no puede ser <code>complejo</code></li></ul> Las columnas cuyos nombres contengan blancos se asignan automáticamente a variables cuyos nombres no contienen blancos. Para consultar estas columnas se usarán los nombres de sus variables asociadas. </qt> <qt> The operators that can be used in a given condition. Operators can be logical, comparison and arithmetic.<br>Not all operators are available for every data type. </qt> <qt> Los operadores que pueden usarse en una consulta dada. Estos operadores pueden ser lógicos, de comparación y aritméticos.<br>No todos los operadores están disponibles en todos los tipos de dato. </qt> <qt> The set of functions that can appear in a condition. It includes functions for doing selections, trigonometric functions and functions on complex numbers. For ease of use, arguments are automatically included when a function is inserted. The arguments meaning is: <ul><li>N: number</li><li>B: boolean</li> <li>F: float</li><li>C: complex</li></ul> </qt> <qt> El conjunto de funciones que puede aparecer en una consulta. Incluye funciones para seleccionar datos, funciones trigonométricas y funciones para números complejos. Para facilitar el uso, los argumentos se incluyen automáticamente cuando se inserta una función. El significado de los argumentos es: <ul><li>N: número</li><li>B: booleano</li> <li>F: número en coma flotante</li><li>C: número complejo</li></ul> </qt> The range of rows included in the query. El rango de filas incluídas en la consulta. Range of rows Rango de filas Start: Inicio: 1 A range selector label 1 Stop: Fin: Step: Intervalo: QueryDlg The chosen name is already in use. Please, choose another one. A logger info message El nombre elegido ya está en uso. Por favor, utiliza un nombre diferente. The chosen name for the column of indicesis not valid. It contains '/' characters A logger info message El nombre elegido para la columna de índices no es válido porque contiene el carácter '/' New query on table: {0} A dialog caption Nueva consulta a la tabla: {0} Enter a name for the column of indices, please A logger info message Introduce un nombre para la columna de índices, por favor The chosen name for the column of indices is already in use. "Please, choose another one. A logger info message El nombre elegido para la columna de índices ya está en uso. Por favor, elige otro nombre. The stop value is greater than the number of rows. Please, choose another one. A logger info message El valor de stop es mayor que el número de filas. Por favor, elige otro valor. The start value is greater than the stop value. Please, choose another one. A logger info message El valor de inicio es mayor que el valor de finalización. Por favor, escoge otro valor. The start value must be greater than 0. A logger info message El valor de inicio debe ser mayor que 0. RenameDlg Overwrite A button label Sobreescribir Rename A button label Renombrar RenameNodeDlg Dialog InfoLabel Etiqueta informativa New name: Nuevo nombre: SettingsDialog ViTables settings Apariencia Click an item in this tree to select the settings you want to change. Beware that the listed plugins are *loaded* plugins (i.e. the are working in the current ViTables session) not just enabled plugins. Pulsa sobre un elemento en este árbol para seleccionar los ajustes que quieres cambiar. Configure the startup behavior of ViTables. Configura el comportamiento inicial de ViTables. Startup The name of the groupbox where startup is configured Inicio If checked, the last working session -i.e. open files and views- will be restored. If not, ViTables will start with an empty session. Si está seleccionado, recupera la última sesión de trabajo (ficheros abiertos y vistas). Si no, ViTables empieza con una sesión vacía. Restore last session Label of the restore last session check button Recupera la última sesión The working directory used when opening the very first file. It defaults to the current directory if ViTables has been launched from the command line or to the user's home directory if ViTables started from a menu or a desktop icon. If the checkbox is checked then the last entered directory will be used. La carpeta de trabajo usada para abrir el primer fichero. Su valor por defecto es la carpeta actual si ViTables se arranca desde una consola. Si arranca desde un menú o un icono de escritorio el valor por defecto es la carpeta home del usuario. Si el checkbox está seleccionado entonces se usa la última carpeta usada en la sesión anterior. Start in last working directory Label of the startup in the last open directory check box Empieza en l última carpeta de trabajo Configure the look and feel of ViTables. Configura la apariencia de ViTables. Customise font and colors of the Logger. Personaliza la fuente y los colores de la consola. Logger The title of the logger groubox Consola You can preview your Font settings here. Puedes previsualizar los ajustes de Fuente aquí. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html> Setup the text color. Ajusta el color del texto. F&oreground The label of the logger text color button Color del &texto Setup the background color. Ajusta el color de fondo. &Background The label of the logger color button Color del f&ondo Here you can choose the font used in the Logger. Aquí puedes ajustar la fuente usada en la consola. &Font The label of the logger font chooser button &Fuente Setup the background color of the workspace. Ajusta el color de fondo del área de trabajo. Workspace The title of the workspace groupbox Área de trabajo &Background The label of the workspace color button &Color del fondo Background color sample A label for the workspace color sample Ejemplo del color de fondo Choose the global style of ViTables here. Ajusta el estilo global de ViTables. Style The title of the global aspect groupbox Estilo Available plugins Plugins disponibles The list of all available plugins. If a plugin is checked then it is enabled (but not necessarely loaded), if it is unchecked then it is disabled (but not necessarely unloaded). Please, note that changes in the check state of plugins will take effect the next time you start ViTables. La lista de plugins disponibles. Los plugins marcados están activados (pero no necesariamente cargados), el resto están desactivados (pero no necesariamente descargados). Por favor, ten en cuenta que los cambios en esta lista tendrán efecto la próxima vez que arranques ViTables. TimeFormatterPage <qt> <p>Plugin that provides nice string formatting for time fields. <p>It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. </qt> Text of an About plugin message box <qt> <p>Plugin que proporciona un formato agradable para los campos de tiempo. <p>Soporta no solo el tipo de datos de tiempo nativo de PyTables sino también series temporales generadas (y almacenadas en tablas de PyTables) via Pandas y scikits.timeseries. </qt> Form Plugin description Descripción del plugin Version: Versión: Module name: Nombre del módulo: Folder: Carpeta: Author: Autor: Desription: Descripción: Configure time format configura el formato de fechas y horas Time format: Formato de fechas y horas: Sample date: Fecha de ejemplo: Today Hoy VTApp Node deletion Caption of the node deletion dialog Borrado de un nodo About Qt Caption of the About Qt dialog Acerca de Qt Version Numbers Caption of the Versions dialog Números de versión not available Part of the library not found text no disponible Configuration setup... A splash screen message Configurando la aplicación... Creating the GUI... A splash screen message Creando la interfaz gráfica... ViTables {0} Copyright (c) 2008-2017 Vicent Mas. All rights reserved. Application startup message ViTables {0} Copyright (c) 2008-2017 Vicent Mas. Todos los derechos reservados. Recovering last session... A splash screen message Recuperando la última sesión... Opening files... A splash screen message Abriendo ficheros... Opening the list of files... A splash screen message Abriendo la lista de ficheros... Opening failed: wrong {0} in line {1} of {2} Bad line format Fallo de apertura: {0} incorrecto en la línea {1} de {2} List of HDF5 files not read File not updated error No se ha leído la lista de ficheros HDF5 Create Accept button text for QFileDialog Crear Creating a new file... Caption of the File New... dialog Creando un fichero nuevo... HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Open New dialog Ficheros HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Todos los Ficheros (*) New file creation failed because file already exists. A file creation error La creación del nuevo fichero falló porque el fichero ya existe. Copying a file... Caption of the File Save as... dialog Copiando un fichero... HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Save As... dialog Ficheros HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Todos los Ficheros (*) File Save as: file already exists A dialog caption Fichero Guardar Como: el fichero ya existe Target directory: {0} The Query results database cannot be overwritten. Overwrite file dialog label Carpeta de destino: {0} La base de datos Query results no puede sobreescribirse. Target directory: {0} The file being saved cannot overwrite itself. Overwrite file dialog label Carpeta de destino: {0} El fichero que se está guardando no puede sobreescribirse a sí mismo. Target directory: {0} File name {1} already in use in that directory. Overwrite file dialog label Carpeta de destino: {0} El nombre de fichero {1} ya está en uso en esa carpeta. Open Accept text for QFileDialog Abrir Select a file for opening Caption of the File Open... dialog Selecciona un fichero para abrirlo About UnImplemented nodes A dialog caption Acerca de los nodos de tipo UnImplemented Actual data for this node are not accesible.<br> The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.<br>If you want to see this kind of dataset implemented in PyTables, please, contact the developers. Text of the Unimplemented node dialog Los datos contenidos en este nodo no son accesibles.<br> La combinación de tipos de datos y/o espacios de datos de este nodo todavía no está disponible en PyTables.<br>Si quieres ver está clase de nodo implementada en PyTables, por favor, contacta con los desarrolladores. Creating a new group A dialog caption Creando un nuevo grupo Source file: {0} Parent group: {1} A dialog label Fichero origen: {0} Grupo padre: {1} Create A button label Crear Creating a new group: name already in use A dialog caption Creando un nuevo grupo: el nombre ya está en uso Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Fichero origen: {0} Grupo padre: {1} Ya hay un nodo llamado '{2}' en ese grupo padre. Renaming a node A dialog caption Renombrando un nodo Source file: {0} Parent group: {1} A dialog label Fichero origen: {0} Grupo padre: {1} Rename A button label Renombrar Renaming a node: name already in use A dialog caption Renombrando un nodo: el nombre ya está en uso About unreadable datasets Dialog caption Acerca de conjuntos de datos ilegibles Sorry, actual data for this node are not accesible.<br>The node will not be copied. Text of the Unimplemented node dialog Lo siento, los datos de este nodo no están accesibles.<br>El nodo no se copiará. Node paste: nodename already exists A dialog caption Pegar un nodo: el nombre de nodo ya existe Source file: {0} Copied node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Fichero origen: {0} Nodo copiado: {1} Fichero destino: {2} Grupo padre: {3} El nombre de nodo '{4}' ya está en uso en ese grupo. Paste A button label Pegar You are about to delete the node: {0} Ask for confirmation Estás a punto de borrar el nodo: {0} Delete Button text Borrar Cancel Button text Cancelar <qt> <h3>ViTables {0}</h3> ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.<p> For more information see <b>http://www.vitables.org</b>.<p> Please send bug reports or feature requests to the <em>ViTables Users Group</em>.<p> ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. </qt> Text of the About ViTables dialog <qt> <h3>ViTables {0}</h3> ViTables es una herramienta gráfica para ver conjuntos de datos almacenados en ficheros PyTables y HDF5. Está escrita en PyQt , los binding de Python para Qt.<p> Para más información ver <b>http://www.vitables.org</b>.<p> Por favor, informa de los bugs que encuentres y de la funcionalidad que eches en falta al <em>Grupo de Usuarios de ViTables</em>.<p> ViTables usa software de terceros, que tiene su propio copyright. Para más detalles ver la nota de copyright de los paquetes individuales. </qt> <qt> Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.<p> Kamil Kisiel and Max Bohnet for fixing bugs.<p> Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.<p> Oxygen team for a wonderful icons set.<p> All the people who reported bugs and made suggestions. </qt> Text of the About ViTables dialog (Thanks to page) <qt> Alexey Naydenov por sus numerosas y valiosas contribuciones.<p> Kamil Kisiel y Max Bohnet por solucionar bugs.<p> Dmitrijs Ledkovs por sus contribuciones al sistema de empaquetado.<p> y por sus paquetes para Debian. Al equipo Oxygen por su fantástico conjunto de iconos.<p> Toda la gente que ha informado de bugs y ha hecho sugerencias. </qt> About ViTables {0} Caption of the About ViTables dialog Acerca de ViTables {0} &About Title of the first tab of the About dialog &Acerca &Thanks To Title of the second tab of the About dialog &Gracias A &License Title of the third tab of the About dialog &Licencia VTGUI Ready... The status bar startup message Listo... ViTables {0} Main window title ViTables {0} <qt> <h3>The Workspace</h3> This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously. <p>The diferent views can be tiled as a mosaic or stacked as a cascade. </qt> WhatsThis help for the workspace <qt> <h3>El área de trabajo</h3> Es el área donde se muestran las hojas abiertas del árbol de objetos. Pueden mostrarse al mismo tiempo una gran cantidad de tablas y arrays. <p>Las diferentes vistas se pueden mostrar en mosaico o en cascada. </qt> &New... File -> New &Nuevo... Create a new file Status bar text for the File -> New action Crea un nuevo fichero &Open... File -> Open &Abrir... Open an existing file Status bar text for the File -> Open action Abre un fichero Read-only open... File -> Open Abrir en Solo-Lectura... Open an existing file in read-only mode Status bar text for the File -> Open action Abrir un fichero en modo solo-lectura &Close File -> Close &Cerrar Close the selected file Status bar text for the File -> Close action Cierra el fichero seleccionado Close &All File -> Close All Cerrar &Todos Close all files Status bar text for the File -> Close All action Cierra todos los ficheros &Save as... File -> Save As &Guardar como... Save a renamed copy of the selected file Status bar text for the File -> Save As action Guarda una copia renombrada del fichero seleccionado E&xit File -> Exit &Salir Quit ViTables Status bar text for the File -> Exit action Cierra ViTables &Open view Node -> Open View &Abrir Vista Display the contents of the selected node Status bar text for the Node -> Open View action Muestra el contenido del nodo seleccionado C&lose view Node -> Close View C&errar Vista Close the view of the selected node Status bar text for the Node -> Close View action Cierra la vista del nodo seleccionado Prop&erties... Node -> Properties Prop&iedades... Show the properties dialog for the selected node Status bar text for the Node -> Properties action Muestra el diálogo de propiedades para el nodo seleccionado &New group... Node -> New group &Nuevo Grupo... Create a new group under the selected node Status bar text for the Node -> New group action Crea un nuevo grupo bajo el nodo seleccionado &Rename... Node -> Rename &Renombrar... Rename the selected node Status bar text for the Node -> Rename action Renombra el nodo seleccionado Cu&t Node -> Cut Cor&tar Cut the selected node Status bar text for the Node -> Cut action Corta el nodo seleccionado &Copy Node -> Copy &Copiar Copy the selected node Status bar text for the Node -> Copy action Copia el nodo seleccionado &Paste Node -> Paste &Pegar Paste the last copied/cut node Status bar text for the Node -> Copy action Pega el último nodo copiado/cortado &Delete Node -> Delete &Borrar Delete the selected node Status bar text for the Node -> Copy action Borra el nodo seleccionado &Query... Query -> New... &Consulta... Create a new filter for the selected table Status bar text for the Query -> New... action Crea un nuevo filtro para la tabla seleccionada Delete &All Query -> Delete All Borrar &Todos Remove all filters Status bar text for the Query -> Delete All action Borra todos los filtros &Preferences... Settings -> Preferences &Preferencias... Configure ViTables Status bar text for the Settings -> Preferences action Configura ViTables &Cascade Windows -> Cascade &Cascada Arranges open windows in a cascade pattern Status bar text for the Windows -> Cascade action Distribuye las vistas del área de trabajo en cascada &Tile Windows -> Tile &Mosaico Arranges open windows in a tile pattern Status bar text for the Windows -> Tile action Distribuye las vistas del área de trabajo en mosaico &Restore All Windows -> Restore All &Recuperar Todo Restore all minimized windows on the workspace Status bar text for the Windows -> Restore All action Recupera todas las vistas minimizadas del área de trabajo &Minimize All Windows -> Minimize All M&inimizar Todo Minimize all windows on the workspace Status bar text for the Windows -> Restore All action Minimiza todas las vistas del área de trabajo C&lose Windows -> Close C&errar Close the active view Status bar text for the Windows -> Close action Cierra la vista seleccionada Close &All Windows -> Close All Cerrar &Todo Close all views Status bar text for the Windows -> Close All action Cierra todas las vistas Current View Windows -> separator Vista actual Change view mode MDI -> Tabbed Cambiar modo de visualización Change the workspace view mode Status bar text for the MDI -> Tabbed action Cambia el modo de visualización del área de trabajo &User's Guide Help -> Users Guide Guía del &Usuario Open the ViTables User's Guide Status bar text for the Help -> Users Guide action Abre la Guía del Usuario &About ViTables Help -> About &Acerca de ViTables Display information about ViTables Status bar text for the Help -> About action Muestra información acerca de ViTables About &Qt Help -> About Qt Acerca de &Qt Display information about the Qt library Status bar text for the Help -> About Qt action Muestra información acerca de la biblioteca Qt Show &Versions Help -> Show Versions Mostrar &Versiones Show the versions of the libraries used by ViTables Status bar text for the Help -> Show Versions action Muestra las versiones de las bibliotecas usadas por ViTables File operations Toolbar title Operaciones Sobre Ficheros Click to open a file Click and hold to open a recent file File toolbar -> Open Recent Files Pulsa para abrir un fichero Mantén pulsado para abrir un fichero reciente Node operations Toolbar title Operaciones Sobre Nodos Queries on tables Toolbar title Consultas a Tablas Help system Toolbar title Sistema de Ayuda Whats this? help for a widget Status bar text for the Help -> Whats This action Ayuda del tipo ¿Qué es esto? para un widget The node currently selected in the Tree of databases pane The Selected node box startup message El nodo actualmente seleccionado en el árbol de bases de datos &File The File menu entry &Fichero Open R&ecent Files File -> Open Recent Files Abrir Ficheros &Recientes &Node The Node menu entry &Nodo &Dataset The Dataset menu entry &Conjunto de datos &Settings The Settings menu entry C&onfiguración ToolBars Tools -> ToolBars action Barras de herramientas &Window The Windows menu entry &Ventana &Help The Help menu entry &Ayuda Context help Status bar text for the Help -> Whats This action Ayuda contextual &Clear Recent File submenu entry &Borrar &More... A Windows submenu &Más... Calculate... Calculate action Calcular... Run calculation on opened tables. Action tip Ejecuta un cálculo en tablas abiertas. ViTables-3.0.0/vitables_ru_RU.ts000066400000000000000000004151431311223072700165260ustar00rootroot00000000000000 AboutPage Form Plugin description Version: Module name: Folder: Author: Desription: ArrayColsOrganizer &Group Arrays Group separated arrays with the same number of rows С&группировать Group Arrays into a unique view Checkbox tooltip text <qt><p>Plugin that provides an alternative view for arrays with the same number of rows. <p>The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.</qt> Text of an About plugin message box Альтернативный метод отображения массивов ArraysColsOrganizer <qt><p>Plugin that provides an alternative view for arrays with the same number of rows. <p>The user selects the arrays which he want to see in a unique viewer. Then clicks on the Node -> Linked View menu entry and the arrays are displayed as expected by the user.</qt> Text of an About plugin message box Альтернативный метод отображения массивов AttrEditor Error: "{0}" value mismatches its data type. User attributes table editing error Ошибка: "{0}" значение не совпадает с типом данных. Error: "{0}" value is out of range. User attributes table editing error Ошибка: "{0}" превышение значения. Error: "{0}" value is out of range or mismatches its data type. User attributes table editing error Ошибка: "{0}" превышения допустимого значение или несовпадение типа. Error: "{0}" cannot be converted to a Python object. User attributes table editing error Ошибка: "{0}" не может быть преобразовано в объект Python. Error: empty field Name in the row {0:d} User attrs editing error Ошибка: пустое поле Name в строке{0:d} Error: attribute name "{0}" is repeated. User attrs table editing error Ошибка: повторное использование "{0}" для имени аттрибута. AttrPropDialog Dialog &System attributes System attributes: &User Attributes User attributes: <qt> <h3>User's attributes editing table</h3> Here you can perform the editing of user's attributes for this node. It is quite straightforward. <p>For adding an attribute click the <b>Add</b> button. A new row will be added to the table. Enter the attribute name and its value in the corresponding cells. Finally, select the attribute datatype in the combobox of the DataType column. In order to delete an attribute just select it by clicking any of its cells, then click the <b>Delete</b> button.</p> <p>Beware that PyTables stores scalar attributes as numpy scalar arrays so you will be unable to save them as Python objects even if you choose the Python datatype in the combobox selector. Also note that multidimensional attributes other than Python lists and tuples are not supported.</p> </qt> Help text for the User Attributes page &Add &Delete &Удалить &What's this AttrPropDlg Name First column header of the table Имя Value Second column header of the table Значение Datatype Third column header of the table Тип данных Please, select the attribute to be deleted. A usage text Выберите аттрибут для удаления. User attribute deletion Caption of the attr deletion dialog Удаление аттрибута You are about to delete the attribute: {0} Ask for confirmation Подтверждение удаления аттрибута {0} Delete Button text Удалить Cancel Button text Отменить BookmarksDlg Bookmarks editor Dialog caption Редактор закладок Bookmark First column header of the bookmarks table Закладка URL Second column header of the bookmarks table Ссылка &OK Button label &Применить &Delete Button label &Удалить &Cancel Button label &Отменить Buffer Problems reading records. The dataset seems to be compressed with the {0} library. Check that it is installed in your system, please. A dataset readability error Ошибка чтения записей. Набор данных может быть сжат при помощи библиотеки {0}. Убедитесь в ее установке на Вашей системе. Data read error: {} A dataset read error Ошибка чтения данных: {} Error: problems reading records. The dataset maybe corrupted. A dataset readability error Ошибка чтения записей. Возможно повреждения набора данных. Calculator No group is selected. Relative references are disabled. Continue? Группа не выбрана. Относительные ссылки не возможные. Продолжить? Multiple groups are selected. Relative references are disabled. Continue? Выбрано более одной группы. Относительные ссылки не возможные. Продолжить? Relative references are disabled Относительные ссылка заблокированы Save expression as Сохранить выражение как Name: Имя: Node not found Узел не найден Node type Тип узла Result name Имя для результатов The location to store results is not specified Не задано место для сохранения результатов Create group Создать группу Evaluation error Ошибка вычисления An exception was raised during evaluation, see log for details. В процессе вычисления возникло исключения, детали в журнале. Result save error Ошибка при сохранении результата An exception was raised while trying to store results, see log for details. В процессе сохранения результата возникло исключения, детали в журнале. CalculatorDialog Evaluate expression Вычислить выражение Saved expressions: Сохраненные выражения: Save Сохранить Remove Удалить Statements: Комманды: Expression: Выражения: Result table: Таблица для результатов: <html><head/><body><p>Saved expressions.</p></body></html> <html><head/><body><p>Сохраненные выражения.</p></body></html> <html><head/><body><p>Store expression for future use.</p></body></html> <html><head/><body><p>Сохранить выражения для дальнейшего использования.</p></body></html> <html><head/><body><p>Remove the selected expression from the saved expressions list.</p></body></html> <html><head/><body><p>Удалить выделенное выражения из списка.</p></body></html> <html><head/><body> <p>Set of python statements that will be executed before the expression is evaluated. This can be used to import additional modules or do preliminary calculations to simplify the expression.</p> </body></html> <html><head/><body> <p>Набор выражений языка python, которые будут выполненеы перед вычислением выражния. Данное поле может быть использовано для импорта модулей или предварительных вычислений для упрощения выражения.</p> </body></html> <html><head/><body> <p>The results of the expression will be saved in the result table. This field must contain a valid expression that returns a pytables array, list or scalar.</p> <p>The expression can contain references to open data nodes. A reference can either be absolute and start from a file name or relative to the current group. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.mydata&quot;. If &quot;sub_group&quot; is the current group then the string &quot;mydata&quot; can be used as reference.</p> </body></html> <html><head/><body> <p>Результат вычисления данного выражения будет сохранен в таблице. Данное поле должно содержать выражение, которое возвращает pytables массив, список или скаляр.</p> <p>Выражения могут содержать ссылки на загруженные данные. Ссылки могут быть либо абсолютными и начинаться с имени файла или относительными. Ссылка на набор данных представляет собой строку, состоящую из имен групп разделенных точками. Например: &quot;filename.h5.some_group.sub_group.mydata&quot;. Если &quot;sub_group&quot; является текущей группой, то в качестве ссылки можно использовать строку &quot;mydata&quot;.</p> </body></html> <html><head/><body> <p>Reference to the destination for the expression result. Data refenrence is a string which is build by joining group names that lead to the data by dots. For example: &quot;filename.h5.some_group.sub_group.myresult&quot;. If &quot;sub_group&quot; is the current group then the string &quot;myresult&quot; can be used as reference.</p> <p>The result table must not exitst.</p> </body></html> <html><head/><body> <p>Место для сохранения результатов вычислений. Ссылка на набор данных представляет собой строку, состоящую из имен групп разделенных точками. Например: &quot;filename.h5.some_group.sub_group.myresult&quot;. Если &quot;sub_group&quot; является текущей группой, то в качестве ссылки можно использовать строку &quot;myresult&quot;.</p> <p>Таблица, в которую будет сохранен результат, не должна существовать.</p> </body></html> ConfigFileIOException Configuration error: the application setting {0} cannot be saved. A logger error message Ошибка конфигурации: настройки приложения {0} не могут быть сохранены. Configuration warning: the application setting {0} cannot be read. Its default value will be used. A logger error message Предупреждение: настройки приложения {0} не могут бытьпрочитаны. Будут использованы значения по умолчанию. DBDoc Warning: file access in read-write mode is denied. It will be opened in read-only mode. A logger error message Предупреждение: отказано в открытии файла в режиме чтение/запись. Файл будет открыт только для чтения. {0} A logger error message {0} Please, if you think it is a bug, report it to developers. A logger error message Пожалуйста, если у Вас есть подозрение о некорректной работе программы, сообщите разработчикам. Error: cannot open node {0} in file {1} Error message Ошибка: не возможно открыть узел {0} в файле {1} Unable to save the file {0} as {1}. Beware that only closed files can be safely overwritten via Save As... A logger error message Не возможно сохранить файл {0} как {1}. Только закрытые файлы могут быть безопасно перезаписаны через Save As... DBTreeSortPage Form Plugin description Version: Module name: Folder: Author: Desription: Sorting algorithm DBsTreeModel Openning cancelled: {0} is a folder. A logger error message Отмена открытия: {0} является папкой. Opening failed: file {0} cannot be found. A logger error message Ошибка: файл {0} не найден. Opening cancelled: file {0} already open. A logger error message Отмена: файл {0} уже открыт. Opening cancelled: file {0} has not HDF5 format. A logger error message Отмена: файл {0} не в формате HDF5. Opening failed: I cannot find out if file {0} has HDF5 format. A logger error message Ошибка: не возможно определить формат файла {0}. File creation failed due to unknownreasons! Please, have a look to the last error displayed in the logger. If you think it's a bug, please report it to developers. A file creation error Неизвестная ошибка при создании файла. Обратите внимание на последнюю ошибку. Если она связана с некорректной работой программы, то сообщите разработчикам. Creating the Query results file... A logger info message Создание файла с результатами запроса... Node move: nodename already exists A dialog caption Перемещение узла: узел уже существует Source file: {0} Moved node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Исходный файл: {0} Перемещенный узел: {1} Файл назначения: {2} Родительская группа: {3} Узел с именем {4} уже существует в этой группе. Rename A button label Переименовать Tree of databases Header of the only column of the tree of databases view Дерево базы данных DBsTreeSortingPage <qt><p>Plugin that provides sorting capabilities to the tree of DBs.<p>At the moment only two sorting algorithms are supported: human (a.k.a. natural sorting) and alphabetical.</qt> Text of an About plugin message box Плагин позволяющий сортировать дерево базы данных DBsTreeView <qt> <h3>The Tree of databases</h3> For every open database this widget shows the object tree, a graphical representation<br>of the data hierarchy stored in the database.</qt> WhatsThis help for the tree pane Дерево базы данных ExportToCSV E&xport to CSV... Save dataset as CSV &Экспорт в CSV... Save the dataset as a plain text with CSV format Status bar text for the Dataset -> Export to CSV... action Сохранить набор данных в формате CSV Exporting dataset to CSV format Caption of the Export to CSV dialog Экспорт набора данных в формате CSV CSV Files (*.csv);;All Files (*) Filter for the Export to CSV dialog CSV файл (*.csv);;Все файлы (*) Export Accept button text for QFileDialog Экспорт Export failed because destination file already exists. A file creation error Ошибка при создании нового файла, так как он уже существует. Export failed because destination container is a directory. A file creation error Экспорт не удался так, как выбраный объект подкаталог. Empty dataset. Nothing to export. Пустой набор данных. Scalar array. Nothing to export. Одномерный массив, экспорт не возможен. The selected node has more than 2 dimensions. I can't export it to CSV format. Выбранный узел имеет размерность больше 2-х. Экспорт в CSV не возможен. The selected node is a VLArray. I can't export it to CSV format. Выбранный узел является VLArray. Экспорт в CSV не возможен. Some fields aren't scalars. I can't export the table to CSV format. Некоторые из полей не являются числами. Экспорт не возможен. <qt><p>Plugin that provides export to CSV files capabilities.<p>Any kind of PyTables dataset can be exported. When exporting tables, a header with the field names can be inserted at top of the CSV file.</qt> Text of an About plugin message box Надстройка для экспорта в формате CSV FilePropPage Form Database Name: Имя: Path: Type: Access mode: Root group Number of children: GroupPropDlg File properties Dlg caption Свойства файла Group properties Dlg caption Свойства группы GroupPropPage Child name First column header of the table Имя наследника Type Second column header of the table Тип group группа leaf лист link ссылка Group Title of the group box Группа GroupedArrays Group Arrays into a unique view Checkbox tooltip HelpBrowser About HelpBrowser A dialog caption О HelpBrowser <html><h3>HelpBrowser</h3> HelpBrowser is a very simple tool for displaying the HTML version of the ViTables' Guide without using external programs. <p>Best of all... it is written using PyQt, the Python bindings for the Qt GUI toolkit.</html> About Help browser text HelpBrowser About Qt A dialog caption О Qt HelpBrowserGUI Documentation browser The window title Просмотр документации Ready... Status bar startup message Готов... E&xit File --> Exit &Выход Close Help Browser Status bar text for the File --> Exit action Закрытие документации Zoom &in View --> Zoom in &Увеличить Increases the font size Status bar text for the View --> Zoom in action Увеличить размер шрифта Zoom &out View --> Zoom out У&меньшить Decreases the font size Status bar text for the View --> Zoom out action Уменьшить размер шрифта &Home Go --> Home &Домой Go to the first visited page Status bar text for the Go --> Home action Перейти к первой посещенной странице &Backward Go --> Backward &Назад Go to previous page Status bar text for the Go --> Backward action Перейти к предыдущей странице &Forward Go --> Forward &Вперед Go to next page Status bar text for the Go --> Forward action Перейти к следующей странице &Reload Go --> Reload &Обновить Reload the current page Status bar text for the Go --> Reload action Обновить текущую страницу &Add bookmark Bookmarks --> Add bookmark Добавить &закладку Bookmark the current page Status bar text for Bookmarks --> Add bookmark action Создать закладку с текущей страницей &Edit bookmarks... Bookmarks --> Edit bookmarks &Редактировать закладки... Edit bookmarks Status bar text for Bookmarks --> Edit bookmarks action Редактировать закладки &Clear All Bookmarks --> Clear bookmark &Очистить все Clear all existing bookmarks Status bar text for Bookmarks --> Add bookmark action Очистить все существующие закладки &About HelpBrowser Help --> About HelpBrowser О &HelpBrowser About HelpBrowser Status bar text for Help --> About HelpBrowser action О HelpBrowser About &Qt Help --> About Qt О &Qt About Qt Status bar text for the Help --> About Qt action О Qt Clear history Очистить историю Clear the content of the history combobox Очистить историю &File The File menu entry &Файл &View The View menu entry &Вид View operations Toolbar title Управление видом &Go The Go menu entry &Перейти Go operations Toolbar title Управлением переходом &Bookmarks Bookmarks menu entry &Закладки Bookmarks operations Toolbar title Управление закладками &Help The Help menu entry &Справка History operations Toolbar title Справка Go: Text of the Go: label Перейти: <qt> <h3>Page selector</h3>Select the page you want to visit. </qt> WhatsThis text for the combobox of visited pages Выбор странице ImportCSV Resolving first line role Message box title Определение типа первой строки Does the first line of the file contain a table header or regular data? Message box text Что содержит первая строка? Заголовок таблицы или данные? Header Button text Заголовок Data Button text Данные I&mport from CSV... File -> Import CSV &Импорт из CSV... Import &Table... Import table from CSV file Импортировать &таблицу... Import Table from plain CSV file Status bar text for File -> Import CSV... -> Import Table Импорт таблицы из файла CSV Import &Array... Import array from CSV file Импортировать &массив... Import Array from plain CSV file Status bar text for File -> Import CSV... -> Import Array Импортировать массив из файла CSV Import &CArray... Import carray from CSV file Импортировать &CArray... Import CArray from plain CSV file Status bar text for File -> Import CSV... -> Import CArray Импортировать массив из файла CSV Import &EArray... Import earray from CSV file Импортировать &EArray... Import EArray from plain CSV file Status bar text for File -> Import CSV... -> Import EArray Импортировать массив из файла CSV Importing CSV file into {0} Caption of the Import from CSV dialog Импорт CSV файла в {0} CSV Files (*.csv);;All Files (*) Filter for the Import from CSV dialog CSV файл (*.csv);;Все файлы (*) Import Accept button text for QFileDialog Импорт Please, make sure that you are importing a homogeneous dataset. CSV file not imported error Убедитесь, что импортируемые данные однородны. Import failed because destination file already exists. A file creation error Импорт не удался так, как файл уже существует. Import failed because destination container is a directory. A file creation error Импорт не удался, так как объект уже существует. Import failed because destination file cannot be created. A file creation error Импорт не удался, так как файл не может быть создан. <qt><p>Plugin that provides import CSV files capabilities.<p>CSV files can be imported into any of the following PyTables containers: Array, EArray, CArray and Table.<p>When a file is imported into a Table automatic header detection is provided. <p>Beware that importing large files is a potentially slow process because the whole file has to be read from disk, transformed and write back to disk again so there is a lot of disk IO.</qt> Text of an About plugin message box Надстройка для импорта данных из CSV файла InputNodeNameDlg Dialog InfoLabel Node name: LeafPropDlg Table properties Dlg caption Свойства листа Array properties Dlg caption Свойства массива LeafPropPage Field name First column header of the table Имя поля Type Second column header of the table Тип Shape Third column header of the table Форма nested вложенный - - Form Database Name: Имя: Path: Type: Dataspace Dimensions: Shape: Data Type: Compression: LinkPropDialog Dialog General Name: Имя: Path: Type: Target: LinkPropDlg Link properties Dlg caption Свойства ссылки Logger <qt> <h3>The Logger</h3> This is the screen region where info about the currently selected item is displayed. It also logs the result of all operations requested by the user. <p>Also execution errors and exceptions are logged in the console. </qt> WhatsThis help for the logger Журнал &Copy Logger menu entry &Копировать Copy selected text to clipboard Status bar text for the logger context menu -> Copy action Скопировать выделенный узел в буффер обмена Cl&ear All Logger menu entry &Очистить все Empty the Logger Status bar text for the logger context menu -> Clear action Очистить журнал Select &All Logger menu entry &Выделить все Select the whole Logger contents Status bar text for the logger context menu -> Select All Выделить все содержимое журнала MenuUpdater Use a unique widget to display Arrays as if they where columns of a Table Status bar text for the Node -> Group Arrays action Использовать специализированный элемент для отображения массивов в виде столбцов таблицы &Ungroup Arrays Ungroup previously grouped arrays. &Разбить группу Ungroup previously grouped arrays. Status bar text for the Node -> Ungroup Arrays action Убрать группирование массивов. &Group Arrays Group separated arrays with the same number of rows С&группировать Error: grouping arrays, operation cancelled. Not all the selected arrays have the same number of rows. An error message in the ArraysColsOrganizer plugin NodeItemDelegate Renaming a node: name already in use A dialog caption Переименование узла: имя уже используется Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Исходный файл: {0} Родительская группа: {1} Узел с именем {2} уже существует в родительской группе. Preferences General Text for page selector icon Общие Look & Feel Text for page selector icon Внешний вид Plugins Text for page selector icon Плагин Sorry, there are no info available for this plugin A text label Описание плагина отсутствует QueriesManager Table {0} is empty. Nothing to query. Warning message for users Таблица {0} пустая. Запрос невозможен. Table {0} has no columns suitable to be queried. All columns are nested, multidimensional or have a Complex data type. An error when trying to query a table Таблица {0} не содержит столбцов, которые могут быть использованы в запросе. Все столбцы вложены, большой размерности или содержат комплексные данные. Some table columns contain multidimensional, nested or Complex data. They cannot be queried so are not included in the Column selector of the query dialog. An informational note for users Некоторые из столбцов содержат много размерные, вложенные или комплексные данные. Запрос к ним не возможен. Cleaning the Query results file Caption of the QueryDeleteAll dialog Очистка файла с результатами запроса Delete Button text Удалить Cancel Button text Отменить Query on table {0} failed! Warning log message about a failed query Ошибка при запросе из таблицы {0}! QueryDialog Dialog Global options Name: Имя: <qt> The name of the table where the query results will be added. </qt> Original indices into column: <qt> The name of the column where the indices of the selected rows will be added. </qt> Orig_idx Query condition <qt> <h3>Conditions syntax</h3> A condition on a table is just a <em>string</em> containing a Python expression that involves <em>at least one column</em> , and maybe some constants and external variables, all combined with algebraic operators or functions. Beware that <tt>&</tt>, <tt>|</tt> and <tt>~</tt> operators are used for logical comparisons. They have higher precedence than logical operators so we recommend to <em>always use parenthesis around logical operators</em>.</p> <p>The following table shows some examples of conditions and their equivalent Python expressions.</p> <div align='center'><table border='1'> <tr><th>Condition</th><th>Python expression</th></tr> <tr><td><code>a & (b == c)</code></td> <td><code>a and b == c</code></td></tr> <tr><td><code>(0 &lt; x) & (x &lt; 1)</code></td> <td><code>0 &lt; x &lt; 1</code></td></tr> <tr><td><code>a + b &gt; c</code></td> <td><code>a + b &gt; c</code></td></tr> <tr><td><code>where(a > b, 3, 4)</code></td> <td></td></tr> </table></div> <p>You can find detailed information about conditions in the Appendix B of the PyTables users guide.</p> </qt> <qt> The names of the searchable columns. They must fulfill the following requirements: <ul><li>must be not nested</li> <li>must have a scalar data type</li> <li>their data type cannot be <code>complex</code></li></ul> Columns whose names contains blanks are automatically mapped to variables whose names contain no blanks. For querying those columns the mapped variables will be used. </qt> <qt> The operators that can be used in a given condition. Operators can be logical, comparison and arithmetic.<br>Not all operators are available for every data type. </qt> <qt> The set of functions that can appear in a condition. It includes functions for doing selections, trigonometric functions and functions on complex numbers. For ease of use, arguments are automatically included when a function is inserted. The arguments meaning is: <ul><li>N: number</li><li>B: boolean</li> <li>F: float</li><li>C: complex</li></ul> </qt> The range of rows included in the query. Range of rows Start: 1 A range selector label Stop: Step: QueryDlg New query on table: {0} A dialog caption Новый запрос из таблицы: {0} The chosen name is already in use. Please, choose another one. A logger info message Выранное имя уже используется. Выберете другое. Enter a name for the column of indices, please A logger info message Введите имя для столбца с индексами The chosen name for the column of indicesis not valid. It contains '/' characters A logger info message Выранное имя столбца с индексами не может быть использовано The chosen name for the column of indices is already in use. "Please, choose another one. A logger info message Выранное имя столбца уже используется. Выберите другое. The stop value is greater than the number of rows. Please, choose another one. A logger info message Максимальное значение больше числа строк. Выберите другое значение. The start value is greater than the stop value. Please, choose another one. A logger info message Начальное значение больше конечного. Выберите другое. The start value must be greater than 0. A logger info message Начальное значение должно быть больше нуля. RenameDlg Overwrite A button label Перезаписать Rename A button label Переименовать RenameNodeDlg Dialog InfoLabel New name: SettingsDialog ViTables settings Click an item in this tree to select the settings you want to change. Beware that the listed plugins are *loaded* plugins (i.e. the are working in the current ViTables session) not just enabled plugins. Configure the startup behavior of ViTables. Startup The name of the groupbox where startup is configured If checked, the last working session -i.e. open files and views- will be restored. If not, ViTables will start with an empty session. Restore last session Label of the restore last session check button The working directory used when opening the very first file. It defaults to the current directory if ViTables has been launched from the command line or to the user's home directory if ViTables started from a menu or a desktop icon. If the checkbox is checked then the last entered directory will be used. Start in last working directory Label of the startup in the last open directory check box Configure the look and feel of ViTables. Customise font and colors of the Logger. Logger The title of the logger groubox You can preview your Font settings here. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">En un lugar de La Mancha,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">de cuyo nombre no quiero acordarme,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">no ha mucho tiempo vivia un hidalgo..</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html> Setup the text color. F&oreground The label of the logger text color button Setup the background color. &Background The label of the logger color button Here you can choose the font used in the Logger. &Font The label of the logger font chooser button Setup the background color of the workspace. Workspace The title of the workspace groupbox &Background The label of the workspace color button Background color sample A label for the workspace color sample Choose the global style of ViTables here. Style The title of the global aspect groupbox Available plugins The list of all available plugins. If a plugin is checked then it is enabled (but not necessarely loaded), if it is unchecked then it is disabled (but not necessarely unloaded). Please, note that changes in the check state of plugins will take effect the next time you start ViTables. TimeFormatterPage <qt> <p>Plugin that provides nice string formatting for time fields. <p>It supports not only native PyTables time datatypes but also time series generated (and stored in PyTables tables) via Pandas and scikits.timeseries packages. </qt> Text of an About plugin message box Плагин для отображения поля времени Form Plugin description Version: Module name: Folder: Author: Desription: Configure time format Time format: Sample date: Today VTApp Creating the GUI... A splash screen message Создание GUI... Configuration setup... A splash screen message Создание конфигурации... ViTables {0} Copyright (c) 2008-2017 Vicent Mas. All rights reserved. Application startup message ViTables {0} Copyright (c) 2008-2017 Vicent Mas. All rights reserved. Recovering last session... A splash screen message Восстановление предыдущей сессии... Opening files... A splash screen message Открытие файла... Opening the list of files... A splash screen message Открытие списка файлов... Opening failed: wrong {0} in line {1} of {2} Bad line format Ошибка при открытии: ошибка {0} в строке {1} из {2} List of HDF5 files not read File not updated error Ошибка при чтении списка файлов HDF5 Create Accept button text for QFileDialog Создать Creating a new file... Caption of the File New... dialog Создание нового файла... HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Open New dialog Файлы HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Все файлы (*) New file creation failed because file already exists. A file creation error Ошибка при создании нового файла, так как он уже существует. Copying a file... Caption of the File Save as... dialog Копирование файла... HDF5 Files (*.hdf *.h5 *.hd5 *.hdf5);;All Files (*) Filter for the Save As... dialog Файлы HDF5 (*.hdf *.h5 *.hd5 *.hdf5);;Все файлы (*) File Save as: file already exists A dialog caption Сохранение файла как: файл уже существует Target directory: {0} The Query results database cannot be overwritten. Overwrite file dialog label Подкаталог {0}. База данных с запросами не может быть перезаписана. Target directory: {0} The file being saved cannot overwrite itself. Overwrite file dialog label Подкаталог{0}. Файл не может перезаписать сам себя. Target directory: {0} File name {1} already in use in that directory. Overwrite file dialog label Подкаталог {0}. Файл {1} уже используется. Open Accept text for QFileDialog Открыть Select a file for opening Caption of the File Open... dialog Выберите файл About UnImplemented nodes A dialog caption О нереализованных узлах Actual data for this node are not accesible.<br> The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.<br>If you want to see this kind of dataset implemented in PyTables, please, contact the developers. Text of the Unimplemented node dialog Actual data for this node are not accesible.<br> The combination of datatypes and/or dataspaces in this node is not yet supported by PyTables.<br>If you want to see this kind of dataset implemented in PyTables, please, contact the developers. Creating a new group A dialog caption Создание новой группы Source file: {0} Parent group: {1} A dialog label Исходный файл: {0} Родительская группа: {1} Create A button label Создать Creating a new group: name already in use A dialog caption Создание новой группы: име уже используется Source file: {0} Parent group: {1} There is already a node named '{2}' in that parent group. A dialog label Исходный файл: {0} Родительская группа: {1} Узел с именем {2} уже существует в родительской группе. Renaming a node A dialog caption Переименование узла Source file: {0} Parent group: {1} A dialog label Исходный файл: {0} Родительская группа: {1} Rename A button label Переименование Renaming a node: name already in use A dialog caption Переименование узла: имя уже используется About unreadable datasets Dialog caption О нечитаемых наборе данных Sorry, actual data for this node are not accesible.<br>The node will not be copied. Text of the Unimplemented node dialog Данные для данного узла недоступны. Узел не будет скопирован. Node paste: nodename already exists A dialog caption Вставка узла: узел с данным именем уже существует Source file: {0} Copied node: {1} Destination file: {2} Parent group: {3} Node name '{4}' already in use in that group. A dialog label Исходный файл: {0} Перемещенный узел: {1} Файл назначения: {2} Родительская группа: {3} Узел с именем {4} уже существует в этой группе. Paste A button label Вставить Node deletion Caption of the node deletion dialog Удаление узла You are about to delete the node: {0} Ask for confirmation Подтверждение удаления узла {0} Delete Button text Удалить Cancel Button text Отменить <qt> <h3>ViTables {0}</h3> ViTables is a graphical tool for displaying datasets stored in PyTables and HDF5 files. It is written using PyQt , the Python bindings for the Qt GUI toolkit.<p> For more information see <b>http://www.vitables.org</b>.<p> Please send bug reports or feature requests to the <em>ViTables Users Group</em>.<p> ViTables uses third party software which is copyrighted by its respective copyright holder. For details see the copyright notice of the individual packages. </qt> Text of the About ViTables dialog <qt> Alexey Naydenov for his contributions to the plugins system and for providing logging support to the application.<p> Kamil Kisiel and Max Bohnet for fixing bugs.<p> Dmitrijs Ledkovs for contributing the new and greatly enhanced build system and for making Debian packages.<p> Oxygen team for a wonderful icons set.<p> All the people who reported bugs and made suggestions. </qt> Text of the About ViTables dialog (Thanks to page) About ViTables {0} Caption of the About ViTables dialog О ViTables {0} &About Title of the first tab of the About dialog &О программе &Thanks To Title of the second tab of the About dialog &Благодарности &License Title of the third tab of the About dialog &Лицензия About Qt Caption of the About Qt dialog О Qt Version Numbers Caption of the Versions dialog Версии not available Part of the library not found text не доступно VTGUI ViTables {0} Main window title ViTables {0} <qt> <h3>The Workspace</h3> This is the area where open leaves of the object tree are displayed. Many tables and arrays can be displayed simultaneously. <p>The diferent views can be tiled as a mosaic or stacked as a cascade. </qt> WhatsThis help for the workspace Основная рабочая область &New... File -> New &Создать... Create a new file Status bar text for the File -> New action Создать новый файл &Open... File -> Open &Открыть... Open an existing file Status bar text for the File -> Open action Открыть файл Read-only open... File -> Open Открыть для чтения... Open an existing file in read-only mode Status bar text for the File -> Open action Открыть существующий файл только для чтения &Close File -> Close &Закрыть Close the selected file Status bar text for the File -> Close action Закрыть выделенный файл Close &All File -> Close All Закрыть &все Close all files Status bar text for the File -> Close All action Закрыть все файлы &Save as... File -> Save As Сохранить &как... Save a renamed copy of the selected file Status bar text for the File -> Save As action Сохранить файл под новым именем E&xit File -> Exit &Выйти Quit ViTables Status bar text for the File -> Exit action Выйти из программы &Open view Node -> Open View &Открыть вид Display the contents of the selected node Status bar text for the Node -> Open View action Отобразить содержание выделенного узла C&lose view Node -> Close View &Закрыть вид Close the view of the selected node Status bar text for the Node -> Close View action Закрыть вид выделенного узла Prop&erties... Node -> Properties &Свойства... Show the properties dialog for the selected node Status bar text for the Node -> Properties action Отобразить свойства выделенного узла &New group... Node -> New group Создать &группу... Create a new group under the selected node Status bar text for the Node -> New group action Создать новую группу &Rename... Node -> Rename &Переименовать... Rename the selected node Status bar text for the Node -> Rename action Переименовать выделенный узел Cu&t Node -> Cut Вы&резать Cut the selected node Status bar text for the Node -> Cut action Вырезать выделенный узел &Copy Node -> Copy &Копировать Copy the selected node Status bar text for the Node -> Copy action Копировать выделенный узел &Paste Node -> Paste &Вставить Paste the last copied/cut node Status bar text for the Node -> Copy action Вставить последний скопированный/вырезанный узел &Delete Node -> Delete &Удалить Delete the selected node Status bar text for the Node -> Copy action Удалить выделенный узел &Query... Query -> New... За&прос... Create a new filter for the selected table Status bar text for the Query -> New... action Создать новый фильтр для выделенной таблицы Delete &All Query -> Delete All Удалить &все Remove all filters Status bar text for the Query -> Delete All action Удалить все фильтры &Preferences... Settings -> Preferences &Настройки... Configure ViTables Status bar text for the Settings -> Preferences action Изменить настройки ViTables &Cascade Windows -> Cascade Каска&д Arranges open windows in a cascade pattern Status bar text for the Windows -> Cascade action Разместить выделенные окна каскадом &Tile Windows -> Tile &Плитки Arranges open windows in a tile pattern Status bar text for the Windows -> Tile action Разместить выделенные окна плитками &Restore All Windows -> Restore All &Восстановить все Restore all minimized windows on the workspace Status bar text for the Windows -> Restore All action Восстановить размер всех минимизированных окон &Minimize All Windows -> Minimize All &Минимизировать Minimize all windows on the workspace Status bar text for the Windows -> Restore All action Минимизировать все окна C&lose Windows -> Close &Закрыть Close the active view Status bar text for the Windows -> Close action Закрыть активный вид Close &All Windows -> Close All Закрыть &все Close all views Status bar text for the Windows -> Close All action Закрыть все окна Current View Windows -> separator Текущий вид Change view mode MDI -> Tabbed Изменить режим отображения Change the workspace view mode Status bar text for the MDI -> Tabbed action Изменить режим отображения рабочей среды &User's Guide Help -> Users Guide &Руководство Open the ViTables User's Guide Status bar text for the Help -> Users Guide action Открыть руководство пользователя &About ViTables Help -> About &О ViTables Display information about ViTables Status bar text for the Help -> About action Показать информацию о ViTables About &Qt Help -> About Qt О &Qt Display information about the Qt library Status bar text for the Help -> About Qt action Отобразить информацию о Qt Show &Versions Help -> Show Versions Верс&ии Show the versions of the libraries used by ViTables Status bar text for the Help -> Show Versions action Показать информацию о версиях используемых библиотек File operations Toolbar title Работа с файлами Click to open a file Click and hold to open a recent file File toolbar -> Open Recent Files Одно нажатие для открытия файла. Нажать и удерживать для открытия недавно использованного файла Node operations Toolbar title Работа с узлами Queries on tables Toolbar title Запрос из таблицы Help system Toolbar title Система помощи Whats this? help for a widget Status bar text for the Help -> Whats This action Помощь для элемента The node currently selected in the Tree of databases pane The Selected node box startup message Выделенный эелемент в окне дерева базы данных Ready... The status bar startup message Готов... &File The File menu entry &Файл Open R&ecent Files File -> Open Recent Files Открыть &последние &Node The Node menu entry &Узел &Dataset The Dataset menu entry Набор &данных &Settings The Settings menu entry &Настройки ToolBars Tools -> ToolBars action Кнопки управления &Window The Windows menu entry О&кно &Help The Help menu entry &Справка Context help Status bar text for the Help -> Whats This action Контекстная справка &Clear Recent File submenu entry О&чистить &More... A Windows submenu &Больше... Calculate... Calculate action Калькулятор... Run calculation on opened tables. Action tip Произвести вычисления над данными из открытых таблиц.

p ?p @p Ap Bp Cp Dp Ep p p p p p p p p p p q q q q q q q q q q hq iq jq kq lq mq nq oq pq qq q q q q q q q q q q 0r 1r 2r 3r 4r 5r 6r 7r 8r 9r r r r r r r r r r r r r r r r r r r s s \s ]s ^s _s `s as bs cs ds es s s s s s s s s s s $t %t &t 't (t )t *t +t ,t -t t t t t t t t t t t t t t t t t t t t t Pu Qu Ru Su Tu Uu Vu Wu Xu Yu u u u u u u u u u u v v v v v v v v v !v |v }v ~v v v v v v v v v v v v v v v v v v Dw Ew Fw Gw Hw Iw Jw Kw Lw Mw w w w w w w w w w w x x x x x x x x x x px qx rx sx tx ux vx wx xx yx x x x x x x x x x x 8y 9y :y ;y y ?y @y Ay y y y y y y y y y y z z z z z z z z z z dz ez fz gz hz iz jz kz lz mz z z z z z z z z z z ,{ -{ .{ /{ 0{ 1{ 2{ 3{ 4{ 5{ { { { { { { { { { { { { { { { { { { { { X| Y| Z| [| \| ]| ^| _| `| a| | | | | | | | | | | } !} "} #} $} %} &} '} (} )} } } } } } } } } } } } } } } } } } } } } L~ M~ N~ O~ P~ Q~ R~ S~ T~ U~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~           x y z { | } ~              @ A B C D E F G H I X Y Z [ \ ] ^ _ ` a • Õ ĕ ŕ ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  ܘ ݘ ޘ ߘ @ A B C D E F G H I      l m n o p q r s t u К њ Қ Ӛ Ԛ ՚ ֚ ך ؚ ٚ 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i Ĝ Ŝ Ɯ ǜ Ȝ ɜ ʜ ˜ ̜ ͜ ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } ء ١ ڡ ۡ ܡ ݡ ޡ ߡ < = > ? @ A B C D E      h i j k l m n o p q ̣ ͣ Σ ϣ У ѣ ң ӣ ԣ գ 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e ¥ å ĥ ť ƥ ǥ ȥ ɥ $ % & ' ( ) * + , - P Q R S T U V W X Y      h i j k l m n o p q ̼ ͼ μ ϼ м Ѽ Ҽ Ӽ Լ ռ 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e ¾ þ ľ ž ƾ Ǿ Ⱦ ɾ $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y 8 9 : ; < = > ? @ A         d e f g h i j k l m , - . / 0 1 2 3 4 5 X Y Z [ \ ] ^ _ ` a ! " # $ % & ' ( ) L M N O P Q R S T U           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i           x y z { | } ~  @ A B C D E F G H I      l m n o p q r s t u 4 5 6 7 8 9 : ; < =      ` a b c d e f g h i ( ) * + , - . / 0 1 T U V W X Y Z [ \ ]     ! " # $ % H I J K L M N O P Q           t u v w x y z { | } < = > ? @ A B C D E      h i j k l m n o p q 0 1 2 3 4 5 6 7 8 9  \ ] ^ _ ` a b c d e $ % & ' ( ) * + , - P Q R S T U V W X Y         ! | } ~  D E F G H I J K L M         p q r s t u v w x y          $ % & ' ( ) * + , -                     P Q R S T U V W X Y                    ! | } ~                  D E F G H I J K L M             pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%0000000000415161718191:1;1<1=111111111111111222222`2a2b2c2d2e2f2g2h2i22222222222(3)3*3+3,3-3.3/3031333333333333333333333T4U4V4W4X4Y4Z4[4\4]444444444445555 5!5"5#5$5%555555555555555555555H6I6J6K6L6M6N6O6P6Q666666666667777777777t7u7v7w7x7y7z7{7|7}77777777777<8=8>8?8@8A8B8C8D8E8888888888899999 9 9 9 9 9h9i9j9k9l9m9n9o9p9q999999999990:1:2:3:4:5:6:7:8:9:::::::::::::::::::;;\;];^;_;`;a;b;c;d;e;;;;;;;;;;;$<%<&<'<(<)<*<+<,<-<<<<<<<<<<<<<<<<<<<<<P=Q=R=S=T=U=V=W=X=Y===========>>>>>>>> >!>|>}>~>>>>>>>>>>>>>>>>>>D?E?F?G?H?I?J?K?L?M??????????? @ @@@@@@@@@p@q@r@s@t@u@v@w@x@y@@@@@@@@@@@8A9A:A;AA?A@AAAAAAAAAAAAABBBBBBBBB BdBeBfBgBhBiBjBkBlBmBBBBBBBBBBB,C-C.C/C0C1C2C3C4C5CCCCCCCCCCCCCCCCCCCCCWWWWWWWWWWDXEXFXGXHXIXJXKXLXMXXXXXXXXXXX Y YYYYYYYYYpYqYrYsYtYuYvYwYxYyYYYYYYYYYYY8Z9Z:Z;ZZ?Z@ZAZZZZZZZZZZZ[[[[[[[[[ [d[e[f[g[h[i[j[k[l[m[[[[[[[[[[[,\-\.\/\0\1\2\3\4\5\\\\\\\\\\\\\\\\\\\\\X]Y]Z][]\]]]^]_]`]a]]]]]]]]]]] ^!^"^#^$^%^&^'^(^)^^^^^^^^^^^^^^^^^^^^^L_M_N_O_P_Q_R_S_T_U___________``````````x`y`z`{`|`}`~``````````````@aAaBaCaDaEaFaGaHaIaaaaaaaaaaab b b b b bbbbblbmbnbobpbqbrbsbtbubbbbbbbbbbb4c5c6c7c8c9c:c;cj?j@jAjBjCjDjEjjjjjjjjjjjkkkkk k k k k k~~~~~~~~~~TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}؂قڂۂ܂݂ނ߂<=>?@ABCDE     hijklmnopq̄̈́΄τЄф҄ӄԄՄ0123456789\]^_`abcde†ÆĆņƆdžȆɆ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԋՋ֋׋؋ًڋۋ܋݋89:;<=>?@A defghijklmȍɍʍˍ͍̍΍ύЍэ,-./012345XYZ[\]^_`aÏďŏ !"#$%&'()LMNOPQRSTU defghijklmȦɦʦ˦̦ͦΦϦЦѦ,-./012345XYZ[\]^_`a¨èĨŨ !"#$%&'()LMNOPQRSTUxyz{|}~ܫݫޫ߫@ABCDEFGHI     lmnopqrstuЭѭҭӭԭխ֭׭ح٭456789:;<=`abcdefghiįůƯǯȯɯʯ˯̯ͯ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}شٴڴ۴ܴݴ޴ߴ<=>?@ABCDE     hijklmnopq̶Ͷζ϶жѶҶӶԶն0123456789\]^_`abcde¸øĸŸƸǸȸɸ$%&'()*+,-tuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<= !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~D E F G H I J K L M            ! !!!!!!!!!p!q!r!s!t!u!v!w!x!y!!!!!!!!!!!8"9":";"<"=">"?"@"A"""""""""""######### #d#e#f#g#h#i#j#k#l#m###########,$-$.$/$0$1$2$3$4$5$$$$$$$$$$$$$$$$$$$$$X%Y%Z%[%\%]%^%_%`%a%%%%%%%%%%% &!&"&#&$&%&&&'&(&)&&&&&&&&&&&&&&&&&&&&&L'M'N'O'P'Q'R'S'T'U'''''''''''((((((((((x(y(z({(|(}(~((((((((((((((@)A)B)C)D)E)F)G)H)I)))))))))))* * * * * *****l*m*n*o*p*q*r*s*t*u***********4+5+6+7+8+9+:+;+<+=+++++++++++++++,,,,,,`,a,b,c,d,e,f,g,h,i,,,,,,,,,,,(-)-*-+-,---.-/-0-1---------------------T.U.V.W.X.Y.Z.[.\.].@BABBBCBDBEBFBGBHBIBBBBBBBBBBBC C C C C CCCCClCmCnCoCpCqCrCsCtCuCCCCCCCCCCC4D5D6D7D8D9D:D;DK?K@KAKBKCKDKEKKKKKKKKKKKLLLLL L L L L LhLiLjLkLlLmLnLoLpLqLLLLLLLLLLL0M1M2M3M4M5M6M7M8M9MMMMMMMMMMMMMMMMMMMNN\N]N^N_N`NaNbNcNdNeNNNNNNNNNNN$O%O&O'O(O)O*O+O,O-OOOOOOOOOOOOOOOOOOOOOPPQPRPSPTPUPVPWPXPYPPPPPPPPPPPQQQQQQQQ Q!Q|Q}Q~QQQQQQQQQQQQQQQQQQDRERFRGRHRIRJRKRLRMRRRRRRRRRRR S SSSSSSSSSpSqSrSsStSuSvSwSxSySSSSSSSSSSS8T9T:T;TT?T@TATTTTTTTTTTTUUUUUUUUU UdUeUfUgUhUiUjUkUlUmUPiQiRiSiTiUiViWiXiYiiiiiiiiiiijjjjjjjj j!j|j}j~jjjjjjjjjjjjjjjjjjDkEkFkGkHkIkJkKkLkMkkkkkkkkkkk l lllllllllplqlrlsltlulvlwlxlylllllllllll8m9m:m;mm?m@mAmmmmmmmmmmmnnnnnnnnn ndnenfngnhninjnknlnmnnnnnnnnnnn,o-o.o/o0o1o2o3o4o5oooooooooooooooooooooXpYpZp[p\p]p^p_p`pappppppppppp q!q"q#q$q%q&q'q(q)qqqqqqqqqqqqqqqqqqqqqLrMrNrOrPrQrRrSrTrUrrrrrrrrrrrssssssssssxsyszs{s|s}s~ssssssssssssss@tAtBtCtDtEtFtGtHtItttttttttttu u u u u uuuuulumunuoupuqurusutuuuuuuuuuuuuu4v5v6v7v8v9v:v;v?@ABCDE     hijklmnopq̗͗ΗϗЗїҗӗԗ՗0123456789\]^_`abcde™ÙęřƙǙșə$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԞ՞֞מ؞ٞڞ۞ܞݞ89:;<=>?@A defghijklmȠɠʠˠ̠͠ΠϠРѠ,-./012345XYZ[\]^_`a¢âĢŢ !"#$%&'()pqrstuvwxyԷշַ׷طٷڷ۷ܷݷ89:;<=>?@A defghijklmȹɹʹ˹̹͹ιϹйѹ,-./012345XYZ[\]^_`a»ûĻŻ !"#$%&'()LMNOPQRSTUxyz{|}~ܾݾ޾߾@ABCDEFGHI     lmnopqrstu456789:;<=`abcdefghi()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxy89:;<=>?@A defghijklm,-./012345XYZ[\]^_`a !"#$%&'()LMNOPQRSTUxyz{|}~@ABCDEFGHIXYZ[\]^_`a !"#$%&'()LMNOPQRSTU          x y z { | } ~              @ A B C D E F G H I                     l m n o p q r s t u           4 5 6 7 8 9 : ; < =                     ` a b c d e f g h i           ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}<=>?@ABCDE     hijklmnopq0123456789\]^_`abcde$%&'()*+,-PQRSTUVWXY,,,,,,,,,,----- - - - - -h-i-j-k-l-m-n-o-p-q-----------0.1.2.3.4.5.6.7.8.9...................//\/]/^/_/`/a/b/c/d/e///////////$0%0&0'0(0)0*0+0,0-000000000000000000000P1Q1R1S1T1U1V1W1X1Y1111111111122222222 2!2|2}2~222222222222222222D3E3F3G3H3I3J3K3L3M33333333333 4 444444444p4q4r4s4t4u4v4w4x4y444444444448595:5;5<5=5>5?5@5A55555555555666666666 6d6e6f6g6h6i6j6k6l6m66666666666,7-7.7/707172737475777777777777777777777X8Y8Z8[8\8]8^8_8`8a88888888888 9!9"9#9$9%9&9'9(9)999999999999999999999L:M:N:O:P:Q:R:S:T:U:::::::::::;;;;;;;;;;x;y;z;{;|;};~;;;;;;;;;;;;;;@<A<B<C<D<E<F<G<H<I<<<<<<<<<<<= = = = = =====l=m=n=o=p=q=r=s=t=u===========4>5>6>7>8>9>:>;><>=>>>>>>>>>>>>>>>??????`?a?b?c?d?e?f?g?h?i???????????SSSSSSSSSSTTTTTTTTTTxTyTzT{T|T}T~TTTTTTTTTTTTTT@UAUBUCUDUEUFUGUHUIUUUUUUUUUUUV V V V V VVVVVlVmVnVoVpVqVrVsVtVuVVVVVVVVVVV4W5W6W7W8W9W:W;W^?^@^A^B^C^D^E^^^^^^^^^^^_____ _ _ _ _ _h_i_j_k_l_m_n_o_p_q___________0`1`2`3`4`5`6`7`8`9```````````````````aa\a]a^a_a`aaabacadaeaaaaaaaaaaa$b%b&b'b(b)b*b+b,b-bbbbbbbbbbbbbbbbbbbbbPcQcRcScTcUcVcWcXcYcccccccccccdddddddd d!d|d}d~ddddddddddddddddddDeEeFeGeHeIeJeKeLeMeeeeeeeeeee f fffffffffpfqfrfsftfufvfwfxfyfffffffffffzzzzzzzzzz${%{&{'{({){*{+{,{-{{{{{{{{{{{{{{{{{{{{{P|Q|R|S|T|U|V|W|X|Y|||||||||||}}}}}}}} }!}|}}}~}}}}}}}}}}}}}}}}}}D~E~F~G~H~I~J~K~L~M~~~~~~~~~~~  pqrstuvwxy89:;<=>?@A defghijklmȁɁʁˁ́́΁ρЁс,-./012345XYZ[\]^_`aƒÃăŃ !"#$%&'()LMNOPQRSTUxyz{|}~܆݆ކ߆@ABCDEFGHI     lmnopqrstuЈш҈ӈԈՈֈ׈؈و456789:;<=`abcdefghiĊŊƊNJȊɊʊˊ̊͊()*+,-./01TUVWXYZ[\] !"#$%Сѡҡӡԡա֡סء١456789:;<=`abcdefghiģţƣǣȣɣʣˣ̣ͣ()*+,-./01TUVWXYZ[\] !"#$%HIJKLMNOPQtuvwxyz{|}ب٨ڨۨܨݨިߨ<=>?@ABCDE     hijklmnopq̪ͪΪϪЪѪҪӪԪժ0123456789\]^_`abcde¬ìĬŬƬǬȬɬ$%&'()*+,-PQRSTUVWXY !|}~DEFGHIJKLM  pqrstuvwxyԱձֱױرٱڱ۱ܱݱ89:;<=>?@A defghijklmȳɳʳ˳̳ͳγϳгѳ,-./012345TREE &TREETREE0 a0ww20021107174532 ww 0CLASSIMAGE HIMAGE_VERSION! ?SNODH@! 0 - 20021107174532 F_ 0CLASSPALETTE H PAL_VERSION! ?dhH!?1.11H!!OB}!&BB̹!!OOOtHP?1F!7BܴN12ihi2hd3&>&}&BB!!!!!!7w7GGGGx&<qB۹!B#BBw#蹌O&Ow}!u#uuuu#uu77O}BܜúO!!!?h?Bh[2Z[oHB1!1iZ$ ||P갺 t.݀!OHOO!t!O!OO#!OtÒܶ..HO!##u###!!!#uOOO!######!!OO##uu##uu#u#u#u#u#u#u#u#uu#u#u##!wdwwu######uÜOXHúOHH!O!}BBB&!!#!HO!.H2117!OHl?l2܊?i@ycccw&}GGqBBù!wOO7!!!!w7xxxG>JJ>gGG&&B}lB}Ow#!O###uuXuuu7OOBúttO!#!BB3liHtOtHH.llN|""[ i2.ttt tHOO!!O!!!!tttt.tH1t.tttO!##u##u!Ouu ##XXX####w!!##uu#uu#u#u#u#u#u#u#u#u#uu#u#uuw}#####u##B?HO#t!}OOOBBBBBO!OtOtH2?2hHyO!BO???2l?[[cY3}G7w7qg}}Oww!wOOO7!7!x7777}G>qG7xG}!B?dOB!OOd&}7wu###uu##!!O7ÜܜúBO!O#t 2No11HHH1궶" 2tootHBt!OOOtOO!O!!!!Htt.t.1H1tt!!7#7O!ww!!ݺt!!!O!!w#uuu##wuu####u#u#u#u#u#u#u#uuu#u#u#uwuɌw#uuuu#uudúù?ܜBùO!BB&B!!!݀!.l.{iBOOtHlll2l2??i?cd}7xxG}}!!w!!!!!!!Ox!7w77G}gBgGGGG77OxwBBdBۜd?&>>>7wO! ##!HBB?dOOB!!#O}B@$lPP.ttOHH܅to2H.P?2H1OOO!!!OO!!OO#####!݀.N[[i2H.OOO!!u}O!!u!!#!!OO!w#u u##w!#u#uuu#u#u#u#u#u#u#u###u#u#uuuw!uwuuuuu#}!lBh11BB!}BBOt2H.1h?H12l?N??3F}G7!x7x!!7!O!7O!7!ww#!!w77!7!G&Bd}GGGx7x!7!}d?}3ܜw!}?:u蹀H!uHB1l?d!XOO!O#1 .Pt.!O!Ht..tH1NtHO!O#!!#OO!!!OHHtt.t2itt.O!#!!!#####uuuw#uuuu##!!######u#u#u#u#u#u#u#u#uu#u#u#Xw#wuuuuuuu#dH#?1úÒB}&!OddHH??l2Ò1lt?2i11222?2?l1ih?FFdB}7www7#ww!!7OxO!#u#w!ww!77!O}dBGGxxwwww!#uulFlܴ]Fz_;:!tÒt.tÒ1lù!O!!}Àu!dBi?PPPPHtt!X ootHl2t !HOOO!!!#!HBꜜ1H[2PHHH!#!#u!1 #!!!!ww##u#u#!!uu#u#u#u#u#u#u#u#u#u#u#u#uwuuwu#}w#uuuu#BlÜBúùO̹ddBBB!tH11OHl22i12211ll?lúl1?hh3}w##wwu###!!7O!7Ow##w!7w!!7O}ddB}G7ww#x!wu!BBly@?Fhi3:Ɨz5d!OH1BHHù!uݜhPH"1ÒtO݀ Hllt.݀O!O!!OOO!!!!#OBHOHt.tHll111.OH HO1OXX!w##uu#u###uuu#!Ow###uu#u#u#u#u#u#u#u#u#u#u#uwwuuwɴw##uuuuOOwX!!lOHOO7Bh?H݀!lO12??1NidH1?llHt?h!ww#uuu##ww!!!7!7wwwww7OO!B۹g}GxOwu!!!h?{@%ii?lK-5!!o1H1BOOO#!!!!d% | 2HPtHHtOH! u!tdlOu! u!OO!!!OOO7!!!!!BtBHHHttt1liN1H11Ht.! Ot!!####uu#uuuuu###!O!u##u#u#u#u#u#u#u#u#uuu#uuuuuuwuww!#uuuu}!uHBdB!B?Bw!dOGd̹OHúݺHú÷iޒ?2B1t2?21HBHHB!}}Ow#uuu####7wwww!w}ɹ!w}!!!&>Oɹ#O}ܵ@@iBhd??BO!OO!Fll2iN2ܒ1ú1B1ܜ}!77www7uuuu#w#w#wɹx7O77&wO7OG>5!uuܴ?. l@[?l}d?<3YcYYa2N2BO!#uu##Hd?.. Pt1tBdH!!O!uu#!OO!!!O!O!OOB1BttOt!H.2i221tt1NP...H.tt. uXu!uuu#uu#u##u#uu##w!#uu##u#u#u#u#u#u#u#u#uu#u#uuuuw#w###uuu#Ow!w!H##?XBO!7!Ow#!?!yOõ?2P2ޜH!ùtÜBll%aO۹!7uuuu#u#uu}}d>Gd>77d}&B]B#?H?.2ldlB>dG}>!!!#l{y[ÀÜ?Bd>GG%Y@lBt!!BÀ#XX#!O#O2ޜ ؊i "|i|Pt.tHO!!!!!!####!OO7OO7!!!tOtOOHl21{i[?N?l |["PPHt. X#uu###7u u#uuu##!wuu#uu#u#u#u#u#u#u#u#uu##u#u#w}}ww##u#uu#O##u#!w}ÜdOOu!OO7!GG!7!7ww!O!!1}!?ÜÀuݹ?[i{Fduuuuuuuuu7#Y5>d>}&ddB?OBd%%t!Oû>̹7&_Tֲ%[lBO!OX!O#uX!ݹHiHi Z2|Pt!OtO!!O݀u#!!###O#!OOOOOttH1dܺ?iN[2iNN|i"[ 22tu#u####wOu##uuu !!7!#uu#u#u#u#u#u#u#u#u#u#uu#u#uu7!uw###uuuu!!!#uu!OuO!77GGG&&G7w##w!d!hô{BBu!B???lhi?hl}dB7XXXuu##w#}ɋq-K;JT;5J}Gdd݀?2[@[tOH}O>>:]YihNBHt!! #XwXXX!BB1PiNN|"|[2PH.u ###u!!##!7u##!!#!!!!tH111ܵ21li2PܶN|||PtݺO! u##ww7#u#uuu##!!uu ##u#u#u#u#u#u#u#u#uu#u#uu#uwuw#u#u#u#uw7Xu#!!?!O!#7!77&}7##ww!!B!lBdhclBBB1ÜB}B2hhB?w##uu#wwx&T<-K5GG̹d!B!ll@úOHB!d:Tdl?hhlBt!#!# #uXuX#!BN2P"| Z[u#!OO.O!7#uuu######!OttHú2??21122l21HP|2|..X#uuwwwu#uu#u#!!O!#uuuu#u#u#u#u#u#u#u#u#u##u###wuuuuw#u#uuuu###!!u#OOXB?BBw#!B7##!OG>>>&̹7!7w#!!1h!HOB}Bùú1?h{%ayù?d}!#uu#w}G<K֗YGwBB1ÀBlihH!OB5>>??d1BBtO!# uXuX!HHH2Z"["21H.!#OBBHO!!!#u##!ttH?i12l2.||" "PޅN[u #!##uw#u##uuuu##!!!#u##u#u#u#u#u#u#u#u#uuu#u#u#wX7uwuu#uu7!O#}dO#}!#!!7#&B&B&&&G7uuw!!OHB?Hi1l??B}B!}}dhF?ÜyFdXOu##O><<<<;YOO?1t1B@iHHBd#&OGK>>&BB1ܜihHHt!! X X X !údHO!O1?ܵ?2OH!OHOO!uu#uuu##!耀!tHú1.1?N12.?ܒ?i2i2i $ |"NPHO# X##u####uuuuuuuu#!ww#u##u#u#u#u#u#u#u#u####u#ww#u#w!wuuuuu#uuO##!#O!!wO!##7##!&}&&G!!###w!O!1!ݵ%c?ld?ddBB}w}d???yyFOu!wuw>>fn_dBdhd.1tP.H@HOd&&:<<JŽ}BBHÜ?a߰2HHt!Ht!! Xu HOOhlܜ?Ht!HHOOO####uuu!#!l21H2Üiܵ[i...귉aYZ i2t!u####uu###uXuuu#uuu#ww#u##u#u#u#u#u#uu#u#u###uuw!wuuuw!wuuu##u#uOO!!!!B!O#####OBG&GO7w#uuu##!Üõ2hc?hBBBdd%߻!%{FO###u7zμ]3!B?yh1ly{@?i[i&<<<BB}Üly߰[i?.úݹ݀uu #!OOddܜB1tH1tO!O#####uuu####!!OHd1H1tHli%ii12 Z$i"N2HO##uu##uuuuu#u###u#w#####u#u#u#uu#u#u#u#u###uu#w#uu#####uu#u##ut݀#!u#wOwO>O&!######uwB&}!#u##!!HdB÷yܜ1{l?1hy?1OBBBB?hhc3?B}Àw#7<f/'ld?hcyBYaYa%[@y><_d>Bdl[@$@1ù!O}!u}O#!#OBúBl??l1Bttttt.!!O##u#u#!###tHÒHt1l1ܒ2lia22$%@[N?H1H!!!O#######uu####wwww###u#u#u#u#u#u#u#u#u###uuu#u###u#u#uu###u#?H!!!!wOdOw#!O7###uu#7d>&ww#O!!!OlݺiܵO lch1}BBB}]ccYؙù?7}O!#w#uw7}&gg/SThhh!Hdֲ%@2l{YYc3>>dBl?@2.H!OBOOHO}!!#!Bút!l1tOO!##u##!!!7#####!!OOHH1Ülill?@?2ܴ%ltPH.11O!!!!!!##w##u#uu#u##!!w!7#u#u#u#u#u#u#u#u#uu####uuuu###uuu#u######t݀ #w#!!7O!###>&}ùw!1܀2[ú2[i@B2h?lBFhF?d!!!,Xuu#w7>gggfS3h[?1Odd{YY@@yYd3&>g}lyy[i[iH}Ow!B}OH!!#uOB}ܜ1ÒH@Ht!!O!##u##!!####OOHtlHt1t1il[ܱh??@$i1..H1.1tO!!!!!!##ww##uuu###w!7!!!w#u#u#u#u#u#u#u#u#uu####uuu###uuuu######2tt!!&7!####>>&&dB}!w#11212l?lh??2hhl?dd]3]?!#uuX#xG&gJs֗5HHݹBOByhY]d&>B&dd@%|iZHOw!!!!w!Ou!!!?2ll12lO!!##uO7##u###耹Hl?2i?2{?N?l?@22@tO!!O!!#####uuuuu##ww7!7w#u#u#u#u#u#u#u#u##u#u##########uuu######"21H.# OO!7O}BFO7!O!###7d>&B}!u#w#O Ü1H12?l2ddB3B]3{B!uuwwwwOGgn-E8888%t݀!tHd!7O!yB%&x}>}>&dBd%?N[$}!w#!u7!7w!!!!!O!BB?d?@y$P2BBB#u7OO####!OBHHHllll??21 i??1212.t.!!OHHù!#####uuuuu##u#w!!!w#u#u#u#u#u#u#u#u##uu####w##u###u#u#####222tOu!!B!7!̹#!&OOwu#!u!ú.1N1tt1i?i?ûÜdBBd_Bh{B#ww&ۙ^;SS֯ HHHOO!!!Bdhd}B}7}>Gd?{i1i%OO!7#w#w7!!!HO!}Hdh@@2ldBO!!uO7!7##!7###!OtBll21l2h1HB1dï?!݀!ù!w!#X#uuuuu#uuww!7w#uu#u#u#u#u#u#u#u#u###u#uuuu######u####uui"a%!! ##!wOOO###7OBd77www!u u# !1Ò.B1ܻl?}1}BBB{@!#Xu77}>K8c?2ldOHO!O!O1dh!wOwwwwG}gdF>™Olll2[tB&}O7###!!1BBBO[@2?BH77##!#77!OB1dllll???@O??tÒOtHHݹú!###uuu#uuu#u##ww#u#u#u#u#u#u#u#u#uuu#u##uu###u######u###wi@@@2HB!#77!O#OO####!OBldB!#w##!u1Htld[1?d?BtOù!Bdd?OBh{%!uuwww}}\+ssY@?1OHBBBB}!#!wO77d}B]:3̴llNi1B!7#u##!OHBOO!dd??tO!!O!!#!O!l2ܜlBܴ?d2ܒ.HH݀!H!uu###u#uuuu#######u#u#u#u#u#u#uu#u#u#u##u#######u#uu#u##wl?tH!##OO7!#!7O!OHHH?l!w#u!O#..ttt1ÜF}B1!!!BO#OO!?%al1uu#u7}f>f'6E8Y{?BBBBBO##Xu!uuw7d}}B77#B?l2??B>B##7O!}O}}Üh?dl?tO̹O!7!!!!!!!O!##!O!d2Hdl}h?hlúÒ11?!!!݀u u##uuuuuuu##u#uuuu##u#uu#u#uu#u#u##uu########u##u##u#u!?!yd!B!#!BOOO##OHtHBH!!uu#!!ݜ.HHHBHOd!}lH!ݺ??2!@!HOXuuuw!}qkj+88ֲ1OB1HHHHHttBHtOO#!!uu!&BB}!OX7B>d}}BHH1?ܴdd?dBO##u!!?B}&]yldܺOO!!!OO7!7!!O!7!##OO!ÜtO}.ҹÜl?H.1.1.ຜH!t!!uu uuuuuuu###u#uuu#u#u#u##u#u#u#u##u#####u########u#u##u##w!#O]#O!BOO#OH111BO!w#݀1tB2dùÜ!X{21ÜÀO1!!!#wwGx7\'U88B!OOOOtO!HHHú#!!}OBw}ddBHtOHl?dB!#!!!1iB}BBB_%]?B!O#7̹OO!!7!7!####d?111?B!}!úݴ@a%[H.t..??1.t.t!݀# #u#uuuuuuu###uuuuuuu#u#uuu#u#u#u#u#uw##u#u#########u#####wwBB!#&̹OOOH122l?BO!HHlܺXuOBBuB!hhcFúh[[22N$%À!ݺ.lB&̹7OwO7xQ\M6E8ֲBOOtttt..ttÒHO!OO!XuuuOBdOû?hۙBd!HOtlh3?d̹!!!!!ݜOHBBBBF_cBH!!!##!!B̹&7!!!!#7##!3htHHl??hdB?lÜú.H?12PHtHH!#u #u uuuu##uuuu#uu#u###u#u#u#u#u#ww##uu###u#u#######w##cBdBO&573d1Hl?dt!!OOH!OHOHOu!X۴d?݀2lÒ?dBHt2B1d?wuwx7ν%dBtHB1Ht.Ot!!!!###BB}??uBOBHHBBdhi?1!!!!݀[dl!Bd555FH!!!!!OO7O!!O!###!?HtH1?݀h.l.1oHHúuuu #uuuuuuu#uwuuu#uuuuu#u#u#u#u#u#uu#!wuuu#uuu#u#####w#w###&_]dtB!&5YJ:l2޶P12ll?2l!HO!!{tÀ݀uOB!]?}O{l!H3{ùttݺ2li[@}7#GɑG)L:yhHHtt!ttttOOO1tH1##!BdB}!7}BùBBBtOtBl?i?ú!!Ü2޶HttBJnY;]BOO!G!O!#!tHO !!OHdll2l?lùl?l? OH?ttl[Núú!u uuu###uuu#uuuuuu##uuuuu#u#u#u#u#u#u#u#u#u#u#uu#####u###u#O!!ud]YBB!!#}缗K:-SK3T?2|"|22lܵ22t!ݺ!}t!>H{Nt1!X#3BdByB?1.1[$%@3dOOɑGGLLd31OH1?t!!OOtHOtOt!t܀ۜO}dB}!B}OOOd?h[?lhݹ}H21P:n;3dBO!!!7OOOHHt.!!l111l[l܀u.OlܺuB?{c!??iltú!#uuuu#uuu#uuXu#uuuuuuuuuu#u#u#u#u#u#uuu#u#u#u############uw}d>O!#}:-;-T;?" "Nl1t22?2?1t!ݺO!!ll21Bdd]]F33B}B?iܺ .ݜ22{%]}G#xwGGxwd?O! !1tuOOOHBOOÜOX!B}BB}O!}BO!tH?ii@aiߴúHBBö222??d:Tn;ֽTd!O!7O7!#!OHHHt!!dllܜ1i2l1u !Ü!X! ly?tl?l2?1tOO##u###uuuuu#w##uuuuuuuu#u#u#u#u#u#u#u#u##u##u#############d#>ϼ/K8K/-KFl?i "?ll212t?|ll1Oݺt!HBlBHdH?dt1i?HBwOdF__5_c?l$.tHH?Y%>wwwww77xxGxuBuX!O!!O!OHt!tOuOBd!u#X}#u!u!Oli{@1HB12N2l-nK8Y5B!OOOO!!!Ollt122OOO!tt2!!ܺݜùtBFy݀ݺ!..1H!####uu#uuu#uu##uuuu#u#u#u#uu#u#u#uu#u#u##u#########X耀u#u]Os8-T32O.2PP?HÒ1HHO?tBl11ù}55Y֗_ N.lBB]YYw7wwww77#Ot ! t2!OOO!tO!tO X #OOH}t!## !#u#Otl?@%[2iÜ?[hh:K/8O!#BO#OBlH!!H?i?2túl1lllB.!ô2l1Bt#lhܺX ݺ1útO!!!!##u#uuuuuuuuXuuuuuuu#u#u#u#u#u#u#u#u#u#u#u##u########u##u#}d3>&T-8ӕ?1l?2Pܜ1HOHOH!H?1!X}%֗Y?$@ih{&_]>7wwwwu#w!O!uܴ?O!!OHHOuO#tú! u!OO!OhHHl11l?i@Fϼ-//6ssO!!!!!!!O!?hhN@# Oll2?BlO!ÜttHl2B#XH?2!݀.O!!u#uuuuu#uuuuuuuuuuuuu#u#uu#u#u#u#u#####u##########u ##u!BO>J>&BsE'::3]{2. 1l2ll21ltH??lO1#,!uuBd?_>:>7#!!!!#O!Ot!!.Hl?cOtOB!!lB!1B!.OHú!! XÜBO!O!!OtBl[@{{y@%yll????@c5T/+E888]&O!OOOO#Odh?llll222OtOtllu!11ÜBH!!!ҀHH1. !tttt!!#uuuuuuuuXu7#7O7wuu#u#u#u#u#u#u#u#u#u#u#u##u#########u#!!##B!&<䕕IS<:?hB1BHPP2llH1!1hlOH!#1#u!7!}wG\Y%%{Yֲֲֲ:B&BGwOu##!!!!!HB?tBܴOÜHtHHy%y?úݜH..l1dtOHHHB?22i1hi??{5 E8B!!OOO!Hli11tXݜH!1l21?HBttO!u!.݀!!w#uuuuu#uuuuXw}O}}!####u#u#u#u#u#u#u#u##u#uu##########u!BHuX&JJMIs/M\JdB}tPPl?"ilݒlB! ݹ}}!}7x;Y%YY%_dO7#!#}túi 1!HHBOBHHôhdÜh%y{BdlHݒ?yN1lݺ#ÜBH?@a@???1Nhh@F58/R++885]O!O!!OOO!t?i?1HHl.HÜttHݹ22BH!ݜd1!u!HB ݀..݀!݀uuwwwu#uu#uu!BBOuu#uu#u#u#u#u#u#u#u#u################u###!<T)M/))<f>dB&BBHܜú1?li2?HH݀!!!!!!}}!wwYYֽY%GO7#w!1!2..Od!B?y@BHlhh@c@hh1ܜl?[@i221BBl?[[ai1?c' 'R88!!!OHt.iH.H1tOH11ÜHOH !11ÜhOܜݺ.!݀!O!!wuuu##u#uuuuuOuu#uu##u#u#u#u#u#u#u#u##############uu#!!#u<-;) S\)g!B2l.ܜޜ?N?2??a!!!!u#u#B}!wwwɋɑ:;ƽ8s88YY?77##Olܵl.?!tOH!HHdh{{B?l??@F{{h211N?@1Bddd??@@N??Y8E R8JO!# B!݀Hl2 tHHH2tB?hO BOHB??HHHtú..!!!w#uu#uu#uuuuuu#uu#u#u#u#u#u#u#u#u##########u#######!Ou#g&L)<<խ'KխqggO7!O!!ݜ!dP!.Hh?1OX!#u#w7wwwuw!}G7G&<\+Ssԗ-5>&!OB11[߷$@?1d!!tútÜ??[h]hhB!܊P11lt1HH!tOOOd??@@h;ES8MIM48<>>BO!tH1tt.211l2?!lB2lܜú!!# HO111.tO!wu##u#wuuu#uu##u##uuu##u#u#u#u#uu#u#u##########u#u#ww#!!!u>gJISEsUsӢ;&O7O!OBB1iiylOBOtH1H!BBBl1?{hh]3Üi?.1t.!O!!OHd{[$aZ%&SS6EMM((Ш48S>u X1[[?H1Ht$tlhudh?lhl1!t!O!OH1H!O!?!t!ܜܺúO!!##u###u#uuuuuuuuuuuuu##u#u#u#u#uu#u#u#u#############ww!!#u#!!/s-SJ<-:<>&O!w##!!OH!ݹHh!OXu!!!Ü}!O#wwww!#uBB&Ď8++++bB}O#!1??2lBBO!t1?HOBl?{yF3t2ll121HtHO!OBi[@@$aaa) MjMАS:JO##OHtܺH?i2liillH궴t!H!t!̯?H l?Blldl!tutÒ1t!!!w##!ww#u##uuuuuuuuuuu###u#u#u#u#u#u#u#############w!!!##!!::)\8EK<<&OOݹú}uݜ1útO!!!!uBd?À##O#w7}۹!dd>g8sUٔ&!#!!O?ܜú?OOOHO!HByyHd?{%Yccddl2lNPP?.O!OBBdl???d[ߵ3<)/6/M *АSJ>Bt1.ݺtOl22ilHH2tO!XOB1BBHdO?݀.t12O!w!OwX###uuuuuuuu#wuuu#uuu#uu#uu#u#u#############7!##!BO-'IRSssE/-><-E8>O.ùܴ?PÜHH uy?Ü!ú#ÀB3ww#?>}g>>g-8sEsz;<:&!O!OH!!!HBHHH!!OOO1hh_Y5hF?22 2dBdBBll1BBd>dxLS8sRM*488>OOu.!ltylHhl?ullt!t O22hl!BúOHܺ.!PlúBù!#ww##u#u#u#uuu#u##uu#u#uu######u#uu#uu##u#uu#u#!uOOuuu!'/j\\LJ3:-SEsJ:d>G!!Ò.}!w}.ݺ..Hl$y1.H ôlܒ!!!?ܺ}BB!w}wO}Bg}G&L68888TO#!!H#OOHH1HH1?]h7#tdd_Y%{y{[ZZ| ||?ôdBddlB}7}B>dgG6E0 8J<d1 1H22??ûylll? #!2lOH1!!!B!O!O#l}lii1122H݀}Ow##u#uu#u#u#u###u#u#u#u####u#u####u#uuu#uuuuuuX##u#!###!!!8--'k)GJJΔ+sJ:3Jd>Oú}!!#.HttHlh$i.?H?X?ݹ}w#!w}}O77GE8K:!##H!O1BÜ11d!Bd?ֲYֲY%ca$$@߷l?!!}B>>Lq)/I88-2ú!#u#uH1l?l1lݜ?B#!O!7!7!7w7I8z<&O!O!tB!H1útt?lddlhcֲ_YY%{@yal?B}ÜdB}!O}Bg}ggLpM0* 8E/JϴdHOHܺ!1H??dô@l1yطltҺ1ݺHH!O!OO!OtH1.t#uuuu#w#uu#u#u#u#u#u#u#u#u#u#u#####uuu#u # #u#u#uuuu#OO88qGǑGI-8;d>>ܴO!!w!#!2?2l?1?ݒ?d!ù!!O7!7#w777788\&>GGOOBOBOH!O!HHHtBd]??l?3YY5_Y%%cy%F]]BB?BB?1ùO!!}}qqG\IRRj*<O}1ܺ!!!www!OO21[1t!uݺ!B!w!!!7!www777w7J--88Ez8LGhBdOOt!ܻ33ϻ3FcYYֽ;5ֲֲ5%زcF?d&Bl?BùO}BG}qxӢ''RȈ(A8<>d1t2ܜ2Ü1l?Bu?yld1%O!yHHÜ!OOO!d?dHtOH BH!uOX##u#uuuu#u#u#u#u#u#u#u#u#u#u####u#u#uuu#uu#u##!uuu#!##!8ɑOw}}>q<E-&>>>>̹B?OOO!!ww!OB1OO11tH.dhHll!!?{dB!uww7!wuw!w7G<:-88LB]cOOHݜ2B33ϙ?]%YKK;_d&BdùBB}qGG/M'M (8sOܜ!.?2h?Bdl?X1 !?i2HOtB#]؜?hhO๺1OHOOHOO#w!uuu##uwu#u#u#u#u#u#u#u#u##u#uu######u#uuu# ###uuu w!!!uuEΕG7#7w&K-GFO!ݺddd<%֗K-S;_3>BִB?lBù}GxxGI M `REsHH2!!lFa{O1Hl! 1{a!B##OOHHO!O?B1B##uuu##u##uu##uu#uu#u#uuuuuuuuuuuu####uww#uwuu#uu#uuuu#uXuu##u##!!!u6/'Ixx}wuu}B&>gqG7G!!!O}!OOOlltt#1úBd}!X!!Owuw!!uuw777Ls<T>&T7!wOOBB:]J:Y֗KSs853>>F_?l2d?ܹ}BGGqR'**`USK5?!#dtOH3?hO2yY{1t!11!B11OHB#!!Xt!B!BúOO!#uuuuu##u#u#u##u#u#u#u#uuuuu#u#u#u###uww#uww#u#!!uuuu###uXu#u6'LGwd&LL<<77#7!O!7O!OHHO!Otl1H#1? w!OݹBu}!!!7uuuw\<KTTJ>G&}7!7!ww!!dTT::F_YֽsS/Sss֗֗5553]]d}ܜB}ddBgB}Gqg8/MI *U8K:t݀!O!#dݺݜ?ܺݺ݀1yd!O!OBO!!!!#u###u uu#uuu#u#u##u#u#u#uuuuuuu#u######ww#w##!!wuuu##ww###uuw#u!!!++<<7!7O!!!!OBù#u#H11Ht!Bd12..?FB]!B!1OO}}wuwuu#wwS88-J&&Td>}!O3]:;-K5_Y֗S6-S__]Fdۀ1d}B&gLs66' *`Edl?H1Xt?h1# Ouc?ùBli2Bú Xtݜ@HXHHH!O!O!!!!!##uuuu#u#u#uuuu#u#u#u#u##u###u#u#w###ww####w!w!u#uuuuuuu##uu#O!!+-TJ<BGdT>g?FTTFK;;K_֗U++6/_YY3]?B}?BB}B}>gGxEs8M*`RE>d2l1?hlO!h]FhBlÀ!1l!1O1l!!#tOO!tu#!O##uuuuuuuu#uu#u#uu#u#u#u#u#u#u#u#uw#w#w#ww##www#!!#uu uu#uuu!##u#u88->&d<<LLG7###u##u!.Üú.Ü?2..OO?HluB]_ֲ@ػwX#!wuw#uuɌ֗G&ddT;sK֗֗8Es+6+SY53]hBl3BB}>ù}}Gq>HÜÜ!{?!?ôߴt??t݀HH??ܓ!tX !#uuuuuu#u##uu#u#u#u#uu#u######u#w####www!w#w!w##w###uuuu##uu#XXu#A8>>:nę\L>G!!O!ݺÜ2?21.1H!B1Hliu3a%%ch?B}!7w##uuɋxq)/<>G&>:<ώ<:]5_88888S֗8UA+SSYYYYY]{aܴOܜB!B7}۹۹7gJn΢R' *`E;dd1ܜO]lBldOOHtOtܜ!Üt#X!!tÀ# ###!##uu#uuu#uu#uuu#u#uu#uu##u#u###u#####w}O##wu##uuuu#u#uuu####uu#uuw ֗5><&۹77!###!#!ݺ.Ni@yBy[l{h%%c{YY%}#w#www##wG)n-Kę>GGJ:ώT88sSSsY֗88EU sԗ֗YYY%hFhdܴÜ7}B}}gwLJnIj 'E<̹O7!!X!. PlNa@lH!OBhYFh55dT%!!uuu77ɑ<&Jd--_Y֗88E+6+S֗888888EsE8c5c]3Bdd}dB7ݹBx}xff'R++/Fl?l??dOOBBdBBl?hd!1{ilh!?dO1u!HtҀHBBO!!!!#uuuuuuuuuuuu#u#u#uu#u#uu#uu#u##u#ww#####u###w!wwu##uuuuw!!########u###* s:G&-JJJB}̹!#u#!!t!ݶN[[iltHH!OBBcB}B&g&ŽcB#7Gwu777;-7GG&&>J:-KK֗888ԖRR/S88888ԖEss888Yֲ%F3dBdB}B!!}7wxGLe'BFFOuw#錌::gG-;;_88Ԗ('-֗8888EU+EEYYYdBB۹}ݹ!}}7wxqGvvj\<[Bl?![HO!OOdHO!!@ܺ Ou}uBhaXH{!#OO!#uXXuuuu#uu#u#u###u##u##u#u#######u##w#####uw!wuuu#u###uu##w##u####uuu##w# Is5TK:TS-d&!7!7!ݜ!.1lúttt!1d!w!}c7GB7whiزc}77G7GG&JT;;֗8Ԗ 'K8sUU88+Uz8Y%y{BOOBB}!d!۹7GLff\v&d@hFO!O!OXO!#Xt!dlBB?t!7wXB?%at!!HÀ!u uXXXuu#uuu#u####u##u##u#u#u#############uu#w#u##wuu#w##uu##uuuu##u#u#w##)'-S֗S8T!7O!!O1HÀH H!!1B1tH1l{d!BF!}O!w7w}d?aYOc{B7苹7>>TTJ3;;;֗4A 'JKs8sS+UsU++SsYacyh[?ùB?!!w}xqqkvI<>lca3BOÀd!ll!d?BOtO#1X#w!O}cF?# ###OOXuXuuXuuuuuuu####u#u#u#u#u##u#u#######uw####u##u#uuwwwuu#u###uu#u######w####uL)LєE֗E8FdBO7OOO!OH?t#u}HBO!!OtcB7##}7!{hdY%]B777&>&:ֽK5֗4惪C Iĕ/E+6U++Y%ya[hO}!w!ݹO7wG<v>;5-3;Y֗֗֗Ԑ̈́`*IUs+6R+AS_yca[h?O!!!!!!!O}GfLqğ:}}Btc32Hlh?Ht?lh#X!h{a#!!!X#X!!###!uXXuuuuuu#u#u####uu#uuu###u##u#########u#u#u#u####w!wuwuuu##u#u#w##u##uww##uuJI E֗֗8sE8YO!#!!OHuOO#uXXú!!.11HB!Oh]5}#!]!!}!#u!}}F_YY>>wOB>Ow&/:Y֗Y֗88EEA((`*MR 44RR/_a@ h?B}}}777G<<:K-J-_%F3OOLFyy?HBh@F?H1{݀![yO Ot!{{!##XXXX#!OOuuuuuXuuuuuuuu#u##u#u##u##u#uw#########uw#ww##u#u#uuuu#www#u##uu##w##w######uuuu#uu/6+M` R6+E88887OO#O>?OO?h?t!O!!!#!ul}l}{%hB!!Oⲝ3&B_><:<Kn<<>FF?}!x&K88֗֗֗֗֗8 AA EEEE8Ԗ((pRS5{a[ylh}۴d?dGww7777xGq£dOB3]{Hll{lh{2HtlܺHO!{c{u݀ u !!!!!!O!!Xuuuuuuuuuuu#uu#u#uu#u#u##u############w!#######u#u##w#####uu#w##w#######uu#u#u#qI 000M+ 83!7!?3OO!O.11B!#H?dBhB!uù53&G}gT<<>3>̹̹K88֗֗֗֗8EUU88s888U ( //SFhZ2[ܺ?!3&77ww77Gg>>B?B?Bh?!!H?d{!Bh?.HOu O!!!Ҁ!! BBww#Xuuuuuuuuuuuuu#uu#####uu#u#u#u###########uu##w#u###uuuu#uu#######u###w###w##uu#wwwwww!\j))))\ (ԗT!!7F!!OOO1HH1t!u Ҁ!Ow7۴dۜOHH5_g5x<<&>3?BB&d;8E88֗֗֗֗8EsEE88֗88s+s R K;K]l"l[?2ݺHdhB}7www7}}:d}3?Od?u!dahu1lt!BtuXX#..ttt.# #uuuuuuuuuuuu##u###w##u##u##uu#########w#w#w#####u#u#u###uu#ww#uu######u#u###u#####GqLLLnխ)MA+EO!]cFOOt.B2.t. !HOB!77}}H!H}5ֲYqBB3>BBŽ;zsE888֗Y֗88888֗8E++R D'p/-K;]dl?ފ$[lBBB}wwu#w7OxG}q?3̹h!B!BFFܻܵܺl!!BtO1HN!.XXXXXuuuuuuuuu#u#u#u#www####u##u##u########7w!w######u#u###wwwwww#u######u####u#uuuuuu#qxqGx:խ 0* (AE8TG}%!OO!BlH..ܴdOdBHÜ12??֗<>۹&G_5>BdH}7&-USSK8888888888YYY֗E AD'/-KKlii?.!ݹO}###wwO7Owww}&>:B{%!XOddl?? tHO!O!1i.1[} uXXuXu#Xuuuu#uu#u###w!wu#u#u##u#########www#w#uu###u##uu##ww!!!#w#u###uuu#uu###w##uwGxɑ&JQ)M0*s>!775dɹ!Oo.HܵlHOOBBhBO}liް3:KSSEs8Jxxg5d&ddBĕRR/;sE8EsEEEEss888Yֲ֗E(M'M'K?1ފ?.Hu#uwww#uwwww#wwwO}d1}B&_at!OO@[?!ttB.ii[hu XuXXuuXu##uuu##### u.!#u#u##u##uuuuuu######w#####u#uu##www##############u###u#u#w!!!77g7LI'I (S-J&77!77L>5w!!!# 22tOh?1?lH?i|{TKS-M+sz8;J<G&&gۙ3>BB>d™<R'+++AA 88YY֗8(MIM5hd22úBݜÜBGOwwww##wO!21dO7:ôt#1B!h1?11 Htu1ܜ?uuuuXuXuuuuu###u !O.t uu#uu#u#uu#w#ww#########u#uu#ww####u#########u##u##u####ww77gGwQk0M+S-O!!#&T_7#u#! .l?B!?F{@[2@%TKn'jD/ӽsTJG&GG}dBBBBd<<''MII RRR6 EE8֗8888+ 'K;5?2i?2?ÀHl۹Ow!ww#wwO#7}d&d>hOh1h 1Hiut! O#݀# uuXuXuu#u###u### X#t111t# #####u#######ww#w########uuu#####w##u#u##u#u#u#u#u#u########u7ɋ7wwɋk M'O!7GG:&77Xu?N?H?h?hdBO!BhcYH12bee''/KJ-BGG}G}G}FBBd>fIeeII' D`A s8E֗888+ MI'S;c{[?2dBxOw7}&dd}B̴O&3c%%BOHtHu !B XOH?yF܀ !!tXҀXuuuuuuuuu##!!!#!Bܜt# ######uw#####www######u##u##u#####u##uu#u#######u##uu#uu#####7wwww77\pI<<! u77}O#Xu !1l12?cBOO3y3BH!]Kj''':۹G&}۹&_Bdf\\\\\eIM (AUsEE4888s'II/K;YY_%altÜl1ùB7G&ddB!dB̌!BF!H#! !tBOXXX@?!uu!X#Xuuuuuuuuuu#!OOttH2?11!u# ####################u####uuu###u##uuu##u#u#u#u#uu##u#u#####ɋww7wwɑIU:d}# !7}!!u uO uH1y>?wX蹹!O#OX?BLL)kLLѣvj I`'` RR ٞUmЫ4E88EIє-KY[?iHÜúH}dd&}}BB!!BBd!OXHl!H?!tt1X!uXu#XuO#u#XXuuuuuuuuu##!O!tÜ# u######w####uu#########uu##uu#u##u##u##u#u#uuu#u#u###u###u###ɋɋwwɋw7/U88U:O#O#wu7!### X u!O1d!OOw#7!7!&!qfJ'/->}d&dGJY5>f&gLLLLL\\j IMp D RR CІ 8E+'/Kֲy@PtOÜl.}dd>&}GOwdBBO!dO!#?!,H!!O!u###!Ouuu###u#!O!tt!!#u#u##########u#u#u####u#u#u###u#u##########uu#uu#u##u#u##u######77ww7w77G<E8Ԗ8;#w#w#!!## O}?dB&OB̴!w!7O}q:L)LOd>>&7qd&gLqGqLLLLLLk\\jM II MS/'nƘ_Fcal.1[úl?>:3&7̹wdd}l1tH?!!h1!u#!##O#Xuu##utt݀# ########w#######u##u#uu#uu#u###u####uwuuuuuuuu##u##u######u777ɋwwG:E8Jww#uw#O#!u !d}!c]BdBw#7&wGGGLLk\L>}g}G7Jd&GGGGGGqGqqqqqqqqLL-ΕjjvvM4R'I?OB1Ü?3dT&}>>۹%B?l1! ??H!Ou!#uuX#######u##uu# HÒXX#uu### u#u##########u##uu#w##uuuuuuu#uu##u#u##u######u#u##w######uuGOGwGGsU((6ּ7Ɍ#u#!!!O݀#X!O}dhF3?BO77w777GqGqLGGGL&B۹}g>>&5>>&gGGxxxxxxGqqqq<ĕ\\vv 444ԖEӔ'nhÜBܜ!?ldFhdh3d]FB1[21dhhO OOOic?########u#w#u݀H22?11t u###uu#########w####u#u##w#w#u#u#u#uuu#u##u##u#u#u##u######u#####w7}>>ǹ&&7:;3&&G쑑xxxxxxxGxx<<5Y]FF#h3!B?llܜO#?!BHX#uu###u#uuuu#X#!OHt?1H!!########################wwww##uuuuu#uu##u##u######u##u###w####u##7wG>}x7G:/I0 RS狋77!!u!O!H#!#O}BBù!!!! !#w7777777GG}}&]:G}&}xGxxGxxxxqgqgf^ve'p AEԖEEMn_Yd}?H!}BO&uO?B!O}l?{{{l!!t!d{XuuOwuuXXXXuuuuu#u#X#!HHH12H! u!!#######u######w####u#########uuuuu#uu##u###u###u#u#u##############w7Gwww7ɋ7x)L77&d!!!#!!!!!!B..o.t21O#77w####wwO77777x}}gG<&G}777xxxGGxGxqqLKKzsEs s88֗+II'n-ֲYdOHHݺݺ}}G>&7G?!!dB?%FO11꓀ XX#!uXuuXXXXXXXu###OtOOHt1t ! uXuu#!##################u#uu#u#u#uu#uu#u#u##uu#u#u##u##u##uw##########&G}G!}>>uW7L&7Oֲ5F7##uu#w!Üú!Ò1P1P2?2H7##wuwwwww777w777}}}}!x&GG777x7xxxGqG쑑qGqfSS6A+ԖsY֗+ M'K_h#1!ݺ}L>&hBlddHOd1w#dHH!u u###uuuuXuuXuuuuu!!O!!OtOtH1Hu!u!##!################u##u#uu#u##u#uuuuuuu#u###u#u##u#uu############77Gɋ7777}#!7Y#!!uu##B!ݺ12?2PP2hdOu7www7uuw##7}Ox!wwww}>BOwGGG&&G77xxxq)L)qGxxxxڟRR448֗֗8MMDIJT5]]񹹹O}B}}G<]3%d???ld?OÀO2B1XXu uuuu uuuuuuuXXuu!!OOݺHHHttOOX##XX###################u####u#uuuuuuuuu#u##uu##u##u###########!¯wwxNjw#!wx888c#O!#u!uݺÒ2111l2BBwO!!ww}wx}w#!###ww!7ww}BɑGG&GGxx󭭭)խGqxxxxx7xqq\\M(888888888Es8MMM ':]_n^nfq7}d>&GGJ3&dcBOBHB!?{aX݀!OHܜ !O!#uXXXuu!#XuO !H2!!#!O!#!#!O!####uu u###w###u#u#uu#u#uu#uu##u#u#u#uu####################O}7>#w77##LL)\)kxxxx7xx77GG)M RAA~6MMMJTKSzgqG&>G&&>&7wyH??#X[tX tuH#Xu u u!!#uuuuu#u!!!!OOHlú!###!!##O!###############u#u#u#u##u#u#u##uu#u#u#u#u####################!}}>}}GwwW7XJ-SAF&u###uuuuXXXXut.OO}}3www7#wG>!B}!!u#!w!777&ggg&&>>>>g><\))kqxxxxɑ)\jM' ӧRRD C MRURIID/;8EULq7&>>dGGGGd>d&7dld!}hlB2À!XҀ!H u!##uX#w#u##u!!t݀tiOO!O###!OOO耀#u#########u###u##u##u#u#uu##u#u#u#u#####################Bd}}O##7#B33s Ap';X#XuuuXuX!úwBB}B:>Lq7&77u!}Xu#ww!7!>&&g&™d77ÜlFlh?{?3XXX!XXX!##!u !uuu##耀Hllhl!#O!!!OO!!!!!!u############u#u##u##u#u#u#u#u#u#u#u#u###################Bugd]dxwww7W#!!B5_;KSII&w#!u#u##}Oݺ!!!7&gdn>q<!#uwuu!###!7g>dggg&&]:J;;;SM ך))7xGgL\\\\ pzzb^ppE8(ADILgGwwGT]F#7!B?BBh!cXuuXuuu!u uXu!u##u#Ott!.11?lP !HH!H1BHtO!#!!7##########u##u##u##u#u#u#u#u#u#u#u#u#################u#!d}!}}BG#u777dOBF]K/'\f<}uu!uu#!ݺ.G}̹&;<n:¹#!ݺO!w!!dJL&gƝ֗Y֗8s+RM0))xxxG}gggqqk\I IbKbpppDUA(rCMjkkkGxw]TB>?tuH!ݹ!h}uwX#XuXuuuuuXX#O!!#u#!tHOH11t2!Pu!!tt! #!!O####w#####u##u##u###u#u#u#u#u#u#u#uu##################w!!Bh}!BBG#7BF]hdh<\G#u###!t?ihltd<Ks<&>G!!wO}!B}w!&>™J>&&gGgd֗֗֗8EE R j0 )xxGGGGxxxxq))eI IM'^bDCC6`(CvkLk}x7G>d3B>h?d!dhBt?BO#X}XuXXX##u#uX !!O#!!!uu.tt111.,X.tott.!.tH2꺀 #!!!!u##uu#######u#u#u#uu#u#u#u#u#u#u#u#uw##################ی}>w#77c%d>&\7Gd###!!!tH1?[N5J>d5cϜ7Yh?!!d7#Xw###!O#u uw!!# 耀!t12t2.o.tHttHH.!t !!!##!!##u########u#u##uu##u#u#u#u#u#u#u#u#u###############u#!##B}}O#3YY&GGw&}#u## tP2PNi2233YY5Kss<&GOuB}?}}>K3>G>n:nK8֗8s/')kGqqxxw7xxxfDMRpRpCCDm8ԧ`CȮ )qgq}g&>wdd?F1?O#O!!uuuuu!##݀u݀##!!Oݺ1HÒ.t.tt.HHHt!! !!!##!!!##uuw#uuuuuu#uu#uuu#u#u#u#u#u#u#u#uw####u#uuu#u#######!##!B&w7}d{O777Gɋ##̹w ݒ2P.to.l?yY_YY֗KT--K/S&G&d&]3}dB}Bg>T:>:::-E s8֗֗֗8s^kkqqxx7xGqkDC6+CrDD8U* kkqqŽg>>ۓBha{yXOh!O!OuX!!uuuuuu#w!w##!! #1Ott.....O.OH.!݀####uuuu###!####uuu#uu#uuuu#u#uu#u#uu#u#u######u##u#u#####!OOO!!}d3d&7B&dBB7#w7#u!w#uOHt.tPH.Hd]Y֗֗֗֗;^ڣJL>>d:T5YF?>B7}}&&uuOXuuuuwwuu!B1H111ܜBB֗88sE88888E88-G<3֗;:gBB!}B&dg><''IIIIM6SEs888888)Lqxqk'RR6 88sEm~(eekfK:g™:3u?HBXd # O##uuu!uu!#!X Ou!!#u!!!O!u!!!!# ###!####u#u#uuuuuu#uuuu#u#u#u#u#u#u#u##########w#ww#݀O!!!OBùuO!O#uX##XXuu#w!w!#tOtOOÜds888s+ +68KJ&&8U5>}}}B>™ggg\<eџŞ+E8888Enqxqq)j/ 88U(~**vvvkkffnnfg%!wOOBOd!#X#X#uXuuuuu!##w!!#u#uu!ww##u##u!!!O!!u#!!!!!###!!!!!!!###uuu#uwuuuuuuu#u#u#u#u#u#u#u#u#u######w#w#w#!!tHHOO!!u#!##G7##XuXX##Xuuuuw!!w!#!#XO}&+R p֗>J֗SKB}Bgkk0jCR 'UEUEEsE8nGgkkvIIٿC8Esrr*vv qkenļƝyO!dB#!B! #X#u#uu#uu#u#!# uXu###uXw#u!!w!#u!!!!##!!!OOOOOO!!!uu#u##u###uuuu#uuuu#u#u#u#u#u#u#u##u####w##w#wttH22!?O#OG7#7#XXuuu####w# uX#X&>: Ij' M j\I-T-''J>}}}JG}GGLLfgqGkj'M00'''R+8KLfkkkj8DRR֗r~~`ͩ`(Cv\fd<<>gGGGGGGGqxxxqGLLL)jIMUD 88Se \jDmA` Ԩ=~̓vvkffn>7w,iOu#XXuuuuuu#u##uuuuuuuuuuu#uu#w!wuuuXuX##uu#w7!!u### !!!1HtH!OuuuXuu#u###uu#u#u#u#u#u##uu#####u#u#w####u#!!tto1[!!!#X#!!O!#uu#uuu#!!!ݹ}Bd>>gB>>d>}>dJqGxGGGGGqGGxxGL\j 'M+ 'ڔU*`4VEԖ9ʈ qkfļ¹OuXҀw#uuuuuuuuuu#uuuuuu#u#uuu#uuuuuuuuuuuXuu#####uuuu## # uOOH1Oݹ!O!!!ww#u##u#u###u##u#u#u#u#u##u#uuuuuuuuuw!!Ht11!uu##Xu#!OOOO!O!#XuuuHH!!#!H>dd<>GxxqLL\G}GwxGG>n6EBGGqqGGGGxGqxG)\\M6E R+UU/I ' *(﨨VU4ʈ\qqfnfff>}X݀Xuuuuuuuuuuu#u##u#uu#uuuu##uuuuuXuXuuuuuuu##uuuu#u#uu#!!OHHHHOH!O!!!####uu#uu##u#u##u#u##u#u#u#u ###uu # uw##!O1H.1tltO#!!O!OOO!!OO!!耀#XXXXXu#!t!#!!!O33&&G77xgL۹7>dG}}g<'/S8533]g&gGGx7xGGGGL\\\՚I ` 8/I ڦD`VVV4E qkļfGL7w#}uX#XuuuXuuuuuuuu#u###u#uuuuuuuuuuuuuuuuuuuuuuuuuuXuuuuuuu#u##!OBOO!##!!##uuuu#u#u##u##u####u#u#u##u##u#u#uu##!l12.t1t1!!!!!!!OOOt!!!! u##.t!!!OBB3GG77GGx>g}g}gG<&&&}L\I688_YֲY:JJnLLqqqqkLLkL)))՚MM `R8+Mj j`*V4VАԐrCkqxk™fqxgww7w#uwXuuu#uuuXu#uuuu##u##u#uuuuuuuuuuuuuXuXuuuuuuuuuuuuuuu##!!O!#XX!#!# uu #uuu##u##uu#u##uu#u#uu#u# u###!!OÜt.P$?BHtO!#!#O!uOH1H!tX#!t.H...P1tH3d>>d7>f:-'<w}ddX}gLI/sY_ֲ__5T:™Jn::Ƙ<qqg£xwGw####uXuu#uuuuuuu##u#uuu#uu#u#uuuuu#uuuu#uuuuuuuuuuuuuuuuu##uuuuuu##w#####uuuuu####uuuuuu#uuuu#wu##u#u#u######u#u u!Hut1?11"@[yHtO!! O!HHtt! 1HH1?..tP2iy]3>G77&ѕ!}Bdu'+E-_cF::-TK<<<<'<\L\<Q)0' 888UpICM `~~ 4444U =(Cbfggggf:7uuuXuuuuuuuu##u#uu#uu#uuuuuuu#u##u#uuuuuuuuuuuuuuuuu#u##uuuu#u#uuuu u#uuuuu##u#u#u###uu#uu#####u###u#u######u###u#!!!#݀1Ht. Hl!FHtOO!!###!OHBdl꒒1?cط2..2h@y55:>GG&SS-J&ddBw}gggfJ:-TJ>£ggL-3F!OX!۹>;YYYYYY֗588sSESssS<<SK8888sK \v++U Dbpp`( s884=9`C\kxxx7wO}!݀ u###uu##uuuu#u###uu#uuu#uuuuuu#u##uuuuuuuu#u#uuuu##w#uuuuuuuuuuuuuuuXuXuuɌuuuuuuuu#####w##uu##u##u#u######u#!!w!OO#!!#ݓ12l2!3ִ!HBH1HH!!OOO!!!!#t#OHH1l+SԗLg<-<>&q<:&d>3>5Fݹ}7R88E8zgGx:<<<<&T3]]!OB۹>KY֗K//+UU''/:D psEԗ88bfkL)jє8U'+UCCmr~~U44=99CfqqGx!1t .7#uuu#uuuuuu##uuu#uuu#uuuu#uuuuuu#uuuuuuuuu###ww!wu#uu#uuuuuuuuuXuuuuuuuuuuu#####uuuuuuuuuuuu#u###u#u## #uu!!!O!XOÀ 1@@[%BOB!O!!!t!!݀####OG}\'jM+C+<>'-;}&gT3d>d<۹}77T֗8Ӕ/+URpM'b+I<<eID C6888se\fL)ej88+C(rrrrmr 4=rCDekgqggxqx7#OHt茌uu#uuuuuuuu#uu#u#uuuuuuuuuuuu#u#u#uu#u#uuuu#u#uu###wwwu#uuuuuuuuuuuuuuuuuuuuuuuuuuu#######uuuuuuuuuuuu#u###u#u####uuuu!OB!# u..["?ty#{!!t!t!!!#!!O!#O7G}GLk\\' ';G}qգ>J:3__F]ddT5_d3d}!}<;֗Y-ΔS6 I'SI\jIDM UEeevj/E86EECrr~m 44V=r9ʈʈDCpkgqxqq&&!HoHl!w#uu#uuuuuuuuu###uu#u#u#uuu#u#uuuu#uuuuu#u#uuu#u######uuuuuu#uuuuuuuuuuuu#uuuuuu#u#####uuuuu#uuuu#u#u###uu#u#uuuݹwX##!Xuñ@$?2@OOlBH1tO!!!#OOO!#wuw!7q)\\/''I:ƙ&G}Lq>gd}}TT5֗֗88S/R6++Mj^ES'ffkj M`6ED+/88p'+~44ʈp^gqkqkqGOO l#!!u#uu#u#u#uu#uuu#uuuuuuuu#uuuuuuuu#uuuuuuuu#u#u##uuu#uuuuuuuu#uuuuuuuuuuuuu####uuu######u#uu#uuuuuuu#u###u#uu##uuu!u!#!XX.t.[y2chOy#HlH1t##?3ϴO!#!!uwGqL'<J&G&dLf)Jg}}G}۝:™J:F&!&}dB__;K֗֗88E// 6EU \eEk\\ 0 *MEs/'jڕ+E6E'MU8 ٧rr ~4=Ȥpzfffkq&!!!l!!uuuu#uuuu#uu#u#uuuuuu#uu#uuuuuu#uuuuuuuuuuu#uuuuu#u#u#uuuuuuuuuuuuuuw##uu##u#uuuu#uuuuuuuuu#uu#u#u####u##u!wOO!!!H2to.Py2l2l?Ҋ@2?#OH1HtBHl%F3BBOHO!!ww77GG-:GgL;SJd&F⻎&B]]3::];֗֗888EEU+' '6I\vK'\LLgkLLLfך) ++ e\e6++''I8EEU~mR 444VrMpz^eek&&1H!X##u#uuuu#uuu#u#uuuuuu#uuu#uuuu#uuuuuuuuuu#uuuuu#uuuuuuuuuu#uuuu#uuuuuuu#u#u#u#u####uu#uuu#u###uuuuuuuuuu#u####u###u#!!!O2#.h coN?P.!#HtBlcH#wu##7w7Gq<g}gg^8Kg77d><GdFT8EUUUA6 IM'\\\LLqLqqqL\0j'p))/s/p'8888~( 4V~(bpp^z8zz^e\fgBB1t##u#u#uu####uuuuuuu#uu#uuuuu#u#u#uuu#uu#uuuuuuu#u#uuuuuuuu#uuuuuuuuuuuu##uuuu##u#u#uuu#uuuuuuuuu#uu##u########u# O1BÜ1l1?.?Niܺ!O3]YYYYYa?!##w!wG<:n&-;zK:::gd}}>:JYd»֗8E88sU US++M)))LLe)GGGGf\)ѕIխG6E8 /6DsEUԿ C44VVV~pee^^^ڟ\v}}BHO!u#uuuuu#uuuuuuuuuu#uu#uuuuu#uuu#uuu#uu#uu#u#uuu##uuuuuuuu#u#u#uuuuuuuuu#u#uuuuu#u##uuuu#uuuuuuuuuuu#u####w###݀u!.ݜ1P.?iauOXBTYֲ%yú!w!777&&<&ggJ^֗T:>]:J:<>5ֲ3Bd]8sUE ++s /'I)LqGxxxq))\Jqxxqq\IDR/p8EEECp44VVVDppbeee^ڟڣG<&&gn8ngd:3_>G33?35Y55;sUU+UEUӕ\LxGxx77xxL£qGGLqGx7xG'ٞŞ88 6 Ԗ4V=D^efeę}BOX##uuu#u#uuu##u#u#uu##uu#uuu#u#uuu#uuu#uuu#u##uuuuuuu##u#uuuu#uuuuuuuuu#uuu#u#u#uuuuuuuuuuuu#u#u#u#u#u#u#u#u#w!ww!!X.t .P?lihOB]Fcù!<{@h13BÀ#!}&>>:<<--<:n;>GBGBOdd]];UU++R+Uӕ777777ɑxqffLxGqG}qx777w77xjEԗUb'sb'DA6 44=rCDDevkkevv>wX!X#Xu#uuuu#uuu####u#u#uu##u#u#uu#uuuuuu#u#uuuuuuuuuuu#uuu#u#uu#uuuu#uuuuu#uuu#uuuuuuuuuuuuuuu#u#u#u#u#u#u#uu#ww!!!X.úHlPtPP.{?!BdYY!!B>>Tӕ:F?2Ü}wwB&&&&GGgfJ<;77!#?KSSK+6// S88qxww7w777xqqqgqxxxxGxxx7777777xE8sD'bIDſ 4444Р`^^eev\kkff}wXuXuuu#uuu#uu#u######u#u##u#uuuu#uuuuuuuuu##uu#uuuuuuu##uu#uuuuuu#u#uuuuu#uuuu#u####u#uu#uuuuuu#u#u#u#u#u#u#u#u#wwO!#@PPd%@Y۴Fdd]F&>d<>d:-+/Δ'6Sdc_F>Bg<<'Jex7ww###w77x7Ɍu77xxx777eDUjIM pRr~ meee^ğekfkɌuXX Xuuuuuu#uu#u#u####uuu###u#u##u#u#uu#uu#uu#u#uu#uuuuuuuuuuuu#uu#u#uuuuuuuu#uuuu#uuu##uuuuuu#####u#u#u#u#u#u#u#u##### H1i..oNܶlBlYyBwd_T;;L)';1HBBBBϴ&&L&<-<<>̹}O#?BgBgGg\ģf)\LqG77###uu#ww77w77xGGGxxxxGL\kvvvvIڟΞDRmmErrrppvڟbDD^kkq7##XX#uu#uuuuuuu#u#uwu#u#u###uuuuuuuu#uu#uu###u#uuuuuu#uu##uu#uu#uu#uuuuuuuu#uu#u#u#uuuuuu#u#u#u#u#u#u#uuuuuuu#uu耀uil މ2l[1d?Odd3daK8K\-Y]BB%cl??lh%]gL:TT:LgL-&f>q}GqqqgLfBOh>-JqfۙfGL:-<>ۀ!BB}}}}}&qGGxxGGGGqGqLL<<w7w##uu###uww##ww7uxg<ęLxGL:KLkLf<ģDpDb A(DCpDȤpmCٟf7uuuuuw#uuu#uwwuwwu##uu####uu#u#uuuuu#uuu#u#u##u####uu#uuuuuuuu#uuu#uuuuu#u#uu#uuuuuu#u#uu#uu#uu#uu#u#u#########u#!!112N|" Z 1[{iy2@B?cFcGJ-<S-TOhlBSS+eeqLGLLLJJJ:O}}}7G7GG}GGxxxxxxGGGqqqfffqx77#u##uuuu#uu#w7w7xg£x>7}B1x!!!!7!x77!777wwww77wx7xxxGqgqqqGx7wuuuuuuuu#wwwq}qqqLqqgfGGLfLLnnğnn^DpDDpDbDppeٔڣkuuuuuuu#uu#uuuuuuuuu###uuuuu#uuuuu#uuu#uu#u##u#u#u#uuuuuuu#u#u#uuu#u#u#uuuuuuu#u#uuuuuu#uuuuuuu#u#u##uw###### P2i|2PHlNH[yF?lFydy?}77GGGggJf'Jl?B&dJ'/ 8USSJ&G&&d}Bd?ù7!7!w77w7w7wwwww#wwwx7xgggLqxxwww#uuuuuuu#ww#w77xgge>fLqۑxkgfĎƽn^^bzbpDpDDpbpşCqwwuuu#uw#uuuuuuuuuuuu##uuuuu#uuuu#uuuuuu#u#u##u#uuu#u#u#uuu#uuuuuu#uuuuuuuuu#u#u#u#uuuu#u#u#u#u##### # ݺPP[i[2ill@{F@h?dBh3Bl{1GG۹77G77gxqxqLJ]?hOJ UsJ&ۙJ7:BG!Bl?}!!w##wwww777wwww###www7wxxGggGw7##uuu#www7www777xgLJļ:gLqGxxqqJ^ef^^bpppDDDڟDpegɌuuuuuu#uuuuuuu#uuuuuuu##uuXuuuuu#uuuuu#u#u#u###u#uuuuuuu#uuuuu#uu#uuuuuuuuuu#uuuuu#u##uuu#u#uuu#u#u##u#### ..PPP1Pi?@1{l?cdBdd⻝{y{#l?:G7wxxxqxLxG:Y3d3lOOI++s7™&wO}}w#w#wu#wwwwwwwwww##7!xxq}x}ww77Gc33Blh?BO}&L\I'R /K:7>>dBddB}BúOw##wwu###wwwwwwwwwwww77GgBBBBùw##w##u#####w##wwwwwwww7xxGgL)\j<ddd>B!X1BHO7w#u##wwuuuuuuuuuu##w7ww7xG}fqGGxx77777wxɑx7www77GGGLLf<^K;nxggxG7xxgĎfƥzzsmpDp٧DCDDI\Xuuuuuuuuuuuuuuuuuuuuu#u#uuu#uuuuuuuuu#uu#uu#uuu#uu#uuuuu#uuuuuuuuu#uuuuuuuuu#u#u#u#u#u###u###u######݀122N22|"1@߷cc!d!B&>J:]w!Ow!}۹7G&d&Bd]d}}ggqG)Bd&>B!!#tBBO!ww##w#Xuuuu#wwwww7xxGg}xxx7x7x7777xxLgGw!7gLkk8zzCDppCpbCDCDII#uXuuuuuuuuuuuuu#u##u#uuuu#uuuuuuu#uuu#uu#uu#uuuuuuuuu#uuu#uuu#uuuuu#u#u#uu#uuuuu#u##u#u##u##uu#### 1Pl.P[[Hc}d#B!}B#Jƕ:Y37O?hG<G}GGGOB<>d}ú.ldB!7ww#w#w#w###uuu#u#ww#w77xqxGx7777777G<Gxxxe!OB>>&>7}B112?l}O777www7www!wwww#w#wuw7xGqG}G777ɑJGGGGqg<Jqգnn}GGG}g£^zƝzzKbſCȾDDڔёwuuuuuuuuuuuuuuuu####u#uuuuuuuuuuu#uuu#uuuuuuu#uuuuuuu#uuuu#uuu#uuuuuu#uuuuuu#uuuu#uuu#u##u#u##u##w!!PP1PP..o1?Üllldh??@B#h{?uX<ՕK:T:dtdB?hG>>¼™BgdGx77q_:>GOOOBd&G&OBB.BB7!ww#wwwwww##w######uw#777Gq}q}77777x>dHB??[2?dB}}}7wu####ww#ɋ##7x7}G}xgwx7xgJ-K/GqGg/S6L^f>7}q£n^bDpCM(mppppM'Q# uuuuuuuuXuuuuuuu#####uu###uuuuuuuuu#uu#uuuuuuuuuuuuu#uuu#uuuuuuuuuuuu#uu#u#uu#u#uuu####u##w##u#! !H1.1t"ii??úl11!!ùh{!?Ou#tX>&OBHBBO>&™q}Fnwd}ddddOhl21dlddB}7wwwuuwww#wwwwww#w7!x}}G7xwx77xG-'qxq:SES/'q}F:g7uBBddddO#lll1ldd̹7!#uuwuuw#uwwwɋw7g>GG}xw7w7xLqqLnzE /qļng}}}}Ogfgfb^nDbDDCCbpppCC Qu uu#uuuuuuuu#u#uu#uu#u#u#uuuu#u#uuuuuuu#uuu#u#uuu####uu#uu#uu#u#u#u#uuuuuuuuuuu#uu#uuuuu#uuuuu##uu!OO.݀ttt1thla1d1}X!OBBl?1?x77&G̹BBB!G&7G7TxBBd<GwwB&BO!1dlldBxOwuu#www#u#www7w7!OgBg}gO}w7xxGfSS++/qLJ:g}}}ggfgļ^ģbDmspDpCDC`D X##u#u#uuuuu#u#uu#u#uu#uu#u#uuuu#u#u#uu#u#uuuuuuu##uuuuu#uuuu#uuuuuuuu#uuuuuuuuuuu#uu#uuuu##u#!OOtOÒt܊P11P?i[Ü?HB?{{HHBl21iyy{l!?t&xGG7OOBdHBOOO&B&7g}d>}xu!!OBOO1꺺2dB}}O!w###w#w#w7wwwx7w7>}&}777GqJI)Lļ 'Jfƥ^nğepbDpspCMC((Q# Xu#u#uuuuuuuuuuuu#uu#uu#u#uuu#u#uuu#uu#uuuuuu#uuuu#uuuuuuuuuuuuuu#u#uuuuuuu#u#u#u#u#uuuuuuuu#uu##!OOHHtH?{޵t.l2ݷ1BÀuHt?i1 ú1ii@a2x7۹O#d33]TJ>Fh&>w躹#!!OBd&OOHHÜ2B}}}!wuu##wwwww77777#7GdFFg}xG™ļƼeڟbmDmUmDCruu uuuuu#uuuuuu#uuuu#uuuuuuu#uuuuuuuuuuuu#uu#uuuuu##uuuuuu#uuuuu#uu#u#u#u#uu#uu#uu#uu####u###!Ot??ttt11H2Ni@[2 ݵ!ݺ2l1ii?رylu?@&F&OOdHtd&>_&>3d>F۹۴?O!OO!B!BO!tÜ1BBۺO!O}ww!wwwww7w7777cFc3}qg<<<///J<dhHd>5:>dd&g]}Bd!#!OBBHHÜ}}}}!7!!}}}}7wwwwww7OGG۹>335F5%3d>}7GgJ<:n/I''I<<<G}g}G7#uw!x}f¼eeebٞMC*`=rCXu#uu#uuuXuuuuuu#uu#u#uu#u#uuu#uu#uuuuuuuuuuuuuuu###u#u#u#u#u#uuu#uuuuuu#uuuuuuuuuu#uuw##w##!!!!Ot#!!!l12tiH1i2 l??ltlP2ilܒ?l2{2۹BBÜ1BtHBOd>:333B}}dwÜO#}BBBÜÜB}!w!!}}}B7۹77۹}۹35}xGf<KJ-K'I>>>}7G}}x!u7OGg™nnefDDٞpr==Muu#uuuuuuuuuu#u#uu#uuu#u#uu#uuuuuuuuuuuuuuuu#uuu#uuuuuu#u#uuuuuuuuuuuuuu#uuu#u#u#u#u##u#u#uu#u##OOOOtH!X݀݀.2HtXܷ.1l1ill?@@{@[ic%t@!B#l1l]]>d3Fdd3BhuBBul?H&O!B1O}}w!}}}BBggg>w&&&d3]gGGgTKK/K&g&Gwwwww##u##77}zeev\bpDCCpCp``(~=peG#uuuuuuuuuuuuuuu#uu#uu#uu#uuu#uuuuuuuu#u#uuuuu#u#uu#u#u#uu#u#uuuuuuuu#u#uu#uu#u##u#u##u##u#uu#u#####!!O!!!#tH!1HÒlúlHtli!!?ilN?aN÷ht.ldBBBdl1HtB33:dώ»BB!BO?OuݺÜBBBB!!}Bú}}OO}}}&}B}d۹dddqGgg<-sΕSΕ<>}Oww##uuu7nƥƼĎbppppDCrr 4rfwXuu#u#uuuuuuuuu#uuuuu#uu#uu#uuuuuuuuuuu#u#uu#u#uuu#uu#uuuuuuuuuuuu#uuuu##u#u###u##u##u##u#u####u##!OH!.t຺݀.݀.l2Ü1??ܷ@[iNܜַ!lB?h1??BB3>d?}B}}&>!Xtݜh1lB̹O}BB1BB}O7ۜOwOB!۹7x}۹3333dTdg}Gqq<:-S/'-ΕB&!Owuuuu7&nnƼnğ^pDCppDCRrmrrrr6^guuuuuuu#u#u#uu#uu#uu#uuuuuu#uu#uuuu#uuuu#u##uuuuuuuuuuuuuuu#uuuu#uuuuuuuuu#u#u###u##u#u##u##u#uuuu#!!O!,耀Ü1Hݜt.212?y1[Ü2ÜllÀ?BB?hhúH1B?%d<&}۹}B}}B?Bݺ!lh??BddBO!!Ü?dB}}}!!}!}dB!}&>55_5gggJnKK--Ӕ '//nJ>BB}7Ouuuu#uĎn^bnğģe^ڤDDDm m~rrquu#uuuuuuu#uu#uuuu#uuuu#uuuuuuuuuuuu#uuuuuuuu#uuuuuuuu#uuuu#uuuu#uuu#u##u#u##u#u#u#####u#u##!!!##?tO!! HݜN@i2i.$N1#÷{?{y1#,tlltd??l1?]>&&&>}B?B}O7B!OÀHOH1BO7!Od??}}&?BùBBG}}>dh3}gqgJK;KK-ӔΔ''nn:>B!O!wuu#uuX#nb^ğğڟDDppCpm mmpDʪruuuuuuu#uu#uuuuuuu#uu#u#uuuuu#uuuuuuuu##uuuu#uu#uuuuuuuu#u#uuu#uu#uu#uuuuuuu#u##u###u#uu#u##u###### ##!u !X!! .tҺH1??H[@ܒi!O?{1OHt??hOdlddld>Gd}B!!!#!1@!ݺ!}O!!O!OÜddldB}B?d]hh]}7w7w}B33::g}w#!O!#XX#xn^^ڟğpbbmbDmCCC96Q7uu#u#uuuuu#uuuu#uuuuuuu#u#uuuuuuuuu#uu#uuu#u#u#u#uuuu#uu##uu#u#u#u#u#uuuu##uu#u####u######!u#u#! ld?l?.N2Hi[@߷12?FBOBBh{l{hhl?3?F?d&&dddy:/EsK''<<>O!#!OO#uXu##!BzzDpDpDȟCDDpk###w#Xu#uu#uuuuuuu#uu#uuuuu#uuuuuuuuuuuuu#uuuu#u#uuuuuuuu#uuuuuu###uu#u#u#u#u##########u##!!!!!!!# X u OݵH?l12?2{%%%d%Y%ܺhFlH!B?HHd}>3GJ>dBdlHO!XX!!OBHO}O#!!#!OBBd??dHOH#B}g3O7O>7>w&}h_YnsEs''ę<<!u####w7zŞUbe^ڤvC((C`pfɌX u #uu##uuu#uuuuuuuuuuuuuuuuuu#u#uu#uu#uuuuuuuuuuuuuuu#u#u#uuu#u####u#u#u#u#########u!!!!u!!!O!HOHo..,N1a{hayh?hYyHhH?Ht1gg>&O!}B!!dO!OB&!#!O!O}}}dd3?B!t]w!&d>F^SbI>B!u!X#wdsRbCpDDCCCRٟɋXXu uuu#uuuuuu#u#uuuuuuuuuuuuuuuuuuuuuuuu#uu#uuuuuuu#uuuu#uu#uu##u##u#uuu#u#u###########w!!!!##u uu!tBܜNiZ@i?iFBOFB?OÀH!OtlyB7]3FFd}wg&<&ܹ#X#}Bú!!Bܻ?tOOO###!O}!Où!BF3??H!hdwB3?O!7Od>>dd:3:'/џ:>BO!!#X##!]֗8spDCebDpC(CC͡CmD #uu uuuuuuu#uuuuuuuuuuuuuuuuuuu#u#u#u#uuu#uuuuuuuuuuuuu#uu#uu##u##u##u#u#u#u###########!w! #u . Oܷ@Nl22H1!úBcÜHúd?at3OBd]d]xwG<3&d!ғ!OO!uuB?dB#!OtOO!!O!t!}B333}>]B!}OO&Bd>B>d::JnğI'ğ<I<&&BOu#uXX#7۴8ŞmbDpbDDCDpppCʩr(wuu uuuu#uuuuuu#uu#u#uuuuuuuuuuuuuuuu#uuuuuuuuu#u#u#u#u#u#uuuuuuu##u##uuu#u#u################u#!OtO1BHtH2tu 2?ݜd!úh%yOOlcFhh!!#O۴}w]]3&ϼT7Bdu#X#HOO?tB#O #!!O!!!OB}d>3]BdhF%]%?Od<>BBÀ#XX!utBtdh!OBtO##!HtOtݹBd&JY3B%húH?33&777#BBwOX X##XOBOOlOOtt1Oú}lh3d35c33B]_YB1̺OB]:ĕKĔ;'e\Ou ##u#uu#O7>zU+pmpDDDDpppțʪ=quuXu#uuuuuuu#uuuuuuuuuuuuuuuuuuuuuu#uuu#uuuuuuuu#uuuuuuuuu#uu#uu#u###u#u#uuu#u##############!utttH2?1.iNY@@d?Bc{H!!FO!]%}w}x#77!}w7GOu u#!!!XOdOtOtHHH1dtݺ2dB}B5d5BhhddY%dO!OOBd>>n-Ε<<f:TddBt!!!#####Ž;zUbmpvȾͪr~puuXu#u#uuuu##u#uuuuuuuuuuuuuuuuuuu#wu#uuu#u#uuuuuuu#uu#u###u#u##u#u##u###u#####uuuO1tݒ1111.!?[hiy@F{d?H#H?hh&Bd☎]۹7u7OO!X!uX #O!t!!HHBOHOOH!OH1B?Bd7&Y%3񻝻ۙcY%hB!HB۹}g<'/nB!O!# ###u蹹Bnzb^bDppCDȟȮȾ(r=pku#uXu#u#uuuu#uu#uuuuuuuuuuuuuuuuu#uuuuuu#u#uuuuuuuuuuuuuu#uuuu#uu##u##u#uuu#u##u###!O! !õt ܜ ذX{%?!tdB!HB1OthBHh3c&>!!7!O# u##!#!BOOHBOHOOtBB}G><:cY5]O?FY1ù?d<3nzDDCD٧DpDڟvvȈCCrpڑǹ#Xu##uuuu#u##uuuuuuuuu#uuuuuuu##uu#uuuuuuuuuuuu#u#u#u#uuu#u##uu##u#u#u#u##u#######u#!O!!112[.$a?#ii1!HHOB{Ht{??Y!>g>]F}w̌#OÜ !O#tHBHOlt!OB?hldh?Bd&dGwGGG>d!7B3&&Fyal3I''n<dBHú!OO݀!!!O3TKss'DCpmDD^DڤvțȾC*9Cq}w!###uuuu#uu#uuuuuuuuuuuuuuu##uuuuuuuuuuuuuuuu#uu#uuuuuuu##u##u#u#u#u#u#u######u#!!tt1P.2ot11iil{u1Ҁ2دOXH!BBayH2YF?cF3}ێcuuO!1t!#!#!OBOOO>B?h?B&&7GG77™{c{OB>IIen<<<<£<&G1BúO!!OBd3nn^ΞDDppDȟvvȾʾ*ʾk77X###uuuuu#u#uuuuuuuuuuuuuuuuuuuuu##uuuuu#u#u#u#uu#uuuuuuu#u#u#u#u#u#u#uuu####!!!O!OttHto22,. X O1t@1H2@l?HÀ%%hHHh?l]dd}g3F7w7u3#!HHt#!!!BH1OBBB̹BdG7>x7G7Ou#&>d}}BBBBw7uw#u##X!t!#dB?BB!OBBO!!O&}O7Bx!Gw&7&&dJf™gJ>fgO!ݺ!ݺOO!O}g£bDpDDjھvvvȾ` ȾȈuu####u#uuuuuuuuuuuuuuuuuuuuuuu#7u#uu#uuuu#uuuuuuu#uuuu#u###u##u##uu##u######OO## ?.ot.1tt.!X?O?FBlyylHlFllhBycùwww777O!w#u#!!!#XX!!tH.t!Bdddh3HOOùO!O7!!7OO}!OB?B3dddd?]c:gff>f&>B.BHÜ.tttg>ff£bbpMevvevv Ȥʾ*țʦv}## uu#uuuu#uuuuuuuuuuuuu###uuuwuuuuu#uuuuuu#uu#uuuuuu##u##u##w#uu###O## .1iZP1ll[t{hHlH관dtO!cc]}>#uuw!!!##!!!!!##uO!!tHH1BBBBBddBHOOO칹!OO!7!OO!#O!Hdh?cG!O!?Bd:-J'//<gggg&&BB̹!!ÒliiNNPP11ù۝^ťmpv vv ʦ``ʂʡ9u&w u uu#uuuuuuuuuuuuuuuuuuuuuw#uu##u#u#uu#uuuuuuuu#uuuuuuuu#u#uu###uu#!!!! #!###!H .oP2X!1ܷ[?hy!!??#l{FFFB3FFF#uuw#!tO!!!u#OOt11tttOBBOHBO!OO7OOO!7!!7!!O!!]]3d]5dBdddd™;-JngGqL>>>g}}}ù݀uݺ2PH1ęe^bbD kk v v`ʡʦǹ7# uuuuuuuuuuuuuuuuuuuuuuuu###uu#uuuuuu#uuu#u#uuuuuu#u####u#u###X##!#u#t11i?.XlltX.aï{{h?1t!??1c%?d}_YF_w##w!!!!Bt!#!!B?HO1BOBO!!O!O1tO!!!OOOO!!OO#d{hd_d}!}?h>dѕ'<<q7GGG&&۹GO H...o..ÜffK;<<<>g}7Gw7wwO!w##!!.tP21HBgkqe^DDDCțv vȾ```eɹwu Xu#wu#uuuuuuuuuuuu#u#u###u#uuu#uuuu#u#uuuuuu#uuu#uuu#u##u#uu#u#!!O!u !!# #t1tt?11?.!?c1?lHa!@dlh[H?dBO>3d_3>w!!!!!!݀!!ݹtO!OHt#HB!OtOH1.Ht.ttHdFOOd?3]33B>>J5KJ<>777777w##wwuu#!ݺH޵|21ú}g£eDCCpCțȾ``ͦ͡uw苋uuuuuww#uuuuuuuuuuu#uu#u#uu##uu###uu#uuuu#uuuu#u#uu#u#u#u##u##u#uw!OO! ##!!#u #tܵ?t1?Hi?XO2iyH?u??iH1y?dHhcww!O!!O!!u# Ҁ!OtX!!#!d21tttH1!Htt2??hl[{%B}>5JGd?}Bf>>7ww7wuuu!!Ò1PNP1}BqfٞRRp(pC```X# ##uuuuuuuuuuu###u#u###u###u#uuuuuuuuu#uuuuuu#uuuuu##u#u#u#uu#!!!!!!!uutHH1tH ܜH#!Üܺlh?l!B@%aaܴ1cccddx7x&7O!#!OOO! # !tOtҀOOOO!ttHHtt2tHl[@@hhiFcYdddd77BBBBdggtݜldܺO݀!!###ݺ.O!H1H.OOOttO.122liNli?ic%%%Fh3T}73O!!}<-fg<g<>O7uXXuu!OOOtttP1H}}gffveDCpC``ͩͩͩͩ(e7u#싌#Xu#Ɍuuu###uuuu#uu##u#uuuu#uu#u#uuuu#uuu#uu#uu#uuu#uuu####u!!ݺOt!!####! OÜH!1HHt!?t OlܵB@ܷ%BB?FFFd>d7ۯ!lú!!###!!!!!!!tHt!!!OtÜ2N?Nl3]F5>d3:7O>B}BTgJ<::&OXXXXu#OO!Otttt111B}GgeeDpbCʡͩͩ̈́peu#GwXuXnj##u##X#uu#uuu###u#u#uuu#uu#uuuuuuuuuuu#uuuuuu#uuuuuuu####݀!O!#!Hݜú!HOtOúOHlt!݀ÀO!O1?dh3%yY&]]7ݜtO!!!!#u###!Ot.H1d܀!!OtOO.1ܜd>>?d>>>&OO7OOO3d&<Bqg>>gg>ێ7O!깺2hdB!BŽfn:<J:}uXuu!OOO!!!OOOttt.t}}qfŸDpp((ͩͩͩͩͩͩ̈́͠k#茋XuXB#uuuu#uuuuuu#####u#uuuuu#uuuuu#uuuuu#u#uuuuuuuuuuuu#uuu##w!ݺú!#w#ww#ݺÜtB.t2NloH.?llHHh?li#2{c{B}BF11lܜÀ!uu#!##uu## #ݹH?tOBBBHB1}}ώ>}g>dxOB21Bd۹g>f<™3B7BÎ11 ! uuuuuXuuu!OH1t11iHOOOÜ1Ü&<ƙB>d&d}}>&5:<&d]¹!OOHݜ&3ggfnq&&BBHOtOHBOOOO!OOO!wx}ŸMr`ͩ999w7wg}u#uuXuuuu####u##u#uwuuwuu###u###uuu#u#uuuuuuwO#!!O!!!##uuu#!#!## !.oH1.i?H[Ohi!2HBh!}7#7w?Ü!}!úXXuu茓X!HÜ2ܶ.OO#d&&d&3?h]::g!}dlB12}HdBdqGL><<£nI;<>d}OO!!!!!OHOO!!!!!w!xfDM*rrͩ9ͳCJ7uOuxuw#77uuuuu##u#uu#uu#u##u#u#wuuuuuwu###u##uuuuuu#u##!w!!!!!w###u#u##w!HOu##O!݀"t.1!.X1dO?H!1BHdh}Bd!ۺu!d?hO̜1B2.!XXXu##ܜܜ11HHH!Od!&BB>&lldd&::L۹#}Bhhld>qwgGxq£J-T:3t!OOO!!!!O###w7}gğDDM**揸`ͩͳ99`p7#Ɍw7uۙuw#uuw###u##u###u#u#u#uw#uu#wu##uuuuuuuu u#wO!!!ww##uu###!!!X##!̜HPN?1.1 !lh[%{{Yc2?@@dw#Bd]Bdܴ???!1Bltu# ##!!ÜH!.1H??lO!B&ddB>&7w!w!}BHhlB}7q}x7qgn)<d!!!!!O!!Ot##w!!qg£DDrrͩͩC9ͩ`pxu###ww7x!wuuu#uuu##u#u#u##u#u####u####uu#uuuuuuuuuu#uuw!!ݹH!####u #u #u#w#!!XuOHt.궜?21Àch[cdl@{?YlB!BBhdHútHt!u!útt1tÜl3ܻ2HBdddd?>7xww!llBBd>}qxxgLfJn>&B̺O!#!!OOOO###!OG}gfeD*`rrͩͩ9ͩͳ9CDɌw#wwu}>7!w#u##uu#u###u#u#u##u#uu####uuu##u##u#uu#u!w!!####u uuuuuuuu##!Ouu u#1lto.HHܺ. H?{ܓdط{l?lܜ3]Ycch@h?dB1?2dHXXt1t11H3{?ld1ÜBd3F3?dx7w!}!}dݜB}}>d}>Gxgq<ĕ&O!###!!!!!!##wG}kfڤȦr=r9ͩ9Cku#w7Oww>7w#uu#w#u##uu#u##uu###!7w#X#######uu#uu#!!w!!!O!# u#uuuuuuu#uu ######!!ttt1?1.. !!B?OhyOyBô%c1?O!!OB1O!H1lt11H?y[llܺH}BddBB}<777!7!dۺBiiHBd}BgqqqGGLJ<LL>O!!##u#!u!###!!xGgfv*Crrrͩͩͩͩͩ99CDvw##w>www7wuu######u#u##u#u#u#u#uuw!7uu#######u##!!!#!OO!###uuuuuuu#u#u#u##!!!u u X!1.1Hݒl1.1?HdB?H?Fyy@idܴH]1ܒBdOO!!!.ݺ!tú112?{2tBùBB]dB}G7!!#!}O!BùiÜ?}>GGqgqGg&&c{l?lH2iB&dd3B&&7蹹#H!OÜ?yH}B3gG>gGGGq&><>!###!##!!77GgkvvȾ`ͩ͡`pNjuuu#ug7uwwuuuuuuuuuuuuuuuuuwuu}uuuuu#uuu####uuu#!#w!uuu uu u##u#uu#u#uuu!!u#u u#Hܜt t݀.o t!tHdaB{?lBl?ܜ #u!X?i2ܒ??.1?t12 #!!.!!HtH1OBBB33?1HÜ1B}Bd3]Fdd}O?F!l2hB!!B?Fdۙ&G}q&&&BBO###u ###!#!!7O!#7!!xGk vDC*`ͩͩ`DڑuwwuXuuuu#wwuuu#uu##u#uuu#uw}7!u#u#u#uu###u####!!!!#uuuuuuuuu#######u!##u݀t ݒH1HH!ຜ H{hc?hcF?ܴ!!!!Bܜi22ll?H!??ttu#Ot! t1tldFF3h1B1?BBB>&&>d]]]ddOOBݹO}B?OH?!!d:J}g&}GO!Ot#uuuu#u!!7##77Ggk\vv(C*ͩͩͩͩCDeɌw7uu77#u7!########uuuu#uuuw!uwuwuuuuuu######!!!!w!w#uuuuuuuuuuu###uu###uu#!H.Ht?12221!?l!H1#lû܀úOBdlhމ??.2?@y?2t#!O!t !Ü]h3?B&FF7B.ldd&<:}۹OBBh?%ݺܹO!u}dh%}>}xqGB&GGGO!!O##u#uu#!!#uuwwGqLk v(`țțͩCDeɌ#7wuuu}w!7u####u#u#uu#uuu#uX#uw#uuuuuu####u#u!!!!!#u###u####u###u#uuutúttÜto2N Ot{hBdOl%ll2d?y@l[1Pi2{@ܺ !!!#!O#OB?dd3B3BOuݜ::TG}>OtO!?Bdyش1uX#]dd¹xx77g>GO7!BO!!##u#####uuuuɹqLkȾCCCͩͩͩͩͩCDɌuu#uuuu#w#u#w####uuuu#uuuu#u#u#uu#uuuu#u#uuuu###u# #!!O7##uu#u#uuu######u##!ݶ211.!o 2À2{%%{Ouda߰H1HH?ú@?2lY{aHH O#OOHd&BÜB!Bddd3::T>7BOuOH]hyرdO#X!!7xxGB۹!G!!H!!!###uu#u#u#uuu#xqqk ڦ*vCCCͩ99̈́C ёuuu###uuu#uuuw##uuu#uu#uuuu#u##uuuuuu#uu####u耀!!!!!#uu##uu############w!wu!1ÜoP| tOHBha%?l!NttHt!u2Ò2221NBHH, !O!!HHB&]33dddBBܻd:JgdBO#!l1Od[?BB!Og>&O7NjG7}}}}w7#OO#!7#uX#GGqvȾȾ```ͩ9'wuuwww#w#u#w#u#ww#uuuuuu#uuu#uuuuuuuuuuu#uuu##!!!!!!#uuu#######u#####u#u##..ݺt.Ht..o| |t11{dhFOt?1l!Hl22NPNt#!Ҁ!tHOBHHB>OBBddd}lB%nFJ}Gx&3>d#?ۺ̹O!u#dd??lܺO!Owww##uu#w!w#uXuuu#ww!!w#uuX####uXuuXXXxxqkv``C9ͩ9(p###uuwwuu#w!7!#####u#####uuu#u#uuu#uuuuuu#u###########uuu#u#uu#u#u#u##u#######uu#!OOto.HtPP| ZZy{c3hhy@l?2.hB1tHܜH..P2PܜH!ܒN?2lܜ1HH?B7B?yd:GT:۹G!}O!?B}!#X#!!>GwO̹?lݹ!!###w#uuuuuXuuw#uuuuuwwuu#uXuuXXXXuuX7xqk *``̈́ͩͩͩ9̈́ \7###u#uwww!!w#w##uuu#u#ww#uuuuuuu#uuuu#uuu#uu#############u#uu#uu#u#u####u#######uuu#u u#!!!tPP["|iiP |[[Fc?21Ü1li1P2ll1liO!OtH1to.l11úHlBÜ!wdy{fgd>xG}O#Oh!O!!dFdd}ú!!Ow#uX#w#uuuuXuuXuuuuuuuXuuu#uXuuXXXX7xk\vȾ*`CCͩ``ͩ9Cpq#u####ww!w}!w#!####uuuuw#uuuuuuu#uuuuuuuuuuu#######u#u###u#uu#uu#uu#u#u#u##u######u u#!.12Z[ i |1hd3Y@Ül}?!BwwH??l2l"[12t??ld2112ݒܶHHÜú}Bی۹!d>>&7u!O!!}O#!B]]ùù!!##uXu#uuuuuuuXuu##uuu#uuuXXXuXXXXuX7qke*C((ͩͩͩ99( Rw###ww#wwXwOwuuw#######u##uu###uuuu#uuuu#u#u#uuuuuuuuu#uuu#u#u#uu#uu#u####u########u!!u!.P2Z$iZ PP !tB!y%d# .! #1221HH222H.H1HBBddBÜ}}Bd-F>dOO!XuO!X#!!O!d]d1OO!uuuuXuuXuuu#uXuuuuuXuuuuu#XuuXXuXXXXuLfjھ*ͩC````9** u#ww!w##Xu#wuuu##u##u#u####u##uuu#uuu#u#uuuuu#uu#uuu#u##u#u#uuuuuu#u##uu##uu#######u!O.ˊ"Z$$ ޶l?O#!Od1# !Ü!tH?iN12iP2OHH!.!2H1l???Bddd}B}}w&&OO## w!O3dG&BBBB!Ow#Xu#uuuuuuuXXuuuww#uXuuuXuuuXXXuuu7qfe ```ͩ`ͩ``''7u!w!!!#uuw##w!wwuuuuu#uuuuu###uuuuuuu#uuu#uu#uuuu#uu#u###u#u#wuuu#uuu#u#u#u########uu#u !O.Ptފ||[Z[ii"ilN %??!u# !XB?O .22[lil2P[!!Xu.Hlt2llldܜBd7333B7>&>]&w##OO #OOd?!!7̹Bù}wXuuuuXuuuuuuXXXuuuuuuuXXuXuXXXXXu7 `9`````9``MM)7!!w!w#u###Xww7uuwuuuuuuu#u#uuuu#u#u#uuu#uuuuu#uuu#uuuuuuuu#uuu#uuuu#u#####u#uu# u#uuຒ1[""2ꊊ[i2?ùBy!!# X#ݹ!1112l@a[[2N[[.H .?i22B1dBBd]d?d&7OO!OBuuu1}BB!OBdBBB7#uuXXXXXuXXXuuuuuuuuuXuXuXXXXXXu*`ͩ((```C`9`* ёNju######ww!w#w#u##uuu#u#u#uuuu#uu#uu#u#uuu#uuuu#uuuuuuuu#u#u#uu#u#u#uuuuuuu#####u#uu!t.H2PN NNޒ1li@@ihH3dX!?.!BP2lܱ[[y2212N2l11.O1HH2h1tÜdddBBB}]}{>>&!!Bd!O!O!OO7&d?dd#uuuuXuXuXuXuXXuuuuuuuuuuuuuuXuXuXXuxڦ``C``````````(C```MDIGu!###ww!ww!uu##uwuu#uu#uuu#u#uu#uuuuuuuuuuu#u#uuu#u#u#uuuuuuu#uuuuuuuu#u#uu##########u OHtHiN2N޵iil1tN[d3l2ܜt#ut2P1H÷222Nl2!1Ht݀HH1tHBBdlB}>B}>FO>&!!{}!Xuu!!!O!!]F?BBd?>}wuuXuXuuuXuuuu#uuuuuXuXuXuuXuuuɭ `C``````* IɋO!www!!!7!#7#uu#uwu#uu#uu#uuu#uuuuuuuuu#u#uuuuuu#uu#uuuuuu#uuu#u#u###############耀!OO2ii1illtH?2?llï{N?i?21P{@?Pܜiy@H1Hli?lli.??HH?HHBB۹Bd>۹O싌uuu#ù!u###!##u!Od3B&Bd>7#uuXuXuuuuuXuu####uuuuuuuuuuXuXuDC`C(C````````Dpwu!wwB!!!7!w!wuO!##uuwuu#uuuuu#uuu#uuuuuuu#uu#uuuu#u#uuuuu#u#uuuuuu#uuuuuuu############!!!ti"iP2Nlllܺllù?ܜܷ12N[2?dP2l21lh{yhH211HH?BB}BBBO}}G}7}]3&wu#!#!1B!O!XXuuuwOd}&>!###Xu#uuuuuuuw#w#uuXuuuuuuXuuuuuu#wC̈́ͩ`````````*```Cpڑ#uuu!uwww!ww##u#}7#uu#uuuuu#uuuuu#uu#u#u#uu#uuuuu#u#uuuu#u#u#uu#uuuuuu#uuuXuuuuuu######u!!!!OOt2?NN[ll??B?!B!Hl[[i@{H2ii2iܵlyYyy@XޜP2[?HllB?B}w}}}}7}7]7}>B>Onj##Xu#uOwX#uOۻB7OB}&>>̹7w##w#u#u#u##w#uuu##u#uuXuuuuuuuuXuu #ɑMC̈́`((CC`C``*CDek7wX#X##wwww###u#u#w##u#u#uu#uuuu#uuuuu#uuuuu#uuuuuuuuu#uuuuuu#uuuuuu#uu#uu#u#########OOO!!Ot22lNh???2??d!l??ݺH iPNN1tHl|li?2ya%%Pl?222i?l?llB!!!!!!O}w}B}}7w%dwu#w!7X!XuO#u!uuX7Od&!O!!O!Ow###uu##uu#uuuuuuuuuuXuuuuuC``C*CDvQɌuu#Ҁ!w!!!####wX!!uuw#uuuuuu#uuuuuuu#uuuuuuuuuuuuuuuuuuuuuuu#uu#uuuuuuu#u#w#w##耀!HO!liii[?[?l?h@cldOÜH?."P1ݒ|2[[N ?t%ذH1?22l?d??dùu#!w!O}}}###!wXu##uXuu##!OH#u###!O!d7O!Bd>OO!!!!##!!#wu#uuuuuuXuuuuuuuuuXuuuuuuuuu##u##xM`(`(CC``C`juɋu#u##!!!u u##u}!w!!u##uuu#wuuuuuuuuwuuu#w#####w##uu##u#uu##uuu###uu#uu####!!!!7!##XO.H..B?i[i@?33{3?!i1NP ?P[il.12l}!ïFt2"iNll1ddBHOF1u}1!?]BdwB##uuuw##uuu7!!!B!!OOOB!wO&O!u### u####w###uuuuuuuuuuuuuuuuuuuuuuuuuuu#uuXX#\jM ```DC(``CCMv)uu#uw#ww#! u uuu!w#w77Xu#uuuuuuuuuuuuuu##uuuu#u#u##w#u#u###uuuuu#uuuuuuuuw#!##!O!###u..PtH12i?[3dط%%2%2l NP[i.iail1h{h3!}h?YZ?12HBBH#OuB!Xuuuwuu#!OOOO #!H!!!!OBBO####7OB!!#!!u####uu#uuuuuuuuuuuuuuuuuuuuuuuuuuu##uXQ)jI ` `CC`CCp#uu#w#u##Ot݀ u uuwwuuwwuuuu##uuuuuuuuuuuuw#uuuuw####u###u#u#uu#uuuuuu#uXuwwu!Ot!#!##!tt121lllllllhcBOOB1yZlll2P?[?[%%{dùd񷊜2lh?dB}}OOHBdBBO!O}wwXuuXuuuu#w!!!#!OO!O!OO!uOB!O}#u!!OO!!!!!Ot!!!!##u#u#uuuuuuuuuuuuuuuuuuuu#uuuuu#u##uuu)DpCCC```ʡCCCpewuuu### ݺHO #u##u#uuuu##u##uuuuuuuw!!wuu#w###uuuu#uu#u####uu#uuuuwuuu!#OtBBH݀!#!݀tN"l1llÜ?ilB!ÜB1H?yy12ili2"ܜ[yYaYYy]d1?[llB}}}O!!!OOO!#}?ùu##X!uuXuuu#u###uu#X#!!#O Xu#!u!?##!!!O#u#!!OOOO!!!w!u##uu#uuuuuuuuuuuuuuuuuuuuuuuuu#uuuu#uwunjqe'DCC`` CC}Ɍ##w##u tHw#wu#uuu#uwuuuuuuwuuuuuuuu#!!7w##w##uuuu#u##u#u#u#u#uu#u#####HHOHHH݀t2.o?2??2l[[lܜ1!t!O!1?HH??NN[[2ޒ[?il2%cY%Y%%cF???d}}OXuO!HB!B#!#uXwwwuuuXuwww#wuXXXu!uuO?}3d#77!!!OOO!!!w####uuu#uuuuuuuuuuuuuuuuuuuuuuu##uXuuXuu#uɑ\MCCCC` `DCC\qqxuXu#Xu# o.HHtt!#!! uwu#####wu#Xuuuu#uuuuuuuu##7wuu#uuuuu##w#u###u#u##uuu### uOtt.tHH݀!.t1P"Z"2@@{[ܷ[?ܺtB!Ht?ay1 Ҝ@y2li$$?P???@dFFc?BÜ}}!!!!7!X#!}F{#??w!u#X#X#u#uuu####uuuXXXXu##!! !!!!#}B}Buuuu##!!!!!O!!!!w#wu#uu#uuuuuuuuuuuuuuuuuuuuuuuu#u###uuuX #uXQveIDMj\ekuuu uutP!#uuu#u##ww#u#Xwwuu#uuuu#uuuu#u#uu#uww#####w#uuu#####u#u### .H1.݀tHot1.H؍ity@?yHOOt1!tH?N1tҜ2lii?"i!BdB}Od?B}!wwwww#wX!?hB?}u###Xu #Xu#!#XuXuuX# ### #XO!!OOBuX##!!!O!!!w!#wu#uuuuuuuXuuuuuuuuuuuuuuuuuuuuuuuu Xuuuuw## u P޶t 7O!#uXuuuu#w!w#u#uwuuuuuuuu#uuuu##uOww#uuuu####u#u##uu##!!.1121.tt2i2"@ZZ2???hhܷ.OOt!tBi2hi.HҜlNl@%%YBOd?cֹ}}O!!O}##Xww!B۹Od?!OO#XXu###uX#!uXu#uXғXu X! !Ht۹!wB!u!!!#!O!!!!!w#w###uuuuuuuuuuuuuuuuu#uuuXuuuuuuuuuuuu#uuuuuu uuuuuɋɋɋwuuuuXu!H1ފ.!!O!u##uX#uuX#wXBw}uw}uXu#uuuuu#u7X#!!!!!w#u##u##uw#u#u##...222Pt P1[?[2?2?2Ht! P12߷@ilh?dF?Fc!w!O!#uu#u#X!#!!OlBB}!!O!#Xu!#!!#Xu#!uu##uuuuuu!!!tH##!OOO}O!B!!#u##w!!!!!!!ww##uXuuuuuuuuuuuuuuuuuuuuuu#uuuuuu#u#uuu#uuuuuuuuuuu#u#u#####u##Ɍu##u 12PP.###!###wX##7uwWuɹw7w###u#uuwuuuuuuw####www#XXX#! o1P22. tPtoH?iP11lܜH1?Bl{adO[iHt ?{[?alNil?yhF?yY?d!##!w!!uwuwuu}}}B!w!w#uu#!!##uu!!!#u###uuut!!!.HBO!!#OO!wO}7u#####u#u##!!!!!w##ww##uuXuuuuuuuuuuuuuuuuuuuuuuuuuuu#uuu###u#u##u #uuuuuuuuu#uXu#u!HPNi޶.!uu}wu#!u#wX#wɹ7u}Ow####u#}u#wwu#w#w#uuuuuuuw!!u .o.21tHot.t1. Hl?[{1B÷ú?u򷜺???il1[??i?ôFlֲcFOB!##w!7!##u!!}!!OwuX#uXu!O!!#!O!u#####u !!!OtHHOO!!#!!!!7!7̹OOuuuu##耀w!w#w##uuuuXuuuuuu#uuuuuuuuuuuuuuuuuuuuuuuuuu#uuuuu# u uuuu#u#.HP22!uuu!OuXw!7u#7uu#u7xwɌ77Ow####w}!wwu!#ww!w#uuuuuw#X!..."2P2Ho.lHtNotP"%߉lhF?ldB2hlB! !dh?c2i2?dlidH2߷ii@2ldd{⯴%F!!!OO!##!O!OH!}!}O#u#X##!OOH!!Ouu uu## uX #.tO!!!!!!!!!!w!www!OO!#####!!!!!!w#w##uuuuuuuuuuuuuuuuuuuuuuuuuuu##uuu#u#uuuuuuuu##uu #uu#####uuuuuuu.Pފ2B#uwwuuw#wuw!#wwxww#wuu###uu#uu!wuuww7w#u#!!t H2Ht2N21t?h P܍@HhB?HddFy?߯{?l@22ld?@@ii@?hܯyhF}?dBù!Oݹ}úBO##7uuuuuX!!OO## uuu##u # !Ott!O!!!O#wuu##!!!!##uuuuu uXuuuXXuuuuu#u#uuuuuu#uuuuuu#uuu#u#u#u#u##uuu# uu#u#u##uuuuuu HPù#uuX uu#77#XXuw#X#xwx7Gw#uuuu#uu#u!Xw####w##u#Xuݺ?ttHP1P2PP122?2[[2Z@t?y{ùtO!!!uHuFFl?B?B?Ü@l{%ycddBBFyd{دdB!!BB?tO!!!!#uuuu!!!!!!#X uu!# tH#!!!!!###uuuuu##uuu###u Xu Xu XXXXuuuuuuuu#uuuuuuuuuu#u#u#uu##u#uuuuuu### uu##uw#w##uu#uu oo||"˶!w77#uu u!w##uuuuu!#7ɹ7}}#uuuu #}#u7w!O!ww#uuu X 1Pt2tP H.tH1|H1lccB!!u!#?l]{F?Bܴ?2?l@[lBOhhlBBl?dHd1O!!##uuu## !OOO!Xu!!!!!OHH!!w!#w#uw#uuuuuXuu#uXuXXXXXXXXXXuuuuuuuuuuuuuuuuuuuuuuuu####uu#uuuu#uuu###uu u####uu#u o.||| ww#w#wu#X#uwwu#wuuɌɌWwx###uu##OOw#X!w!ww!w# !ܒPPPHt.H21ttPt2221B?ad}B!!!!!O?ya]c?hdB1?[i@[[?lldBBdd}OdF{lHtBOXuX!úHtt t!#######!# X݀O!!ݹ!#uu###uuuuuuuuuuuXuXXuXuuXuuuuuXuuuuuuuuuuuuuuu#u#Xuuu#u##uuuuu#uuuuuuu#uuu# u uXw##ɋ#uu.o X7!x!#uuu#u##uwwu7w####77}Guuw#!#!u##Ou!!# u .i1tHt. 1tot2.HH2.HBO}BOOttl??hB?BlB?11!2@l??l?[lllFh?O!liO1lHyd#!Ҁ!!!t݀ #t.!!#!t! #!u##!7###u#####uuuuuuuuuuXuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#u#u####u#u#uu#u#u#u#uuu#uu#uuu#u&#u##HPPX#uu!ww7w#u##uuu##wuw#!#uuuw7w7g7!uu##!#!!݀u21 2H1l21 .t2?Pl?h!OG苋 u1BHB1?HtHt2?[@[?B1lHlô{@ܺOO?hÜ1FyH!O!!X!ݺ2tt1!OO#OO.O#uu#######uuuXuuuuuXuuuuuXuuuuuuuuuuuuuuuuu#w####u#uu#u#uuuuuuuu#uuuuu u u#u##7###!1P1.u !uwu#uuuu#uu#u#wuu7#uu#!77ww7}#OXOH!H!݀ . ຒ2@1޵. HtP@[NPilصlhHHBOO##!1h?lh?OBBÜÜlli1tHl1l211??Fcc???h{1ttH1?H?l!?BO!t11݊t!tOO#!! !t######uuuuuuuuuuuuuuuuuXuuXuuuuuuuuuuuuuuuuuuuuuuuu###uu#uu#u#uuuu#uu#uu#uuuu uu!}wu#!.tPP..݀###u#uu### uuuu##uuuu7Xw!7ww!ɹXddBBHO!!!.oPP궷i1H.?2H .N.122$iY؜tdhO!Ol?lyyhdh!1h?[2tN2hl?2ܴ??h%c33Bܴܻ?[OXHlB!HHHOON22l2111tX!!OOO#1Ot#uu##uuuuuuuuuuuuXuXXXXuuuuuuuuuuuuuuuuuuuu#u#!!!7!##uu#uuuuuuuuu#uu#uu#uuuuuu#uX#u7##u!.H21!!# uuuu#w#uu#uu##Xuuuuu7!wwww7!7!wBBOtH!tܵt[[1.11?.1tHt[2$a%ya??#?dOX##td?lܒ?dh?hdÜ12Nl[iliݺ1?3>hFdôh@h.l?lHúO.hllHt.t1H1HH!!!OO!HHHúu##uuuuuuuuuuuuuuXuXXXXXuXuuXuuuuuuuuuuuXuu#uuu#w!###uuuuu#uu#u#uu#uu#uuuu# uuuu##}#### t11PP2PH!!u#uu#uwu# uuu#u#Xuww!w#u#!!tuB!!!!OHt!H212ll2HHi1@N P12@܉?ܺ??cyaH1!.!!t11.uBd]?ܻl1Hl1Hdi i?1i[@l11ÜO!BB]]]cFyt !t! 1OlHHtt1!t..Hl??Nܜ.?HO!!OO!!úu##uuuuuuuuuuuXuXXXuXuuuuuXuuuuuuuuu#u###!####uuuuuu#uu#uuuuuuuuuuuuuuuXuww######!t1111l21O!# ######w# #uuu#u##uu#u7B!wuuu#wÀ!.1!!!u!!t!tH111?귰2@2H?1t.?yN?ܺBB?hlh}1t.HH..Où?3{d?}1?1?i??22?ܜ?O_FF3F?d{{lHH !ùH!21tP1.12?H1!!OHH.tO# uu uuX##uuXuuuuXXXXXuXuuuuuuuuuuuuuXuu###!u#u#u#uuuu#uuuuu#u#u#u#u#uuuuuuuwuu#!t12ޜܒ!!!#Xuuw##!u#u# uu#X#wuu#O7wuu#uO.HO!t!Ҁ!tt21.2PHN?2t1l1iH11!!u!B#B.lt lydBBÜ?hhHO1.1H21ܶ11l?ii?]d>]3HBOt#tlúOt .H2[i2ܺ 21t. HOOtO!# uuuXXXXuuuuuuuuXXXXuuuuuuuuuuXuuuuuuuuu#uw#ww###uuuuuuuuuu#uuuuuuuuuu###u#uuuuuuuXu###!.ll22l2PHO!#uuuu#!!!uuuuuuuuuuu#u#w#uuw#uuuu##.HHt!!uutHH1?X? HtH2tH22.!?tw#wiB h?BBd}#!!ud1d2it2[@2i???2B3Fd>}}w&dHOHHli!!2?ÀO1tt.t1.tÒú݀ H1!t!tHú!u#uXuXXXXuuuuuuXuuuXXuuuuuuuuuuuuuuuuuuu########uuuuuuuu#uuuuuuuuuuuu#u#uuuuuuuuuuuuX!tH221݀uu#O!#uu##uuuuuuuu#uu##uuw#u##!.HHHt!!!HHHlttl?i?ti1 ll2HH!...ݹ}O!}}.u1 %YF3Y!BXXtHݺ2lh?hh?dBdO}̹}ܴlB??[d 1u 21li?l1?Hitt.tt! t! Ot!!!uuuXuXXXuuuuuuuuXuXuuuuuuuuuuuuuuuuuuuuu#####u#uuu##uu#u#u#u#uuu#uuuuuuu#uu##uuu t12N21Ht!O##!!!!#u##uuu #uuu!uuww#uwwu###!!݀ !tHtH1HHHll.2H.tl2?.tB.B?Hi1 }!# À#y%ydw#!O!!1OH.H 1d[{ylh@l}}!Bù#?BB1B2BOH2t!H ݺtݺ.1B!. t!.HH!ttttt.Ot!# uuXXXXuuuXuuuuXuuuXuuXuuuXuuuuuuu#uuuu#u#u##uuuu#u#uuuuuuuu#uu#uuuu##u#uuuuuu u#!t11lHt!#!!!OOO##uu#uuuuuuuu#uu#wwww###!!!݀#耀OH1tHHHlHhtHHlyi@ܜt1ܒݒahBBOO!!wu!uuuc_}Ot!O!tt1H!H2y%?{ùO}}O!!?ҀB?21!HuÀHt.tO#utt1tt.!tú!!!!#uuuuuuuuuuuuXuXuuuuuuuuuuuuuu#u#uu#uuuuu#u#uuuuuuuuu#uu#uu#uu#uu#uu#u#uuXu1111H!uXuuu###u#u#uu uuuuuuuu####uuw##!!OtttO!###!ttttH.tHoHHH12?l2ll2!ih!{@}!www#u?}wd3uOB}BO#HltBlF{c¯]?}O12OOÜd t#1?htu!Ht .t!ݹOX#!O.tHttt út!! uuuuuuuuuuuXuuXXuXuuuuuuXuuuuuuuuuuuuuuuuuuuuuuuuuu#uu#uuuuuu#uuu#uuuu##uuuu!111P1t!!!####uX #u# uuuuuuuuu#7}7#u####OHHtO!###1.O.H.tt.l2H?ҀX?H11l2i1i.!!wO!###XuX!#uw#uGB7uO}O!##!!lHô[B]#yd}BBll2?2HH?dOX 1Ҁ1uݺHO#!B!H.t.HHHttHdt###uuuu#uuuuuuXXuuuuXuuuuuuuuuu#uuuuuuuuuuuuuuuuuuuuuu#u#uu#u#uuuuuuuuuuuu###u#u!.1ttHtt. #!wu!##uuuuuuuuu uuu uuuu}wu#w#OOHO!!###tBHHtHt2H.iõ!.HH?[À?H݀daa?[#wuuw!###X#u!!#Xu7GG>g77Gu###!#uҀ!12H?dB!#}}GB!}BF??1PHHBBl, ,uúO!!!!!!uut݀.t11ttttB!!uuuuu###uuuuuuuuuuXuXuuuuuXuuXu#u#uuuuuuuuuuuuuuuu#uu#uuuu#uuuu#u#uuuuuuu#u##uuw1HtHHH.O#!###uuuuX Xuuuuuuu#uuwOwuuu###!OO!wu tH1.tt121H1t܀H!H2H?HO?{1?1!? uXu#uuX!X}uw}wwwX}OO##OH?B3FOB!7!u7!OB}?ddciHP2??BH#,XX!! B躺݀#!!OHOOt.!!݀Xt1.Ot!HO!O!uuu## XXuXXXuuXuuuuuuuuuuuXuuuuuuXuuuuuuuu##uuuuuuuu###u###uuuuuuuuuu#u#uuuuuu###u#!ܜt!O!݀ݺ݀####uuuuu##uuXwuwuuuuu#!#w!OÀ!uO# ҀHN2tP2Òl tH1X.t@htt ! uu##uXu!uu!!uuuwO7wwuw##OwuuuuulttB!d?d}}?11l?21 .Hu !t!Xݹ݀##!#! u!݀tt.tt.ttHHHt!!!u uuuuXuXuuuuXuuuuuuuuuuuuuuuuuuuuuu##uuuuuuuuuuu#uuuu#u##uuuuuuuuuuuuuuuuuuuuuu#!HBBO!!!#X# .###uuu#u#uu#uuu#u7u#77#uuuw!!!!O#u#?Ҁ ..t oi..HH@t1 tlݜOtu# #uu!XuX uuuXXu#茌uw#!#utOhO!Ow3dhh3B}ùBܻNl222llt.2 !!X!X!#Ot! u#####uX !# !H1tt...ttHH1BHOtO!u#u # u# uXuuuXuuuuuuuuuuuuuuuuuuuuuuuuXuuuu#uuuuuXuuuuuuu#u##u#uu#uu#uuuuuuuuuu#uuuuuu###tHtOO!耀 !###uuuu###u#uuwuwuw#w!uX #ww#!!uu!##O!BOt?21t" . .i.{tPt 11t,tH!h! OH!2ݺ!!# uXOX##uuuuXu### !1Ot. !&!FlBd??ddBBl222ll? .1!!X!O# uu##X#u ! #!O1ݺt!ttHHBBHHO݀ u!!!uu##uu#uuuuuuuuuXuuXuuuuuuuuuuuuuuu#uuuuuuuuuu#uuu#u#u##u#uuuuuuu#u#uuuuuuuuu!!H݀!## Ottt!##uuuuuuu###uu##wwwuwx!O######u#uuX!!Ot݀t2NP.H.l[2.tP2!1lOyܺXuÀw!#uuwu!XҌXuXX#!##X tH1?2{3O}?hdH}??t?1܊N?Hܜ?1122O!XX#XX##uuuuXuu!OHB1t!ttHHHtHHtOO!!!!!uu!!!!u ## ##uuuuuuXuuuuuXuuuXuuuuuuuuuuu#uuuuuXuu#uuuu#u#uuuuuuuuuuuuuuuuu#u#u#u#u##!!OOHOOO!!!OtHHO!#u#uuu#uu#w#uuuuX#wuwuuu##u##uuXuu#!X !!ttH?P2|P?@H. tH. tNÜ1Hût1XHܜw##wuuuXuXXuXuuuXuXO!H111?N21@l[BuB%Fd?û?ܜ1l?lii..tܒt! u Xu###XuuXu#!OO!!OOtO.!H.OtHHHttO!!耀u耀# ##uu#uuuuuuuuuuuuXuuXuXuXuX#uuuuuuuuuuuu#uu#uuuuu#uuuuuuuuuuu#uu#uu#uu##!!OOOO!!! Oú!uuuu#uw#w#uu#wwwuuu##u#uu#u !!Ht Ht.[."ZH.PtN1వ.aHdÜtXһl#uX#uuuuwOwh}wuuXu#uuX!t..1oPlZZo?NltBBy??Bl?lll[[.ÜúHú݀݀Xuuuuuuu#uuOO!!OtHHtHtHHHtO!!!#######!####u#uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#u#uuuuuuuuuuuuuuuuuuuuuuuuuuu#u##!!O#!###!Bù݀X XuuuXuuuuwwwuuXww7u##w#wwu###u #!uOtH[2 tNPto2.N1tPl%1t#th݀uwuXuu##uwwuuuu##!tot 1t2%1lhyll?{yllܜdܴ?l?l2?N?i[t1?2?. H݀X uu##XX#XO!!!O!t!!tHtOttO!!!uu#u#u ###uɌuuXuuXuuuuuuuuuuuuuuuuuuuuuuuuuu#uuuuuuuu#uuu#uuuuuuuuuu#u#uuuu#uuuuu#O# #u#!!B!#wuuuuuuuu#uwuuu####w!wuuuu##uXuu!t!tÒttH1itZtްNP2oN22H12hH???û@ut#uuw#uu#uX}!uuu#tBܜ11 @a2F@c{B{lÜ?lldllll2li?ih212Ht?.. #uX茋##u####!Ot!!!.O.!ttOt!!## #!!!#!!##uuuuuuuuuuuuuuuuuuuuuuuu#uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#uu#u##uuu!##!!!O!!!#u XXuXuuuuuuu!u#uwuw#uuu!!###uXu!uܜ.ö21yiNPP t.H122[l!tlHll?t uX#X#w!O#O!u#uu!l@2ܵ..Ni?2dlF1lhl@??[?lliiiht B1111t܀tuX#uuu####!!O!!OtO!O!!!######!!#####uuu#uuuuuuuuuuuuuuuuuuuuuu#u##u#uuuuuu#uuuuuuuuuuuuuuuuuuuuuuuuu##uuuu#uuuuuuuu#!###!!O!!#uuuuuuuu#uuuu#wwuuu##wuuwX####!uuu## #u !ttot.ගt H.2l.PtN?$1%[2i21À!! !O!! uuO#O!]}!OXXuOoiޜOҺ&?OBBB?lN{[?ܜ?ii?iihhhlHtݒ21Ht2HH2ݺuX###!!!!!!!!!! u##u uw!u # ###w##uuuuuuuuuuuuuu#uu#####uuuuuuuXuuuuuuuuuuuuuuuuuuuuuuuuu#u#uuu#u#u#uuuu##!!!Ot!!#uuuuuuuuuu#uuwwu#w}!##!###uuuu##u#! !.121ݒi?@l22112H[ia XOtl ݀uX!!dOu!!!!#!# 耀.lylPފwOww!GOܴlhhh22l?[[[[i?i[Ht1HtH..22Hu###!#uu #!!!###uuX uuu #w!!耀!!#w###uuuXuuuuuuuuuu##########u#uuuuuuuuuuuuuuuuuuuuuuuuuuuu#u##uuuuuu#u####耀#!!OtOtO!!####uuu#uuuuuuuuuuw##7Xw!#!!# uuuw##uX!#.o12.ݒ?.l?12tHt.tOO XҀ!X!#X !OOttB݀!# ![[{il!!BHܷahl2Ò2???i?Nii?[[h1OttHt22Nܵ..XXXuu###!uu#!݀# uXuXuuuuu#!O!O!!O!!!!w###uuuuuuuuuuuuu##w#####uuXuuuuuuuuuuuuuuuuuuuuuuuuuu#u#u#uuu#u#uuu#!!!O!##u#uuuuuuuuuuu#wuu7O#wX!u #!!uuuuuu##u! !o..P.õhl12t1Üt.1tH1t t2 ú !.ôl!1!!!!݀u #.u.l?yyYطcFd̹dBdd{@a222l?2?i?i["[[iihhiHtlttl?Po1 XXXuu####u Xu u#!#u XuXuuu#u!OtOO!!!!!#####uuuuuuuuuuuu##!###uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#u#u#uuu#uuuuu####!!!!O!!#uuuuuuuuuuuuuuuuuuuuu#uu##7#w!# uuu##Xw!w!u oo? ܜH!}ÜHHt.OB#!du1X!? H,!!Hݹt1OHݺtXtHla133BOBÀHilh{h2lܜl2Nl?2[[Z@ hlBH1.t.t u uXuuu#uuuuu#XXXX Xu ## #XuuuuXuuw!OOt!!!##uuuuuuuuuuuuuuuuuuu##!!!##u#uuuuuuuuuuuuuuuuuuuuuuuuuu#u#uuuuu#uuuu#u##!OO!OO!!!#u u uXuuuuuuuuuuuuuu###!!u uu#uuuw!!.12P1tt.u!!#XO!Ou?}?u?.!#Ü1!!݀!Olt l2h2HHi{y{H?!HB1.l?l?i߷i22i @@@i [@htNHt22ot"iN݀ uu#uuuu###u#uuuXXuuXuX# # XXXuuuu#wOt!!w###uuu#u#u#uuuuuuu##!!7!##u#uuuuuuuuuuuuuuuuuuuuuuuu###u###uuuuuuuu!!!!OOOOtOO!!!uuXuuuuu#uuuuuuuuu#uw7wu7w!}u!uuuu!#!!1.À!!!H!X.B!!À!݀11O t!Htݜ12ݺtܜh{dB!hB1l@[2@h@{@NN iNN[i{hhht...tް2" . u#uuuuuuuuuuuuu XXuXXXXuuww!w!w##uu#uuuu#uuuuuXuuuuXuuuuu##!!!!!#uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuwu#u#ww!!!!OttOOOO!uuuuuXXuuuuuuuuuuuuuuu#XXwO!O!w}OX## ##Xu.u.úÜ! u1!݀..!H.1H t!1!. t !t1P2 NH?H[c!Ohl?d3BBO?dl[[[@@@[ |2l@߉h[hߊ t..ttt.1o.PN1#uuuuuXuXXXuXuXuuu!##u#uuu#uuuuuuuuuuuuuuuu#!!u#uuuuuuuuuXuuuuuuuuuXuuuuuu#u##u#uuuuuu#!OOOOOOOO!##uuuuXuuuuuuuuuXuuuuuXwuwBw۹!}#!!#uuuuu [N.H݀X..11ݜ12!ݒO l1HHt.l.thÒPi.t2y?OOOd̹B?Üܻ@@[[@߷" ["[ [i Z{@@߯h31ݒHHtH.P݀ #uuXXuXXuXuuXuu####uuuuuuuuuuuuuuuuu##!!###u#u#uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#uu# #!!!!!!!!!##uuuuuuuuuuuuuuuuuuuu#u#uu!w#̹w#w#Xt1?22@P..݀HN121݀l.݀H !y21...N2111H.212ߴFFdd]O7!BBÜBl[@iii[$ ""[@@@@@333333h?ll.H1l. [Ò.wuuXXXXuXuuu######uuXuuuuuuuuuuuuu#u##u#u#uuuuuuuuuuuuuuuuuuuuuuu#uuuuuuuu#u## ##!!!!!!!##Xuuuuuuuuuuuuuuuuuuu#uXwuuwuO#!#!!X# #!O#t.2Pli2t ҺHHtN?[.Һ?112.?H2H! 212.1HHH1HP.1H??%dtBOO!B̹#Bl?i?2?i[|[[ Z{@@@h3h21t2ll@HP|?.1##uuXXXXXXXuuXuXXuuu######uuuuuuuuuuuuuu#u####uuu#uu#uuXuuuuuuuuuuuuuuuuu##uu#u##uuuu#耀!!O!!!###Xuuu#u#uuuuuu#uuu#u#uwuuw#u###u##u# 2 HHHu!11O2..21?ܒt12 l2܀H[ݜҀ12P21Htޒt2OOtd?ز@X#H?7!!!HH?212?[@@@[N[i{@2i[i2HHll[?N.uuuXXXXuXuXuXuu######uuuuuuuuuuuuuu#u#u#u#####u##uuuuuuuuuuuuuuuuuuuuuuu#u#uu#uu#uuu u ##!!OO!!##uuuuuuu#uuuuu#uu####u##uwwu!u HH1.1[,2H112?.i.t.. 1ݺhH2t.ݜ.2l 2PiݒlO!!!{lcdOBBBO!!!OBl2?ܜlliiii2ih?ܵ?ttH, ҀH@[22.!!!wuuuuuXXXXuuuXXuuu#####u#uuuuuuuuuuuuuuuuuu#u#######u####uu#uuuuuuuuuuuu#u#u#uu##uu#u#uuuu###!!!O!!#uuuuuuuuuuuuuuu#u####uwu#!u##!!u݀.Ü1Hú 2݀ta!l1?.tݺlܜݺtH,# HX?N[[2iN2l{yBBdttOB?ihl2ll2?l[[l22l2lh[?d?紴t݀.݀t1O .!11.!!w#uuuuuXXXXuuXXuuuu###uuuuuuuuuuuuuuuuuu############u#uuuuuuuuXuuuuu#uuu#uuu####u##uu##uu!!!OO!!###uuuuuuuuuuuuu#uu#u####u!uuwuu!#tuútt?ttuH 2t2?11!ti??t?!H!.?1t1 NN2P2B?yOHB??O!!OOtO@ii[i[?i?l22?i???dddϻdd݀ttHtt.Hl !.P1ú݀!wuXXuu#u#uuuuuuuXuu!!###uuuuuuuuuuuuuuuuuuuuuu###uuuuuuuuuuuuuuu#uuu#uuuuu#uu#u#!!!݀!!!#u#uuuuuuuuuuuuuuuuuuuuuuwwww!w##uu l 2..Òl1݀ t.ݵ{t@1hl. ?.o .iú1.l.1@?i1HaN.t!B!?O#1HtdlBOHBt!!!!괯h@[iiiii?????d???l .l ttH .Hú.HOO!#uuu#uuuuu##uuu####uuuuuu##uuuuu#uuuuuXuuuuuuuuu#uuu#u#uuuuuuuuu#u#uuuu#u#uuuuuu!!!!!!##uuuuu#uuuuuuuuuuuuuuu#u#u#!ww##u##u!.!Àt. ?aH.t?ݜX?Ó2À1 2l t1t õlPiPޜZ@y[H!dyylO1dttB@@i??Ni?["[iidddd!1!1H1!.OH1..ݹ!!!wuuu######u##u#uuuuuuuuXuuuuuuuuXuuuuuuu##uuuu#uuuuuuuuuuuuu#uu#u#uuuu#u#uuu#!!!w##u uuuuuuuuuuuuuuuuuuuuu####w####uu u!!!ݺlô.XHu 1ÒOH!t.it2l.1X1l2!,ݜHllúHl[PPtl2${B]llBBHtHOH1??i??N??N2ll?i@@h?dddddddddÒl! O1HtHttt!!!uuuX####!!!!!!!##uuuuuuuuuuuuuuuuuuuuXuuuuuuu###u#uuu#uuuuuuu#uuuuuuuu#uuuu###!!!!!݀#u uuXuuuu#uuuuuuuuuuuuuuuuuu#u#uu#u#####u##uXu###! Ot! ut!1. H1HO1@l.À t ݜtH?l1t.$a@N"tt...1Blܜ?!OttHÒ2ܒH1ꜜ2ll212?@߉?紴?dddd?HOt!OtO XuOu #.t!!!####Xu###!!!!!w#uuuuuuuuuuuuuuuuuuuuuuuu###uuuu#uuuuuuuuu#uuuuu#uuuu#u耀!!!!!!݀݀uuXuuuuuuuuuuuuuuuuuuuuuuuu#uu#u#u#uuuXuu#!!ùݹݺ}t݀#HtuҺݺX?H1Ol2t HHÀ.1@ݜ12?2P?1@{h22.o.H?HBHlHttlHO݀OH211tܶ2?l2ii[i[$@hh[]h?ddl?ddddddd! H݀!OtHO!# ###uuXuu####uuuuuuuXuuuuuuuuuuuuuuuuuu##u#u#uuuuuuuuuuuuu#uuuuu#u#uu#!!!## ݀#uuXuuuuuuuuuuuuuuuuuu#uuuuuuuu####u#u#uu#uuu#w!wuu##t#ݺ ,#1!tX!t.H1H!lúXX!1?tXi%?@@.P?[@{@HPNt1[H.!OHtHtH?ll22N2112?i[Z%i??l?dddddddddd!HúB1!11ttHt݀ X ##uuuuuu#########uuuuuuuuuuuuuuuuuuuXuuuuu##uuuu#uuuuuuuuuu#uuuuuuu#uuuuu#u## ! ݺ݀#uXuuuuuuuuXuuuuuuuuuuu#uuu##u##u#u#u###w#!!w#}B!X #t.XH X!ttH!O .݀ltNtݺ1!22{l.212222Ò귍Ni@l1H1t1?l?2l21111l1i[[$a%@hi?l???dddddddddd1H! #!!!!!!OO#!!####uuuuuuu###uuuuuuXuXuuuuuuuuuuXuuuXuuuuu#uu#uuuu#uuuuuuuu#u#u#uu#u#uuu####u u݀!݀!#uuXuuuuuuuuuuuuuuuuuuu#uuuuu#u#####u#uuuu###OO!!!X!!u!H!.. ݊H1ܶt1[Àt݀1Ptil122..?ltt@?al1N@y?$@HH1HH@l?d1N܊i222 Zh[h???dlddddddddd!!!BHO!!!HO!# #!!#Xuuuuuu#########XuuXXuXuuXuuuuu#uuuuuuuuuu#uuu#uuuuuu#u#uuuu#uu##u#uuuu#!! Xw!}Ow#wuuuuuuuuuuuuuXuuuuuuu################uuu#wuXuu#!HO!!!݀t 11..o.PފN"i.iit2o1tHltܺti%@2À o[@2i2{[1l1lHOHd%{?l?llN?[[l2[h[@@Z߉h@hd?ddldddd??#!!OBOO !#HHOH!O!#uuu#u#######uuuuuXuuuuuuuuuuuuuXuXuuuuu#uu#uuuuuuuuuu#u##u#uuuuu#u#uu###!#uu!!wuuuuuuuuuuu#uuuuuuuuuuuu#u#uu#u#####u#uuuuuuuuu#u!Ot ,X.1otN"|˵1tHP.y2ttHOH!HÒ1N2t݀ !H1lHy?ܷldtBH!td?l??ܺBll2߉@Ni[[i?2li[߱ayy@]hldddlddddl?1t ,Xݺtt!!u!!##uuuuu#u########u##uuuuuuuuuuuuXuuuuuuuXuuuuuuuuuuuuuuuuuuuuuu#uuuuuuuuu##!!u u!w!##uuuuuuuuuuuuu#uuuuXuuuuuuuu#u#u##uuuu#uu#uuuu!t!!!tO1.ot޶P Z N N.tt2o.2. 2l1NH tHX lH2l@N귒?@i2{hhdBBOtO!?lO1BHú.??i޴2HHHl߱a$@3dddd????2iltl2úttu !!!###uuuu#u#u#uu##u#u##uuuuuuuuuuuuuuuXuuuX##uuuuuuuuu##uuuuuuu#uuuu#uuuu#u###!uu#!####uuuuuuuuuuuuuuXuuuuuu##u##uu#uuu#uuuuu#!tO.OttO!݀ .HÒ.޶P2P NtN.N@@l ,1?tݒ22t2?2[?1i[NHN2.HH2lt?BÀO!!HOH?HO!tH1PH1iN%aayy@]h?ddd??.to oPl21to..o.t.!O!#uuuu#uuuuuuuuuuu uu #uuu#uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu#u##uuuu#uu#u##uu#########uuuuuuuuuuuuuuuu#u##u##u#u##u#uu#uuuuuuX ###!OOOHO!2iPiNZN.H?Nt,2t .?Ht?tt22Í P11HiY2Hܒlt!tOO !OHOl?HBH12l܊11N??aY%aayhldddld?PPޜ.oPPPP2.t.!!###uuuuuuuu#u# uuuuuuu#uuuuuuuuuuuuuuuuuuu#u####XuXuuuuuuuuuuuuuuuuuuuu##u#uu##uuuuu #!!w#####uuuuuuXuu#uuu#u##u######u##u#u#u#uuuuu#耀!!tttttP2|[Z߰2oHtltlH 1. 11i2P2l2$2.1[?Ht#X#OtB!!ÜÒ11122111112?i?߱yߍ߷ϴddBddddd1P12@ iÒPlPÒ.t!!!########uu#######uuuuu#uuu#uuuuuuuuuu#u#######uuuuuuu#uuuuuuuuuuu##uu#uu#####u##!!!!!!!!###uuuuuuuuuuuuuuu##u#u#u##u##u####u###!!!OOO!ttHoPNi[[lt.H1..Ptl,t.to2ޒ..tyil@B1ii"i޶i%%lܴ# O!?uO݀OO!OBÜ1B11Ò1HH12?[hi[??ddBBBBddd?...Ò.22...H121tt. #u##########uuX uuu#uuuuuuuuuuuuuu#u###!!!uuuuuuuuuuuuuuuu#u##u######!!OOO!!!!#uuu#uu#uuuuuuu#uu#u#######u##u#######!##!!OHHtttt..HlPNit..Ot[tHt HPN$tt?.HlZ"Nް..|N[݀tBOtHdl!O!#OOOHB11111tH22??lh[hhdBBddlH11!O!!.Ü1211 ###uu###u##uuuuuuXuuuuuuXuu##uu#!!OuuXXuuuu##uuuuuuuuuuuuuuu#######uu#!!!OO!!!!###u#uu#uuuuuuuu#u########!!O!!!O !t1NiNlP2..t2!tiltNt tH1ݰ22 1HHO1P?|NPi?2HtO!h?####!OOOOOOHBBHú11l?lNlܒi?lih?ϴBBddBd??!##!!!}OB.11.1H!uuu####u#uuuuuuuuuuuuuuuuuuu#w7!u耀!!!O!####u#uuuuuuuuuuuuu#uuuu####u##u##!!!#w!!!!##u##uuuuuuu#uuuuu#uu#u###### ####u!###u!!!! O!!t!1út.H2t!2ll ݜ..tH1.|NHi2it1H?|ii"H.Hto.t!! OBdOO!!!OtOHtHHHH?@lh2h?dBdd?##H!OH!..!H1H!!݀u uu uu########u#u#uuXuuuuuuu#u#!w#u##!!!O!!!!##uuu#uuuuuu###uu######u#耀w#!!!w#uuuu#u#uuu#u#uu#u#uu #u######X!# #X#!!!!OOtH.tH11.O.Ҁõd?2t1H?.1 ݺH.2?Y?tHtҊޅlP221tHHt!HOd?H!OO!!!!OOOOùH?ll2?iii[1B?绻dBddd3Ou,###!!OO!# ݀ tHHO!!O!###uuuu XX##u#u# u#u#uuuuuuuuuuuu#uuuw##uu##O!!OOOOO!!!!!!uuuu####X###u #u####u####w!!Oݹ!uuuuu#uuuuuu#uuuuuuu#u#####uuXu!!݀tH!OHtHt݀ttÒ11!!Oi2X1ܺ ?t21 ?@1H"i2Nt21.HOtBOOOO!!!!7OOOOtBBúHHH1HHÒ2ܻܵhF33Bd3O2t#Ot!! ݀!!!!!!!!O!#!#!!uX##u#u#uuuuuuuXuuXuu#w###uOO!!!!OO!!OO!!!!u u # u uuuuu#u######!OO!!uuuuu#uu#uuuu#uuuu#uuu## Ot1O!OH!t.tݺtu! ݀Haylltt݀.2HH?HHHHl[2P|lP.1H!݀!tBtH!!BOOOO!!OOOHHHt1l?lll]FBBBBBBddl?.t??HtH ! .ú.!#uu!! #!!!!!!uXuXuuuuuuuuuuuuu##wuuu## 耀!OOtO!OOOO !tt!!݀#######u###!!uuu#u#uuuuuuuuu#u#uuu# u#耀#u###!!!!OtO!X݀!tHtB!X XÜO t,,Ht iܵliN l.1222.Pl1Ht!#OBHt!OOOOOO!OOHBHtHBHHB12?ll]]?BBBddl?i2oo .ttt݀!uuu#!!!!!!O!!#uu #XXXuuuuuuuuuu##uuXXu uu!!!!!OOOO!OOH!# .H1HH11Ht####u###u# uu!w# uuu###uu#uu#uuuu#uuu#uuuu#u! # #!!!!! O!!.HHHH!u!!H21OXttH?1XݺtútBl?i1N21P1tHH!!!!!tOOOOHHOOOOO!OOOOBHOtHH11B1H1BB?h3??dBBBBBddd??d ݒo.N2.o .# !!XX!#!!!O!!!!!uuX u##XuuuXuXuuuuuuuuuwuu#uuuuuuXX#BHOtH!!OtOOO!!OO耀 tHl111tO##uu##uuu#!uuu##uuuu#uuu#uuu#uuuu# uu!####!!!ttttO.t!!.HÒH121d1}#XBlyiX1li tll.111Ht1i[ltHHt!!!O!!!OO!OOOOOO!ld1ttHOtdddBBBBBd?dddd o1Ht! XuuXuO1B1!uXu#u##uXXu XXXX X##u#苋ɌX X # ݻlHO!tOHOOO!!!#X!.HHHttP?"ޒHH!##u##!u!Ow#uu#####uuuuuuuuu#u###uuu#u#! !!!!O#OO#ut[!# Oh?B!XBXlO!Ê[".?ޒ1"22|P2HHH!!!O!OBOOOOOO!OtBBBBHBBB紴d>>BBddddddH.! tt11O#Xu!OH11H!u u##X#!!uX!X݀wwu##ww#,XOHl2BHHHtùOOO!!!t.!tXҀ1??lNPoPH!!uu#!!!#uu##uuuuuuuuu#u#uuuu uu#!!##! #耺BXXO#!.oHiމi?H uB1d?!!?OÀҀ1 121i2P.!!!O ##!7OBBBHOO!!1BBBBHHOBdddBBBBddddddddd..tt 1221.1Ht!O!##!tO!uu!!!!!!tO!u H÷?t XOғXuu#uuw#X y{dHO!O!!!!!!OO!݀!t111N2. .!#u#u#OO!!w#####uuuuuuuuuuuuuuu!!!#u##!耀u#!O,21|Hld[BBO!#O! O!Xtt2P$ 2NNliiN21HO!!Ou#u#!BHOOOOO!OOOOO!OOBBHtOOOtBBddd?ddBBBBBdd>ddd> .lt..HHܺt!O!#!! u !!!!u #O1i2?tt1HoouX#u X#u@?1H݀u!!!!!O݀݀ !tt..HH2iHt!!#uuu#OHHOO!!!!#u##u#u#uuuu##uuu##OO!! u###!O!!HOt܀t1[|$#OH@?.!!!! O#!2! .tN2N2?N"HH!!!####!BHOOOOO!OOOOO!!!OOBHOtHHHOOOBBdddddBBBBddddddd1. ot.ttot.tt݀!݀u# u X XH! # u u@[H2[?"P. .11BH!!!O!!!#O!OtOOt!tÒt|OOOu#uOBB!!#######u#uuuuu#!O#####!O!Ҁi1.H$"P??HH!O#1!t!H?O!!OB.111"i212[2HOOOO!###XXXu#!!!!OOOOOOOO!O7!!!7O!!OtOOHBO!BBBBBdd>dBBBdBB>>>|?oott.tt.݀u X X##OH݀ X .?lYy?$P|ZZ.PPH. .!u u OtO݀!!!1B11ttt2Nit#u#u#OBHO!!u######uu##uuuuu#!w#uu u##!O!!!݀tttot"Nt.X!HuX B!H!XH!Xt.H12@?"P22l@H12!!O!##uXX#!OOOOOOOOOOO!!O!OOOOBBOOBBBdBBBBBBBBdBBddZaZtP[N.o.ttu XX #!.O.!tt. t.t.2%Z"||Z$$"PP1l! !t, !!#O.!#!!O!t11.."ZiN!##!耀!OO!!!!#u######u##u####uu Xuu## #u #!t!!!.tt.it2t!O!u!!!O1tt?y߷N2ili2?l121.O#!##u!!Odl?dBBBBtOOOOO!O!7!!!!OOHHtHOtOddddddd>B&Bddddddd P[Zt.l P.!! uX t1?dO#...o.t.?2HttHlaNi@.$$Z˶o. .X u !.t1HHt!X X !tOHܒtt21N1?P1OO耀!OO#u##u#########u####uuuu##u uuu#!OHO.tt12.H|1t tB!#!uX1t!H?tHNl??2l["NiN2H1HHO##!B??BBBùOOOOO7!!!!#OtHOHddddd>BBBBBBBddddBdddd@P.H2[@t..tt..݀uu !?lB݀Ol21Ptt1H.ttN$PZN|?t.H ݀HH݀tO!OOH?@N.HH..ttHHO!O!!#!!###uuuu u####u######uuuuuuuu#uu!OOBHHHH2NN. #!BOOH!t tݵt!HHHHN@[i?굵lt.tt݀##OHBBBB1l?1BHBOOOO!!!!!!OOOtHBHBBBBB>BBBBBd?ddddddd1ttt..ooott݀ uuûi1?!!!!!.t2ii2HHHtHt....t궵2?i.H1H1t.݀! tHHHH.. ݒt!!OtPyl otoHtOOOO###uuuu######u#u#耀!!uuuuuuuuu# !!.OtOHttHH2| i1. H!tdB?!BhHHtlttNlttH?l2li21H.tHHO!#!BdlBBBBHO!!!##!!OOOHBBHHBBBBBBBBBddddd>dd.Ht. ݀tt!#uuu u!!݀ ,X##!HݺHXot!.tt.H2@H2HHHOHt11ܜ.t12l..HtH1HtH1ttY , 1.꒶?!!OOO!#!uuuu######u#!O!#uuuuu##### !!.ttOt1H.H .P22t.!#!OôHH1!t .[2tHtt2?[2ܒH22HHHtO!!#####!OB??BBOOOO!#!OO!!OOO!OttHBBHBBBBBBBBBBdddddu !X !tt݀uuu!wXXu!!tHBOt!2Ot..NB!OtBtOOÜ2y@i.2i?1t?[PHP1t1tt[tNtttt1.t!!# #! u#######uuu#!!!!#uuuu######!!OttttO1HoH1H.݀OOO!O!!O!Ohltt.tttl?21l2il112H.tt!###!21lll?lBHBOOOOO!!!!OOOOOtOHHHBBBHBB&BBBB&BBddd?d>d X##!!!##uu#!!d݀!X!uuB# #.tttHO!OBHHHH.H.1l2221HtotHHO!dtOPܒ .HP1Ht ## !uuuu#u###!!O!wuuuuuu#### #Otttútt2tt݀!OHOB#!lH!!XOtt2.to2l޵NtHt2l.HtH!u#uuu!tBlll2l2lOOO!OOO7O!OOOOO!tOHBBBBBHBBBBBBBBd?ddddXXuX####!##uwu#!O!#t#!##Ou u !!1HtH!tHHHH111ܶH..HHÒHH1t!!tܺ.11lH11H# #!!!#XXuuuu#######!!!OXu#uuu#u###ݺO.tt1.!,11. X#!!!t?2!Bݒl  1[@[2Nt.t2HHݒB!#Xuuuu##uOHBlllllN?ll2ܴBHH!O!OO!O!O!OOtHHHBldBBBBBBB&B>d?ddd紴#u##########uu#OO!O耀uuOO!## !tHtO.Ot1H1tttH.1Hút..ttiH1dHX#o...tHt.u!t.tOO#XXu##u###!!7!#uuuu##u#u###Ot.ttútt! #tOO!##!XHB??ttt.ol[iltH.ꒀ.Ni݀! Xuu#!!OH1l?l2221BBBBBO!OO!!OOHHBBB??dBBB>>Bd?dduXXu7X#u##OO!!!!##!#w# !tHHHHHtlt2?tH....t..o..1?݀!HҀ!tH212tHH2HHuHHtO!#Xuu####!#Xu###u#######耀t.!.t !ݺ݀OOO!!!!!!iP2XtiZ[޵$tt1ܒ..1lit?.HOttt!#X#uuu#!OHB?l2ܶܶ121HHHHHHHHOtt!OHOO!OOO!OBBBlBBBB>>?3d>>d33uuu##XXu#X u####uu#u tt!!!OOOO!O#ݺHHtOHtH!tH.ttÀ.1Hli?iN2Hܴ!!O#!#tHl.Xt!OBtHHHHO!u u#X##u########uu####Xu!t!!.tú u!!##!!!!7#tu! H!H. HP?1H귱i2t1tH11H.tP2HttOt!##uuut!H1Nl222ފ?211HtH1lN1111HO!OO!!BBB>d?>BBdBddd?ddd&3uuuuuu## u Xuu####uu#u .HBúOOO!!# !H1Hu!H.!tH!ttH1!!tO?{ö?hld1O!##7OOO t.!##!!tBÒ.ttO.!!##uuuu#uuuu#uu###u###uuuX# X t݀!..tt!uu###O!X#X!#!Oݜ.l.Hi11H1HHHNlP..t.OO!!###!!tH2l2lN[Nފ11Hލii2HHOOOOOBddBBddd?dddddu#uu## u# XXuuuuuu##.1BHHHOHO!#uX!ttHtO!tOHtyHt!꺒hFܰX#!!7u!tttBO#!!OOHtt!!u#######uuu#u#####u###uu #u #!.ttt݀! !!!!B!tO1 uX[OltH1iiHH.HPHHt2Pt.O!######O!HHl2?2222H|iN?{H[11HOOOO>dd??dBBBdddd?dd??ddd3uuu## u# #XuuXuuu !tHHHtOt!Ot! H!11HtttOttOtl?lhlBt!#OÜִ ###!! HH!OHtH1HHHt!#!!####u##u##u#####uuuu u!!!OO. u# 耀!!!OO!O!OOl2tlN?2lH[t1N2i[t !!u###OtO???11212[i?@hl.N"@N?2HOdddd>ddddBBdddd??dluu#u!u!#u XuuXXXuuuH11H!!.11t!ݒ1HHH!!HOt2tlldhhHl_!! !X!#O݀tHH#!#t11tH.!!!!!## uuuuuu#u####uu# # #!!!!!!! !tOO.O!###!#uݜ݀Ht?HHtH.NtHHHtt݀#u!#OB2l22iiiN"i??ti?l1BtBBBdd>dd??ddddddddd?dl?duu##!!O!uuu XuXXuu耀ݺP2ܒtH1B.lBHt!HOt1???@yhiyhشBdF3c_#X.݀X!!O!!O.tH!݀!t.t.t!!O!!!!#!####uuu#u#### u## #!!!!!!## .11 !!O#OXH?a2tHllN?Ho2ޒoH@?H!!!O!OOBlhli21Ni[ill?HꜜܜHOO!7!B>ddd>dd?ddd?d???l?ϻdd3uuuu!OHH!uu Xu#!OOt121l?l.HH22l2Ht#tHH1BHd{{hد{h<tttt݀ u!BBOO! ݀t. !!!O!!!!!!!!!#uuu#u#u####u!# #!!!!!OO!耀.1H1HO #Xtuú 11HHt .t[lPtH!tO!OOOOOHB?@?iilllli2??HBBdH1}OOO!!O!ddd>ddd?d>d??紴d?3uu#躺}ú#uu#!úH11222@[?i1[1Ot1l!dHdBBdBd?t.#!ù!OOBB21.H Ht.1t !O݀# u!!!OOOO!!##uuu####uu u! u#!!OOO!7#.2222!t݀!OO!O.1ݶ?H1 Hi1tHH.H.2HH#!OHtOOOl{[ih@߰ll1HBBBBO&Bddddd?dBd?ϻ??ddddd>d3##u#u#B#X.# u.t!HútHll1BHlHlHHtHllO?Hllt?HO1BHd}Ocd>OݒNHHH݀!O}O#!Bt.t2Pt21t.!!O!#O!!OtHHO!###uuuu#######!Oݹ!##t1P2lt.!t #!1 ݀ ݒtt1ll1iiHPt2ttPHHH݀!#HtH!̀!HNiN[@N@@@l2BBBBBBB!OOBB>dddddd??d紴3dhddd3du###!!!O!!!!݀XݺHHHtHt.HHtt21HH!t!1l?O1BHÜ?l?BB!O#!OB贷1H1t!uu###!O1lt1H2HO!# !!!OH!#uuuu######u##XuOOO!#u##1P22t.݀ OX!!uX tHݵltNH1t..12P.H.!!tHBlÀ!!HH?NNiit22" BBBBBBOOOBd?d?d?ddddd3d?3d3>>>u#!u# u!݀O!tHtttO..ttHt!...Ht!tHtHtH11td?1hX!Oddu!#O#OOHH|? uu,X!12[YPt1tOO!!!# ttHHO!耀##uuuu##u##uu uuO!!!uX u #!Ot1Ò1t݀ u#! H Ҁt2i2.t.tHHݒ2ltÀ!tBHOHHH12N"ilNl1N$@"il2BBBBBBOBBddddddddd??ddl紴hd>d3dd>d:<>>玌uu#u##ݺt!OH궜11HtOO!OBBHHOH݀!!Ott!1dúHthlh!d3%5%5_%t1t.uXXu##tH1Hl?11ҒNÜ1t!uu XX#!t1Ht!!OO!u#uuuu####u#uuu##u #!!!u#u#ttot1!!!u u!!!H.H1[?2H1t.t?N?.?lt11H !1HHt.ltH122N|@lꊵ N[N"[ ldBBBBHHBd?d?dddd?d?dd???ϴdddd>dd>]:™XXXuuu XXu!!H1HHÒOttOHtO!X !ttH!2 2{B%%3?3{5Y_Y{! #ÜP11P!!Xݜo?2P#####uu tHHHH.OOOtOO!#uuu##### # uu !!!w#u##!tiitHú!!#OHO# !ÒPPiiHHt11 t?HO1!11HtHHBHH?lN""|NN2H2[2|[1Bdddd?dBBd???ddddd??ddd?ddd>dd:Jd>:J:duuu#####!OO!OHt1tHH1 t. ! !݀#X#!1!B33&>T33h݀###!ݺ.oo.H.!ݺ!##!ttlB.!ttO! #Xuu! !1ú!!݌!Ҁ12.P.t..1NP1.t.NPPPPl1tPHHH2[21t.ttH t1?lP2tH1tH1[NN[N2Nld?ddddHBl?ddd???dddd?d?dBB>>ddd>>>3]3uXuuuuu###uuw7OO!!Hú2P22.11H1ttttt!tt݀!t!t!Ü1ú]B73d>BG>> !#!O. o21ú}!݀tX,!!!tBt!tttO! XX u#u#####!຺! uOH%2.t22PފPo2P1Ht122NH1PN1Ht..HtҒ2?O22lN2li2"N""i2[iil?dddd?ddd?dddddld?dBBdd>d:3>uuuuuuuuuuuuuu!!#tt?i?211t!1!!OÜlwddO>&777d>>ddBX Xu!!݀u .2[i11B!uu?{.܀OtOOH1H݀t݀ u#u##uu#u#!....݀u !221Pt2.lt2Hꍉ|2"2HNްN[|"˶.l22P11tHtHt11to[No2lll1[NiiN|"i ?Pް[illܴ??dddd???d?l?d??dddddldddBdd>3::uuuuuuuuuuuuuu#!OtO11lilPl22Ni?1܊Btt!tܺBBB3dB#}G7>3dBBtXuu###!!!X ..1ܷ[u!!O!ݺ H1õ1 tHt!u u!!݀#u # ##!O..ҀHttN@P21i?lHHN2[[@iiiNP222Z|"Z[[Zi2NN2ii2H21H.2121PtOh??l[[[[i222i2?2lldddddddd???ddd???d?dd>dd3uuuuuuuuuuu#uOtH2lii??@2ܒHHt!!HBH}d?d?dd۹}O7>B>dOuXuXu#!O!݀ݒܶPuBBBXuOu #1HH!t11ou u!!!!##uuuu#!!t... .HHlZlti  1@t굊NNi"޵P Z Z"2HP?l2lO t܊?lHiii1lN?ll2꒒2갵ll??1lldldl?d??3??dddd?紴?ddddd>>>d><J:uuuuuXuu#uuu####耀!H1??1t?HdHllHtHt!utdBddۻ?ddBdBwOwdwXu####!2[{ ? HuXOwu!݀HH.t.X .t!O!#uuuu!O!o.o .1H.HHi[1 ! !ܜ?? ya$al"aN|ˊ"212N["ll2HHtHHH,.l܍i???2H2222P21?lll2HHddlddl??3???ddd?ddddddBBdddd癙™:ęXuuuXuuuu#!u!!OHl???l2i?HtH!!BBd}dhhBOBO#!O!!u#tÜ2l2h??w#u#uu!Hݺ1l2HH.. uݹO!##uuu#!!t.....22?N21tt݀X!!1h2l@12221N[[|Z Z"2HiNi2l1lHtt11l@2i?N2222l11l2llBHBBBldl??紴3???ddddd?ddd?ddd>B&BBd癙Jf>::<uuXuuuuXu#!BlHl11y%?3?l1!躹&!}BOBddOuOO!#WwOOu!.O.. !#uO!!u###OHtt2tHt.݀t!##uXuuu!!O!t...P.!1PttOlܵ%1.12i?"NP|$ "Z$ߊl22l2꒒t12HtHꊵ2??l22?N2ll܊l1BBBd?l??3hl???ddd??dddddBBBdBB&̹d3J<dŽnn:uuuXuuXuuuuu#!OOHHHl?h%{dB?c[1ݺO!!!wOwO1}}hOÜ uuXXXXu #ݹHH121u u!!!HHt221t!.t.t!u####!OttH1t궶2P21H$Z1t! B#uH# t2iN@ZZ$|" [it1Niii2l212.lll?NN?l22l?2l2BBBBB33?ddd?ddd???ddddddBB̹d:JJĎ:nuu#u#!OHH11BBHB1dhl{aOO3@OOBHO#!!wOO!!O#d}#!wOuuXXXuu###!t݀H ݀! tO!O!!ݺú21Hto!O!u#uXX#!!OtHH..2.?@2i1 t !H[@{ܺ.t!.1.tN"Z [ Z$[ [ "2ܵ޷Nii1HHHt2NNll?2222?22l2N?ldBBBddd?h333ϻd>dddd???dddd>&33ϙJJd>&dd3ώ<B&dJ:<:J<d33:JT:Tϙ!!!O!! #!OtÒ11HHO1BHddBO#B3BBadܜO!݀w###uuXXw#u#uuu####OOtt݀ Xui?2P2HHÀ.Htoo!OHO!w! !HHH222tP.HutO!uOO?t P?[2"߉Pi "NiN2l[?l[[ [N21l@{߉["222?221111dll?hh3h]]33紴?ldd>>d>B&dd3333:::T::JTY####!!OOOOOO1tݹttHtH?BOO!!O!Oh!B1dܺݺ!!#uXu#ɹX#Xu7w##uu #!!OOHHHOú݀u#t!t2l2P11tHttH1HtHOO#!7!HO.HފP1H.11..HOO1OuO OOt12Z1PoNꍷ2N2lll2?@iN21Ptt1?i[@Z߉Z@|iN11211l2dl?hl?]ϻ3ϴ3??dddddd>ddB>d333:::T3J>YTuu##t1HÒHH11úH!XXuXO!!B[?HlHX#!u#u#uXXXXuXuuu#XXt11Bt݀!! ݺl#uHH.t?꜒.tttOHB##!݀!!!tHoPt.tú.݀OH1H!!tt [NPi2. @l2l?lil2lߍ$Z[2l1tHHHH?i[߉ [[l1111ꜜ2?lll?dd?33h33333333ϴ????l?d>dd>>dd>d]]::ϕ]####O.t1HÒt.O1H1?l2h? ݀#O!!O[?2ܜX#w#w#!wwwu###uuuuX!.H1P11HHHO݀ݺ.݀ O!ݺHXܶ1t.tOHO!!!!#!!!O!!.HtP|"|l11Ot11݀!#H1i 2l.P|2[l??l??lli[a$߉Z[[i?21HHHl?i[ZZ[l22?2BHB22?i33333]]333333????dddddddd>d>>>>d3:T]Fuu## #!.ttHHHHHtO.BÜ11H!!!XOHHH.#!##!u!uuuuuuuXXut22.!݀!..!ݺt!!1Hݒ.21l1t...ttHHtO!!#!OOO!!.P˰ |1HO.tÜi# !...i .NaZ[ll???d?lld܊@@@$$iNi21Ò1ܴ[@Z|l2221HHH1ll??iihh33333333333333dddddddd>>dddd3:5F#!##!tݺtHHHOOOtOlBtB1Ü1OOO#!OB!!OHH2 OX##u!u!O!#u## t2t !HݜH!!tttܒ1.tH21HHBO#!##!Ottt!.t1NP..!tH!!tOHHto..˰$$H1t2?Z $Z[??lll?iyy$$$$Zi?221?hi?Z|l2ܶ1úHHH1l?hhϴϻ:3dddd?ddddd>ddddd33:T53_Fu#! !HO.tttOttOO#HdBOOd?H1BHO!d!!OH222!u!1!!uXOO#!Ot.t..ttH!ݺBttBÀl2l111HH1úHO#O#!ttO.ttP[|޶otO! !.BH!.tHO1??P..޵|N[@ZN߉2Nll?[%$$$Zl2l?2lݜÒ12?Ni"ܜ11112hdϻ33ϴ?dddd?ddd>ddd>>>d3ϻ]3:F;TTT53F5#!!!H!ttttOOOOOOO!HB1!l{h#OOHtOOH1lNÀ.Bl?OHly u !OHOtÒú..tHÜú.OݺH11l2.HÒ1ttO!##!!!t!ݺ..tN|N22PH.tt!Ot!ttttt!OO12lފN2NN2?ll?122B2hߍ[ill??l1ú2lhll?N"22211l1ldl?ihihhhi????ddddd>d?B>>>>d>dϴ]T:K:_FFFF!!!!HOtttOO!O!O!!OOO1Hl!B!OHBHHtH.ܷ?t?u1ݺHtHH1ܵ2HHl!!!ݜl?Ütt.t!tHÒO..!#!Ott.|Pt.. !OHtOO!tHOt![@2112P11BHBH?iiNi??lÒB1HHúÜHH?l?11111útHH1?l????ll?ldBB>ddddBBB&BBBBBBBB>>>dd>>ddd>d::::T3d>d .  20021107174532  0IMAGE_VERSION1.2 0CLASSIMAGE 820021107174532 ^ 0CLASSIMAGE/  0  h20021107174532  h 0CLASSIMAGE 8IMAGE_VERSION1.2&Block_number  Ocean_flag Block_coor_ulc_som_meter.x!?@4 4Block_coor_ulc_som_meter.y !?@4 4Block_coor_lrc_som_meter.x!?@4 4Block_coor_lrc_som_meter.y!?@4 4Data_flag%  XHDF4_OBJECT_NAME#Vdata table: PerBlockMetadataCommon 8testthis is a teatIcebergiceberg_palettepixel interlaceplane interlacelandcover.umd.199906.jpg @IMAGE_SUBCLASSIMAGE_INDEXED @IMAGE_COLORMODELRGB H IMAGE_MINMAXRANGE 0PALETTEH0/-0/-10.21/51.51.62/62/83/83/:3-:3-:3-:3-:3-:3-:2/91.91.80-80-91.91.:2/80-80-80-80-80-80-80-80-6.+6.+6.+5-*5-*4,)4,)4,)4,)4,)4,)4,)4,)4,)4,)2-)/*$/,%/,%0-&1.'2/(30)30)63,63,74-85.85.96/:70:7.A:0B<0D>2F@4IA4JB5KC6KC6MD5MD5OC3NB2OC3OC3PD4RE5R?1Y?2b@4nB5}E6H8G9F7G:G9E:G;G>G?H@E@FLCLDKEICIBD>B=A;A:@:??-?/?/>.>,=+<+<+?+?+=*=*=*>+?,@/?6>5=2?1B3D3D4D4?0A2F8H;H9oA2T8*C3&=5295495473271160050-50-72/72/72/61.61-50,50,41,//-.0-//-//-0/-0/-2.-2.-5,-4+,4*+3)*7(+=.1E69P:0U?1^A3jC4xD6E4E5C3C4A4A4B7D:E@<@6>/@.?-?-?-?,?-@-@,@+A-A+@*A)@*A,>-?/>.>.>,=+<+<+?+>*=*=*=*>+?,@/@5>5>3>1A3D4C4D5A2C6F8I;G:l@3S9*B4)>63:6595484382271161.61.72/72/72/61.61-50,50,41,//-.0-//-//-0/-0/-2.-2.-3--5,-4*+3)*5)+<-0C47N8:d>=vEAJINLTVajl}r{{ou[[QHuOCiOFeOG_PH_RN_[Yfnot~ojkY][LVSJXSZVRaXQa/.,/.,0/-10.40-40-51.51.72.72.72.72.92,92,92,92,91.80.7/-7/-7/-7/-80.91/80.80.80.80.80.80.80.80.6.,5-+5-+5-+4,*4,*4,*4,*5-+5-+5-+5-+5-+5-+5-+3.*2-'1.'2/(30)30)41*41*52+63,63,63,74-85.96/96/:7.?8.@:.B<0D>2G?4H@5H@3H@3I@1I@1K?1K?1K?/L@0MA1NB2MA1QA1YB2dC2qC3|C2B2A0<-:+;.=2@6D:F=D>CE@FBGBFDFCEAD?D;@:?;@=@@@A=@;@5=.@-@-?,?-?->,@,?-@-@,A+A,?*@*@+>->.>.>.=+=+=+=+>,>,<+<+=,=,?+?.A6?5>3>2A4C5D5C5D8F;I=J=G;h@4Q:,B5,?74=77<66:4494183072/72/62/62/62/51.52-41,41,21,.0-,1-.0-.0-//-//-0/-2.-5//4..5,-4*+4*+9-/>24I56[97l?9|E@IDOM[`fvmw}}u~fmTVMEvLAkMAeOFcQHcMH^NK\[[eqty|xzlfiXZ[MVSLZU[ZT`[S`.-+/.,/.,0/-3/,40-40-40-61-61-61-61-81+81+81+81+7/-7/-6.,6.,6.,6.,7/-7/-80.80.80.80.80.80.80.80.5-+5-+5-+4,*4,*4,*3+)3+)6.,6.,6.,6.,6.,6.,6.,4/,30+30)30)41*41*52+52+52+52+52+63,74-85.85.96/96->7-?9-@:.B<0E=2E=2F>1F>1G=1G>/H<.I=/I=/J>.L@0JA0KD2NE4UD4^D3iD2sB1~A/?-9)9'9*<-@3E8HDCACBCDCCDBC@C?A;@:?;@>@A@B=@9@3=-@,@,@,>,?,?,?+@-?,@+@*@+@*@)?*>,>.>.=-=+=+<*<*=+=+<*<*<+>,>-?-A6?5>2@4B6C8C7B7F|F:b@4L:.A7-@85>96=77<74:5294183083062/62/62/32.52-21,21,12--2.-2./1./1.00.00.10.10.5106005//5,-4+,6,-:01D22T71c;3qA7{E;HDRU_lis}yx}ow`fQRLEyL@pL@hPEgQFfLC^GBVMLZ^^fjnquyxx}wzvwzokoa`bTWYLTTL]WY]V]]V^------.-+/.,0/-10.3/,40-3/,3/,4/+4/+4/+4/+6/)6/)4/,4/,3.+3.+3.+3.+4/,4/,50-50-50-50-50-50-50-50-3.+3.+2-*2-*2-*1,)1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,41,41,41,41,41,52-52-52-52-52-63.63.74/85096196/<5-=6,?8.@9/B:/C;0C;0C;.D:.D:.F:.G;-H<.I=/J>0I@1JG6MH5RG5YF5bE3jD1uB/}>,;):):*=,B2F8J=I?GBDCDBEBBBAA=@<>:?:<<>?>B>C:A5?0?-?,?,?,>->->-?->.?-?,?+?,?+>*>*>,?.>->->-=,=,=,=,=,=,=,<,>->.?.B4A4@1@3A7C9B8A7C;H?LCJ@tE;Z>2E9-<5+@93@85?75>63=52<4194083/62/43/43/23.32.12-12-02--2.,2.-2.-2./1./1.00.10.3205105104..2,,4+,7./=/.N5.Y9.e=1n@3sB;yKKZegpzxu{ks_dTTOGLBwNAmNBhMAeJA`GBYGFXKKWMPU]cc`fbbia`f\Z`TW[MUXMXXP^YV`WX`WZ,,,,,,.-+.-+/.,0/-3/,3/,2.+2.+3.*3.*3.*3.*5.(5-*3.+3.+2-*1,)1,)2-*3.+3.+3.+3.+3.+3.+3.+3.+3.+3.+2-*2-*2-*2-*1,)1,)1,)0+(3.+3.+3.+3.+3.+3.+3.+3.+41,41,41,41,41,41,41,41,41,52-52-63.74/85085085.;4,<5+=6,>7-@7.A9.A9.A9.C9/C9-E9-F:.G;/H<.J>0HA1JG6IH6NG5VF6\E3dC2n@0v>-{<+;);*=,@1F5J:J=H@EAFAE@CA@>>?:<;<:;<=@=C=C8@2>,?,@,?+?+?->,>,?,>-?,?,>,?+>*>)?*>+>->->-=,=,=,<+=,<+<+<+<-=,>/?.B4A2@2B5C9C:B:A;A9I@NGNEoG=S?4A;/96-@93A75?74>63<4194083/74/43/43/34/23.23.02-02-.3--3/-3/.3/.3/02/02/11/11/21/32032040/2.-1-,4..8.,G4-O4)X8+`<0e?6mGFyYdku||w|nudh[[RMLB~OArL@hI=cH>`HB^ECX@BO;@FBGJDMJJQJJQIIQFKQEOUIVWO^YS`YS`XU++++++,,,---/.,/.,0/-0/-1-*1-*1-*1-*2-)2-)2-)2-)2-*2,,1++1++1++1++2,,2,,1++1++1++1++1++1++1++1++2,,2,,2,,1++1++1++0**0**3--3--3--3--3--3--3--3.+41,41,41,30+30+30+30+30+41,41,52-63.74/74/85085.:3+;4,<5-=6.?6/?6-?6-?7,B8.B8.E8/E9-G;/H<0J>2H@3HE6GF4KE5QD4XC2_B2f?.n=,v=,|:*9);*=.B2F7F8FF>E>D@C?@@>>::;:<.>.=->-=.?.?-?-?,>*?*>)>+>->-=,=.=.<-<-<-=-;,<,.=0?/C2B1A1B6C:CCC793@72>71=60:5/94.83/63.43.43.34/13.13..3-.3-.3--3/-3/-3/-3/.3/.3/02/02/00.11/22021/0/-/.,2.-4/,?0+D0)K3)T8-Z<4dFFu]js~tzmpceVSLCK?qI_FB]DBW?AN;?H:BE>HGDMHGQIGQHJRGNVKUXM^ZOaYNaXO++++++,,,,,,.,-/.,0/-0/-1-*1-*1-*1-*2-)2-)2-)2-*2,,1++1++0**0**1++1++2,,0**0**0**0**0**0**0**0**2,,2,,2,,1++1++0**0**0**2,,2,,2,,2,,2,,2,,2,,2,,3/,30+30+30+30+30+30+30+41,41,52-63.63.74/85085092,:3+;4,<5->5.>5.>5.>5,B8/B8.E8/E8/G:1I=1J>2I?3FC4FC4JB5OA4TA2\@2b>0j<-q<.w9*}8)8(:,=/B4B5F:E;F>G?G@FACAB@;;;;>;B;D:D4@->(A-A-@,@.@.?-?->/>.@.?.?->+?*>)>+>->->-=,=.<-<-=-=-<.<.<./>1?1D2C1B4C6C;D>D>EAPL[Te\f]u_T[UIGMACI?<92?82>71;6094.74-63.43.43.34.24/13./4..3-.3-.3--3/-3/-3/-3/.3/.3/02/02///-00.22022010.0/-0/-3/,8,,;,)C0*K70S<6^IHtbnzƄzrxikWWIDE=nG^CAY@CV@DP>EKGQRKWUQ^WU`XS_UR^TT^SY_S^[LaZJaZJ,-/,-/,-/,.-------.-+.-+/.,/.,1-*0,)0,)0,)/+(/+(/+*/+*/+*/+*/+*/+*/+*0,+/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+1-,1-,2.-1-,1-,1-,1-,1-,1-,1-,1-,0,)1-*2.+3/,3/,3/,3/,3/,3/,3/,3/,3/,40-51.62/74/80-92,:3-;4.=4/>5.>5.>5.?4.?5,B5-C6.D7/F90G:1F<2G?4H@5J@6P?5T>3X<1^90b6+m9.t8-|8+9,;/=0?1>0A3A4C8E:G=G>E?C@@?BADAE>D8B1A.B,A.@-?,>.=-=->.?/<,=,<->-=,=+=*>*<+<+=-<,<,<,:-;-=/3@2A5A4E5D4E9I>G@D>EAMGZRf_qfsh~rdjj^V^SIQFLLBJF=B>5<8/95,74+63,33+43.34.14-14-02-/1,,1+,1+-2.-2.-2.-2./1./1./1./1.02/02/11/11/11/11/11/40/4+0;/3A32C4/J;6]OOymyϐكtzjn_bZ[LItHBdA>]>>X?BUAIVLU\U`bbqnn}xv|rulyoguh_k_W_P[ZF`ZDc]G,-/,-/,-/,-/------.,-.-+/.,.-+0,)0,)/+(/+(/+(/+(.*).*).*).*)/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+0,+1-,1-,1-,1-,1-,1-,1-,1-,1-,1-,0,+0,)1-*2.+3/,3/,2.+2.+2.+2.+2.+2.+3/,40-51.62/80.91.:2/;4.=4/>50>50=4-?4.?4.A4.B5-C6.E80G:2H;3H>5H>5L=6O>6Q=4V;2Z90_7/h70p7.w7-9-9.<1<1=1@3A3B5D8E:FF8C2B-B-C.B-@.?-?-?->.>.=,>,=-=,=+>+>*=,<+=+<,<,<,;+;-<-2@6A7B6G9E7Ga[C,-/,-/,-/,-/,-/,.-------.-+.-+.-+-,*/+(.*'.*'.*',+),*+,*+,*++)*+)*+)*+)*-+,-+,-+,-+,-+,-+,-+,-+,,*+,*+-+,-+,-+,.,-.,-.,-.,-.,-.,-/-./-./-./-./.,0,+0,+1-,2.-2.-2.-2.-1-,1-,1-,1-,1-,2.-3/.40/51.80.91.:2/;30=31=4/=4/=4/?40?4.A4.A4.C60D71F93G:4H;5J;6K<7N=6P;6S:5V72[6.c60k6.t5,}7/9/;0<0<1?3@4@3@3C6D8E:D:F@H@IBI?E:C3B.A.B/A.?.>->->->/?0<-=-<.=.>-=,<+=+<*<*<,;+;-<-:-;-<0<0<2>3?4A8C:D9J=H;H>KDKFLGSM`Vsgqz{wsocqbXcUNRDMN@HI;DD8@@49;.46+/1&01)01)/0*/0*./*./*//-//-//-.0-//-//-//-//-//-//-00.00.00.00.00.00.00.1/26+97+98/4;63HE>_^Yzz|DŽ}{|}}wq~n}n~~o~y|{j{i\hTVV>[W:]Y>-.0-.0-.0-.0-.0-.0.......-+.-+-,*-,*.*'.*'.*'.*),*++)*+)*+)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+-+,-+,-+,-+,.,-.,-.,-.,-/-./-./-./+*0,+1-,1-,1-,1-,0,+0,+0,+0,+0,+0,+1-,2.-3/.40/91/:20;31<41=31=31=31=4/>3/>3/@2/@3-A4.C60D71E82F93H94I:5J;6L:6N94Q83T50^72e60o6/x8/90:/<1>1?4?4?2?1A2B5D7E:G>H@JAI>F:B5A0@.A-A-?->,>,>,=.>.<,=,=.=-=,=+=-<,;););+;+;,;,;-;,;/<1<1>5@7C:DJCLIQL]Vj^oyzxm{jbm]SZJQUFKO@EI:@D6;=057,13(01)/0(./).-(.-).-)/.,0/-/.,/.,/.,/.,/.,..,/.,..,0/-//-0/-//-//-//-//-2-17,:6*83-1961HJ?bfX{z}|k|iXfOSV;YU8ZV9+/2+/2+/2+/2-.0-.0......------.-+-,*-,*,+),+),+),*+,*+,*++)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*++)*+)*+)*,*+-+,-+,.,-.,-/-./-./-./+*0,+0,+0,+0,+0,+/+*.*)/+*/+*/+*/+*0,+1-,3/.40/901:20;31<42=32=31<20<20=20=2.?1.?1.@2/A30B5/C60D63C84D95E:6G96H94K84N50X72_60i70r7/}:1<1>2>2@6?5?5?3@3C5C6E8E;G=H>G=D8A5?0@/@-@-?.>-=,<,=/=/<.;-0->0-?1.@2/A4.?4.@51@72@93A:4B94C84F74H5/Q51X5/a6/l8-u9.0=1?5>5?5?4B4B4C4D4B5D8E:E;B7?4>1>0?.?+=,=,<+<+<.<.;-<-<.;-;,<,;+;+:*:*9):):+9*9-9-<1<3?6A8CHCNJVR`Zper}~~yup{jdp\]iSR^JJS@BK:>E5:@29<134,22*1.)/,'/))0**1++2,,1++1++1++1++1++0,+0,+0,+1-,1-,1-,1-,/.,/.,/.,2,.8*75(13+(56&EK1\gGudyťέɭʰ˱Ȭ{wrdx]Q_EMQ6QQ5RQ5,03,03,03,03./1./1./1./1/////////////.,/.,.-+.-+/-..,-.,--+,,*++)*+)**()+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)**()*()*())'()'(+)*+)*,*+-+,.,-.,-/-./-./+*/+*/+*/+*/+*.*)-)(,('0,+0,+0,+0,+1-,2.-40/40/:12;23;23<34=32<21<21;10<1/<1/>0/=/.>0->0-?1.>3/=60;60;83<94=:5>93@72C60G4.O4+Y4+d5+n8,x:-;.;.<4<5>3@3A2B1A2@0>1@4B7B9@6>5=2?2?-?->,=+;*;*<-<-;.;.;-;-;.:-:,;,9)9):)9(9*9*~8,~8,<1=4@7B9E>IAKFMFIAH@JFSO]Xhb{ny~wxnjxadr[ZhQQ]IITCCL;>D60-?1.=2.>3-=6.<719919:2::2;81?6/C2+J1,T2)^3*h6+o9-v<.{;/=2=3?2@2@3@1?1=/2B6C7B7?4>2>1>/=.=-=,=,=,=.>/<.<.2>5@6C:F=JBMEOGICIDPJ\Th`uiu}zytog~bby]\pUUgON]HGRA@I8=A388.85.50,3+)2()2()3)*4*+2),0**0*,2)*2),2),2),2),3*-3*-1+-1+-0,-0,-0,-1+/4)/4*+4-%46!?F%T`8m|Qgtz~z{Ĉːəǝƚ~xvolfZnSJZ?FL2FJ/FH0/0+.0+/0+01,01,01,12-21-32.43/43/62/51.41,3/,4/,50-50-4/,3.+2,,1-,0,+0,+.,-.,---/--/,,.++-*).))+.)/.)-/(/.)-/)-.)-.*+.*+/+*/+*-,*.-)--+-.)./*./*------.,-/-./.,0/-2.+2.+2-*4,)5-*6.+8/*:1,:1*;2+=4-=4->50>50>50=4/<3.;2-=2.<1-<1/;0.=/.>0/>0/@1.B/)B1)<3*96-58-47.66.;2-@-)G)'O''V)&[.(a5,f<0m?0yA0@/A1B3@3=0;/8-;/=.A1B2C2A0>.;,;0:2;1=0?0?/?.?.@1?0>1=0-v>-v;-}?2};/?4D9H?LAMBOCNELITPcYqa}jq||r{nuhia_[zXYtUZnSVeNOXEIK=B?6@93:0.5+*3')3'+3'+1&*/)--)*-(,-')/&+1&,3&-3&-4'.4'.3(02(00)1/*1/*1/*0/)-1++0-(//#A./0*01+01+01+12,12,21,32-43.43.74/74/63.52-50,50,7/,7/,6.,6.,3.+2-*0,+0,+0,-/-./-0--/-,1+*/)*.)(-.)//(//(//(//)-/)-.*+.*+/+*/+*.-).-)./*./*./)./*.....0....../.,/.,1-*3.+5-*5.(7.)8/(:/);0*<2)=3*>5,>5,>5.>5.>5.=4-<3.<3.=2.<1-;0.;0.=/.=/.>0/@1.D/*F/)C2+@3+=4-<3,;2->0-A,+F*)K)(P*'V-)\3-a91g=/pA/xA-A0@2?4=3:2;19..@0A1A1A/?1;2;2<2=0>0@/?/@.@1>/=0<.;.;,:,<,w9,w=1p;-m9+r?.r?.q9*u:,=1@5D:H=J@MAOCMEJHTRf]wfpwu}mvdi^`YZY{XZwXXoSRaJMVCEI;AA7;8350-3*+2)*1(+.(*1(+0',0',0',1&,3&-4'04'04'03(02(10)1/*1-*3,+3,+12-12.-0,)--%8:,SXBox]iolnpppw{xwy||{xuqnh{eYjWMZHFM;@D3;>-12,12,12,12,23-23-43.43.54/54/85085085074/72.61-80-80-7/,6.+4/,3.+2,,1-,1-./-.0.1/-0--/,,.+*/+)./(/1'//)-/)-/)-/)-.*+.*+0,+0,+/.*/.*/.)0/*0/*0/+//-///0./0./0/-/.,1-*2-*6.+70*90+:1*<1+=3*>4+?5,?6-?6-@7.@7.?6/>5.=4-=4-=2.<1-;0.;0.;0.;0.<1/?1.D1+G/+J.+L,-O+/N*.J*/G*.D,,A.*B-(F-(O.)Y0*c2-i4,k:,o;-w;0=4<6<5:4:4<2=2>2?3A2A3B5C5?2=/>1>.>/>,=.=,;.<,:-:*;,<)~=+z=+|>1x<1u;/t@29:,23-23-34.34.34.45/54/54/650761961:72:72961940940:2/91.91.80-50-4/,4..4..3/03/01/01/20.1..0--/-+.0)02).0*.0*.0*.0*,/+,/+*1-,1-,0/+0/+10+10+10+10,11/1111/010.10.2.+3.+3.*92,92,;2+<3,>4+@6-@6-A7.B8/A8/B90A8/A81@70>5.>5.=2.=2.<1/;0.;0.<1/=20?1.B3.F1.M-.T)0X&/W%.Q&/K(.D/.>1+<2)@2)H/(T/)`-*e.)i9/k;/u<3}<6;8;9;7:6>8@8B9B9C7B7A7A5@1@/?.?.>-<,;+:+8*8*9*9);)}<(z=(x>*@1z7.x8.x<1u;-v>/{A3{@2B7D:G=I?I@KBNDPHQJZQe[rb}gmv|~yrolihgfeggde`}_\v[QgPL]JBP?9D62:/.4*,/(-*%5%&8#(8#(7$(4%(3'+2),0,-,*+++-*+-(,-',/',/%-/(,-.*+1++0+'.+"88,PUAiqYvc{hyh|il}mykzmrtq}p}p}s~v~x}x|x}zzwuqnje|bWkRN[GEG9?=097*45/45/45/560560560761761872872;83<94<94<94<73<73<41<41;30;3083072/61.61.5106216213122011/00./1-.2,04+.4+.4+.2,.2,,2,,2,,3/.3/,3/,3/,21,21,32-32.32032032032051051.61.61-;4.<5/=4-?6-A7.B8/E8/C9/D:1D:1E;2D:1C90B8/@5/@5/>3/>3/=2.=2.=20=20>31>31B41F21N02U,4Z(3Y'2S(1L,1D20<5-97+<6*D3)N1)Z/)^/)f:1j;3s<7z=:<:<;;;::;7>8A8B9C:C:@9@7B2C1@0>/<.;.9-8-6+7+8+:+<+z=*w>*x>*9-z0'8/?4u5+q5*|B6}C7E:GJ?JBLDOGUJ^NfQmYr]ybiu|~}w}p}l{lxkxmulpgl~dcqX\hRSZHIK=B@4=6,9/&7*$9''9%'6&'4&&1'&.((,+),,*)+()+*)+*)+***,**,+),-)*,#$2*'50*86*BC5UZFfpWn}^teqbuexiwkshtiwkznxlwmxnys{u{w|wyuzwwtsomhd{_WkPN\EDE7>:/84)560560671671782782872872983:94=:5>;6>;6>;6>95>95?74?74>63=52;63:5294194184184395484373243151240/6-06-.6-06-.4..4..4..4/,40-40-40-51.32-32-43.43.43/431542540841850940:5/=60>7/@7.A8/C90D:0G:1H;2F<3F<3F<3F<3E;2C90B71A60@51@51?40>3/>31?42@53@53A62D52K25Q16V.6U-5R/5K12D52?80=9-?9+C7)I6(S2)X2)]2+d3,l50v64}77877766~75}:4}<6}>5?9@8?9A8A3A1A1?0,~<,5*3,MEYQA8|90F;K={G:zJ<|L>}M?MBPEUJ\LwiOupRrXu]ub|iszz|~yvpoppp~pzmvkm}bht\`hSWZGPM>H@3B6*@/'=+'<*(8*'5*(2*'/,',-'+-(+-(,-(-,*/+*3)*4(*6'*6((3($<3,E>4IG8QR@]bKgqVjyZn]k\l]pbqeodoerfumrjqitnxrzvyvyvvtwvurokjfc|^UlON\ECD6@9/:3)671782782782893893983:94:94;:5>;6?<7?<7?<7@;7@;7B:7B:7A96@85=84=84<73<73<73<74<74<74;639529338308/09/.8/080.80.80.61.61-61-61-52-52-63.63.74/74/540540841952:63<94=84@93@70A8/C90D:0G:1H<0I=1I=1J=4J=4J=4I<3F<3D:1B8/A7.A81@70@72?61?61@72@72A83@64A75C86F87H96J86J86H94E80E8/E9-F8+I9,I9*L9+R6*Z/&d/'n3-z6398;9;:=;A>@:=6<3:3<4=7@7?5@3>2>2<1;0:/;/:.;.~<.=/=/(+A&+E$+C&(F5-LC4VQ>[YD`bJgmQiwVj{Wl[gWfWl\oananbrfskojoirnwtyxxwuvssuvsrnlicb{[TmMM]CHI;E<3?6-7827828938938939:4:94:94;:5<;6?<7@=8@=8@=8A<8A<8C;8C;8C;8B:7?:6>95>95=84>95>95>95>95=85<73:51;30:0.:0.91.91.91/91.91.72.61-61-63.63.63.74/74/74/540651952;83<94?:4B;5B;3A8/B:/C9/E;/H<0I=1J>2J>2K>5K>5J=4J=4F<3E;2C90B8/B92B92A83@72@72A83B94B94?82@93B;5E<7G<6I<6M<5N;4M6.N6,Q6+Q6+Q7*R8+P9)V6'g5*r6,~;3@9D@HDJGLFQJLDD;;07-7-91<4<5=7<6;5;5;4<3}=3z>3z>3z>3}=3;3936331)&?;}zhcH@K@xH:pLjV>oV@vZE_LfP|qQvUs\k^__T\Q[R\ouyxυ|Î~}xvrtuuussrn|jwyapnWiaNbRBWD5S;/O4-M1-I0,D/*@/(;.&7.'6/'90):/)=.+A,+F)+H(+K'+H)'TB4YQ9B?:D?;D?;E@8E>8D=7B;5B;5B;5B;5B:7B;5A:4A:4A83A83A83@72@64>71>71>71<71<71;60:5/85.85.74/74/961961961:70<71=82A:2B;1C:1D<1F<2J>2K?3L@2N@3N@5N@7N@7L?6K>5I<3H;2E;2E;2B90A8/@91?80?80?80@93@93<5/MD=M@:K:3T@9R62Q0+_<6[4-^6._4+\0'^/%e6,m=1r<0I=G;I?KAF>>7=6D;NDPEVJYKOBA5;0>69888553274>8?6u<1uA4s?2t;0y906223,1&,HIcaFDYUzvVOF=8?>9>=8>=8A>9A>9B?:C@;D?;D?;FA=E@8E>8E>8E>8E>8D=5C<6C<4D;4C:1B92B92B92B92A83A83@93@93>71<71;60;6096/85.74/74/96196/96/:70<71>:1A:0B<0C;0E;/I=1J>0L@2L@2N@3N@3N@5N@7M?6J=4I<3H;2E;2E;2C:1B90@91@91@91@91A:4A:2C:3I81K/+V.,j76t:9{;;ECD?H@IAH>JBOHPLOGD7B4B6C8>37-7-=0C5?0@0E3G6F6H:NEKMGL@D8;78=:>8y=3r<0|H;KA>8++(.9DKWLNOM@=A?`\YQ@5TDyaIe[@`\?khIulOwfJcKcNfXa[XZCN.E'D(H*I0N5N?RLZR^T]U]Zbbielinlqprttvwxw|}y{vyqukseoal_lanT_LUHQDKFIk79HT1-M0*H1+J6/K81K:2O>6UE8[O5cZ9gaAifEnrOz]zbt^r_p_p`q`udwdwdwfsixrzxyx~}zzromhhd`y[TmMNaERSCVPDVOE8938938939:4;<6<=7?>9@?:@?:@?:C@;C@;C@;C@;D?;D?;FA;FA;FA;E@:E@:E@:G@8F?7JA:I@9H?8G>5F=6E<3F<3E;1D:1D:1D:1D:1D;4D;4D;4C<4?80?80<71;60:5/:5/94.94.96/96/:5/;7.>7/@9/B90C;0E;1F<0I=1K?1M?2M@0NA1M@0P?5M?4L>3K=2I<3H;2E;1D:0C:1C:1A:0A:0?;2@<3@<3D;4SEI?MAOBRJURPSLKA4B0@0?1;.7+8+=/E6>+7$:'>-A/C2C:029BDLKRMRKLA>71{8/v6,z1*0-378@?:A@;BA5G=3F<2E;1D:0D:0E;1E;2D;2E<3E<5E<5@91?80=82<71;60:5/:5/:5/96/96-;7.;7,?8.@:.C;0D0K?/M@0M@0M@/M@0O?2O>4L>3K=2J<3G:1E;1D:0D;2D;2B;1@<1@<3A=4B>5F<3Q81X+&;?U`UeVfVcKO40:/>0B3F=JGCH?@B7F5B3@3?3>3B4D6G5B/<);(<(:(6&3(979=8>7<=BJLTSXS?74*-%61HKPWBQ4@;9/*9484F@]UXKWFwW@xdI~pSoQfJcKm[uiUWFP>J/?@.;D/AF/QJ._T8g`CokN||`rv}qzq|s|szozm}ouzsqh|c]tXSlNPdHPXCVWEWXH671671782893:;5<=7?>9@?:BA/K?1M@0M@0NA0O?/O?0O?2N=3N=3J<1I;0G;/D:0D:0D<1D<1B;1@<1A=2A?3B?6K=4[6.t42MS^iN_AQ7E'+2)8(:&=)A3E=??<;?5B4@2?2@5C9H;J<>/?/=+;)9):,;/=1GAEA@?998MCTLUMKJ@B5>374.9.3+;494A9[PUC{N9bIjP`FZFdTpdmhFKDDHIKJLIMLSDM:I7H4G1F4L:R9V:X;X;Z<]?_AbCeEiEkDlDmCoDoDqCoHpBhJmOpKhPk]rcs[c@D`&$Q+"V@3VO=JL7AC-RJ3eYCujV{gyýþyvi{e\sYTmORfJPZBTYCV[G560560671782893:;5=<7>=8@?:@?:C@;DAGB>GD=GD=HC=ID>IE2I=1G=1G=1F<0F<0E;1E;1D;2C:1A:0A:0@91@91=82<71;60;60;7.;7.;7,<8-?9-A;/D0L?/M@0NA0NA0O?/O?/O?2N=3M<2L;1I;0G;/F90C9/C;0B<0B;1@<1@>2A?3B?6N;4j94GEZ_XbDQ9F4;,+2'8%:!: =&@.;2817,:-9-7,:1B8E;E:>2?0<,6'6)>0D;G=:-A6F?DB?A;>470095IBULPG?92002771(=/."814,7/h\l\WCZCV?Q=[LjagbSTEK>F<@>>B>HBPMWWORDM;G6F2F/D2G7N9S:T:V;W=\?aCeDkh?j@l@n>n=l=8A>9C@;DAHC?HC?GD=HE>ID>ID>JF=JF=MF2@@4N:1o2/KKTV?D16031/2)2!9#=!== ?#;%7%6)8-6,4,81@:C<@6B7A4?@HE>HE>HE2G=1E=2D;2C:1C:3A:2A:4@93?74<73<71>7/>7/<8/=90>:1A:2C<2D=3H@5I?3L@2MA1NA0P@0O@-O?/L>1L>3K=2L;3J91I81F70C82A8/>:/=;/<=/?=0@>/B?0S9,=7][ZY86/*2+/%3#:&C*G,F'B&B&=#:#9*;0:07.<4C9=46,4.84GH?E:D9H9I7G:I?NCUAV?T;T:U:Z;^HHLC4J@4KA5MC9LB8F=4B90E<5C:5@93?74@85?75<74<42C:5B94A96>95?:7>:7?;8@<9B?:D@7G@6J@4L@0O@-O@+L?,F@2E>4H;3J84K65M47K79H::C>:7807;->B1>@+:8#C;$eB.j\KA7,6)7+6'8&=+9$<&@*A)=)9&6%7%6'7)8*<.@2B4B2A1>,=,<,=/C4F8>12&9+9*9+9-7-6.4/2-.,/-1,2,5*7):);(:&34 8'8'6(B5SINCSK\W]ZPR>C8??G@FCD@A>9<3:/;/;0L@KCFC>?I;GEQDQDRDU@VHH>HH9H?:F=8B;5D:8A96?74?74@85@85=85;62=4/=4/=52<74=96>:9=<:>=9B?:D?9G@6J@4M@0O@-P?+L?,A@.?@2E<5H96J67J47F37C47A<9<;6==1E?1J:*P6%dA.J:PB;-2#6&:'7$9%>*;%<(?+@-=,9*6(7)9):*9);+>.A1B/@.?,:(<+E6H9?18+6)7+7,9.;-8;1:-<-=.E5L?NEGC?>?B?F@JCJCLDPFTBS>S>XBaFhCi?i@jBpFvJzK{HxGsJoRt]z`{XvOpFkDkDhIf\ojtsGHysΰų~/.,0/-10.21/43/540762761:94::2<<4>>6@@6BB8CC9DD:IF=IG;JH;LI8MJ7NL7NL7OL9KI:NKBTRS_^fihxmmlkkh`YiYQ\OGRH@KH>GG=EE93>:1=9083-94.;60<92=:3>;4?<5@<3E>4G?4I?3L@0O?0P?/P?-L?,<;':=*>.<-:-->-<,?-8(>.L=G:6*2&9.6,6+8,:.:/8.6/3,0-.+.+1)2'6&8"7!8$5#9'>/=.6)9,A7<5>8EAKIJJCC?ACCCAD?B==4:.8*:*;+8)D8NEIE@@>ABIHPAG@ICOGTEU@U?XA_DfCiCkFpIwK{L|JzBtDtHqNt[|bWvEcMmVw@\G^yy{g@;{pױξ/.,/.,0/-10,21-32.54/650880991;;3==5??5AA7BB8CC9HEQPL^]bmlzzz{urke_{YSmTLdMEZG@PB;2?=1@<1?;/A;-F?/H?.K?/M@/O?0O?/P>0L?/B=*?>,@=.A:0A:2@93>95<94=84F85P41X,+k)+067A=A6.7(:(?-?,9&8#;&:&<)>,@/>/=0=1>2?3=29.8*9+:,:,9*;,;-B4E9>31'2(9/5+4*6-7-7.6,3,1*0,.+/)0(2&4$6 5204$<.=/9.=2D:5-60;5D@MIKIC?=8@9A8>4UbqӍh93qK@wmң10,10,0/+0/+10,21,43.54/77/880991;;3==3??5AA7DA8IE:LF:NH:PJ:RK9RM:SL:QK=OJDVTUfdqwxÏƎ{wpmid_[~UPnNJaKGXEBM?=B;7895296/85,85,671783891;;1>3M?4L>5I:3C82?82<948;47<59<3@91H3.Z1/w78>D=G8<;0<+@.A/@-<);'>*8$:'<+=.<-;.<0=3?6>3:/7,7,8+8+8+7+A5C88.1&3)7-5+4+3)4-6,5,5+1*/*/,/*/)0'2#4!541/2"6)9-:0?6E=F>@7<5@9KDNGE>;1=1<0CBLIUJYFXCYC]@_BdElJsNzO|LyHvDrN|PzHoJlVtWsQiG_H]XhHEl/*jbΕɿȾȿ65143.32.10+10+21,32-43.66.77/880::2<<2>>4@@6B@4JD8ME8OH8RK;TK:TM;SL*F@*G?*H@+IA,IB0IA4HB6HA9H?:L=:L::G77@65:65574181/907<574+C0)]82~BAGG?@44;/<+?-?->,>*?+?-8%9(:+9-9,:.:0<4>5;4918.8.9/8.6,7-C9@70&,#7/<42*3,2(2+3*3+2+/*-*/*.)0)1(4$5"6 57#3#3$3&5)8,<1?6YQRJHAC;E1:*;(:*:):(:+>0A3A6<3<6A=EEGHIMLPBF@CCIKTNYJZF\F_A_BaEiJpNwOzNxLvMwOvMtOsWy_{UoG^VkScdq삆_bMLhe΍<94;8185052+41*41*52+63,74-85.96/;81=:1?<3A>5C?4JB7MC7PG8SJ;WK;UL=UK?SJCSJK]WcnlŚڟꢩ뙛啘ݔ֐ʉzyrqfc~XVkPN\IGRFCLCBJ??K==G;:@;9:<94?;/C=-E@,F@*FA+EB/EC4CC7BC;AC>AAAE;CG=FG@HGDKFGLCHK?HG>GBCHAA=4K:0fF;PFJ@?58->/>,>*?+@,@-?-<*8'8)9*9,8-8.91;5:4:3818192:2706/<5>5912(4*;2<33*1*1'1*2)1)/)-(,(-)/)1)3(5'6%7!7 9%8%6%4%4(7+8.7/NGXPZSQIG>D9@7>/<*<&<(:'9(;*>0A4D;@7@:FCIHHGGJIKFHBDDILSQZO]L]K`D^DaFfIlNuOxOxPwUwTuTvYx]{\wSkJ_YjWfO]^kNYV`V`Y`cdǀ|橦@=6=:3:7074-52+52+52+63,74-74-96/;81=:1?<3@=4B>3JB7MC7RF8VJ:WK;XL?:6@<1A>/C@/CB0BC3BD7?D=>D@)>'<&;%9&9*2D9A9E?KHLIGDEEHGIICDEHMSSZR\O^OaH^G`GdIiNrQxRyTzTtZw`~`}VqNgQiZm]lftP^XfSaZhO^S^\]roؘB>5A=4@<3>:1<8/:6-84+73*62)62)73*84+;60>93A<6E>6I@7MC7RF8UI9WJ:XK;ZLA[NHTIMXR`gd|~ʗ㞪쩫蟡ڙҍtrhe]ZXR~XQzYQvVOnMH_C?M?:@?;:B?8>>4@B5BE:?D=:CB>FHAKTFUjUe~eqlrwuwo~_j[eX[WWWQNDA3:(;(<*=*?,@.@-?-=,;,6'6(6*7-7-8/91838495:693616183:3C<=670@7[Rlc]T?63)2)2*/)*&(%(&+(-+0,2+1'0#1"4$:(;&<(<)<*:,9+8,7-@881GAc^XQB<@;4*:&<$<&<&:(:+<0>2>4C;PJXROJ?:?:HDHGGEJKPTRWNVKXL\RfOfKeJfMlQsRvRvXwYvYu\x]x[sXnVjeuYg_m^lIXIXTeXefggeˎ赲C?6B>3A=4?;2=90;7.:6-95,73*73*73*84+:5/=82@;5D=5H?6LB6QE7TH8VI8WJ9YK>ZMEUJNWQ_eby{ɔ⛦뢣㘘،ɀuqiec^`W`V]TVPtMIbFCTBAIAAC<<:AB=FEACD?A?@DBEOMRXVcfgtt}}||q`uYkWbQXIG@99<7<7>9B=C=B[O@66,+#)#-)/-,+((0.4/616.3)2&2%6&:';'<(:(9*7)5)4(9/5-=6PJTQLHB?1(;(=&<';'9(8(:,:/>4B8OFWPRID=C;HCLHJFMLSRTWPVNVOZVfUhSiRkRmSqStSuLlTs\y`{[uUnRiTeWfTb]h]hR^Wc]iV^`_\W}کEA6EA5C?4A=2?;0=9.<8-;7,84+84+73*84+:5/=82?:4C<4G>5JB7ND8RF6TG6WG7YIBZEJpW]cssz{vpcTnG^L\IR=>60:+=)='<);):);*<,<-<-<.6*8.<1?5A8>7<3:4714.3-93A;E?B<=5<44,4+7-2', 6*G:K>@64--),*,,,,*,*)/+2.5.4+1(1'3'7(:):(:);*:*8+8,4+<4:5<7ONYWEE3/;,<(;*:)9)8(8*8,=3A6JAUKRGG>D:G>KDICLISPSTPSMSNWXdZh[pZrVnRlQlQpFjOtY{ZyVqTkWk\mYh[hbmbk`ginjm^_]W~MFlf×߹IE9HD8FB6D@4B>3@<1?;0>:/:6-95,95,95,:5/<71>93@;5E>6I@7LD7OF5RE4UE5WG8WI>XMKXNW^Zqppԕ革ꗖ⌋ׂ}yumpgf`_ZYXQQuGGcA>Q=5DH8BT=C`@EnCJOU]dgxlnoiaXxIg;U3HAPEO<<81@2A,;$6"5$5$5&7(8+;-/?0@3@36*LBJE50GFZ\IKA?2F9OBPDH7/=6.=6.=60>71@93?:4C>8EA8KC8NE6QD3RE2VF6VH;ZMGVMR[Whlk~Β㚦铕⊌نу{umkde_aY[RQsNHbWFY_CQmBLEMMTU][bZhTpSvTuPnJcCY9J/?9EDMHK?<>6G:I4?)>+=-<->/?0B4D7E:E9B7>5;26-5,3+3*1*4-7.90807/6.5,/&5+7+2#1"9)>-;)<-D7JAD?64*-*-/26755301,0*/,0-0+8191:1;2<0=0?0>17+WLaZ;6;:PQFHPQ<4:/8,9,:-<.;-;,:-<.A3H9I;D6@2>0F3;18/4,3*4+4,6-81<4=4<3905-5,7-.$;0=.1"-7&=):&9'8):/=9@@<>37,/,.+**)+(/,448899757473717-6*5(5&5(PEmcHA42CC>BVVA<>48.6+:-/=.9+<-?0A2A2@.=.<-C6D9H?PGRLOINLON^cagitnzduVjQiVoVsVqWn]nmxujsWb_m^m`or}΀|uhzjujXRM:aUGpgݿSM=RL4D=3B;3A:2@93A:4A96@;7A@;CC;IE9MG7OG2RF0UF1UH5WK?RHFXR^jg}Ēژ礧흤蛢晞⒚ۋ҆ʃ„ymczXiQ_MYIRAI>A>>A*9$2:&4%1'51<<=@7=37-1-.--/.439:;=9=2603011/1*2(1%3$1$=1j_TL95@?:=RSJHC=:36.8.;0<0=/;*?-@.?-;*;(;+<,>0>2D8LBPHNFLINLaeafhro{hxZkUj[r[r_sbqkt}vy\detk|bujwĔ|jiUIQSK>PJH@:C7F7J7J4G/C,@-SED<97>=DC@@8953C9D8C8A5>29,6)2'2(3(4*5,5.4.4.4,B7<16,6,9-9-5)1%8(1 1!9(8'4"7%C07&8*6,5.3/53:9?>LKHFBB>=<=7:26,1+1)/,./.1+4*5)7(0!.dY]S@:DC;;MMRQHE;66/8.9/;-:+<,@-A.<)8%9&<)?.7)7+>1G:K@IAIBJEa_^`djnwku]iXe^matdthpnrnspyxaqXfӭ`hPEQ9RT?kaUXO@WP@WN?UN>TK2G?2H>2F@4GC:GE9JG8NI6RJ5UJ4UJ4VK9XNDULMZTbkh{~Ñט禢줩שׁޘӦ˴ixN]FTAM=I=G>E@E@D=A==FB;4D;E<1)JEKICE>B;?;;<9B;?7D;MAK>=06)9,7+6,5-2*/*/+2/5.A58+1$2&9+;-7&2234!3"3"3%5'5)0&2)5)6*4(3&3'4)2)3.5233/2-2-4.5-3+/+,/-5.9,7(4%-3"XHYN;3NI41HHOPJJC@;6808,9+<+<*;(9&;(<)=)=+<,8,;0=1?3?3@4@5A7japic_mjqqadgmpykzhxgoeigjmnnomow{~_liwgpuapQJY:MQ8snZͶYPAXO@XO@VM>UL=TKC@DAFLAC5:,9+7*7+6-4-2.3/5384=2:-5)4&4'5'3"28$8"8%:&:+:,7,3*3.5-7+7)6&4"4!4"2$2&0+.,,-,/-2.3+.,-0.2.4*5'8'9'?.*D5>1F>VPB?BAUVRRKHC>=59.9+8(;*;(:'<)>+?-@/>.:,;0=0>1?0?1B3C5i\mdb[kfolbaklsxo~n|kraf\`cfnpwxuwy~Ydcpcn򨩲vk^rON_;SZ;us\ĸ\PB[OA[OAYM?XL>WK=VJ?>A>C>D>FB;?9<686696;6HA;15+A5K>H:=/8)6)7)7,6.507195=92*3*5*4*4*6)9*>,3!34!5"7)7)2(,%@;>8=3<.9)7$7"7#7%3$/&.'.*.-//./,)0+5-5,3&4%9&>*A/1 SE;0A;C?JITUUTSQOMJCC;<28+6&7&7%7&:'<*>-=,=,:,;/<.=/=.?0C4E7\Qg]aYlgpma`fgjqP^^kjqhmcgfioquwruouQ]Zham힡lz`YmHOd=W`Aww]\PB\PB[OAZN@YM?YM?XL>XL>UI;TH:SG9RF8RF8RF8RF8PF:LE;KGKDJDCEADABC@E>F>F?F:>?@EDA<61>:ZYAB@C=@:=8997<8A8E;:.2(/9(8)9)8.:/8091;7>80+1*3,3,4-6.8.;/6(:);+;,:.:0;685C@@<@7=19*9%:&;%<(7'1%1%1(3,1,/*2*5,7+7)5'7%;(>*;(<,^PF<3/.,@@WXusrojg^YPGA75(. 8'8(8&;)<,=-=,<-;.<..B3F7MA`Wa[pltr`a]a]dFTXeirkohlmpqvsvosgnJXRb]k攖jtYUjCSh?\gEy|_\PB\PB[OA[OAZN@YM?YM?YM?WK=VJH=HBI>@@?IE>82,C??=@@8;76715,4&5"7#:%=)8&4&5'8,:09/8->1;-8'7%9'<)<):(>-:*>2C:/-::245653;6C>KCQISHTHUG?0?.<,=->-?.?/>0<.<.<.=,<,=.A3D6LAbXc]nlrr`c`e_givmznvdhbfmqu{v|ks_jGWK]Zh≍sy]]rI^uIhwPfȿ㽻ݺ޼[OA[OA[OAZN@ZN@YM?YM?YM?XL>XL>WK=VJQI>QI>SK>UL;XM9XM7YL9XM;WK?ULGYSWe^nnjut~}ȋόԍՍӐӋʃ~x{rtlnohib{XxOqAf8W5N:HBEHBLBMBIEEG?I>JCHCCA>ID;44,I@LFBA?=;;<;@=E?G2A5A5A6G8A1;(9&<)=*<*8&:+7)0'C<2/?A/2*,1/5.81908.5*2&1#E5A2=.:*9)9+:,:,;/=0>/<.<+<,>/A2SGg^c_jinochjqnxn{r~pufkgntzu~nugpZfHYH[Wf܀kq]oZy`rխӧѨҫկֲں[N>[N>[N>[N>ZM=ZM=ZM=ZM=YLUL=XLJ@KBHEDG?I?JADFDA=HB:/7,OFB<=8641051>8E;F9D59(:(:*:'8%9&:':&9&:):,9+7+5+3+3-*+*--3.4172738587;7<9>8A8D7F5H5E*5-2124/6-8*;+=,5&8*;/=2>4=4>5A6J0/..46663-7.90:1;1;0:0;/L?F:@19*6)6(7*8*;-=/>0=/<+<+<.=0KAdZc^kiosinrzuepoytyosovxt}eobnTbH[DYQav{zk{fhṷݿԶˮǤÔɚ˞ˢΨӱٻ[N>ZM=ZM=ZM=ZM=ZM=YLVJ>XL>YN=B;E?FAEBCF?H@I@AGDA583/,*&/*:3C9C6>/;*;)<):';(<);'8%5$7%8)7*5*3*3)2*33688<4:-2(-(-+1-3)0&1)6,?*A 9/"0(.,10/1,3+5)6*6+90=6>7:4715092H=KYM=WMCWLHXNOZPX]Ub`Yi`]rggjmprrtxw~Ɋlj~~xpprjZGRB<>DE><>:>=A@CCDHBICH?>@9?6>3,7%:'<);(9%9&:':(:'9(6(2$."/%7.=593611.++()&(&(&(&*!)".'7)>!;61%6"+"*+---*',(2/6264666512./,,/,92:191SK"+#F>.&.(<7E@:7/*.*51<7>4<.5)3&5*;.;08.bXZOC:6,:/8-3'6*0%2&2&4%6':*<.=1:0C;\Wppsvx|yq|zwu{vzt|r|kxds^nJ\E\F[FVgkzm}f~cjw|vzqyo|rvuwyç͹˹ZM=ZM=ZM=ZM=ZM=ZM=ZM=ZM=XK;XK;XK;YL]P@[OC[NFYNJZPQ\SX_U^^Xfa]tedkinluqzċď}tlosgV}=E7.6.=5A;?:@:A===;<<>>ABEBFBFBC<7=4<1;/:,:+A5JAG@A=6351@9C89+5#8';(=*=*;(;(:(9(9(6&2%2%5*8.80912'1&/&-',(-*.,./*-%+$.'7%;730/-82;)0'+-//1*-:>7=4:26/40325872-;582E?E?/+2."51?:E@=83-2,60:1:.9*5'5(9+<0<29/cYXN@84+91:06,9/5+4*4*5)6)5(6(6);0B9YTljqtx||uzww}v}u}o{hvaq]nK]D\F\IYfhwobu\x]ckppmp]l]h\g^k_qeyi|ktv|}Ƿȿüμŵ\L<\L<\L<\L<\L<\L<\L<\L:>:?=B@EBEABB?;4909+9*8(9*?3F9674;7C=OEH<3#9(:';)=+=,<+:)9)7)2#/#4*=3?6914+6'6&2%0%.%-&,(,),-(+'/)6%:733%7/:4@5@9B:C5>-726;3=6=8<7=6<2;19.6*6);/@6TMgeorz~{zyzyun|cu\oYmI^AZF\LZaazeZnQhOmRtX{]}^x\qX`zM_PaUeYn`ug}jmrtxyyz~ĺȹƷ[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]K=]K=]L<^M=^M;^O<^O<^O<^Q@^Q@]OB[OC\NE[NF\OI[OO^P_bTmdY{g^ohzu|{zxtcMlHRCBC?F=IEAHBDA@@;?6<19+:*9)8*>0D:<731;9A?D?SLUJ:+9)7$7%;)=,=,9*8)4&2&2)9/>7>65./&6)7)4*2(.).),),+*,',(1*9'<";=%A8J(6,:MY]iNZ;GD=:<9:5807-6*4&3#5#6$8&;,9=9?9@8?5<2:.9-9,=1NHc_no|}vwzzvm{bt[nThG\=VDZO\[ZhRomG_sB\yCdzIl}PtVvXrXoWmZl\obuh{loqpqtuvvvwz|{|ŸƸ[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]L<^K<^K<^M=^M;_N<^O<^O<^O<^N>^N>\O?^NA]OB^PE^OJbNYcPdcTqeY}lexrwv}‰΂wlYwE_FTINMNLHG>EC>BB?C?GAJDIDFB??9A7=/:+:*9)8*;.?6FA=;BBAA;6JBXLK>@28(3#8(<-:*7)8+0%3)8/;4:5600+,'0+2,10203536585:.5-6/=1C.F*G,N4R:M3?>K\ihvUdCS@R3D3A3>6<99834*/$2*.(72YT\ZXVA?HFB@<7706-8-9+7'5#8#9$:(=-;,6)7.=5NGEA501->9@:815120215283:2:/9.:.6*8+IB_Ynl}~t|v~z{tl|auZpQeH]>VEZS]VR[Bbb<\p?[vCfyKn~QtVxZy_wayexhzm|qrrporttttrtw{xxZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:ZJ:[K;[K;\L<\L<]L<^K<^K<^K<_L=^M;_N<^O<^O<]N;]N;^O<_O?_O?`P@aQAbPFeLPeM]aOebUsh`to{t}qvˌڃteuQd?P7H@NIQGJA@B?6@5;-8(9(9)8*:-;3IE??=>782/A:ZPh[PCA35%6'9+9+7+8,0&6-;4;440/,-+--484;3=2<1=1=0<1>1A2B5K5N1N.O1X>_3HN[_l\kTcO_DX8JAQ:G2:/22-8-;+:*:/2(JBkcLGPK;9;9LJ@<707--9)3':/D;GAC=722.;7:62.2-,-,,./3171:1<1>26)4)B:XRjh|}u}w{zriy^sYoOcK`@XF[U_SNyT:^`8`sEa|InSvY{]~`gll}m|o}ponllqqrroprtvtwįξʬZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:]L:^K<`J<^K<_L=^M;_N<^O<^O<^O:_P;`O;aP>aP>aP>aPK/B7KAO@I?CBBCCABAE@E?FAFCFBB@<>5>39+7':)<*<,=1?7=:9903/24294MElah[QCD>63;7UQF@918-:,9(9(=)?'<&;&=*7(3(=4LFGAE@963073510+1-,/+-./1/4/81;1>29.3(;2NHa^yzyz|zo|euZoVlK`Ja@WEYT]MGpM1\^6_rDf~Nu[chjnsttr}pnmllnnoolknrttwǯϽ̼ɥ[J8ZK8[J8ZK8[J8ZK8[J8ZK8[J8ZK8[J8[L9\K9\M:]L:]L:^K<^K<^K<^M=^M=^O<^O<\O<`Q>aR=aR?bQ?bQ?aP>aO;bL?kMKjLTeO\dWkkexu}|xzƄ~uzmoZ[FL4E:N@Q?LAJEIBF<@?D>C>C@ABAA=>8=4?1;+8(<,?.@1A7C=7485..30:60'5)UGwj[PC7<0;07*6+:0708263320112365<%5#8"8!8 75452 9'B)G'J)M5\Fh`s^jUbP]P]KY>L0;=F6;/..(4';(?&=%9'8+VJ;2?8412/C@WSHA916*6(5%5$:(<(:&7%9*4&1%?5RJIAHB;62.411/-+22,/+.+-++-*1*4,8,=12(7.IB\Xww~}}wkz`rWlSiD\G^;UAVQZICfF-X]5Zm?b}Jt\glnrvzwr~m|i}ggikmmlhijosrxƩ˵¶ğ]K7\K7]K7\K7]K7\K7]K7\K7^L8]L8^L8]L8^L8]L8^L8]L:]J<]K=^L>\L<\L<[N=]P?^SA`SB_R?`P@bQAcRBdQBdNAdLBkKLhKPeO[f[lnkx{Ђyrsjfa`MWAO=JBLEOAK=E>F;B;?:=;:<9;6:09,6&A0<,6(A5F==57285715.6-8*<*:'6%;0SLZOE98*>.B3:-2*GB//6;7>-8BM(3&2)2)2'"*'/'/&),7!.&7,@!9Vp+B\l^iYcT\OWGM>@64=7@7>16&1!5#:';)8-7/E?;7316454DCLHKED;:04)5(4)5*1=3_Ysqxh{_t\sVnMeHc[BY^i?;\C-S[6\tBgMw]}cgjnonm~l}i|h}feflmlk~gfgimrv|¤|]K7]K7]K7]K7]K7]K7]K7]K7^L8^L8^L8^L8^L8^L8^L8^K:\K;^L>_M?^N>[N=[N=\Q?^RB_SC]QA]OB_OB`NDbPFcOHeMIiLNgNTeSag_tnoy~ǣxy|}uoid^cQZGRJSLVGP@J/8(8);.:3IE017<6A.aP@`P@]P?\O>[O?[RC[QE[QG\OG\OI_PMcQOfTTgTVgTXgV`h\plisv|ɊΘҠĪ}π䃊~zsmfiU\IQHOIRGQAK=E7=7:89<7?7?4=0=-=-<+:,B6H?;20):26/6.7,8,7(8&9&:*4-4.A9OCH:5%2#@2>5HD025;6?1=BP.;)0#&$'13-/''&%12()79*0(0295,>2A5<17-1)+#& $/*EC::,,35AB^]?:C;A9=39/=4@8@;@<=;>;A?>>::?=IDB9<45,2+1-311202020201/00.1-4-9->24%8+;0[Tzw|qdxZrUoOkIfA_?\GbTg@Hu83XF2U_<_wEfNrZu^t_xc{g{gyfyfycxbybya|bzczf{h{h{e{a{`}``jnstwuynolQcW@OL2A>^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^M9^L8`N:aP<`Q>]P?ZN>YOCXPEXOH[QO_UTbXYeX_iYcl\fk^hl`llctokrty~ȅ֌܎ԟЭ³y{ށ|{ttdgX\OTIPDM?G-=0F:RGH?5.1)9181;0=1;-6'6&8+5-2+=4NBK=:,8*B66->:/0052:4>JVFO>E38$&/1,,22**/.9926+18?DLWbKUA9=897897838192@:MHUSMNB@7295KIMLQRYZRQYV51>6B9@7?5B9C<@;?@8=9=?C:?58>=MJ93603+3,4.30210102/201/0/.0-4-8-?36'5(9.VO|yyn~cvXoPjHfCb=\B^MdZh25k90\M8[eCc{KjPsYt\u^wbyezfwdvawav`x`x`{azczfzgzfzbz`z]|]~_gntsuqtiidPbTCRK8G@^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M9]K5_M5`P9_P;\O>ZN@XOFXQKYPQ`W\g`hnfsshysg{sg}qgolpprvv|zЄ܊ᓎ֠ulnsuovksmmlhi_`SWGM3=16*4'6*3,70=5E9F9B3A2>20&720/-0,23;LTW^Z_OS.103,-EE66,,,-=?1426bh=B)1-4&*;=AE7:379=7;/043;;GFSS`cilek^a@>E@^[hgopjjKK=;40>7D5<4:1415;-7,6.8,4,390`T>cjIf|MkSt\u_v_xcycxbu`u`u_v_w_x`{azbzd{e|d|`y^yZ{\}^agmpsr{nrjdwd[k^QaT_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N:^L4_N4`N8^O:[N>YOEZSMZTT_Zahbprmzu{u{qzpvpqtrwt|wz~τ؋ږڙɛ~{k]R@NBRIXRXUTRKM?C4:8<9;:9=8@8A6?0>/9,A65+.$I?g\dZUI<26)3):0;06,3)6-1*71;29/>0F5B39+0'4-31-.)-/5BGRW]b\a9<9<+,JK89//35'(%)WY=A9=6:#(+=>BE59,21705).47LNbeindl`i`lbkLLNJ\ZVTMMHF423/ACJJ1.3,3,5,4-4/4/3/02/2.1-0../-2-7-=1;-1$7,C=yv{qhx`rSkEb:\7Z:\HcP`JMf4+YB0_W@cjIf|NkRt[w_x`{dzcv`s]r\s\t]v^w_{azbybzb|b{_x[xYzY{Z~_ekmsus|rupomgxf_P=_P=_P=_P=_P=_P=_P=_P=^O<^O<^O<^O<^O<^O<^O<_N:aP6aP6aO9^O<[OA[RK\VV_Zakgvso}z~|}w{uxvsys}x{~ĄȍΔ͚ƠɭŦmgLF2A4A4B9HDNNJK?C=?;=;;<:@8?5>1<0:0?64,1'I?cVh[eWOB>24)7,905,2+600,4/7/7.>1C4>04%3)/*3/..-.0367@CMRY^FKQW37FJ8>A7<.6*22;=DMS_emsjsaj[gZh\fddZVWT@=104433C@JERKSLJA?7938133.70>0=*7.:;ECHAB1/4-4-5,4-3,4/4002/2.1-0../-2-7-:/>01%7,;5sqth|at\pRjDa7]8^=_NfQ[}96^<0QD1[V@]dEewMjRr[v^ya{dxas]pYpWqXqXt\u]y_x`x_y^z^y\xYxWyV{X_dhloqmxjphleey`_P=_P=_P=_P=_P=_P=_P=_P=^O<^O<^O<^O<^O<^O<^O<_N:cQ9cQ9aP<]P@ZPG\TR_Zaa_mtryx~~yyyuwww|x}ĂąȸоѻЬoT\GG5>0G?WQWVNO@C=?<==;=:=5;19080<5:3=5OEXM]OeXcUL>:-8.914-2,60402-5.<3C7C4:-3%4+-%0-0-4265./24BFX]W\ouDJHMHK;>8?>F8B.8@J_gnwkrdn^g_kco_nZe]]PIJG74/0540.95D?JDIA@86/4/7166'/0<2=+60:>E?A443.5.6-4,3*3,4/4101/2.1-0../-2-7-9.?20%6,61poncx^qZoQjCa9_;`CbTgRWb0'YD3JE/US`P@`P@_O?_O?_O?aQAbRB_O?]M=]M=aQAcSCbRB`Q>dS?aP>]P@^QI[QPZSZeapsqyxz|~}xzrslotwv|ʀʋƖäŵ̰Ϭϥϣѡ˜˜Ѩg]FzgteH?QNccKL?A99;::97561;6815.B;<3I?XKOAdVcTXIG9:/6-7/6/4/0-2,70=4<07)5(7,/$/&/)1-2040516479JNY]NS8=6-92>>HU_aihrgpdmdnao^gSSF@854111/.3194D=B:?7<4908193667<4;4;4<6;59331/3,5.7.5+3+2,2,201203/2.1//0.3.7.?58,6,/&;7XW{mf|]rQhHeDe=d;`OlTd=?P, E:&DF.MM5Z^C[iEcxMqZxbx`t\rYqYlSmRnSoTrXtZu]u[tXtWvXwWvWvUuTtS{[{]z^u[mUb~MXrCSj>?U.?U/>T.[K;^N>`P@`P@`P@_O?`P@aQAbRB`P@_O?`P@bRBcSCbRB`P@fVG_QF\OG^TSaZad`omkvwwy{}}x|qukplonquw|~ӉјΨǸźα֬ۧާݤۤأўǚԼ|dNJw}mVJ`[rpZ[KL?@>>?@;;6664=883?86.>3K@H;]Mo``QH:5)0&6-5-0)5195=7<38.5)4*5*7.5+2+0+0,2,4.5287>@JLW[^b\d]eaiOWJRNV\dhoekY_OT5:-5,6/9(5"-)69CQZ\ddlemfnem\hRZEE<7646355302/62>9>7;4:3818295:69;7:7:797965312,3,6-7,6,2+1,1,201203/2.1//0.3.7.<3=28.1*74Z[s}gz^vWoPiGfAb=cBcQhLVw<8L2#>9#=A(GG/PS8XcA`rJnXu_v]tXqVpTkOkPlQmRpVrXs[sYtXuWuWuWtTrQqRpQnPlNhLbFXu?Ni6F]/@W+@W-@W-@W-YL<[N>^QA^QA^QA^QA_RB`SCaTD`SC_RB`SCaTDaTD`SC^PCbUM\QM[QRcYbkdtqmvuy{y{y~x|nsei`gjnru}}Շٗ٩ػۥϠĚkpn`QG]Umiuu`_JLBDAD>@9:66=:;6A:707,>3=/F8j\i[[MB62(4+6-2,52A>GC=62)1'2'0%4*1).)/)2,7/=4B9-(43DCVX^bZaS[Q[EPFQMW[ektmsW],9(47ELWJSPWW__fdkaiRYCI977175<8;;955160:3;290907183:6<8999997988874402+6-7-8,6,2)0)0,10121302/1//0.3.6.90D9804./._blwcxXsQmNlEf;]=_JfUgDJk<4O>,><';?(FD/HH0Q\U'C]0D^1E_2WJ:ZM=\O?^QA]P@^QA_RBaTD`SC`SC`SCaTDaTD`SC_RB\PDZOMZQVbXcjcsqmvuxzz|w|symrbi]daglrx{ʉݕᤢᶵ۪ӧÞvqqcbWh`qmvt\]LNEGAD=?<<:8<8E?C;:0:/6)1#I;aRk\SE:,4'6+4-42MKZXKF803*4+2(.&,%,%-%1)6,;0?4/'4,:6CBFHEIGNMVQ]VbWa[dfoksV^8=27/4.6+4%2)4>IS_?IAIGLQVZ`X]GM685373;8@>@?=;957282918080717396:7:7;9:7:8:6845.3+6,7-8,6,2)0)/+0/222312010/0.3.6.8/F<913.,,fjygtdyVqLkHj@c7Y?^RhYeCBeC7ZO;HF1AC-LG3FD-LU6Sc>btLlUpXnRkPiKgIhJhKjMkPmToWpVtXsUqSoPjMgJeHdG`D]AWy=Rq8Mi6Lf6Ne7Of8Mg8Nh8Oi:UH8WJ:[N>\O?]P@]P@_RBaTD_RB`SCaTDaTD`SC_RB_RB^QIVMR_Xhnf{tpxtxwxzy{syjr`g[c_gjrv|ƀΓߞ୮份޼׶еƯy{qukrimeoi扄~trfdXYONEEA@:7;7B=E?<3=3B51#0"I;XKN@=/8*6*3*42UUkh]XD>;3;2804-2,1+0)0'/$/$0#9,4'3):5CAEGBG@HEPP[VaVa]hemW_?D;<5738282=9CHSV_5?3;6;ADJOHM;A135195<8<9;9:77370;2;1:09082736475:8;8:8:9;7956/3,7-8.9-7*3)1)0)1-323322011/0.3.6.7/C:701-13jpqzgt_tRmDf?d;c:^Gd[mV[wE>dJ=aYFTO;KI4PI6GE.GP3L\8ZlFf|NmSmRlMhJfHgHgIiLjOlSnVoUtVsUnRjLfKcHaF_FZBX|?St;Pn8Ok:Rl=Wn@ZqCUo?Up=Uo?RE5UH8XK;ZM=[N>\O?^QA`SC`SCaTDaTDaTD`SC`SCbUEaVP^Vcje|yu}yzyxyvyswjrcj[c]ehpv~ǁшљܣݯ⻿þź|yt|tqxkekenga[`[smzu{~yspdcUTIGD?>:<6A;:1C:TJ>26)9,=.?/B1C5@17-2/LM_]WSD?:48170939292:19/9,8+8)(3"@2I>D@;:7;:@9CISV_Yb]f_hSY?C@>?;@CFJLTQYT]U^3:.5.37:a7^7b@dOi\iGFjF:]L<]VCXQ>QJ7OG4ID.DJ.GU2Sc>^sHgMjOjKgGgFfGfHgJiNkRmUmUqUoQjNgKcH`E_F^G\E[~DWxAVr?Uo@YpB]rG^uGZrBXs@Xs@NB2QE5UI9WK;XL\P@^RBaUEbVFbVFaUE_SCaUEfZJh]Yngwup|x{ywxvwpujoah^f_gempx}͉؏֙ҡҪٴ޺̼Ļuoqwnoseezfemj^Yc_ZTg`un|v}wxsjf\WSNHB=6D=;4G=\R;0<07+6(>.D3B3A1A386>>CCB@=7817/7/:393:3;3>5A5E8G6-;%J8L==50+009>AJLUVaZe\dYaLR>@4/5/99?@BHDJ@I>F3;06167<6914-2142095740.,*0,3.3,=5=4=4<3:59565655757576866542.1+7.9-:+7*4&1&1(1,425342211/1.3.6.;34+:520UXpxcnZiK`Hf:b1]6bChMePYj5/^G7XK:UN;YQ>UJ8L@0ID0@F,AO.K[6Xj@bxGfJhIfFeDcBcEeHgLhOiRkSnRlPhNdJaH_F_H_H_H_H]~G]yF]wH`wKcxOczN\tBZu@Zu@JC3MF6QH9TK.E6>-2"7'E7E?973.50;5=5<4=4;4925.4+5)8+<,?-S>G2<):-=2;57443KNLQPUTYY]VXMOC@4+6+5/42141608.63>2;4?8B3>)5(3.9-35759./*+0.515/<4=4=4=4;6:676664635253455411-0(8,:+:+8(4&3$3&4*5052423/2/2,4,6.=4/&>945bgpy[iPcF]Hh=e2]7aGhJ]BFS+#XH8TK:OH6YP?SJ9E@-GF1=C'@J(IU1Sd:_rEe}IgJeHcCaBbCcEeHfMhPiQlPkMfJcIaG`F`H`I^G^F_}G`|Ia{Kd{Mf|Nf~N]xC\y?]zBDB6FD8JF;PG>RH>WI>]M>_O?`Q>aR?`SB_VGbYRgb_ojnso~wqzt|yywppgg`a\_`bfhopyz̄֍ߖ眙蠞ߡڣۤܦܥۥؤեңϢɢƟ|qo|hglc_`fZZlYUsVPUNVORIYPXP[Skdzr|uqus_]PLEAZT712*6*7(7'7&9(;+<.?18.<2?4;05(3':/@590907.7+7):*?,A/=.@4E:G+?*?)?'?&?$<#<#7&8*;,9,6.556<:84:3;4;5:595735435465454535/5,5)8,9*9(9&8&7%6%4&5-4/504.5,5+6*8,:07.:5>@mubqUjKcOi:Z9^?g@cPkIWa$#G+ A8'KD4RL[K>]M=`O;`Q<^SA^VIc[Xhcinlysotpvptppmgfaa]^\\edkjtr}{φٍ易囕ݜٝڞ۞ڝٜ֛ӞҜ͜țƚysm{keid^^e[YkZSqVM|TJTKTK[RXRXRfarjxo~wusgdUSZU2,/%7)7&7%8&8';*;-=/9,9,:,:,9+9+8+8,;1908.8,9*9(:&9&6*80=5@8A9?7<4914->6H@OGQINFC;7*7%8$7)4,//+3)7(:+@*A)A&A#@!<=:98$:);-92:7:<<94:5;4;5:595735235465464716/5,5)9*9*9(9&9&8%8%6%5+3+4,5*5*6(7)7*=14+53TXfr[oIbLhEc@_8[>aNmLb8@Y)%E3'<6(>;,C@1CB0=@-8D.:I,_?bB69.:<1??7DA:KB;OE/>/6(/":.8-7,8,:+:)9&7$5)6,8.:0=3@6A7B8:1@6E;FG=@67+6%6&7,4/03-5+9*<';'=%=#;!:77675#7*;2<7>9<;;94:5;4;59585735236475565616/5,4(8)9)9'8%8%7$7$6%5'4)5*6(6(7(7)8+=22*86lp]lQh>[Kl;\Bd8ZAbWq@Re")Q.*A4+45'56&:;)?>*>=(<@)>E&>FXa4s~Tdw`hSa}LaG`C`?a@c@hEjJkMlNnMkHhHgGhKhKfLdJeKdJcFdGfHfGeFbBcDeEhH25*58-;<4A>7G@:KB;RE.>.8(/!6)5)4(6)9+<+=*;):-:/909/:1;1<3=3D9?9;9894:5;4;59585735447476665726/5,5*8*8(8(8&7&7$6$6$5%6(7'9(9(;(:):+;13.IJowUhE^>_Cf7[A.A@+?=$A@$EF$T]0p~Mr|mjW_{J]~E_Ca@bAfCkJlLmOmOoNlIiIhHiLiLhNgMfLdJdGeHgHhIfGdDgHiIlL-3'36+891<;6B=9G@:MD=QG=SI=SK>UNDZUQa^eigumklkjhb`XVPPQQXY`cfjorux|Ђֆه؊ً֋ыΊщ҉҈ӊӉό͋Ǎ~xnZh}TZlWTc\R\`O[_HfZDzSBJDSRSWRY]dfjllvqunoh~v{~l`?28(;(='='<';':'8(7):/8.8,9+:+:*9)7(9+7+8,7+7*8*<,>-<0=0<2;/:08,7-5*@7@5=49.80;1:25,/%0)2025/8-9+;,<-?.?/@/@/A/?-?.@(8(7+70:6=8=885494:5;6:79585654448485676726/6,5*8*9(9(9&9&8&7&8&8%:&;'=(=(>*=,=.7/<8]d`oPg/=PJ(^\5ySlwo[aK^F`DcBeDjGoNpPoSoSoNlIiIgGiLiLiOhNfJeIdHeIgIhHgGeDiIiKlN+1%.4*470893>:7B=:HA;KD18*4&8)<,:,:,;/;-:/9+5+5(6,;/>4?3?6>37.,#+%-*02391;0<0?0?0@1@1@0=/<-9,9*7.;.:0:3:6;7:665394:5:6:79585654459596776746/6-6*7+8)8)9'8'8%7'9%9$<%=&?'@(@*?.<071HHgqNbHd8ZBl1\9`7WSjWfk29G)+G7:;23830:709;-5:#38BDfc:TwΗǓ}vbeQ`F`BcBgFmJrOrRqUpToNlKhHfFhKiLiNiOgKfJeIfIhIiHiGfCjJkMnP(0#+1'/4-350764<85@=8C>8IE4>1>0@/?.$?%@(@*>-;1:6U[^oGa>_:`8f5b:_GcP`@HT23C54D9=>37B36@51:8+6<"9CP\.}PqŊˎ̒Í}{egQ_E^@c@iDoJsPsSqUoSnNkJgGeEgJhKiNiNfKdIdIeHgJhIiHfEjLlNoQ&.!(0%-2+13.331764:95<;6GD=DD*;'7$4#B2OAN@B47)7)>/;+:*8(7'6'6(8*8+;.;/9-6*7,<1<271888=:A9B4A/<,;,:/;19384857563657265:8;69454476<:869796:7877767465:5:7:8995827/7+8+:*9+;*:*:(:*;(9":"=$>%?(?+=.81<>]fQgHd8[?g.\>h=[]oLU[--G83FB?@7:C49G06F21@9)?D&EV*`t?aˌɋËz{efPZ|@^?a>hCoJrOrRpTnRnNjIfFdDfIhKiNiNfKeJdGeFgHhGhGeDkLmOpR(0!'/"(-&).(.0-3317839:4==5?@8DE@JLKORYVXeZ\s]^}YX[Y^]eennwx؄⌌솇䂂܀ւӃ΀ƁŃɄΆЈӋҌϊŊ}xwozkegf]Xj\Ql\Mh\Lf^Ke_If`Hj`Gr^FrO;TA\O`YYXQTS[\`heYPD<707/:1=/;+9(:&9(:)8)8*5,5,/%3)8,>/@/@-=*9'9)0"WJK?/#=12<07,8->4C5;687899:97877;=<<::8785747575979899::9;9<9<8<7;6:8:9:;9;5907,8+9)9+:):):(;*<)9#=':#49%D3@61,_eWgKb=\3X2Y8cEi[oGQn43N3,C?6ABcAiDnImLlNkOlNiIfDcBcBfIhKfLdJgMhNgKfHeEfEjIkJqQqRrS*0")/#).').(-/,130561782;<4>?7AD=HJGOPTSUaXYkZ\u\Z^]dbkjut~·ߋ鍍년 ؀~Ҁς̅džLJɉ̋ό΍̎Ȋ|x{stkplb`d]Sc`Ob`Ke^Kf^Ki\Il]Hn^Gq]Ey]GYCXFZLVPSSRXY_USLE>9606/909,9(8&8&8(8)7)6*4,5,0'5)9+=-A/@-<*9(8)<.REH<4(:-:,4&=,<+;*;*:)9)8)6(7*8,7,3)1'1(7.<5DG8>/9/:0=.;1<6?5:3622:8EBIFDC?>:7989796858598988788999:9;9<9<7;6:596888;8:59/7+8*:*:*;*;*<)<+<)9$?):%5:'_:2H:/;=0;=2I;:U==Q/.T7/WK5dhEw[p}ǁ}xr^YuETp=\{B_@b@iCmHlKkLiMiMgGeCcBcDgJiLhNgMiOiMiKgGgFfElImLpQoRrS-1"-1#,/&,.)//-11/34/45-9;0<>1@B7EHAKMLQRWUUaVWi\Yt^]fdpnzx΍ߐꐎ튉燄߁|}ȀÆĈĊƌnjɌŌ|v{pujrndci^Xc]Q]bL]bKa_Jg\JmZIp[Hr\Gr\Ez`I{W?R=UDXOVSPTOS><<784716/6.7+7(7&8$8&8'6)5*3,5,3(6(9)<+?-?-<+8(5'J=F:A584627272728596;8;877888:8;8<8<8<8;58475777:7:48/7,8+:+;+<+<+<)<+<)9&@*9$6$;+1'40PT\iK`;U9VA]IfKdOa89f>6U?2G@0;<,86)A4+N7/H+#S<,g]B_t{z{xm\uKHb5Nh8[xB_}?c@hDlGjIhJgLfKdDdCcDeFhKkNkOjNiOiOiMhJgHhHlKoMsVsWuX24&04&01)01+12-23.34.46+9;-;>-?A3DF9IJDMONRQWSS]XVd\Zoda~nlzwÌ֑㔑ꓐ뎋≅ق||~}{vynrfpmack]ZiZSc[N\aKZbJa_Jg\JoYKsYJuZIw[FvVA{Q;Q=XF[PTPGI?A2/5/51605.5+6)8)7$8$8&9'6)6*3,6-6)8'7&:(>+?-;+8)4'UI<18,B45%=+=+8(8'9(:)9)7)6(3'6*3)2)4,:3>7?9=:45596;5;2:397=<@UVbbmjidVQA<634/61717182859697:878898;9<8<8<8<7<5:686797<7<49/9,9*;*;)<)<+=);*<(:'@,8&8';-+"54agUdH\>U>XI_QdQ_UZwFA\F9OB2JC1FC0@=*=6#=2A2QF*nkHfttsx}l[K_:AW0Lc7Wr?_{@d@iCkFiHgGdHeJbBcBdEgHjMlOmQnRjPjNjLhJgGiGmKpOwXvZvZ78(68*66,56.56056067/68+;>-=@-@C.DG4IK>MNFQPNRRRVUSYX]a_lkius}njӕᔑ␍܋ӄā}||~zwszn|relm__j[XiZSjYOfZLa`L_aLd_Li\Kn[LtZKzZK}ZGTAQ=QAVFSHH@:8431-3/5/5.3,3)5(9(8$9$:&:'8)7*5,7-;+:)6%8';+=.;.7,90\T=55+A53$:(?+:):*:+:,;-:-8-7-3*1)1+71<7>:;77475;<8>7=7;7;797:::=:=7;2;/8*:*;*<)<*<(;););(=*8'9*8-0)@CirN^H[EYI[P^U]VWZUgK?SJ9PD4NC1IC-B@'?B#AG#MU.^g.==1==3==5;<4;=2;=/?B/@D-CG.FJ3KL:NOAQQIRRHYWJZZN_^\gerqn{yďяӍϊǃ~yzwyv{w|z}~}y|tzrvksrfhm_^j[VkZRlZPlZNk[Ng^Mf_Mg^Mj]Mn]Mv\M|\MYI^OUGM@I=@78.2+2+516/5.4-2)4'6&;(9$;$;&;':)9*7,9->,;(5#5#9)<.;/7-?7[TIA:0@36&3 <)9'7'7'7(7)7*7,7-<3:293<7>:=9854196<9::8:>@PPbcppheTP=61+40;7=:;7;5:294837373556669697;8<8>7=7=6:8<898:;:>:>7<28TXfpL\J]L\N[SZWV\RaRTG7MJ9SF5M>+?396AM%Nf6lTw\edfkt|mn}\Q`Cg{HiFlGmGjGfGbGcGhJlMoPnPlMiKjJjLsTsUsSrQrOsRwUzZw[u[tZRK;RK;RJ=RJ=RJ=RJ=RJ=RK;UNXQ?YR@[TD\UE\UEb[HaZHaYLbYRe][kaiqftuj{zn|pss|puj{mbre]jc`i`_e_]b_Z^^ZY^YUaZRbZOe[Og[Ki\Kk\Ik\Gm\Hm]Fj^HjbOreTqZJuOBWJ\PZL[LN=F4<,8(8-80411-6/7.7.7.7.7+6)7)8)8)9)9)9+9+8+;,;+>-9(1 2!9*H9=,2#PFJ@F=:7487::::977493=7E>A99/2(0&4);/?3:0=3@7@:>;<999::8:8:8:999797959540516576899:9:9;;>9;99=:A=B;A6?1:)<+=*<(:&:%8&8&A0<-/#/&LJmomoVZLNNOQMUOXO]RaTjSXY/=K8EVa)Poyxs~ahL\mCYdBT]BHP9?D0:=,@C2<@1:>0]sBgHpKoKlGjIiKgJlPmSoSlPmMkJmJmIqLqMrNrPtRvUyYz^{eo\eRWN?WN?WN?WN?WN?WN?WN?WN?XO@YPAYPA[RC\SD]TE^UF_VGd[JcZIcYMcYOf[Uj_]nbdpdhreltgpvirvirsfmm`gg[_bXY^[VZZRYVOWTKXTIXTH\VH^WGcZKcZIf[Ig\Hi]Gj^Fk_Gj_IfaMogTw[MSFVMXORJREI9C0=,9)8,7042306.8.8.8.7-8-7,7+7+7+7+7+8+8+8+:,<.>.9(1 2 :)>.<.:-4*4);0E:OBQCOCF?A;<5;4>7>8:6538788898887:7>9B:@7=49,4'4&7)<-@1@4@6A7?8:787768:6:6<7:89879595:592:3:5;6;8;89999:;;;<=?=A;?6=2;-;+=*=+<);(:&8%:%9'8)5*<5QPee^aMMNLTMYP\Q^S^S_VfQ`_/Sg*^r3zOn|pbjHauBTe;JX7FP7?H59?158-:^tEgHqMpLnHkHkLhKmQnTmSmQkLkHlHmHpJpJpLsQuTxXxXx^nYdSZI]TE]TE]TE]TE]TE]TE]TE]TE[RC\SD]TE^UF_VG`WHaXIaXGe]Je]Hd[Jd[Le[Qf[Uh]Yh][i]]j^^k__k__i^\f[YbWS_VQZVMWTKUQHRNCQMBSOCWQCXRB^WG^WEaYFc[Fg\Hi^Hk`JiaLe`MqeU{^PXN[UXQJEG@A7?10>.:(2 3:&>,>.?08+2(4*<0F9M?ND;6533052:7?<><<<9<6:37366899<:@:7-8+5'4%4%7(;+=.D5C6B8?7:484657969696977779595:3:3;4;6<6;8:999889:<<@>B=?9:17+7(;,<+<+;):(9&7%9&z6#y6%9,F=SOWTPOIFMHSLYP^SaWaW_VePsrFzVn{|[[oaXIaXIaXIaXIaXIaXIaXIaXI_VG`WH`WHaXIbYJcZKd[Ld[Je]Hf^Gf^Ig_Lg^Of\Pf\Rf\Sh]Wh]Wh]Wh^Ug]Te[QdZPc[N]YMZVJVRFRNBPL@PM>TN@UO?WQAYTA[VC]XDaZGd]Jf_LfaMgaQocUw[O[Qb\[XGD=:=8<6:09-8)9*=.>/9-7,8-9-8-8,8,7+7+8+8+8+8+8+9+;,?1>.9'3 38"=)@.?-:+7*5*7+:.?=>8<481625688775713(6'5&6&6&8(:):*A1B4B7@8<5:58687687878868694:4;492:2:4;7:8:89799<:@3B%:F.=F3;A3:=2:=4<=599-?@2<>39<1<@29B/?L2PbNK:NK:NK:PMTQ@VS@XWC[ZF]\H_\Kc`Qi]QpUJ[Ricd`OMCC==:994808+<)A+A+:+7)8*:+9+9*9*8)8)8)8)9)9)9)9);,?1>0:(6"47 =&B-;*;,:,9-8.:0<0;4:<5<3938585848356<594:8:9<86310(5(9(9(:(:(:(8&7&:+;/?3@7>8<8:6977666667484:3:3<3:2;2<5=7=:><=;>=@?1;=28;0;?18A.>K1Pb9780:.>+B*@(;*7(8)9*9*9*9*8)8)9)9)9)9)9)9);,?1=/<)9$65;"A*B.@/;,7*2(4+;0=86:4<7=9>;>;>;=:<587:9>=>=>:63/0'9+=*=*>*=)<(:'8%6%8);0>3=5<7;8;787757585:4;4<4=4>5?7A:A;A>A?@=B??:@8=38-5(5'8(<*<(<)<(:&9'7%6$6%}:)t3!~9*OAYNRGOEVJYN[MZM[M\Q_T`WgW~xXy^r|ZU`B;E,/;%0;*0<.3=24<16<2?1:<17:/:>07@-=J0Oa;bxIkLuQuQtNqNrSpRrQsPrOpKnJpLsOvRyX{Zz]x]qWgO]EXB_MW~GRyBg^Og^Og^Og^Og^Og^Og^Og^Og^Og^Og^Oh_Ph_Ph_Ph_Pi`OjaPjbOjbOjbOi`Oi`OiaNiaNiaNh`Kh`Kh`Ih`IhaGhaGhaGf_Le^Kb[I\WDWR?PM:LI8IH6IH6GH6GJ9GK:HL;IM-@*<$:)7(8):*9*:*:*:*9):):):):):):);,=0=/=,<)8 49 A)C-A/=/6+/%0'6.:8596>;A@CBEBC@A??2276:<>;<9815.5)<->+>+?,>+=(;':'7%8'8+9.80:4=9?;:79595:4;4;4=4>4B7C9C9<3:/8+6(7'8):):(=)<*<):'9(7&6%}6$x3#x5%B2UEWKPCPDZLYMZN\Q\Q[T\U[VbUkbEV`=JS4=G,6?*2=,4>35?66=68?8=B;CF=EG/;9*78*=>0:<17:/:>06?,=J0N`:awHkLuQuQtNrOrSpPqOrNqMpLoKrNuTyX`~az]qUfL_G]E^IaOYIRyBh_Ph_Ph_Ph_Ph_Ph_Ph_Ph_Pg^Oh_Ph_Ph_Ph_Ph_Pi`Qi`QmdUlcTjaRi`Qh_Pg^Og^Mh`MiaNiaLiaLiaLh`Ih`IhaGh`IgaKf_Le^Kb[H\WDUR?PMTPDUOAYL[SSOFE;:75;3=/<)7":)8'9(;*;*;*;*;*:):):):):):):);,;0:.<,>+9#37?'9#;)>0<18.7/<5?==B?DCEDC@?;7501.0,61:6<6:29.8,:+=->+?,@-@-@+>*=*;*:(7(6)5+90?9C><7;5;5<4<5=4>5@5D9D:C;A9?:;685937-8(5'6':)<*:)8&=*<+<*<)~:'|8%{6&{6&y1#8*G8SCPBL=RE_SWLYN[R]T]V\VYT^QaX;EM(6@8A&>G26BE*;:&78(=>09;069.:>06?,+?,@-A,B-@-;*:(7(6)6+8-:3<4=6=6?8A7A9B6@6@5H=E;A8;25/3-1*2+9-;*9+:*:););+<+9'}8(|9(|9(|9({8'y6&x3$w- A4OCMAL@QEUJRG\R\RUMTLZUXSWTgZ]T5IQ*AK(BK,>H/7@+2=-4?14<1HPCZ^PW[JMO:DF.AA'==%:;)>?1;=2:=2;?14=*;H.PbF7>F7=E6BF8AC5@E1HL5MI0RA'|R:ubdX`ZVTHG@>@=>9809+=,=.>-;-;+9+:*:,:+:,:+:,:+:,;.?5B:B7=/6#1125#6(;/A8E?IDJFKHBAEDB>;39/=0?1=0?1>2>0=/=/>.@.?,=*<*<+>,?+?+?,>,@.=-:,8,7+8-908/<2<2?5A7C9C9D9E8B6A4=3:06/5.4,7,:.=,;,;+:*;*<*<,~;*|;){9)y:)x9(w8'u6'w4$4'D7NCK?J>QDTIRGSJXOUOVP]XWRSOcT]W5Xc9_jBZfBIT66C)4@*0:<19<1<@25>+;H.PbMKD6=C5>E5:>-BG1IK3E?%T@'\Ct`WJdZebTSFHGHBD967+:*:,:*9,8)6)6'8+7)7+7)7+8*8,8.3-5/6-3(0"/1 3$A2C7G?LFLGJFFBD@BACA?:;13?3A4A3A4;,:,8-7+6+6,7.:/;/<,;-;,:+;+;+<,};+z;*z;,w9*v8)u7(t6)v4&;1FEI0?C(=@#:<$89';<.8:/9<1=A36?,MKB3?F44>4>4>4?5?5?5>7?;B>D>F=FM@PDSHPGMGIEGBC?A=A=EBC?>7;0=.B0F3I6E4E3B3B1@0}@.{@.|?-;,9,:+;,;,<-;+;+:+9)7)7*8,:/;/;0:/8.9/:.:.:,9+8*7)7(6)6*7+8-9/<0<.<-;,9*:*~9*}:*};+|:,z;,y;,w9*s8*q6(r7)u5)D8H=K?H:IB)=A(;='78(:;-79.9<1=A37@-NK+e>-ZL`S?44+@9YUjgeeRUINMPIAF<@6>4@6D:G=G>JAJAJBJBKCKCKDKESRTTSRROSLSLULUNLHIFEBC@B@C@EBFDIFD@=7<2>2B1D3G4D3B3A3?0>1>0}>/}>/;.:.:.:.=-<-<-;-9*8*8+8*9+:-:.:/;/9-9-:,9,8+8*8*8)8)8(8)9*:,:-;-:-:,9+8*}8)}7+|8+{9+z8,y9-x:-v8+q5*o5)q7+t9+H;IC-B47@-;H.L^8_uFiJtPtPtNrOsTpQnMmLpPwY|az`rXiQZA\EaIeMgMgKhJfLcPY{IRtBi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkaUlbYlbYlbYlbVlbVlcRlcRldQldQldQlcRlcTlbVlbXlbXlbXocUnbRkbQlcRlcRkbQg`Pd]M^WGYSCSM?MJ;KH9GE6EB3@A/=G.BF-QB-b=-E:YROJ.+<9>;TRpnvvdhX^]_UQPFG@C:D=G>GAG?HCJBHDJCJFKDKGKGHHGIHHGGHDHDGBFBBAABBABBCBB@A>A?IGB?;6=3?3@0A0C3@2@1>1<1<0;1;1<1<1=1<3=1=1=/=1=/.9)9(:*:+;,;+;,:+:,9+7)~6({5){5){5)z6)x6*x8,w9,s8*p4)o5)r:-v<0M@KN)?O(J\2_rEk~QexKXj@M_7@Q-6E&7D*=F1=D4:>07;-8:,:;-68-8;0>B47@-9F,I[5[qBeFrNsOsMrOsTpQmLoOsUx\z`s[iQ`HYB^GeMgMfJeGgGhLaNXzHQsAi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSlbXlbVlbVlcRlcRldOldOldMldMldMldOldQlcRlcTlbVlbVocUmaSkbSlcTmdUlcTi`Qf_Ob[K^WGXQARLB>@9C?C=C@D?CAD@ECDCADADDFGHIHJIIIGHACADBEBEAA@>=:<:EF<<63:2>4=1=0?1G]/AV-7H$1@!6B*=F5PK8MH5ID1EC.AE*GC(\A,SG\X?A13JN@E=>;GBGBC>>7D=D=D@EAEBECCEDF?C@DBEEEGGFFBC>?BD@C>A=>>>@?C@ECAB8840:4>6=3)=C5$bI3gWxmleYWOOBEBEDGFHHKJKKMKMEEEEFDHEFBD=C?>?=?=B?B?>:937090=2>3>2?2?3=2;393838192;0<.<.<-;/:.:.:.~:-~:-~:-~:-~:/~:/~:/~:/}90}90~80~8.7.7.7.~8,8,~8,}9,|8-{9-z8,x8,x8,x8.x8.w7-v8-v6,t6+s5*q5+m1'r6,n4)m3(o6+m4)q8-I=SHSJRGRHPHQJQKRLTMTK[NcQo_HYU:MV7O_;j~YbxQYoHUjCRg@Mb;IY5CR17D&4>#2:#6;'<>0@B5@@6<>358-39-4:.7:/9=/;?.=B,%Q?)kP=XGNBE=D?WVTTQQPONMMMLJLJUTIG>>=:C@FAB;>4D9D9F=E>EBBD@E?ECFCDCDEEECFDFDFDEAC@B?A>@=@=@=B?D?C<>6:090:/<0<0A2~@3~>4<3:3918190;.<-;,;,;-:,:,:,9-9-9-9-~:/~:/~:/~:/}90}90}90}90}90}90|90|90|90z:0z:0y9/y9/y9/w9.w9.w8/w8/t8.s7-r6,r6,p6+p6+k1&q7,m4)l3(o6+l3(p7,~H>RISLQJPJQLPMQNSOOGSH[K{ePsiPhkLfqQgxT^tMXnGPf?La:K_:K\:GV7CP4>2;=04:03;05;16<0:A,>D*Q[9^mDkRpRpSqRsSsVx^|exakT`I]F]F\E`IaJcLeNdMbK`I^I]LRtBIk9i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTnbTqdTo_Pm]Pm_RqeYog\ldYhbVfbWpl`{xi~{jyizubpiVe`JTT(MB.S@/U8(]7*l=3n70u91~;5@:IBPJXP[R^YTNHEC?DBGCD@@:A;BF@FCEFDFDFDDDDDDEDEEFEECECDBDBD?C>B=B=B=C>E@E?B<>5:18-9,;-@2@1~>2=1:19181:0;.;,;,;,:,:,:.:.9-9-~:/~:/~:/~:/~:/~:/}90}90}90}90|90{8/{8/{8/{;1{;1z:0y;0x:/x:/x:/x:/t8.t8.s7-s7-r6,q5+o5*o5*j1&o6+m4)k2'l6*i3'm7+}G=PIPIPJQLRMSNUPVPWO[P~^OtbNoiQorUlwYfwUQeBK_:EY6DU3EV6GV9GT8ER8?I0*7;*:<.<>0;=/9;.6<25=26<26<0:0=@-=C)MW5Zi@f|MlNnQqRuUtWz`w`nWcL\E\E\EZC_HaJbKdMcLaJ_H]H[}JPqBFg8i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTnbTrdWoaTm_Rk_SkaWlcZle[jf]jf]xtix~r}zg`cNOT>DG2FE1HC0F=,L<,VC4P9+R6*V4*Y5)\6+a9/e=1m=1LBSJVOOKFDBBDCFF@>A?B>D@ECEDEDEDDDEDEDEDEDEDEBGCFBEAD>D>CCA8;18,9+<-@0@1~?0=/:1:/9/:.:-;,;,:+:,:,9-9-9-9-~:/~:/~:/~:/~:/~:/}90|90}90{8/{8/{8/{8/x8.{;1y;0y;0y;0x:/x:/x:/v:/s7-s7-s7-r6,q5+o5*o5*m4)j1&o6+l3(h2&k5)h2&l6*|FG2:A/9=,9=.9=.8<-7;-7=36=56;46<2:<1;=/bxIjLnQsTwWxZ{ar[eN\EZC\E\EZC_H`IaJbKaJ`I^G]JZ|JNo@Ef7haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTrfXth\sg[mcYjaXle]snhzwp~wz{kcfSOR?GJ7EH5BE2BE2EH5KL0A9,A7+@6*F4(U5*qB8OHOKIGGIEIBE@BABBACBEAEAEAEAEDDFDFEFEDEDEDECFBEAF>E=E=E=E=F>A:C;E=B9>39-;..=-;/:-:-;.:-;-:,:,:,9+9-9-~:/~:/~:/~:/}:1}:1}:1}:1|91z:1|91y90y90x8/x8/v7.y:1y:1x90v:0v:0u9/u9/t:/r7/q6.q6.p5-o4,n3+n3+m4+j1(m7-j4*h2(j4*f2'j6+}D;NGNHQJTLUOWPYR[Q{YMv\OkZJ]UBYXDY^HOYA?K3:H/7E.4B+5A+8D.=I3CL7EN9BK6?H5.5<,4:,5<45<56;56;49;0:-;@)GP1Ra:`vGiKoRuVyYy[x`nW`IZ}C[~D^G^G]F`IaJbKbKaJ`I_H^IW|ILpBBf8haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTkaUndZpf\lcZkd\rmg|ľrfcTPQ?FI8>E3;D1:F28E38E38C2:B3/?/>.=-<-;-:-;.:,:,:,:,9+:+9-~8,~:/~:/~:/~:/}:1}:1}:1}:1z:1z:1y90y90x8/v7.v7.t8.w8/u9/u9/s9.t8.s9.r8-r8-q6.q6.p5-o4,n3+m4+l3*j4*h2(l6,i3)f2'h4)e1&i5*{B9MGMHPJTLVOXNYO|\Qs\Nk[L`WFVSBPSBJQ?@I64@,3<+2;*09(09(2;*5>-9B1G4:F2:C25@/3>-1<,3:33954954928919;.;>-;@*CL/O^7]sDiMpSwYyYwYqYfOZ}CX{A\E]F]F^G`I`I`I`I`I_H^G]JUyIJn@Ae9haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlbVj`VjaXkdZkg^upjμzym]_YIKL:@E1;D/>J6=H7=F5;C4;>5:;3983:70?<3E;2Q51c74GH\_`dWZQSOONKMJJGHDEADBDDDFDFCECEBDCBCBDCD@D?E?D.>-=,<,;,;,<-:,:,:,9+9-9-~8.}9.~:/~:/}:1}:1}:1}:1}:1}:1z:1y:1x90x90w8/t8.s7-r8-t8.s9.r8-q8-r8-p7,p7,p7,o6-o6-n5,n5,m4+l3*k2)i3)g1'k7,h4)e1&h4)b0%f4)zA8MGMHPJULXNYOxZOr\Nk^N^WGRPAKN=CJ:9B12:+08)17+17-06,/5+/5)08+2:+4<-9D4;F5=H7-.800621622717829;0:<.:?)?H+KY5[qChLqVw[wYsVgP^IUx@WzB[~F[~F[~F]H_J_J_J_J^I^I]H]JUvIJk@@`7haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlbVpg^ng_lgatqj}ub^\GKM7CH2AI2AI4@G5BD7AA7B=9C97A96;:5B=7G51L-+f66QRfimm\\ZWWSTNNKJHFDDCDFEFEFCECEBDCBCBDCCBC?C>C>DD69A208+/7*6<247058157247025.06,08-19,6A3:E5=J9>K9-,6..400511606718:/:<.:?+WzB[~FY|DY|D\G_J_J^I^I^I]H]H]LStIHhA?]7icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSjcSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUldWibZgd]vsnʵƶibbFEH-DH/CG0FE1GD5F<3C60F42I99A<9B=:F87K65eEFijƓ鬩ӌwp`ZVQROMLGIEHFGJKDF<>>@HJGI>@@@@@A@B>B>@<@;@9C>A9@9A9B8@5:.8*=0>/>.>-=,<+=*<,:+9-9-~8,~8.|8-|8-|8-|90|90|90|90z:1z:1z:1z:1y=5w<4w;3u:2t91q8/p7.p7.o6-m7-m7-l8-m7-l8-m7-m7-i2+m6/p92o81k4-g2*g2*h3+e0(i7.d2)]-#`0&_/%b2(s>6OJPKQJRJ}YMv_QfYITN>DE5>E5:C25@04&DR1WlChRs]w_rWkR[~DXyDTu@Tu@WxCZ{F[|GZ{F^JbNbN^J\}H_K`L^~MSqKFdB=X7icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUldYgd]onjͲcgjKLQ3GJ/EC.GB/H>2I:3L95K<9B87G>?QEE`PP|hgϲſ걨Ƀ{c]WUSSJMCEGFFEIHKKFF>?=?CE????@@@@A>A=@/>.>-=,<+<,<,:+9-9-~8,}9.|8-|8-|8-|90|90|90|90z:1{;2{;2z;2w<4u<3u:2s:1r90n8.o6-m7-m7-l8-l8-l8-l8-j8-l8-l8-k6.n70o81n91l7/i4,g2*e3*c1(d4*_/%^.$b2(^.$`0&p>5JERLXR~XOrVKdRDQJ:>?/:A16A05@03>04<14<15;17:379477577557246116//6./7,.9+1<.4A08E49H58G44E24B1.8/.5..3--2+23+46+8:-9=,7?(DQ3WlEhUt`wbpYgPY|DWxCTu@Tu@VwBYzEYzEYzE[|G_K_K\}H[|G^J^J^{MRmJF_B;T7icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUneVneVlfZed_y{xشğl`gEQX7DG,DC.JD4LD7KA8I>:D:9TJKk__vv꧟eaCDHKVYXUOLFBEBFEFFDDCD=?>@????A@@?A=@:@:@:B:E/>.=-~<,=-=-9-9-~:/}9.}9.|8-{8/{8/}:1}:1{;2{;2{;2{;2z;4x<4t;2q;1r90o9/n8.l8-l6,k7,l8-j8-j8-j8-j8-i9-j8-j8-n91m80m80m80m80i7.f4+c1(d2)a1']-#_0&c4*\-#_0&sD<}PJVP~YQpTI^J?OC7?<-46(2;*0;+1<.2=/4<14<15;17:379479668357257227007/08-.9+0;-2?.6C27E48G48G49F54>33:2/4-,2(/0(13(57*6:)6>'DQ5YmJkZwfwflZ_KWxCWuCTr@Tr@VtBXvDYwEYwEZxF]{I_}K]{I]{I_}K^|JZwKNeHAW@6L5icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVneVneVmg[jkfڴefmLMQ6FH0HJ5KI:HD9D@7PFDj`_㍌ddDBSLUNRIHAHBMJJG?>>>>??>@?@?@?A=A=>9@:C=E?E>A9=5;2<1=0>/>.=/~<,=-=-9-9-~:/}9.}9.|8-{8/{8/~;2~;2|<3{;2{;2{;2z;4x<4r90o9/o9/m9.l8-k7,j6+h6+i7,i7,i7,h8,h8,h8,h8,h8,m;2l7/j5-i7.j8/j8/f4+a1'e5+a2(].$a2(b3)Y* a2(yNE\VvWRiNGWC:I<3@:.:;-8<.08)/:*3;.4??@@B?B?B?B=?;A@9>5=3<1<2=1=0=1~<.=/=/~:/~:/~:/}9.|90{8/{8/{8/|<3|<3|<3{;2z;4y:3y:3w;3n70m80l7/l7/k6.h6-h6-h6-i7.h8.h8.g8.g8.g8.g8.h8.k92h6/f4-g5.i70h70e4-b1*c2+b3+_0(]1(]1(V*!b6-{ULtYRaNHN?8A7.=6,;9-9;.9<139-3;.5;/6<06<07:/58-47.69049238139/39/2:/19.19,.9+.9+/:,0;-3>.6C2:E5Qn>Qn>Qn>Qn>Qn>Sp@Sp@WtD[xH]zJ]zJ_|L_|LZwGRlEAR?6C9+8.gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXpgXng]lnmz׹ĥregOMP;GK:FM=GOBJRGz{sþԏdQK:UFXJGC?B?B@B>B>B>A=A6<5/95,;8/8:/57,36+69.5;/7:/69.69.58-57,36+28,19,28.19,19.19,19,19,.9+.9+.9+/:,0;+3>.6A17B2ex\umtlf_RwKBh9KkVsCZwG]zJ^{K_|L_|LVsCNfB;I80;3&/*gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXqhYoh^hikmtzƯ}un[ZWFPQCSVK[bZcmdꨐoYWDUERFMAJAG?E?E@D@D>C=BUrDYvH[xJ]zL^{M\yKQn@G_;6B4+4/"(&gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSicSjcSjcSjbUlbVlbVmcWmdUmdUmdUleUmfVngWogZnh\oh^mjekormtzη|ubb_NXZL]cWmwn|}ɸqUGUHUJE;J@G@F>E>C=BG>G>C;>5:2;3>6=5>4>5=4<3~<0<1<1~:/~:/~:1}90|90{8/{8/{8/z:1z:1x92w81v70u6/u6/q6.m80k90j8/j8/i9/i9/i9/h8.g7-f7-g7-f7-f7-f7-f7-f7-f5.j81m;4k:3j92j:0m>4oC8l@5oD;d<2c=2zVJdZyWMbLA>:13814927<54:0/5+25,9<336+25*24)03(13(25*46+47,.6),7)/7*-8*/7*/7*/7*/7*19,08+08-/7,/7,/7,08-08+7?09B14)//%%heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdVjdVjdXldYlcZmeZmeXmfVg`NjeRnkXol]he\feasqrԶ|qtY_dMbkXr}lצ`XD=KBOEG=C9D;H?I@H@G=G8H8I8G8E5B4B5C5C5C6A4?3>2<1;1;191~:1|91{80z7/z7/w7.v6-w7.w7.w8/w8/v7.u6-q5+n3+l7/i81i81h70h70g6/g6/g6/f5.g6/i70i81h70g6/e4-e3,h3-j5/m80k90j:0i;.i=0kA3gB2jI:dH:v_O~k\xjoRJ=79.4:04:039/39/39/28.28.17-17-36-06,25,/5+14+/5+/4-.5-/4-.5-/4-/4-/4-/4-05./4-/4-.3,.3,/4-/4-/6.1;23=26@58B79D67B45@03>-4?.DQ=WeN[kQPbHEX<@T8BW6Ic>Ke>Kf=Kf=JeOj?UpGYtK\vO]wP]wRWqNHb?;O6%0*&+.$),heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVidQjhSmjWjk[gg_lll~ЯvkqUYaI_kUtoᄍĀwPFNAL?K?J=D8=4?6F:F7J7L:I7F6C2D6G7D7C8~B7|@5~>4<3<1<3}:2}:2z:1z:1y90x8/v7.v7.u6-v7.t8.t8.t8.r6,o5*m4+l7/i81j81h70i70h70g6/g6/e3,e3,g5.h6/j81j81j81k92k60l71k90k;1k;/j>1j@0iD2gH6kP=gRAufSuesrKL<69.39/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4..3-.3-.3-.3-/4./6/.80/:21=34@66B66B66B45B16C1CP>P]IR`IIW@AO6BP7EU:Jb@Jd?Ke@Ke>Ic6I5&1-',0%*.heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVmhUkiTmjWjk[kkcwwwۿʫyuy`kpZt{iםK4z>4z>4x<4x<4w;3w;3u:2t91t91t91r90r90r90r90o9/n8.l6,k5+l7/j81l71j81k60i70i70h6/g5.g5.f5.g6/h70i81k:3k:3l;4j;3i:0h<1k?2jC4iD2fE2fI7lVAjYGujVm{mEF658-28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4./4./4..3--2,-2,.3-/4..5.+5-+6.-9//;12>24@46B47D38E3?L:ER>CQ:;I28F->L3DT9J_@Jb@LdBKc?Ia=G`9F_8G`9RkDXpL]uS^vVZqTPgK=T8.A.&1-',0%*.heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZmfVniVljUlkWlm]pqiؼǫ}ſ迭nO?P@YKN@D8E:A6F;I?G=@9<4>6B<@;B4e=1f>2hC3iE5fG3cG2cJ6hV@i\IskVozpq_9=,47,28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3-.3-.3--2,-2,-2,-2,.3--4-*4,)4,*6,+7-.:.1=14@25A36C2:G5N4DX;?6s>6r=5r=5r=5p>5o=4n>4m=3l<2k;1j;1i:0i:0j:0n72p62p62m61m61l71i70i70l;4k:3h91e90e90e90e:1d<2fB6cA5cC4dD5dG5dI6bI3_I2^L6eV?jbMrmWor[`L3:(28,28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3--2,-2,,1+,1+,1+,1+-2,,3,,6.+5-*4+*4++5,.8-0;-2=/2=-5@/6A05A-1=)1=)5A-8F/=O5@T8FY=H\@J]?I^=K^>K`?TgG[pQcvZauZYkSJ]G6G4&4%$-*$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjcYkdZlc\md[meZlfVjgTkjUlnYorasvmθκƶø̦jWZFWEL;F:FF?B>=:;9;9=<>=?=}@;xA5o?5o?5o@6n?5m>4k<2h<1h<1h<1l<2o83q62p62p62m61l71j81i81h70g80e90e:1d<2e?4f@5dB6^B4aG8cL:dM;cM8`K6]K3]M4]Q9bX?mhRss[nv{eFO:4=*39-28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0*+0*+0*,1+,3,.5.,6.*4+*4+*4++5,-7,.9+-8*0;+4?/5@/4?.3?+3>-3@,7F/9K3@O8BT:GWL=K>K@I@E>?:;7=9>:?9@:zA:uC:qE:qE5j>5n=6o83r73p62p62n72l71j81i81d8/d90c;1d>3d@4cA5cA5_C5ZE4_NnlUtv^|kcmU2>(6B.3;.39/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1+,1++0**/)*/)+0*,1++2+-4-+5-*4,*4,+5,+5,,6+-7,,6+/:,2=/6A17B27B15@04?.2?-4C.:G3=L5AO8DT:JX?L\BTbI\kTcqZ^mXUbPDRA2>0#/%&/,&,,$**heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdVjdVjcYkdZlc\md[lfZlfVolYmlWjlWgkZflbr{xخr[YDT@Q>RAQBM@D<=5>7?6>8@7}A7wC6tD8sE8q?8q?8s>8q?8q?8q?8q?8p?8sB;qB:o@8m>6l=5j>5m>6o>7o83q73o83m82m82i81h91f:1f;2d>3d@4bB5`C5]A3\@2WB1TG4[S>f^Gi^HbX?ZS9ZS7\W:ZV;XW;kmUsw^u}fUaI&28D03;.4:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0**/)*/)+0*+0*,1++2+)3+*4,+5-+5,,6--7.-7,,6+.8-2<16A39D69D47B46A10;+2?-5B09F28u@:u@:t?9q?8sA:q@9q@9q@9p?8n?7o>7o>7k92m82l:3l;4l;4h<3g<3c=2c?3^>1dG9cG9T=-N9(M8'@1WQ;PN7KI0OK2]Y>ieJeaDVU7XX<]`CosZzfdlU=I1-9#2>*4-1=)2>*9E/BN8IU?O[GVbN]hWYdTLWI8u>9u@:t?9o=6p>7sA:q?8p?8p?8n?7o>7m>6n=6m>6k<4l=5m>6k?6j?6gA6eA5bB5dG9[A2^G7^I8N=+F7$G8%>6!LL4GK2DG,DD*MM1\[?baC`aBYY=dgJsw^sy_X`I:D,/;%7C/6>16<26<26<25;15;15;15;15;15;15;14:04:039/39/39/27127127116016016005/05/.3-.3--2,-2,,1+,1++0*+0**1**1*)0))0))0)*1*+2*,3+.5--4,.5-07/4;39A6?F>BJ?;F8:E57B14?.3?+6B.F2v?*u>*vB-yF3xG6q?4n<3q<4tB9sA8o?5qA7xH>n>4m>4m>4k?4l=3j>3l=3j>3g?5gA6gA6gC7eC7cC6`C5^D5bK;UB1ZI7`S@RG3C;&E=(FA+AE,BH.AE*<@%?B%NN2_`AijKaaEnqTvzagmSJO94<%4=(=F38>28>48>48>47=37=37=36<28>48>47=37=37=36<26<26<25:449349349338238238227105/05//4..3--2,,1++0*+0*).().().().().(*/)+0*,1+160/4.,1+,1+/4.6;4=BK:4.8/.5..5.-4-gdUgdUheVheVheVheVifWifWifWifWifWifWifWifWifWifWkeWkeWlcZmd[md]mf\mg[jiWkmXimVjoYjs`hthm|wڻּҼyvR2f>2f>2e?2b@4bB5`C5_C5_C5[D4ZE4WD3XI6OB/\T?oiSc^HMK4IG0IK3>D*?H-@F*48>47=37=37=39?58>48>48>48>48>48>48>47<67<67<66;56;56;55:45:438238216005//4.-2,,1+,1++0*+0**/)*/)+0*,1+-2,-2,05/.3-+0*+0*-2.2718=9;B:@K=@M;@M;=J68E13@,1?(0>'4.:0-7//6/.5.gdUgdUgdUheVheVifWifWifWifWifWifWifWifWifWifWifWkeWldWlcZmd[md]mf\mg[jiWkmXinWiqZgs_drejytܿչйѾϼзvavWChI5hI5mL9pOA.:>-;>39?59?58>48>47=37=37=38>48>48>48>48>48>48>48>49>89>89>88=78=78=77<67<66;55:449338227105//4./4.-2.-2.,1-+0,+0,,1--2.-2.,1-,1-,1-,1-.210513764;4;G9=L9@O<@O:8F71?2-9--7..5--4,fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWldWldWlcZmd[md]mf\mg[jiWkmXinWiqZgs_bpcgxrڽѵ˴˺ѽͻsucz]K}^LtUCaD2W:(Y<*[>,X=*`E2`E2`E2_F2`G3`G3`G3]H3\K7\M:\M:YL9XM9UM8RL6QL6NL5QQ9ikS|gmqXSY?FL2>G,48>48>48>47=37=38>48>48>48>49?59?5:?9:?9:?9:?99>89>89>88=78=78=77<66;55:4493382382/40.3/-2.,1-+0,+0,+0,+0,+0,,1--10.21/32/32/32-4-3?17F3=L7@O:?N7M:MJ9BC3=@5;A7;A7;A7:@6:@6:@69?58>48>48>49?59?5:@6:@6:@6;@:;@:;@::?9:?99>89>89>8:?9:?99>89>88=78=77<67<6495273162/40-2.,1-+/.+/.,0/,0/-10.21.23.23-12+1-+9*/@-6H2;M7=O7A6>A6>A6=@7=@79?59?59?5:@6:@6:B7:B7:B7;@9;@9;@::?8:?99>79>89>7;@:;@9;@:;@9:?9:?8:?9:?98?87=94;4382160/4..3/.3/.21.21,2.,2.+2++2*,4))6%$6)=!2F+8L1;O6;M5;M5;M58J29K3;M5H&DK*FM+DN)MX0KW/FQ)CM(OV4^cC`cDZZ>YY?[YB_ZD_ZF_XE\UBXQ>UN;KF3GD1DA0A?0@>1>>2??5?A6E=8B:7A97A87?45=03;.28.160.40/51-7/-9-.;)0@&6G'7M';V+;X,ZUA[VB\UB\TAZR=YQ6:@6:@69A67B47B46C26C2:B79A69A68@58@59A69A6:B7:B7:B7:B7:B7;C874>63=40>-3C)9M*BY/Ga1Op;Ln;Li=Fa>BY?[S>\T?YS=VP:QL9MH5GD5DB5CA5?A6=>6:@6:@69A67B47B46C26C2:B7:B79A69A69A69A6:B7:B7:B7:B7:B7:B7;C8F;C<>E>9C;6@74B19I/BV3Pg=XrB^J[}JWtHMhECZ@9O:6G54E28K5/9./6.,3+YgMZhN\hP^jRblTdnVhmYinZklZklZmj[liZnhZnhZog\oi[mgYkhYkg[kg\jf]jf[hfZfgWfgUafP_hUdq`p}tѾ˸ŲüĸƸ˿ɉlPJ0RM0TM0TM0TN.UO/UP2UP2TP3SO2PO3ON2QM2ON2OM4LO4LN6JP6JO8GO7JS8GP3FO2HR0LS2NU3U[7[cZT>XR6:@6:@69A67B47B46C26C2;C8:B79A69A69A69A6:B7;C8;C8:B7:B7;C8;C8=E:>F;=G<=G?>H=>I9@H9?G8?E9?D==D=9C;6@74B19I/DX5Ri?[uEYzEWyFTqEIdA>U;3I40A/.?,6H2@R8K^BReGSgKOcGAX>6I31;007/-4,YgMZhN\hP^jRblTdnVinZjo[mn\lm[nk\mj[nhZnhZph]oi[mgYkhYjfZjf[ie\ieZhfZfgWghVafP^gTdq`p}t}пɶıþʾöʊmQK1TO2VO2WP3TN.UO/VQ3VQ3UQ4SO2ON2NM1QM2ON2OM4LO4LN6JP6JO8IQ9LU:IR5JS6NX6QX7RY7[a=ckDbsyosxZZ_APP8NN6NI5LG3NG4QJ7VN9XP;XR6:@6:@69A67B47B46C26C2;C8;C8:B79A69A6:B7;C8;C8;C8;C8;C8;C8F;=G<;E=:F<F7=E6>D8=B;:A:7A95?64B19I/BV3Ne;Uo?St?Qs@Ol@E`=9P6.D/,=+,=*1C-:98876677766554/.//002235435I[l|}ufTMLMOQMN[qxfZVZZ[.//0344466668888776666778888888855544433666666643334455555678899>?@BEEFFGGHIIJLJKNU^is~µº|bLA@>=<:98866635221--//0011565546:DTcq{}xo`QLLLPQLGM^juxzwk`WT]]]--./013433444466443333445555555533222111444444444444455555667899<=?@BCCCDDFGHIJIJMRYbju}ŹľtZE<@@?>=<9864423110-,--//013554247=NYensyzuk_TOLNNMJGGKM]`b`ZWUX^``,,../03322333355332112333333333322221110333333334444444445567888;<=>@AAACCEFGHJHJINV\dnv{;ºoSA9@A?><9874432200.--..001123342148GOX`emy|wnd[RLOLIHHE@;BDJJIKOV^``++,-//0011112222221111221111111122211100333333334443333344567788:;<=????BBEEGHJHHGKQX_fnv|ƵsWC<>@>=:98644311...----..0001220/24?DKTZdu~tmcVLKIGEFD?;:>DGGJNU^aa++,,./00111122222110011200000000222110002222222233333333445667889:;<>>>>BBEEGIJIFFJOT\bjqw}ѿu[GC;97644321/...----..00/02210038;CKS^tzriWIEGDCC@@>GKQUSRTY^aa,,,,--..//1000/////////0///////////0011211111111012333333333456789:;=>>>??BCDFGFGHJPTX^bmt|ȷ~jVILJB<976343110/,,----////001111144;ACJ]ytj_ZLHA>?ALUbnvrlg_W[`c,,,,--../.00////....///////////////0001111111111001233222222345689:;=>>=??ABCEGHHHLOQVZ_hpwIJmZNLKE@=841220//.../-//////0011111259>@@ACDEFHIJLNQT^eoxözmbSQKE@;510/..../0/////./.0/0////27639Hb{}kXSYZ++++--..--.--,,,,,,++***,,,,,,,,,,,,,+++,--..////00000/.////01349:;<==<<==??@ABCDCDEGHKNX_ir}~tj\VNE?<7600.///1211111/1/202000028516G`z{gTQUV,,,,..//../...-----,+***++++++++,,+++***,,,-..////00//.-00/01234::;<=<<;=<>>?@A?@@@ABCFHQXalu~ypd]RJB>:9321//012111110001111///28535E\uwdQMQR,,,,....//////../..-,++*+++++++++++***))++,-..///////.-,00001244:;;<=<<;<<>=>>?>=;;<=>@CGOYdnx~~~xjdZQIC><6430112422222000110000016544AWq{q_MIJL.,...../000000/12110/,++++++++++++-*,))(*+,,-.//--//.-,,12223456;;<<=<;;<<===>?=>=<99:;?CJT^hov{~~|||}ztgb\UNG@=8853223420022222331100014444?Tm~vlZJFFF/./000123446543455432100..--,+*).././...//-.--..--.//02224568::;==>>>=<;=<<;=>>@BB<9546;@GOV[afmy{~vpvvv}}|rnha[YZVOIB@:53331/---/13344320////10//000112344776555776632000//--+))./////..//..........//135578:;<=>>>>>=<<=<;;==>@DFC@=<;>AFKPV\agpxwwpmrrquumd^YYZXRMEA;5321.100013444320/-,,220-8SoxqhYMF@;1111224455888776887643211/0/-,++/1////..00///000//000/12679:<=>???@@?>===<;;;;922333455679::999:998544433110.--020000//110011111111123399;<>@@ABABAA@>>==<;;<=?BFMTXWQKD><@HT`eiku}}zxzxxuv{{rlhfgd`\QLB92.,-58874320,+*(''%(.10.8Piv{y|}yz}}}~~}|}zuneWNE?94445557788;<<<<<<<;;876656632101244422223333223333335566;<=?ABECDDEDCB@@>>====>>BFNUZYSLD<98556677889:=>>>>>??>=;:998898745466664444444533444455889:=>@ACDGHFFFFECBA@@?>>?@@ADKQVURKD?=?CISX]dlv}~}}}~|y~|{z|}wu~zvmh`WPHB@=<852/,++,-/34663???@@BBA@==<<<<<<;99889888866665566775589:<=@@ACDGHIIJJJIFDBAA@@??@@A@ACFHJJHEEEFIILRZdnz~ثurqrv|qtÿzwpkg^XPHCA@;842..036:>AECFLV[`gijlgflonnrsoorwyxususnibTMHE?778889::;>=>>>>=<:;::99999766666777569;>><<;:8877999:<=ABCDFJKLNNNNLKIHEEBA@???@@?>>AABCDDFEEEDDEEEEEDCCDCBBBBAA@@><;;9877999:<>ABCEIJLLNNNNMJIHEECB@@@@AACIKVjt{yr|Ǿгye`kuwñkHTMHJKKOU[cginzztrppquwwwsxzy~zrmh`TNRVV8889;@BCEFIKMMNMPMLKIHEDCCAA?@@DSRiĚģ{vzͻƔ}jhuǦr]XWQB:?LVaehq~wxurrvyzzzpg^TPRXY7789;=@ABBDDDDEEGGGFFFHHLKJIHGFEDDEEDEEE@?=<;:::99;;?@CDFFJKMMMMOOLKJGEDDDB@@ABFQXɝ˱ľȧwx~մ|hXPG?;AQ_go|}z||zz}sh]SPPVW6678:@@CDEEGGGGHIIIKLLKLKLKJIGGFFEEDCAA@@=<;;;;;ACDFHHGHIIJJMMMLMMNMNMJJIHGFDDCCA@??<<<<<<@ADEHKMNPPOOOOMLIFECBAA??@@NoĻҦӯhisyʺte\[\\^55555689<=@BDFGHHHHJJKKNMMMMMMNNMMKJHGEDCCAA@?<<>><=>ACDHILMNPOOLLKLJIFCA>=?>?@BDGJLOOLFEHJKMKHC77>>:CežɻŒͻyrp{wv01356788:;=?ACDEHHHJKLMNKKKPWYVROMHFGHFBDA??@@=;===<=>=>BDGJMOPLA?EHJJFCA<=EJPdŷ˶sʳ/0124577::<>@BCDIIJLMNNOKNT_imlk`YOHHGE@C?<<=>>=89;<=>?@EGILOPPL<:>ABC??@?AFHKMOOPLB?@AA@><=FPXkĽȾǾhqɺ11001245789;=?ADILNPRRSQOVfw{pi_UNKE?;9988678;>?BCGJKLMMLLMLIC?<879@HZwžlɾ64311234678:<>@BJMORTTSRQZlxnf]VMD>;;75468CAKfĿҿ@=:75556779;=?@BJMRVWXWTS^pyj`XRONKF@??@ACCBB?><;AGPY_ccef_jĺ߾BA@><:876678;>AEIMRUWXZ[TXg|th]XXYVMC??B>@B?<:>AFUelwŷƭCBA?=;:97778:=@DHLQTVWYZUWeyuic``]VMFBA:999:<>@EILORUWWXX^p}upf_YQGA=HT`nºƿȱhNMLJHFDC?>===>@?CEKNQRVVZV[l~{md_YRNW_m¶¾YnQPOMKIGGBA@???A@BEKMPRUUYUZi||somijyȾΩuRaSRQOMKJIEDBA@AA@ACIMORUUWRXj}¿¿ģjIXuVTSPOLLJHFEBBACACDJMOQTUUQWj~ǿþӤ`ERkXWWUTRRPMKKHHGHFGGJNRUUVXUZk{ʺͿ¾aJMsYXXVUTSRNMLKJJJIGHLORSVTXUYk{ջĿv^NSu\[[YXWVVSRQOOOOMJJMPSVVTWVZkyľƻlYOWw\\[ZYYXXUTSRRRRPLKORTWWWVU\jyƺ»ĽǽjUS\y\\[[ZYYYWVUUTUUSOOQSUXYXUU\hu|~пľs]^hɿ[[[ZZYYYXXWVVWWXQQSUXXYXWUYenu~~xrloκƼܴqoyŲ[[[[ZZZZYYXXXYYYSTUXYZZYYUX_djsyzz}ysnioɴþ¿̿ٽ{Ļ[ZZZZZYYZYYXXYZZVVXYZZZZ[WW\^bjqttx}}zzxt|òüʾĤ~ʿZZZZZZZZXXXYYZZZZZZ[]^\\YWWXZ]``gjprxžǵȹо}~zy|ZZZZZZZZXXXYYZZZZZ\]]^\\][[YZ\_^aeknuǽͻɺÿ¿зuxplhgkqy|ź\\\\\\\\ZZZ[[\\\\\]]]^^\_]\[Z[]\]beiq}εɿü˧nhmt{}xq`_aenu}Ʒ[[[[[[[[ZZZ[[\\\]]]^^^^^^^][\[\[^bdgozſ߿ƾÒo_\dltvromlou{Ʊ[[[[[[[[ZZZ[[\\\]^^^^_^^^^^\^]^^bccelx¹Ⱦ㼃b\[fntxywyxz|ϼZZZZZZZZZZZ[[\\]^^^_^_^^]]^__`abeeabht{}ɾɾ½Ĵºy^`anv{~}|}¬ZZZZZZZZZZZ[[\\]^`^_^_^^^_`aaaadhgcbjv|ǽɺıɽp\_fu}׼[Z[Z[Z[Z[Z[[\\]]^^^^^^^\`aabbaabkjedkx}żͻһľñѿעfXZbt~|}˶]\]\]\]\^]^]^]^]]]^\\[]^`_`bcdddkhefnxĹŸ¿żվ؍\S\gw}~}|}~|]]]]]]]]^^^^^^^^\^_^[[\^_]]_`bceigegnyĺ¼׿€XR[esxw{}}|||{{{}~|}}}|}vcS]]]]]]]]]]]]]]]]^_a`]\[[[[\\_cfggghls|½¼ߥuXU_frutx{{yyyxyy|zz{{{{{}yoQ@2^^^^^^^^^^^^^^^^^`a`]ZYXX[_beilklloryƿǺþIJ·׈k\[cjstuwyzwvwvxx{zzzzzzz|~tiPC8^^^^^^^^^^^^^^^^]_`_\ZXXY`gnsssqoprvzɻƴrb`cfktuvxyxuuuvwx{zz{||yy{}{rd[Q________________^_`^[YZZ_hrz{{zvqrtwz~ü˸Ѻɳ͠fY_cfktwx{zvsrstvw{zyz|{xxz{~|uog________^^^^^^^_aaa^[[\_ks}}{xssx{~Ū½úй͵}^Q[]ejrvy{xsppqqtuyxxyzyxxy{xple________^^^^^^^_cca]Z\_aty~yywwx}Я¼ѶbYJUXciqvz|xrnnnortwwwxywvvwyz~~{ri_\V\^``___ab_]]acb`da]^[Zesyz~}xrltvѸؽǻƹ̿щPEDMZ[cqxxtrqlmnortuuttvwvvut{{zumbXS??>[^```_`ab`_`bcb`f_\^admvw{}xqklnu|Խʶʹƽ¶wL>=GPX`nuvtqpkklmprsstuuutrqpnlhbXNF@@@@Y[^^^^_`a`_`aa`^b\[ckqvyyyxne`jr}˹·ǻқkO>;FHQYgrtqmkiiikmnpquutrpmkjea[ULEA>CDEWZ\^]^_a```aa`_\ZZbjqvxzwsmb]alx˼úɾÇeZHALFLSblpnkighhjkmoptsqojged`]WRMLNOMNOUW[\]]_a_`aa`__^V_ntxxxysj`[_jvξįثwdaTKPGGLZfmmlhfggijlnotsnjfca_ZXSPORWZUUURUXZ[\^``aaa``ba^jy}zxvsjc[]hvŴ||x¸İȋj]]XQOIDGS^gjjggffgikmmqojgc`_^\[WVUY]^ZXXNQUWXZ\^abba_afhnu|{wvpja^_ep}uwszĽ̮ƻ۱j^XUYULI@AKXbfhfecceghiknlhda_____]]]`cc\ZZJMQTWY\^dedb_aglwyxtrtlbZ_fmv~fldl|{꺾ȽɔSXTOYSEG=@IS_egecabcefhilkfca```^^_`adff]\]DFJPRW]_`a`_bgoswz|ypg`\`foyqhcflsŻaGAKROB;CC=8:<>>Xswhaa``achjklnkhghhfdedcdffebceh25;AGKRVXYY^ciorrj`WTW\alr{~ykc`bm¿āNH628>A?AETpj_]_abfklmmolihiihgfddeghfdgil-38P^yoa^`cejopoooligiiihfedeghgeiil+.48>BHKNNOW_fggb[QNR[eluz{|~md\YcvľݹkGG;8:953Bfve``cgmrrqpolhfhiiigfefhiifjkn(+/37<@CIHKR[ab`_ZTT\gpv{~wu}yke][dtTCD>B@:69P}{g_^ciossqonkgeghiifddeghifjlo&(-137:AHOSXZ\^dku{tldcbefilnqyઃ_H;;IUQTWdwrYT\_bimlkiigeccgihgiiiggflmpor--,,/1349<@EKQUV\^fpz{unic]]agmprrz{ľ¿ʂfUG;8ANHSg\HN[_chljhgfddcehkkjiiihghlossu200012349;?DIMRSX\dnzyrmkic\Zagosuwv{ȽѾžαw\OJF@==AQnlKALW_dikigdebcdgjlmnjjjhgimpwvv76655566;=@DIMQRVYakuzrmjijfa_dintz}ĹϸúDzgSPNIB?AM^xuR?BOVbeijiebcbfgikmnojkjiijnrxvv?====;;;?@CFKNQRYZ_gq{~zy{||zvrmjkllkgfgjnv|̸ƱTMSM?9ANlwnQ<9AOWcejkieaccijlllmnmmmlkmrs|{zDDDCCCBBDEGJORTU\\\air{ytoprvwwtsrmljkmooonmklou}Ͽ̾ƾʶNKPLEGWi}|XG96:=JWehllicaaflmnlkkmpqppoqtw~{yIJIIIIHHIJLNRTXY][\^dnx}}uokijmmmlkjghhknqqppopsw~ξʫӸ¹ȷTCBHXn|nuu[;45=<9CUgilmjfbchlonlijjsssrrswzwutRRRRRRRRUVWXY[\\baabekquz||umec`__^^abegikkmmjjrquͽ·ǿͽX=8V~h\YTH?:@<:<:AR]gpoljiglmolmkmmqqrrtvyz{oeWWWWWWWWXYY[\]^_dcccfjnprtvvsmgb^ZYWXX\^ccfgijkjfowξ»ķѷ`S^zjaTJF?95:A=:=:@R^gqpnkkhmnmmkklmpppsuxxxndZ]]]]]]]][\]^_`aaeeddefhhijkkifb_ZWURQSWX^^acgikieq{ȹzysz|[?AA?:6659@=9=9@Q`isrpmmkpqonlllnpppuxyuq_VOaaaaaaaa_``abcddeffggfffhhhhgedc]ZVRPPTUWY[]adffgow̹ʻvsN/-3:=;::<9?<9<9?Pajtsroompspommnpqrty{wmeZRMccccccccccddeffffghiiihgjiihhhhhd`[VPNNNPRTVX[]_cip»οŹu{]D2$-059<=::9>;8;8>Pbkutsqqorrrpmmpstvx{zqdY\UQeeeeeeeeefffgghhghijjjjjjihhhhijfb^XSMKIKLLNPQST\_d|Ƚµû}t~~yrU;/00346<@?<78>:7:7=Obkuutqrprsrpnpsvy{zxqg]X_WRggggggggggghhhhijjjjiiiiihhhhhhhfeb\WPLIIGGGHIHJRY\i÷ǽǿ}xxkVJ=624568=CEC@;7=:7:6=Nakuutrrpqrqporuy~zqf_]^aYRhhhhhhhhghhhhhiimljihgghiiiihhhhgfeb\UPMEDDDBBBCJTUYes̽ļ~|{{yaE68><3-17BGHB?;7=96:67244HZWMDA=:>;:;4;Pclusrprqpqrrsv{xj`^afhd[Tiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjhhggd^UOIEB@?>>=BA@HMR|żоù~|{yxwuw]X_ZI64=>:BIET¾ñ~}zzwvutv~lL6=Lee]PE?=:8;89=6?=;7:79=7<:8:68>7;L_itttrspnmpw|zriZ\aegghfcYRiiiiiiiikkkkkkkkllllllllllllllllonkllkgd^YSMKGE@=BQbͼ~{{{zxxwsporv{f`E>?J_keXM@67==:78:68>79I[erssrspmosxzsi`Y^egfeghaXQiiiiiiiikkkkkkkkllllllllllllllllomklmlifb^XROJIA;4356:<>>Q^kppqssx|xk`]]\`acedb`^]RIiiijjkkkjjjjjjjjkkkkkkkklllllllnqommqolhfp{~zpeTFCMSU]lnu~ó~~~~~~~}}}}|{{{{{zyxxxxttssrqoojomklim}~toolfQKEDEGGE?<97:<;96566:<==MZflnqutzwnc\\\Z_abdca_][PFiiijjkkkjjjjjjjjkkkkkkkklllllllnromkklljjx}`ODFHFLVPRVY\aemɺ~~~~~~~}|}{{{{x{yyyxxxvsssrqoomjolhkhl|yidd\NEA=:999877666:;<;:888:<@CG@Shƶ~~~~~}}}}zzyyxvvtwuustsrrqqponmljhlifhei{|sk`VPJ@43200259::531334489;;CO]ipwywqfZX\]]^`````_^]UJAhhhiijjjiiiiiiiikkkkkkkklllllllljjkkuθy_K@;>==;;:9:?EQcȼ~}~~}}}}}}zyxxwtsrtsrqrpppoonnmlkigkhehbfzxrk^RKC920110//0249;=<;631.01279::?K[hqwwsg^UW[[[]____^^]]UJ@hhhiijjjiiiiiiiikkkkkkkkllllllllpnlt}^KCAA@BABCA;BGLfʿ~}}~~}}}}}{ywxutsrqrqpnpmoooonmljihfkhcebexzqhZI?>90/6455420016:=><721,.0168:::54344676431/..26::841*,-.47::6DWhswrk[XTTWZ[Z^bb^\_`^SF=iiiiiiiiiiiiiiiikkkllmmmmmmmmmmlgogLGEGHILKBGQ`|ɼ˿~}|||||||z{{zwuusrnommlllljllknonligecd_^b^`p~rdQ>:6534457777541//.1489844...-24897DWhtwpgYWTTVYYY[__\[^^^RF;iiiiiiiiiiiiiiiikkkllmmmmmmmmnnleyҼ`QDDJLKIDTk꾱~~}}|{{}}{{{{zxtqronllkljjjjijjnmmmmifcda]_c\_s}~p^O?42012445777655200.026788943/,/1566DYkwwl_WWTTVXYYZ]_]]_^ZNA6iiiiiiiiiiiiiiiijkkllmmmmmmnnnnmjζfMFHKHDPjȰ~~}}|{{~~|{{{zxroomlkjhiiihhhhhmljijjfaea]abYayviWI@:80/34556676643311./0257;<972-./244E]r{wfUSTSSTUVVW[]\^_\WI=1gggggggggggggggijkkllmmmmmmnnoonqʶ}YGFFCAb鶤žɽ~~~~}|{{{|||{zyywnmllkhhhihhgggghkhfgihebcb_]]Vb{taNA=;993356675464333211../036:<=:500/112Gbw|q\JOQQQQQSSW[]]__ZRA6+gggggggggggggggijkkllmmmmmnnoppnlzűeMGFGJzԵŸ~~~~}|{{{|{{zyxwunlljiihgggffffffhhggghgfae^\`aiuXE<9;8536576655321211111.../0367<:8542100HeutfRBKNPPNNOQVZ]^__VN;0&gggggggggggggggijkkllmmmmmnnopqohmuZPS[c귨³~~~~}|{{{{{yxwvvsnjjjjhhhgfffdddfghiihijlgkbaoxtnC548841255544443/.0...00100/01349:;::62/2IcmfWI?HLNNLLMOUY[]^\QG6+"gggggggggggggggijjjllmmmmlmnonomkm|bX]m|Ǽ~~~~}|{{{zzxwvuuqmkjjiiihgfgffffffjmkjjmolodczyb>3474/2932201244.,/-////100///0079<=;82-2Jch]OFAHKNNKJLNTWZ[]ZNC2)hhhhhhhhhhhhhhhhjjjllmmmgjnohfsպq_brףþ~|{zzwvwwwwvuqnliihhgggfgiihgeehjmkjiikgjdv~R7443332211302/1//././///0//..///136897534DW[PE@BIKKKJJLOUY\]]WH;%&$hhhhhhhhhhhhhhhhhhjklmmmijmjgl~̴kY_tĤ¼ÿ~|~}}zzyxvvuvtttromlijhihggeeghjjjkklkkkjjigkguK6333222111100///////////0/....//./1466656CPRIABEJJKKIHIJSX\][TC6&'%hhhhhhhhhhhhhhhhhhjklmmmmkmjkwɰuktדνù~{zzzzxxwwutttrrrronlkljljkiihggfghikkljihkjiffljuE5222111011100/////////////.--./.++-/24678?EC;8>DJJLKIGFGRX]^ZP=.&'%hhhhhhhhhhhhhhhhhhjklmmmnlllpDz跔ż|ywuvvvvusrrqooonkjjimnmllkiiljhfffhfjfefhifcchisp94211100011100///..........----.-*)*+.1456:<8228>DEKJKGHFSX`^ZL9)&%#hhhhhhhhhhhhhhhhhhjklmmmlknot·ĝü|wsrsqssrrrponmlkjiijnppmmliilkheeeedfccdddb_^ejr[32211100011100///........--,,,,-,,+**+.0225651158=@FHJIKKT[caYJ6&$$"hhhhhhhhhhhhhhhhhhjklmmljkloṣ}xspppqqqqpooonmkhhhloqppmljihgeedefd^acdc`]]]bmsvF43222111011100///---------,++++,,.,***+-.-045433379@BGHMMU\d`XG4$$$"hhhhhhhhhhhhhhhhjjjklmllllkkly򫏪zuqqpqqqqqppqpnlijjnorppnljiddcddcc_Z_ghc^[\]]nt|c263333222111100///--------,,+**+,+-+**++,-,/26775424:=ADJLT\c^UD2#&&$hhhhhhhhhhhhhhhhjjjklmllomjgfrت}wtsqqsqqqqpsqomljmooqommihffddb`]\WT[fibZZ\ZXksuU&83443332211100///--------,++**++,+)*++,--,.2699760259<@FJR[a\QB/"*(&hhhhhhhhiiiiiiiikkklmnmmqkkkjpytssrrtsuutqsqqqpnookmlllhgcc^dcTNM@WPKO]ieVX]ozd=-245444333333211101100////,,,,,,++.--,--..+-059=??753129BIOV]YLLGDDM\b`YdssX:/7666655555554433322211100..--,,++**)))*+,.-.049?B;:7436<@LSYWL=1+,+*hhhhhhhhiiiiiiiikklmmnmkmijkiqߨvuvyxqnqtsoqxnmmkljljggggec`^bUZ`RCEFABA<84235DKQQH<2...-gghhhhiiiiiiiiiikklmmmmjkijjhmvuuw{}xkb{sqsogdgiiigfffebb`__[ZWXO\ocMII>?@<:;99887778888888899988877654320//--,++,--,,,,.034;=@@<7426:@B?81--.-ffghhijjiiiiiiiilllmmmmjkiigbgͳz}taWY[X```_```]\\\YXURQNQi|mSF><<71-,.-ffghhijjiiiiiiiilllmmmmjjhhfchteb\^\\]]^^\YWWVUSPNMP`fUEA>>==999:::::;;;::999;;;;::::87431/....,,++,)$)28;;;;89;<<71../.\]_`beghfhhhjkklkjmlmjhffgfbcr˼VXUSWWUUTTTSQRPPMKHGJFA=>DFDMKFCO^`ZY[___\XUKGDA@>??<::99777:998899:::9:;<=>87775321./--.067;;<;;<==:?DDC@7.-,)YZ\]abggggiiklmmljklkjhehggfjySTRQUUTTSSQQQOPNMJHEGEA?BFJJKKRY]WSSUVZ[\\ZYRPKHCAB?=::97766:998899:::::;<=<=<<<<:98743039BGOLLFB<;:=DJLKH<3++(YZ\^acghiikklmnnlkkkkjhehedgoPRRRTUTUTSQPQOPMMJIFHECBFIOQPUgwpXLNPQTUWX[\YVQMGDC?=::97766::9999::::::;<><@?@@A??>>9649BPX^[WMC964==<>>@???=9649DR[YWTI>30.6@KRSOA610-YZ\^bdijmlnmnnpomkjjiihfga^dp}þQTVWTUVVUSONQOOLLJJILIJNQR[csZPNNLNQVXXVSPLIGC=::97766;;:99:;;;;;;<=>=;:<<>=>=:7549BNUSQOE9.,,1@ABCCDDCBCCDE??@BEHGFGGEGGGHEFCDECB>=;::??>>=<?@?>=?BDDD?AFHHA835553100022211001/0////..,+*)(.6:BIMOWdot{yaKDJGHQd}|gWNRQQ//000122333333331100001100000000..---,,,-------.+--./011334456779;=?@ABBCCAAABCD>?ACDEECCAABDEFCEBCDDB@?;::@?????@@@AA@A@A>?>>>=<===>?@@>>>ADCDACFIG@946654211122211001/0////..-,*))-48>EJNTalr{u[HCFGHNYok[SSRQ../000112222222210////0100000000.---,,,,-------.-./00112333456678:<>?@@@@@???@ABAABCCCBA<:;=@DFDC@BBDCA?;:;=@A@@=@@???>@?@@AA?@@>>>>====>><<==??A?>>ACDCDFIJG@:577644322222121110100///./.,**-259?EIO[fmw}~mVEAAFHHK[tzi[SUTS-..//00011111111//....//00000000---,,,++......./000112222234556679:<==>>=><==>@ADEDDDBA?999<@EHFDABDCB@?;:;>AB@@=@@@>???@?@@@@@?>>>===<<==<<<>>?A?>@BCCBFJLKF@:789775433222221122211000010/,+,027;AEHR_isy}wfRE@@EFCBL^ny}zobYTWVV---./0/0//////////....//00000000..---,,,////////11111222223345665689:;;;:::;<=>@GHGFEDB>;::=BFJIGDDEBA=<::>>?>?????>>>?>>>=======<>>?BA@@ACBACHLJE>95987654432333222222221100211.,+./59=@BKZgpx{sdTGBABAABFKPcfif`[XXYWW,,--.///.......-..-,,-..........----,,,+........111111111223455545677999999:;<>AGHGFEC@><;;=@FJJHEFEC@>:;:<@CC@>?@???>>?>??>?>>?>>>>===<=<<<<=>?BA@BCCBAAINNG?;69776443433433223333322111220.-..448BCB@GMQQQQUWYYX++,-..//---------,++++,,++++++++,,,+++**-------.1110000011234455345666678889;<>@EFEDCB?==:9;=BFFFFFEDC@>:;>=>=????>?>>>>===<<<=;<<>=?CBABCCCCFQXXRIC?9776543333433333333333220121/../0038BBA?BHMQQRVXZYX++,,,.//--------,++**++,********,,,++***,,,,,,,,/000000011233455234555558888:=>?CCBAA@><<988:=BBFEFGGFCB;;>BDD@>AA@@@??>>@??>?>>>>>==<<==<<<<>>?DCBCCDDEP[ef_UMI987644333443433333333322/0220///,,07ACDEQW^`_^^_[ZZ---.----..-,,,+++++++++,+++++++++++,,--.--------,-./////////012402344555455679:<969889;=?>AACEGGEC@BDEDBABA@?>==>?<=<>===><<=<<<:;=<<=>@AAEDEIGDEMZfqsrj^QLF>85433344421112222111122111110+/34;Omznb[IB>>BIU`q}yuk_ZZ]------,-.-,,++++****+++++++++++++++,,,----------,,-.//....../01201244554444568:;>>=>=;9777799<<=@ABDEFEDDEFGFCBBCB@???>>=>===>>=<=<<<;;<<===>@ABGEGJIGLTdq~|sfXNIC=:841333210001211111122111110+-25?Vrytn_ZUW^gvteXX[-----.-----,+***+***))))++++++++**+++,,,,,,----.,,-....-----./01012334444444679:;;<=;:7666579;<>>>?<=<=>=<=<<<;;<:;<<<>?ACDJHHKKLS`sqcRNID@;611100/////0//////0000000/++/6E^z~}~{hVWY........--,,*****))))(((*************++++,,,,---+,----,,,,,,-./0123433343323467899:;:98576689:<>????ABDEGHJIFBA@AA?>>>=><======<;;;;;;;;;<<>@CDELHGJLQ]j{mZUOID=7310/---./........///////-,*-6Jf|fVUV////....---,,+++***))(((*************)))*++,,---+,,,,,+*++++,-/00234332222112356689:99857677:<>>@???@CCEEGHGDA?@@@?>=<==<;<<<<<<;::::::::<=?BDFHKHGLPXfvue_ULF@:810-,++-.-----.-.././///-,)+6LhzbTTU0000////...---,,+++*)((())))))))**)))(((***+,,--++,,++*),,+,-./01134322121001244579:987555689<>=?>??BBCDBDEEB?>>??==<<<<;<<;;<;;::9::999<@ABA@>@BB@>=???>=;;<<;;;;;::;99:99988<=@BEIKMIHJS]h{xrh]TLD?740+(()+)))))***++,,,,,+))-6Hc˽s]OML/0//000/000///.-.--,+*))))))))))))(((''&()*++-..,,++*)((----./013344321111///0123679::86212369<;==?@@@?=<>BCB?>>>======><<<;:;;;:;:;;:::>>@CFJMOIIP\hu~ypg]RIA850+(()*)**)))))**++,,,+)*-6F`|nZLJH00011121233211//00/.,-,,,,--,+))))()))**++,--.//--,-./..-,-./112445554322110/001/1368762-)').5;;:;=????@?>=<;:;9@<8>>;?;?DHLMONLTcq}ztneXK?90+'''&))('&&&&''(()***)+-/?\z|kZRIA0111221233443200//...-,,,---,**()((())**++--////......-.-..//023555554332100//01//234320,*)*-39=AAA@?=:;9<>@AAA?;;<=>@?@@>=<;;:<9=;9??9:=@DHJMOMJTfw{woaVIA80*)((('''&&'''(()**++-.,-:Xx{jZMD>222233334455542100/./.,---.--,*)('))))**,,.../////../.--.001134566776544210000111/.,+***,.--.024:;;=<<::<=>?AABC?=>>>>==;<::;<==><;@BBCBAA@@??><;:8899;<=>@78<;>A@BDGIIKNPQZer}}vg]PD:4/*%##$%'),*++,,,-,*+++8Uq|k[G=755566666778999774433321112210/.-,+++,,,,////11222222111145467889::;:985533222233420,('(,257631//:;<=<<;:;>ABCC@@BC@><;98678:<=>>908?55BCEGIJJLOU^fmry~qhZK@6/*'%&&'(+,++++**))#*06CZp}{k\E:46677887789:;;;997765654444543310----.../000122333344454567789::;<<<<;976554334556521.-/158997622235678767:<>?@?AAAA?<:98789;<=><53MYA9FKGJLMMPU\ipruu|}thZM@6/+****,----,+)('((3>GRbqy|l\D93788899899:;<<<;;::98887777776533///000111122334444456989789::<=====<<:87877667786788988988989996//369;;=A@=<:<=@?@>><;:;:;<==<;91=l[DLNIMPQSUZdqxvsmkotwk]OC:210//////.,*(&$&5CQYbmw{{m]I<688999:99:;<===<<;;;::99899998753001111121133344445589:;;8:9;<=>>>>==<;989987789989;<<<<;6666789656;@DHJLQLD;779<<=<;;;<=>>>=;963)?}hHKHLQSVVZ_fqvsk_TQRoyynaRD;410//../0/.,)(')BQ^elu{~|m]OC<:::::;<<<<==>???@@@??>>=;;;;:;::8887677777655544666778:;:<<>?@@@@@?><;;;989888995D@:@60<4640/6==DNPVYOA;>98537>?==>>?@??A@@@??>>>>>=<<;:999988997766654466677::<;;=>@@@@@@?=<;;;:99999:::8/.7:;EDHIHJOPODBBC>77=C?@EGFHNKG@87=>=+(9KLO@A`Y@Ta[\hlfccfaXC.'(*05?LRTUZbeilptvx|yvqkea_aTLHDF710168:>EOZafrymaSPO999:<=>???@@@@??AAA@@@@?A@?>=<<;::::;;;<887655446657799;;<=??@A@??>=<;;:::::;<<;E33ALV]`BIMORUPLAB@?;78=E>7:>ACC09DKMKA786103?@AAAAAA@@BBBAABAACBA@>=<;::;;;<<<9887655566778:;<<=>?@@@@?>>=<:;:;;;<<=><8+;UUVVK4:>BFJC?BFB@?>BDGB<;<:639987=JTX?4-6HPB4;/98F]XWWdpofcmuUF><@C=7B<7642383568:=?@CC@?ACGJQTWUVcfY1018>@DFJT`k||tldXWX7789;=>?AAAAABAACCBCDDCCCBA@==<;;;;;;;;;9998766577788;;<=>?@@A???==<;;::<<;<=??=64M^NA7'28:=AE??=;9:;=GE@98CMSDMTUK@53493;9A[UNbj`ZdpmF<;>DIJILD:7414:9:;;===<<;;;:::99876677789;<=?>?@AA???=<;;;99;<;<>??;9GZXD94,28::=@;87:97:BEE>?<66>DG:AFD?;409IUP?2071=.847hlWZVQ[jgSE><>BHPWOD;62/279::;=?CD<>?@@>=@ACCCDEDDFFFFEDCCBA@AAA@?=<<<:::988778888:;<=??@A@@@?===<;:89:;:;=>@:2KT?101229===?;768648@C@BA<8:CDA@@7,$',1,057542347377?aeVLVdcRBE?>@??EMJ?86526;::888;=?@@ACDCCCIDHMMXa^kqo]C6AUe}źxsojih66666778;<=?ACDEEEEFFGGHGGEDDDCCCDBA>==;::::97777789::<=@?@AA@@?>>=;98788:;==>?9=]Z8/2/3:CGFBB=:9;:7=648G?:997:?CA?;::;<@???@A@BDOVLBVif^`hppf\Y~ʿ{urrpn12357888:;=?ACEEHHHHJKLKJFDFIID?EC@ACB=9<:978774:999::;;8647:>8;B@8;BjK76768=9<@A=967678<@BBA>=<=CF>299997642./1257:;:34886BSNS\]P>8?@C@><:;;LKF>;EDDD@<=BFA;:=DIKNNQROOZg]EV^[u\rɺ}{}./2456779:=?ACDEHHHHJKMMJIJPUXTOID?=>?=;:977888644579:<=??@@@@??@@<96434<;=?:6AJP;26:79>;AB@?:;:<=ELNG???@CCDFB>>BFC?@BFJKHGJR]`XOFDDI\jGyƲ./0134669:<>@BCDFGHIJLLLIKR^hmkhYQG@>=<:::7789:93469:;<<>??@????;=<:75427981+.:E:219<78<;=AA><:<<<99<>>LG629668::8630..12687859>=69A<>EKJC?CCDB=:8:;8DNI@>BHA@CGE@?ADCCFIKLJBDHN[bWEMV@Gyy@{Ͻ../0124589;=?ABCEFHJKMLLJP]lzuk_SLE@?=>=::999884,)07=67:??98;:<>@>==>?=989::9;;BE>129546776310./02465204<=9=D56;DMKC=@A><:89;4?HHB@FN??BHHB@AACFIMOLH?JOIMWWOKN>b9Kwƹ00//0134789;=?AAEFHJKMLKJTdxwmd[PJGB=75655789;<<=?>:889;<<9317>=8;<@A@<;>8:<=<;<=?>:778887AC813754346551////024541/269:?EF@<@KNE;=<<;9:BIJFCC@BEJNOLHDNPHJVWQGHXH/j53200123678:<>@@DEHKKMLKLWi~~vkeZTKA<:765567:<>@?@ABABA?=:766789<408BG?4;>??89:99::<>;9889867C@0,7<2322332/-/.014565733358:;::::>AA<?BCGJKLKJJWlyqcVNGCB?=:99;=@@ABCCCCA;=@DGHHGH=:FPJ?8>>>?@@?<8899889;::889:76<>924;<311121/-,-/13567798644787NXZQGD@><<<:9;>AD@@FIHGIFBDLQOLKDDFINOOPUTTY]\SJYWO^NVVYc=:7422234468:<=>BCFJKLKIJXmyi]UPMJGB=::<>@BCDDDEBCHQ[acb_XJHSXLA?B@A@AA=77888678;77789986A838==952000/-,,-/245778787679744Nd`OA;9>><;99<>DAEKLGEHICEMSROOHGGINQRTTZ``VNQZ]fPXSZOS\r>=<:8643223469<>@CFIJKLNIRd~reZRQQOH?:;?>BEDBCFKUeqruwo_[XWWNA:;<=?@@?=;6667789889:9668:C=7@[l]?322/*((+-021014:;<<<:987@8GcXB@4:<<<::<>>CPXO??HHGJPRNKLROKJMQRRXYY\][XVeY_^IITXfg?>=;9765333458;=?BEHIJKMJQb{qe^WVTPICAA<<>BCBA@B@816I[@6+)-/,(04663226:;<:975495=PTLB1;=<;98::>BOWRDCHLJMSTPNOVUSRRSSSLT\`[URTWT]]RW]V`\AA?=;987443458:<>BDFGGIJKP^uum`]ZWRKD@5EWcsz{vpcTGLI=6:==<;:;<<<<68<:7439AEB=<4472,6GK@4-,,,**/2541137:::;:884<:<;:6555579;>@DFEEGIMNZpymg`ZXQG>58=@CO]glnoiaXI;3AE<8@A;655578;<@@@?=964.-.3:<855,)7B?4.FIH<-#'/-/2310/079:<>?@@6LJ5GZIA<;::::99<>FOPHCCHFJPRMKKX[aaXOMNLOSRTZcifbbegjjh^F]HGFDB@=<8766679:>ACEDEFHMMWkukea[QHFCBEMU[ZTSTPJC9/9DH?>GI?>=<>?BDEEB>;653314798765/57219>;7Wa;;PFP<:89:<;;:FEIPRNKLZ^fh]PMOSRQR\giee^^jskeneGV{KJIGEC@@;:9888:;?BEFEEFHLKSixupg__WPOSTPHAAEEEA;6JIB89AD?EEFEFGGG>;8434468<=<9557.;=1-7=:98:=@<3,,+*+/489777776555PmH4C>VA>86:<>=9=;:9:9;@CEGGFFHKHRgymcXQMIA>>AEJKGDAVH<68;98:<;:874243333568==;876433346=>92:415<=73---/49;9200112131=jT9@:RJC:68;<=;?@?;;;<>>DLPNLNaahohZU[[_bk}v\ekbjiQUgONKJGFDD@@<;9::<@DFGGFHHIGQhf]RJB><=@CFJJGC@SD9>D@85CDCA>96223455444B<6699518119847C786535:?LHB><72,+),/14570.d]@D;MRH;689;:<@A<89GKIIJa^dnk]X^adhnnpxaXhQTaOPNNKKIHCCA@>?>@CEGIJJJKNLTh~iNFA==>@@==F;DE1JKC>;<=;@A<9A;B@3OC?;888:;E=FVBBURKC=998;;:<>?@>:;=>??BCimbkobksonka\cnwuyYccr_ZsPOOMLKJJGFECCCCCCFGIKKKKMMWi{s[FDA?>>>>><8?AC<9WB>;9669;H;5AKH=86776579=2354469>3345772,@>=<977773/.../.,055349>A1S;ACJTUSOJC<86777:<>==:;<==?CE\galpafjP^jhcfouroQZazmd`wPPONMMLLIHGFFFFFEGIKLLLKLMVhy|sfXH>DDEDB@>>?:?EA6>ZA@=:899898:89;>0133468;6:;;::;8C@@=99:;<711131/257757;>;<^F3.@Wurj^PA5.888;<==<;<<<;>BFM`apt`]]FXikhmqsogJR]tjhg|PPOONMMMKJIIHIIIGIILMMLLKKUet~}snf\NA;;CGIIGB>=B>@I>2CUDA?>?@DF=859==;<:;;;88898412341/0696339>8775457:=8458:98>;879<<:>:>C/:255;CKQSTU??<=>??><<<=<=ADLbcnr``_imndbmuvk_GKZyruwOOONNMMMLLKJJKKLIIKLMMLMKLS^jt}{tnhibXOA85:BHLMIE?>CCAI;4ILB?;<@EGG888998:;;=<;86652.+/3642.352..5:0033579<866:>AAAGA;9<=<8:70C2?/*15898521EA=:99::;=><<<>ASgcjncjnnrpfgtungZHHWNNNNMMMMLLKKKLLMIJLLNMMNMLOW_foy|vpke_^UNJ@64:@FJKHD??AFAH:7OB=615>EFD9:::89::9::97533**-.123577988755*-1468;=58;=>=>AJGA<998929@D0.46379:;;:;LF@96678;=>=<<<=KdckoirueotooxtebTHDQvNMMMMMLLMLLKKLMLJJLNMMMMOMMRX]fqwz}}ytomie_OHEGB:6:>BEFEC?@@GAG9:U>8/*/:CC>;;<:;<;8578753323684-((+-)&),* "(,0135669=>:759HKE=636846C82 8614456657YRH@;;<<9;==;99:>>ACDBC?@?><7:<;99:::962./7=961+(&&&&!"')!%""+-*,266661.,/9:9S"+F..<535;;8bZC6:83602246:<=:C\psxyqzwuvtrkd^JEFFgMMMMMMMMKKKLLMMMLMLMNOOOPONNPSUX]dilqz}tlosgV=76=A?@A=;<>BBBB<=<;::AJGA65@C958;==;;:99622588921/-,-..*%$'%-2)'-/*:742/0282;8EE/2"5?E=326::9559<<9cX@49:6954456566;BYlqx|uzwwvuoha]KDFIfüLLLLLLLLJJJKKLLLLLKMNOOORQPNOPQRTY_clw~}vosuhQ=66=DEB?=::=@BAB;99989?FD97;COH39:;==<:972/4=?946620.-,,,(')%%/459:5-2/.-../40=6;mC//:@A<75566668;<<;`T<0;>;==<=<;966;@Tgoz{zyzyunc\YIAFLazzKKKKKKKKJJJKKLLLKKLMMOOOQQOONNOOPTY^hu|{zxtcMHCCFIHEA@<<>ABA@?<9:98>D<3;ADSU:977;==984229>>5/6742..,,*'(*'"%8(,M]N<:)*-020+(072CsV>G=<:87643568;<9:=?@?<:99=Ncn|}vwzzvmb[TG=DO[hmsyz}KKKKKKKKJJJKKLLLLKKMMNOOONNONOPONPTYerwv}wlYEFIMLGEECB??ADDB?A=::98;?F=BA;JXK@838<:78038;:60,02123355.-/1.*,4:3>\hUC@3336984/2.7Y\XAHB<76897589:=;67=NE51>@852258::9:68I_n}~tvz{tlaZQH>ESV[bpvy~ƺJJJJJJJJJJJKKLLLKKKLMNOONNOOOPQPLMOU`otqvteQ?7@IGABCCC@@BDDB?@;8998:;I?=72AZhPA56997806;;4/--4432110112551.1>3N_\TOD8A:2/28;::2JkLP;;L@77<<:;;:<>93:DGC72;:22,,.37:<>64BXj|uw{zri^YOK@FUST`s|²KKKKKKKKKKKLLMMLKJKLMNOOOPOPPPPNKKNTapvsuqeR>/7A@?BCAA@?ACB@>>97:<<=?=90/49MlhQ<::76847961/1120-+&# '+/1,*3BC_gUJJA1@7-(.8?@?:Y]GD6;UF98:99=?<;=73=LGE937501,+.148;>93;Nayyz|zoeZVKJ@ETMM^r~JKJKJKJKJKJLKMLLKKKMMOOOQRRQQPOLMLOWeu|xz~umZF4:@?AEB>@BA>=?;80=6/.4;?=98V;?42CWH96655:<:7941?RIH;241-2,+++-148=27I\w~}}wk`WSDG;AQIF]m}ͿKKKKKKKKLLLLLLLLJKLLLNPSSRPQRQNLKKO[k{yrjaMA=BEA=>;;:;<;:96A<6AF=787568<:6;SZE8>B:2G/67-B(&))"'',!&,!V+\^YTOG>6=@>615:;87E;365DLKD:4545<9/(-9CHPE700211/0000259=2>=_sxh_\VMH<>B^?C[tKKKKKKKKLLLLLLLKKLMNNNQRSQOONPOMLNS_o~xy|ui^QGJLG@<9:9<=<:;88;:I076.?%$%)+*((+$%%;2?#haZVNA;=7BG=/'&'-:TH54=WGGA93677=95248?EJA600200010/0149=3<=^vsd\YTLD=BJS=C\vo_LLLLLLLLLLLLLLLLKNPPPOORQQOOPQTTTV\iv}~sfUIHIGA=778H0561B.)#$1-'&1(7*(2Q;Y^UNLE:7>5>A<71+&$/E:,3A^?CA=9=@@@=>A>:?IB<521310000/0149>48;[z|qdZUOIA?GT@8F_wcOAMMMMMMMMMMMMMMMMLNPQPNOPOQUXXY\^`ckt~y{tdXOID?<679<@@@?9>=FRH5198;=;66852=NK:8B6>/024JF>3$/,2*/92+8DWK<@B>9879889@MUMB79KMQYRY5>B@?BC@?89?:5>M963343200/0//048?659V|yncXPHC=BMZ29Me{bRGMMMMMMMMMMMMMMMMKMPPONOQPW`fhggglpv|ulnuvsmh_SG<7569<@AA@7@:;R\M;979>=64637=EFBA>070-,3LWZO.0,E6,,=12b=)-&;A7397/4;GS`ie^@E^hojK=4>DC><:45-,.,,9J333354420//./037?828N|~ulaUJ@;:DPW.>Tj|wkaNNNNNNNNNNNNNNNNLNNONOSTZbmuuqpptw|~kRNRXXTK?489:=@A?>9A5.IgdU<63:;63617;9>FB9043-)/BR]\99+J8/3'%W=96(=B5,10)4Lbid``bLN\VMH43AKOJ@:6.2-*')0>J133544430/.-./27=;17Cy{qh`SE:7:HPJ4BWj|xPPPPPPPPOOOOOOONPPOOORVZgoz~|wuvy}gFAABHNJ?=;;<@?><:?41IcheO>4795260477>C>43/3.-06@MYFQ3F8A5,.F77#;9<>7.*2=M_mja[Z\dZW@143CJRSJ?983.00*.;CA144543440/.-./27:>17;stha\RD78=NQ9GWWN@=<===;98<:=OX]ecL:894264258.@_nkd^_c_Z]PJ7/509DJI@6476'02+0>?4356433440/.-./279?066pnc^ZQC9;CTR0DES]suqkLNPPOOOQROMMQSRQSPPQQSaqx|zsow|¨]ztHQcK?9;:76;85BUahgdda^SF841/39DB?<9896744465313575322210/./037?86/;X{mf]QHD=;OT=,:FM^ix~rjUUTKNPPPOPQRPOPRSRPVQOTZ`kwy}|upoqw~Ǽ|}V`rZK?>?;66=8?6>KH]o`H5065059=<8545752002458>JW^\]aOJN\heYO5-,/(")9Q\defe\RE<665326>>;:889:977776323676211210/./037<=817Zsg^WPGA=BQL<29AGScrui]WWWWLNQQQQRSTSRSTTSPUQQYdmu{{~|signu}ĮnQ]mu`JBA>96=;A77>=Fji[B24625AG=212041./27=B-4DV^ZSQEFM[kmWS?AGQZXG657;@@=978988779::;:::853678620/0221000368F93,fygdVLH@7?RYCCOFCGDUctyqifefghiHJNOPPRTRSTTSRRQMXfptwz{yrgcgr|ƶ{urmotfXOEA:;BE<=B10IXN=8634Uk]D;;842100//0943:CEB@EPVV]eW?;53229HV536AJH;159<<;:77;;:98767:;::;96378973101332010367C711jqg_RD?;:G[VEJYOIIEP\l||tnklnqopoEHKMNOQSSTTTSSUVVeuyyyywrjcep~úytkkna`sz~sdUID>69=?BC@72L_WD:87999:9988(3@ID;7:9IVY]_S?@?@FLQTU3..7<:4049842244<=<;87448989975378:72001443111369<70@nkcTJ>77@O\GFLVQJGDJUcs~xroprurssBEIKLNPRUVVUSUZ]gpxyxwuohfgmxonefm^cZgu|}xj\SH=D;G\;<76>DBAA8>CB=877:9:;>AEG-;JL=009ALVZ\YL>459?BD@>301761-12970,033===<:9665556652179:7411145421136;4:2UpcZKH:16CMP5GKNQJ@DFO[jx~ywwxztuuCFHKKMOQWXXVUW^cruvsrupgaels|~xacXZcVbMUaly|paTGOBGW,14>E>27EE935;=<=;954584bp[PFH=27GJB+HKHPJ@FCJUdr}}|{{|~xyzBDFGHIMOQRSVYbjoqtywpga_bhpz|og_ZYVUVRYX[kzuu_PEZ7267779;mbUKO:9?@PI$+8DLICDIHKS]kv~~~}{?ACEEGKMOQSV[clopppmfa^\djr{yme^[ZVTTT[XXfrx~ugUZ2/77788;;=99::9988;98899:968=@A?<94>HOQNC77874/+)(+*)&#!$)-27<9:;;:975345676559999988653455677=45Tf[ILE@8>NL8)36;@B@DIDPbovz~~9>6/:878::97568:=@AB:@EFHG@766740-+*''%#!#*279;9:;;9875345666548998877654566778=28l]Q>K;B8AW@".456;>=@EFa~}58<>@BEJLMQW^gnomg^WUX_cns|yp`ZY\^[VRT[YXclpy}zk<8;:;:::98:658>>8/65469<=;::99:;<=DEA=C7<=<;:875@@=98;:5/022/-+,-.////-.((+068859:;:986444577665899998788:;==>==7<]`PA==J\1479:=ADHGJS^egfaYQOS^iow|vjWQU^da]WNUTR\bhqyq|sx\;5;==<;;9757:::8:==@A>848<::;;:9556;>??>7,+-0310000110/-,*..0367659:::986455677666788988799<=?@@?<7HgNH8B197SW2)7237;:8DcǮ014568=>EEHP[bb`^XTT]isx|qfVQW_ed`[R[YU[]bmzrxY[D5::<==;:86038;;;;<;CKH=45;999988776?@@>;:U^G>:85:GP@2593358;74BONB77>;:876688;;967<<788:94/,,/13455352586447<899:8764557898778:9;:::;9:=>??=8<]QH8?.>=]L-8B74029DVtú|0/-.038:=@ELRX\^XY]enx}xoe]\\\^_``^OT\`YQS\hYD77:=;9:9:8855/38>@@=990WK/=<8;:9876547;><78>CB9242--275679:77;<:88777999:99987689;;97899:::;<9=:49D@1_WK=328E[G43?B6+.18Jn˾v{0/../3686699988887645059=A@<98BHMRUWY]dnx|}|vpjd^]bb_\Z[\\`WRUXVPO><87667778886535369?@<647+<]ubhx}44112346;>AFJOQSVZalw||~}{vnfa]Z[ab_\YYZ[VQQX[TG?2556556878896636687:>?;84U<8B5==889:97636324:>?=4565237>IQQUFFBCC=622Fk_Wcr{88666678>@CGKNPRUX_is}}||~zwsne_[ZYZ`a_\[ZZZTQQVSH:41355335989::8757;:68;=;79\=5A3:?::::;:873117<>;77;<615BMxq`J827@9977677767788877777:==;;8:;<<<;;;=8980@iNHEIPUVZKJDCC@BGUgcPSal{=>===<==BDGJLOQRWZ^enyywvwz}~}ytrkf_[ZZZ[^_^]]\\Y^UMI@8225654246;9;;;:979>;559<;7?[I:@63<97777777<:9<>=849<:8>PbphT=14;=;;:98775666788776888;>><<8:;;<;::<9;96>TfLJLNSW\aGJF>36Mf}`JFP_jzABBCCCBCFHJMNQRSZ\]ahqz~{sommoqssokia_\Z[[\\\]^__`]Y_OB;723576434579:==><;9;@<538<:59NTBB?1<<97679;;DA?>=;88897;J\dc=848AE=4;;99887767688776768;>><<8;;;;::9>7=92Pk]PKJMT]ejKH?75GofTEBDJXh|CDEEGGFGHJLNPQRTYZY[aksx{}|wnigfghiigb`]\Z[]^^]]]]]]][WTE97866664447766:<<=;;:A>;;=99989:9:88889877668:==<;9;;;;;::?5=8/\zXYQMMWahnTH9;Pt~}bD<=DECPe{KKJJJJJKNOPQRTUU[ZYY]afjnpsspjb]`_]ZZYZZ[[\\\\]^beZOW\Z[NF<88841677777678899998;;>9129<955:CKH=2PJFEIHD=78::979=EA9204;?:=@@><9:8889999945678999;99=ABA?:<=<::88ACCNdsNNNNNNNNOPPRSTUV[ZYY[_bdegiif`[X[ZVTTTVWZZ[\]^__ag[SVXRRIC=98743688878777777888:<>912:><:44;EOQOFA<;>>:588888:>B@=9447<@@@A?:8786678899:9::;;;99:;>:23:>>?824<963369<@785447;=DCB?:8676667799::;;<;:989<@B?:77;<<;:979669FSWPIMSY^aa_eroRSPLC<98;A?978988877888889;?>9338=@?:757:<:72248<>=84126877365668::ABB@<:88677889:;9::;::99<@CA;667;;;;:879=55EPMLQPUZ^aaag`A>BFFA===9@><@BLbw{vZZZZZZZZZZ[[\]]]^_`aa`_^```__``a^ZUPMKKKMOQSWZ\\`]U[idOC=:988:647=B;;:98:<;:533554365489830599:::87:;?@><:976678::<:;<==>=>@BB=757:;<;:9878@43GQNNWUXZ\]`ahkS@2:;=???;:9?=;?AKbx|x\\\\\\\\\]]]^^___`abbbaaaa````ab_]XRMJHHJKMOQTVUXUPWhfXSA<98:>B@;78999988999999;?=<965;AB@;724;=6479;;;:579==:309==>=<:868;>=<;;8778:;<=>?AAAA@B?@=8558<<<<:9766:39OYROVY[Z[\_`gx|`E;;<=<@Jax~y^^^^^^^^^^^____`abbb``aaa````aaa_^[WRMIHHHJKLMONPQNRYWT[KA97;>@<:78:9:::9::::::;===<849ACA=6/06:56;@BB@?27:><855<>>?>=;:78898:=?:99:;;=>BCCBA?=><:8678::=<<:976635BUWPPZYZ\\[\[bb`SG?=>?=?BFGD>98><:>?J`wy________^_____``dca`_^^`aaaa``a`a_^[WRMLFGHHIKKJJPOLKEJ[SF;7;=<7:89;;;;;:::::::;;:<>937?9;><87?@@@>=;:7659?C<;;<<=>@DDCA?;897856:<:8=<<<:86618GSPLR_WY[]]\Y^XM@AGE=78>EJIC>:8>;9>?I`wz```````````````_```````aaaabbbbb__^_]XPLIHEDEGGEJKDJQFKkhVGA@=;;356778;=<<<<;;;<27;:7579A;646?@AB@;:7668:<==?AAB@@HEA;53129;9::;;<98999863-AOMLQUR\\UTZXWgTQKKH@=?89==>;;9::::::::;?BB=611256;AEIJKBEB;9=?=?>>==>@?=<<>???>@=:87898<<<@>Hbzy```````````````__^^__```````````a`aa_\VRKIFEEFDCE>GK?@\tWdeTFGB97:::98668777788835630/13ACGLLJFDBC?;?AAA;:87667:;<;;:;;<;;;98764;FNJHOSROTSV]Y[l}xXDJZqoeUIC@<9<:>>>???>?BDFFIMPSPMIGCAAEC>;=BFIEEBB@@@?;9:;;<;;:9778:;;:89:::987766789<<<;9:9:;:;;98675DHKHIOTTQTQS\_h~hRO`rtiXLEBA=8;9>Z`?4@YjeRIMIF@>@DGGJJJJKKKKSTSRSSUULIECBCEFID=<>BDGDBA?>>>>;:::=<<;98889:::;99:988888889::;::98878989:85579HIIIKRWXQURV`bgzriYRZiv|i[LDDCA=9;8;B@H^u{t````````bbbbbbbabbbbbccdddccbbbbcbbccb`]WSMJHEBAGFB=EYO.<>TpvdX]UPGCDGGGHJHJJKKKHGHGHHGFBABBCBAAIB;=?@AC@@><<;;<<=<=====<<;99876989:;=<>99::;;;::9765556689845:;:;8;B@F[qzs````````bbbbbbbbbbbccdddddddccbbcabcdc`_[WQLIGCCFE@FPH94CAKbqmaYQLDBDEB@CCCDCDEDAADGIJIGAABBA@===?<;:9889:<======<<=<:986699999;<=9::;;<;;88654445268635:@PNNQVXUROTT\f[KKNZgryzl]VH@BFD=:;<8DDDEEECD?@BEGFB>B@>=>@CEA84:>=CB<<==9IgxlYOBBDFHJKKEEFHFDCFDEEDCB?=BCCDDFFECB@????BB>979=>>??=;9889;<<<;:::::::::::9988777888989888887866551643648ISSRRPQQRTT[c_UV_~xojgbYRD>:;>B@>89::=?BE_rvm```aabbbaaaaaaaabbbbbbbbcccccccbbabcfgedchigc^ULJ>?PXNEDWTQPNMLLUI>=CFB>DDFEEB@?CCCEEFFFECBA@@@BDC>:9:<<:989;<;;;:::9999::::999999999::99999888766661743637HRSQPQPQSOS[eikqxtnfa_\VPF@;:=@>=:;;<B@87=79;@IPX[^THCDGD@ABDFFEDDDDDEEFEEDDDCBBBCEEB>:89;@@>=:98:;;;;::::99::::::99999888;;:;::::887765551642637GPPPQRSUVW[^birwwe_YUVVTRID>;<>=;<=<<<>@CWi|}qg```aabbbaaaaaaaabbbbbbbbcccccccbda__acefftzcTGEC=97645BOOIGEB@ABCEEEEEDDEEEEEFEFEEEEFACEB>9;=;::;:;:::999::::::::9:999887::9::99:766543341742426DNNQTUWY[Y\ZUX^YKHEBADILNKHEA?><:<<;;;<>@Pav}~|pfaaabbcccbbbbbbbbbbbbbbbbccccccccadfcdmcQIEDFEECBBCEE48=DOWQCGFFFFFDDEDEEDDDEEFEEDEFE?@CCA===>?>=<;:;::::9:98::::::::::99877889998988665434342632415BMMPTVXY\\[WSSQI@<;99;>BEHHGFC@><:9999;>@L^s}{yneaaabbcccbbbbbbbbbbbbbbbbcccccccb`adgpμmYLEDJHFC>;87<;57G\`WQONMJHEDDDDCCBCCDDDEDEFE@@BCC@;9=>>=<;;<:::99989::::::::::99887889888777665543231741404AMMPUXYZ\^WPNJB:8776558:86678;64567:HG>@@ABB@@@CA@AB@:8=>>>=<=<:99888889999::::=<;:98776778787726984223072-0/2>OPQRY_YNEEC@<;::886656669=CGIGC?422359Rl~yuux{|{}~qdXccccccccccccccccbbbccddddddddddddnͻjQJCB>:9<8>EPhձcWSJCGFIKF>=C??@@AA@?A@@BCA;8=>>>=<<<:99898889999:;;;<<::9867788888886789742314/.2.0>JRXXVRJ?AA@><<;:977766679:J_veCHVXOFEFFDC=>??A@A@@@BEDB<9<=>>=<==99:99888::;;;;;<;;998867888889889888874121-04-0DPVYTJC<6;;<=<<;:998777789;?CEGGF>:42037:>Qmxurrtvwwx{}{{}|weWLcccccccccccccccccbbccddddddeeeegkmQHJID@F`ײdDSURHHMJ?>>?@@@AA>@CEEA=;<=>>=<==99:99888;;<;;;;<9999876677788888;757884152.23*2N\WNC<:;<8:;<=;99988989999:=?BEHIC?830148=<<===<==:::99888<<<;;::;78776666788888889645774123011*6UYN?769;<9;;<<:8799899:9999:;>CEGEB;62135:Suponnnnnpptxzz||wlRC8dddddddddddddddccbbccdddddeefgggnİgPKMOR{ҏdKUXG?JCCBBBBBAACDDA=;<;<===<==:::99888<;;::989777877677777777776556765262045=SG>558:769;:9987689899999999:;>ABDC?;64347Txwhkkmmkklnswz{||sfI;/dddddddddddddddccbbccdddddeefghhitƱnWQVbmoWURMJGEEDDCBACEEC=;;<<=<=<<==:::99888;;:987777888888877778887678878;=8<65CLIM9659;7458876666779899988988789;:;>=>>=<<<<:::99888::987666898899987777777758;:9:>C@D<=VdWL:89<:55<654335676778777798877788?BEDA<64;Vr|vmfadhkkhgikqtwxzvj[>/%eeeeeeeeeeeeeeeeddddceef`ekleeqԹtdk}`DKOGCDHIHGGHIGEBBCCCA?><;;9:9877767788765378877666567876433589:;=ABIH_kxJ9::99988776655454545444454433446;=@BDB@>?QekbXTWceffeegjptvwwqbO0+)eeeeeeeeeeeeeeeeeecdcdefdhjkglиqak龀PNLKJD=?FFJLIFCDGDCB@><<<::::9877678886547887776633568889679;;>@DHPRfuL999988877776655544444444543333468:=@BBBBCP]`WOPUbdeeccdenrvwtm\I1,*eeeeeeeeeeeeeeeeeecdcdefhijkkwʱyp{̝KQK@GYT?DHKIB?AFBBBA@>>><<;;:9999999986578786776555678::;;:@BDELRQIFLT_bdca`_`kpuvqgTA1,*eeeeeeeeeeeeeeeeeecdcdefijkmqDZOPYNDEAFIG@<>B@BAA@@@?===<=<<;;;;:988787677677:977779:?>=>CEGGJV\kq=787776667776655533333333332222344467:=@ACGIE?@FNX]`b`_^^ipuuncM:/*(eeeeeeeeeeeeeeeeeecdcdefgimpuʽܛbKLPJADGE?:;?>?AABBCB?>>===>=>=<;;:::76666777;:9999:?@ABDD?????>??@?><<<<<86666788789:@FKOTW[]`eotrgXB2-)'eeeeeeeeeeeeeeeeddcdcdffikmnrwQ]PLKKIE?;=>?@ACEE????????BA?==>>=8766778889;>@AACENVWSOORVYlvm>B;99988877776655522222222110//012454455676:=ABB@??CGLOTX\bkqmbR>//,*eeeeeeeeeeeeeeeeddcdcdfflllkl{rYTQRQMD=>?>@ACDE??>?????BB@>=>>>8788889:;>@BCA@BGS^^XSSWVWmw}a2D;::999887776655522222222100//0012345567768@@??A@@@??>>98:;;<<=?>GG=981QNIKYeaUX`slI9><;:::99999987776665544441111110054434455247=AEGJB@>=>ENU[bhdWF930/.eeeeeeeeffffffffeededeghnlnrt|u\\\WSFDDDCBA?@>>@?=>A????>>=><=>??AABGAGI=786LKGDM[aaYgwy`D;C><<<;;;;;;;::9997776665533221100110001235457;AFJFEB??BHLX_dbVG;5310eeeeeeeeffffffffeecddeghlmotu}뿃ZS]]RF?>BFG?<>>?=>=>?AACCCCDKBISG;=AEHE@BN`jaqzmO<=F>>>>===<>>===<<<:999888755432100...../0164114;BHKKIEA?ACQX^^TH>8554ddeeeeffffffffffeecddfgimmost|ҐRLKJNPK@7MDBDC;8=????>>>?@BCCCDEDIBTi^KGKDHFBAIYemxv_C;@C???>>===?>>>>>>><<<;;;::8865421100//0122530027=BKMMJE@?>IOUVPG>:765dddeefffffffffffedcddfgimnqsryϷvWIILOGBBEIJKKABBBBBCCFGGGGHGGHHd~rXLMEFHGFGNUwznUBAA>>??>>===>>>>>>>>>>>===<<;:987544221001221111257;GLOOKFCAEIOPMF?9754ccdeefggffffffffddcddfgimnqspxѻu]^UD:<>=EEEFGGGHKMMLMMLLLQkqYLGFFHJJGIMxsdRIJE=????>>>>==>>>>??????>>>===<;:9884321000001123334?FLONKHGDGKMJE?9654ccdeefggffffffffddcddfgilmrsqyʏ^OLHJJJKKLLMNOOPONNNOTfo^OKFIILNMIPXmf\VTQJC@AAA@@@?>>>??@@@@@@??>>>??>>==<<976421//001222119@HMONLLGILMKG@;754ddefffggfffffffeeededfgikmrtq{Ǿ܎PBHHMMNNOOPQOOOONNMMNR\YIFLJNOQSNMZje^YZ[UNIBBBAAA@@???@@BBB@@@??>>>@@@@?????=;86433222222466=FLOMMMJKMNNHB<865fgghjjjkggeedeefegghffddgloopпONLJNNNNOONOMNNPOOMLPOJFHKMNXWQMVccZYYZZXUQNFDA?>>?A?@@AABBBBA@@?A@BAB@BBDDEBAA?=;864579;@GMVXVTRONOLQVWWTJ?730ghhiklllhhffefegfgghgfffilpswɿMOKJOOOOOOPPMNNQOPMMPNJIIMPRVX]de^XVUVUVUTRQLJFC@?@A>@@ABBCCBAA@@AABBBBBCDEFGHFGDB?=>>=>CMYapniaYRLKOV]__\SF52/ghhjkmlmjjhhfgfhfhgggfffijmt|ɾ߆JMKKNOOPPOPOMNNPOPNNQNLLMPUY[btx_QQPQOPPQSTSPLHDBAA>@@ABBCCBBAAAABBBBBBCDFFJKJKIGECEC@BIVgr}thZOGENW`efbXK963ghhjlnmnlljihhgighggfffggfhq}ż߅JMMMNOPPPOONMNMONPOOSPORSU[cru_WONKJKNQSTROKGECC>@@ABBCCCBAAAABCCBBCCEFGGHHIHGEDDC@BIXiuzyqdUIA?HR^egcXI;74ghhjlnnonmkjhhhighffeefghfgq}ľKOOPNOQQQONMMNMONPOQURSXXYakx_PNIGGJNPRPNKIGEE>@@ABBCCCCBAABCCCCCCDEFGEFFGFEDBAA?BIVeotsl`PD==CN\cfbVG52/--./..////------/..--../--------+++**)))))))))))$%%&'()),,-../0.002445665532334512456897:9:;>?@@LLKIIDBAA@??@><7/..-----,,-,*)*,-//.,+++++***+,/65213344028;92*&244210--///.-,,,---------,+*+19<6/.---,--,+-+*)*,-/..,++++****+,/55313445268;:3*)354321..///.-,,,----------+*+07:=AILVj}uie___ftoYLJZaa,,-.--......,,,,..----./........,+++****+++++++*''())**+,,,-.//...0245331111/01211223220-+.26:=>EFGFFEDD@?@@@=;5.--,--,,--,+,**+-...++++,,++,,+.653245558;==;4,,476410/////.-,,,--------/.-++/4679@DM`vvkecc^\ey|lXML[``+,,-,-------++++--,,,,--........+++***)),,,,,,,,+))**+++++,-../---.022111/.//.00244321/-)'*-38<>CCCCDCCA@?@@@=93-,,,,,,+-,+*+*)*,..-++**++**+,--65246877:4.-56742100///.-,,-........00/-,-12137;DUlyphgf^VZfqxwvoaTLLY]^--+,-.,-,,++++)),,++++,,--------++***))),,,,,,,,,,,,,-----../01/-,.//00....-./01655531/,))*,28=?BCBBBA@>?<>>>:50-,,,----.-,+,+**,.---,,,,,,,,-..44137987;?C@;2-+3553210////..---........000.,,/...13;Kewmhe`YXWUcba\TMMPVXZ,,++,-,,++****(*++*))*++++++++++****)))(++++++++,,,,,,,,,--./00.,+,-..../--./.016656320-+)*,15:=@AA@A>?<<;===82,,,++-,,,-,,,+*)*+---,,,+,+++-,/.42259::;9@GE=4/-354310/////..---/////////00/-,.,-)+06Fd~rhc`^XOFJJJIFEIOSSU++,-,,--****))))*,++++,,++++++++,,,+++**-------+,,,+++++,,-.//0.+,-./--,../-/023645422.,,*)*.278<>>>@?@>::<<;6/)---,..--..--,**)+--,..----,,/.0/2116:<==AJRQI>763210/./.../..---////////./0/-,-,+))-4Fjƽqgc_]WNHEGHIHGKMONO++,,-,--****)))*,++**++,********,,,++***,,,,,,,,,+++++++,,-../00,+,-...,/.//11234454220-.*)(,/45:;>?@AA@;;;;:4-(--,..--/...-+*)+---,.----...//112146;>>ALT\]TIA?2210.-..../..---////////-.00.--,,)*06Hnƶnda^YVPKRUWXUTSSLJJ///---++,,*)))((*******+***********++,,-,,,,,,,,)*+,,,,,,,,,-.//-,-./....,-./0124565310+.-+,/010348:=>?@?AA>81.,.-,.--./,,--,+**++-,,,--///03254549>@>AGR_fhd^SFB=5/,+,+..---,++........////////032/6OyƷtd]XUV\bnx|uoh_PFDG////---+,+))(((())))***************+++,,,,,,,,,,+)*+,,++++++,-./.././00-...-.0235566420/0.--.1113358:<==@@A>82--.-.---..,,-,++*,++,,,+--//11267697<@BAFN\foomeZMA=741.,)--,+,+++........///////14733:T|¸qjjhmvyqeTC>C/////---+++*(''')+++****,,,,,,,,++,,,------....,++,----,,,,,-./.../01///0...01345676652.0.,//001343368::@@B?:3../..---/0--..-,++**,+----002348:9=;>DFGMVgqz{wobUD@;84.+&))****----------.......29943>Y|û~~{iT>:>000000..++**''')+****)))+++++++++++++,,,,----...*+,,,,++++++,-.//011111////-.0123456643020//0/114421257:>@A>:50.---,,,..,,.-,+-,))++,,-,/1157:<<@<>CILV^oyxj]JF@:60,()()()),-,,,,,,,,-------1:811?Xz|iO;89222200..--+**)))+++**)))+++++++++++++***+,,--...*+++++*)****+,./101221000.../0/034566440200/112265533568;=>=850/--.-,,//.-/.-,,,+***++,.01469=@?A=?ELQ]hw}qeRLC:62/-)(('(*,-,,,,,,,,-------1:5+,8QpxdI989333311//..,+++**,,,+*)))********++***)))+++,--..**++**)(++*+,-./2212210/0/--./..1234444/1//-./015554444458:;7410.+,,++..--.-,,++**))+*--1368CJRZer}~uj\SJ@:521,*)')*+,++++++++,,,,,,,.71(&1Gdy{r]E65533331111////,,++.--,+**)***********)))((**+,--..*****)('++++,-//23342110///.--./00345320.+++,-..4533212014796522--,+**--..--.-,,)))(**,,1479>AFFA@FOXbnywna[QIC;64/,+'))*,********+++++++-2-%!&;Wm}{tkWB3001111////...--+,,-,,+,+********,*,*,))((')*+),+,,****)('',***+,-.112210////..,-..-.11221/+,)*+-./2322311//2677421/.-,,,./../.--,,++**+*,.256:=BEGCDJT`iuyob]UOHA83..,)))*+,*,*,,,,-------//+%!%8Qgtz~z{xofS?2/0+++,,,--.///.,,,--,+,,++--//.-.+/-/---++***)+)**---.,-++*)*+*,*+--000/.-.-/..//.))*--..-)''&(,000/1330/-/.1220.,02100/..1010/.--+3.)---2/49?ABCEIPYajq|{ui_XUSNE=63.*)++*-*,)+,--..001110-+(#*@Xgusvwvu{}|{~}~|umcUF=3.*+++,,,-..//.-,,,,,,+*++-.0/1/.-////--++**))**)*.0..,,*+*()()*)*,,...-...-..../.*)++-,--+)(')-1//-024321./.011/122200//.1/0..,,,,1-+..*,15:=@ACEHR]fpw}vi`ZXXSJC;73-+*+*+,,,,-00001113311-)%,B]iolnpppw{xwy||{uneWH;3-,,,,--..//000/.---,+,+,,..10/././/----++++**)**+-///-,**+*+*+*+,--../.--.-..../.+++-/./.,*(()*-,,-046544222323552/1./,.,.,-*,)++11//11.-58=?AACFHQ\ent{}xmea``]VPE?92,))((****+./..0001102.'"*A[ikjjnnmqx|zxvvuwyy}ytmcUF:2,--...///01122100/..--,..000210/.0....,,*,,+++++,/10..++*,,+,+--.//0/10..../../0....0/./..+))()*)//368976889977751/..-,++***))((*1..1-/327:=?@BDHJQ[bgmv|~yoigege_[PJ?6/*(%&((((+,-+---///-++'",AYchhilmkmrtqppsvxxxzwqjbRG90*///000112234443311000/..011210/.0....,,,.,,,,,-.00000..-./--.///11210/////..0011112432110-+*))))137::;;:7889::97210/..--+++++***-'/4+*67:<>?BDGJNQY]biu|~}wpllkmlgdXRH=4,&$'''&&()*(***,,,*$'**5FW^ebeikhiknlmnsuwwuwtoh_PE7/)0011222234566655443232111343212/0.0....,---.--../120100/0/./001233332010110/12332256655220-+)())+,047776546598983110/..-,,,,,,,,*,EQ80;=:<>?BEJLORX]biszz|~yvpoppppmkb\SG>3*''('('''(((*****($,48@KVZ]\]bedefmjinrvvvtvrkf^OE6/)122233344567777777654433344432300.0....-----..//001234430/001011444331/.10211223456766640/-+,*+*&'-389:;>:633477532210//.../////+8fyTDJQVW[WW\aabfkjintxwvsvrlc[MC;3-22333444567888888887655455555310..../...--...///01234453////01225544320/2232234423576654.,++*+)'*,39@DGFJD;0--145765543333333331&;zc@@:<=>>@ELPQU\^_\[\ux|~}xvrtuuussrnjaWNB5/--,*(&''))+++++'476;DEJKB506885248614200231,IaDUvOBHLG74683--0500366:EMLD;8:830;A8+.DWNM=?\Q5DI@?IOJKNX[ZNEDHINNRZ^]]bilnqrtww}{yusolln_UQKI9-*+/126859AEO]b^__``dddfirxx}zohd[MECDE3334679:::;;;;;;;;;:::87:9856331111144440010//..///.//00101120105432321011002334<.3GW`fb>?ABJRSK4001.++/6+$'-/2:2BLRRL>1/,*-7GW[I391K]?JLCEOQJNYbZQIJNMHOKJLMKLPX[]acehkkjjimpsv|tllr]2',45-)1936?DTeidiedcehijv~ymbYMGCFI223468:;<<<<<<<<<<<;;999<98753210012235510210////-.,..0/0.0/00/024323110221134531&?`efcO0/03=GH@753333465/)(((&(7=>CLMJB>7..+449PC9IPFFTdhKDCDHKLMSMIHGFLRVXXZ]_beiklmooqophmphkrscD$"3=7-3CVgyþveYOJBCG00123578::;<==>>===><<:;:88543211100112100112100..,--//000/000//23210/0/001123644E_bQF;+'%! &.21,--,18;:20,')0;=-6?BA>705BLG9027(/"1,/\\CC?=LabTKF@>>BMWRMGFFDGNSTVW\aekehjlnnliradnnmonjL8-+2:AUn~k[RNGHH00001345789;<>??=>>>==<<:99763332210101111212211/---.//0010000-/110/0.////001241/KVD63/)!#! #%%)-,,1:<674/+08=7--+&%+14*+,,,,-+%&&,.7UqSB:I[_TIMD?<87ALNKHHHEGMPRRUX]agjlpsttsomaejktzt~~waA/7J\v˺qbWSPOO11101123678:<<=>>><=;;;:;;:;;=?=7532212213243431///01223532100-/13231102////0/0,7[Y6*+%#&*,'&&##*00.4<;50/.09A<,$(.,*++'*+,,*)(%*0)-56`YBAZbRFJD=<94,.4HEDHIGINUVTTUZ^chknopqspjmsh`swx{}xgXQw©xh_ZYXV/0115444565799;;@><;87889:;CMPOE>44598405534554254657789:7640-+,2434579::0-1+#$.\A,)+'&+$&*))&%%')*.2421,,,/481&+*+--./-,-,,*))(& ''(5ICKWZRC?GFDA93//0@CC?AGIGQQRUVUZdkjggmsyzyutqjjwivxm}\mʸxoksmk/00232324557798;>><966588=ER`jj`K?:89:8586445552//2469:9:9640-+,.25677779611*%.:B-#&'$%*%(+-,*())*)+.1/.,(+691+)+,.-/./--+++)('$'#%**&/BFJJLPTSSXahiijpvz{xsotz{vpkkhfotHsŮ~,-.//0214246689:=;;87779:BSfxi\RKGEA<;7432310-.02345344300/-,'*/03421452,',9C0$ ')$"&&)-/.--/..+++--,-(.=:*&.,+,././,-++)'&"!$#'/.),758AIJCACA?=4.**+)8EE@AIPGIOTUUX_fikpw{|zttqt|vcmw\^{;pι,,-,-./001355789<;99888;>Lbz{mdZPHF?730/./013211/-/.//0/0/*,.02354451++6AA.((-,&#&&),//01232.*+,,*,-493'(/+*--.,,*,+)(&$ $./.2:-05@II?8984/+*+-&3@C@DLUEEMUWWX^cfmry|{yqzzpnuujfgUq3@m,,++,,.//0133578::::9::=DUq~naXMB82/,,1311/+*),+,/02434532244531./8DG<0+./-)'*$'+.-.0363/,,++++58.&)-++)-,,+**,*)'#!")-06=>759DG>110/,*+-0-2:?BHOVECLUYXY]_dlsz|yvr|zoltsi_]hE*bÿȿ1..++,-../022464888;:;ACFHKLKGBA40;F@5-/,*+,--*')*,-.154311220/551(*23**'*)))(()))('%! %%%%(+./GPSI>97/*&('(*04;7:CHGJKHDISZ]]`^afluxxwwuvx{wk_jf]kY```d|630-+++,--/11343778:;61//037=@DHR\cjnmhaWE?IL<1.0/--./+&(++--/142222443/:/*/551,)'()))(())))'&$#"%$&)++*+G\YF72-)'&%&*/299?HIDEGIDHSZ\^a^`dirxyztw~}qgimlt^fah^^]o5431/-+*))*+03667789:;AHM`~zvn_M@:845:=>BHTj~~je[WQD3((**,.--,,'(*--/1345631133<607RcT6))*)&%&(+,+'#"$(&()*,+,-81A^Q<;*&$&&(+024;JRJ::DGEKTWVX\ffeflsvvwvuxxsnjugmlXXeege63420.-,***+/255667889>EN_ɻtbTIC:=A?@ERcukbXG9/))%%&('(((%(-235559779==<;:97/(+>O6,##)-+(./1.)&%&''((*))(/-6JQH?((&''((,/48FPI=;CHFLRWVVZfhikmqtulsy{uniefbhh^ci^_W}65420.-,++*+/2445786670+)')))*,--.*.1587341.-3;?<54,+-' *:>6-)*,,,)+..+(''()()**+,+457NWE/,(*))(*,36AKG>:>DCIPTSSWdhprnllpjt{yqkkmhhmkgnm_WFf9864310/-,,,/1356775458>KWqŶucQDBCEJUdxxgUHPO<12,$"$$&(+-/676653.,('(-441--",60%77/.*)(,4895431-*(&(EcA2CBV<4.+-//.+-022..-69?GLILNcgtzujiosqnnxsbmmo}|hjX:Gg=<=;978743323467;;972015?F^·zi_YRIA><=<<521I?735640....+*'&**()*,./321/-,*)&%%&)*$&%'1<@=71.-.3:==631/*(%$$1_L5?=SH=3..00/*-.-*(+,028BHFILefr{xkjrrsqtydt|uw|U><:878543122369::72025=E]˾rcXNHC>:7774/,-E<7=C@9398852,)'((*,...,71,,--)%( !('"%0&*,./39>KFB==:611/..+*)(!YS:C;MQE6/./-+,-.)%&).)+1:@ABE_`jwuiemttprsyqfP9?U@@?><;:;76532224:9865449DMb˼x]TMIGEEDA=B4;<)EIEB??>;9;7;A>0),+,-**+/.5+$&+-&!""%')&))*(&')).2322453/,-.,(%"HN3I1HPJ@60,++*(&())+,,0133457ai_jqdmyzxoijnoo{lwpuQ:8ZA@@>=<;:654322248986547:EMcͽbMFCACCDFC?D;?=1PFDB?;987?54>A5,+*+--./342-)&''"$"%&+,,*.-+)&"!"$&+,-/23.-..*'''.51>P?AVRH>5.+(*(')+-/.,0010135\d[flalx~|rf`fpxw~dpnkO;;\BAA?>=<<987555579;97657:CNb̽oQLDA?ACDFC=A@?86WCB?<8666A1+5>:/))),.0159*****)*,!!"))(%;83.)$"#%$&'*-//)+-,&%&*/ E0;?IUTQMC;2+&&%&'*-,,,/./.047Q]Ygm`gq^kqmgiqwuu]hm`H=A]BBA@??>>;:98888:;<;9768;BK`~ҽxaKJCAACEFFF>@D<1:YBC@=9788;.(/76/())./0178+*,,-../()+,.065@<71*%&%('%%(,,**,+)'%(*(,PCIHHG0.,--./0...,,.36AX]lrcegvzvhfq{|sjW]h]IIPfȽAAA@@???>>=<<==>>>>;979;?GWn{xqfWNHEBBBEGIJHC>D4,@FA=;;=?<:*(*('&((),..../02/027751*/2214=D62/,)'(($$(,255681(&)**&+)'>>>====<<;;;<=<:::@BEGIJDD=B/,F<84018;95((*'%&'&&),++++-+-347788;<>ADFHE522/-*+,&*/24456<71,)'*)'/8>/.66-.01100/?:1*)(**-/0/++.0AZ^isnzpyysv}onb[Ya{zkfhuǿ>=====<<=<<;;<=?>>><<::=CHOXbirR<@CC>>E<:=@CHIH>963/08D16..;3',%')(%&'('(($"%.531.+)(((*).7>;616+*--'(/24652/,,211K#>&(7@7**174.)&*.0.XO:,/-'*%&&%'*.10;Wpv||{z||xsn\\[Vkzmfcjw|vqorvuwyļ========;;;<<===?===;<<>@CFJQX^ft}E..5;::==<>AEFFC741/,+5A@=3198+#'(**(((((&%%*.01'&&'(*,/-+.7;730/8;0+/1->=:64357-52??+.1:@8-,01.*'(+02/YN8+10,/+**))(()09Tjt|}}}{vqn]\\Yhwob\]ckppm]]\^_eiktv|}<<<<<<<<:::;;<<<====;<<>?BEEB?40+*(*3<>647=E<#(')+,+)))##*361+'&%%%&()-+/6:7337:@@BC>7<;973112,949jA-,7<;6.-+*'%').111YM3(363687621.*)/6Mer~|uom^Z\ZaeZQORX]^\XMPUY`gjmrtxyyz~;;;;;;;;:::;;<<<==<=;<<<@@BCEFIO_m{lRB?=<;;>?ABEJYdq}w_TNNH><>>BCGJIF?97/+*)*.6A;BA6BL>2(#(-*)+%)/450+'+,00568:56=CFGNRM?KivdSRDA><93*$*(2TZV?F@70--+'##$(-,).5GA0-9:1101232/..*+BYl|~|upe]VZ]RB65-(()*-3E?>8/:P[C3%'+++,&-440,+-8;=<==<>ABKNNOX_H[lkc_XJQG:2--+*/(BcGK99J<0-/+)(&%)-)'/;A=2.76.--,/11112)):Rh}}ysoc`X[_N:8EISY]`gllmoponllqqrroprtvtw8888888888899:::<<<=;<<<:;;>>>>37Q@1-,(()'&&*((4FA@6031+-/-///112.(2H^z|uol`aWY]G16DN[chjnsttrpnmllnnoolknrttwɽ8888888888899:::<<<==<<<>=???>;?KT\kzo[LENQLJIF@DCCAA=841+(,.17=45.06')GjP700*+00232126<5888754529BGJM\hsjb]]YL;F;.('(&%'+J281/@SA1*(%$((&%*&%5JAB6.1/+2/.-+**,,1(.BXwzrli\^UVZC-5?J\glnrvzwrmiggikmmlhijosrxķ777777778888888:<=><<=?AB?@ABBABLP[lsf`WOJLOKEFB?=:960,&0,(5=5251.-**'%0LO9*.3-*B/;>8M3222'*//&)7.7@9pBlic\WM@4771&!#')-/?7144CHE;0)()*/,#$/;?F=0*,134111..--/0%13Yq{tsnecY[Yi;-6BM]cgjnonmlihfeflmlkgfgimrv|777777778888888:;>?>==?BCABBDFHINTatǶ}odcZRSVPJE?<:874/,+-(,64170-*(&&%'.;D@@?>?CEGGIMOTVX`pIJzmi\QORQKE=:97740--+,6?2)2/.,,(&&*-.9C:%#25D2;?=P;0&'3/'%2)900<]Ief\TRI;49,251-)# *C:,5B]:;93/48;<;;?>:=D94,+-1222210.---2%+0Twxrokf_\bgH3299999999999999998:<>?>CEHOTY_cfhlt§|{tg\TPMGB;877641.*-0:G?.)1101-'&+-+4B=,*6-:05:>VOE8&1,2*.961?LbUCDFA=987312:HSN@25ILRZQV169759<;@==C?8=J30+,.0112210.---3'(.Oy~vojfb\^dh508CKPY\^befdaa```acfgfb`]]_gntsuqidTK@;;;;;;;;;;;;;;;9559;>@FKQ\hsy{}־sokmli`WMB=;887750/)301HQC00-/31*'*,0599322&2/02;T^_S13-E6,-?46hB14*=E:7=;03;FSclka>@[gpjK;07<;5411;76843IMS\__ccb``___`abded`^Z\^agmpsrnjd^T<<<<<<<<<<<<<<<:448:>EMTapɴ{]@BIRURMC:<;98860/,6+$?\ZI2))00,)-*12/053+'-1.-5GWba<<,K9/5()YA=:#+>E9275.7NenlilkLJZTMF2/A<62;DSessjghfdVT=043@EKLA73137>=7:EHB/--,-,/02210.---/0%,5q|tpja]^_f[601@EMR[^ada]YWXX\]_`_^^\YWVX_dhloqmjhe`========<<<<<<<:99<@GRamTG50?QVOC?=;:5100535EMOXU>-.1-,00-.374-%+%--25/4F]\uJMC`s@pT?2>K>?FB8Jgwrngkone]IG404.5?DA8//16/<=6:EA4..-,*,/11210.---.2%,1oxqoja_`bgW'3/@@???AB?==ACB>?>@IPZpþgFge?NcLA9:95161.;3?KAVTI9/-///-,040)(,$&)-00149N]S=<`qkmka\`ZKBA>9>H_irpmnogS@511.14=:740136<;;<;93/,..++,,02321/...5,,&7W|rheed`ld? &.5CEMZb`\YYSRSTXZ][XWXWWUTS[]^[UMC>./.;>@@@?@AB@?@BCB@GFGSaodwmJ[p[L@>@;64838.3@;M`Q:)&--)1573.)**.+++,,.27@L[bdeiWRVdok_T:5695-6CZdlmnmhZE74350/297431256;::9951,,-,,+,,02321/...32.*4[}zvoifbcchV8##(/8AJX_]XVTOPQRVX[YXWWWTQRQPNLF?6/+---<>AAAABCDCBCDDCCMMRbtkp`GUiu_LDD@:6:6:0,3/8\[M6(+-,2>C6)''%*))),/49(3CXba[[PQWets]B54<>94EWSW_fkiYI7158;510320013689978840+--,,)),02321/...090..bwxsmlf]_fgJ4,'(/0?;5221001367797864.+,-,,))+/2321/.../<1.,jtyqkjcY^heB7;1-3-6>LUXRPKIJKMPTWVXUSPMJHGDA=8667888:8:>?@@BDBCDDCBBIRh{¿yqkiei~rdYNE@77=?335#";K@/***2UhX>320-,+)'$$#,')5AGGHP[aahm_D<788=CS_?;;DOMA31589973021002345888975/,-.-*)))-2321/.../:0-3pzttmfdc^dm[>=F;46.38FNSRMJHHILOSVUVURLKHFFB?;8:=@C?=?58;=>?ACCDDDCCEPc|tqeeg[[mu{ypcTG?:6;1:J2),./151-/M]S?4103221/,+)"2>@:;@CS_bfhYC>;CJTY]^:53:A?822562000.44323333888975/,-,+*(((,2321/...131-Cuuqifa^bdiiF:74..2>HMOKGFGHJNRUUUQNKHEFGEDA?@BGGB@@259;<>@BEFFECEJYwqoeejY_T`nvwsfWNB6=4=R00+(.33136>C@71//33335586%8=5+0>JUaedaR@//9@HJIF;66<9424054.*,.,54435555777864.+.-+*&&(,2321/...3+50Xxni`fb]bheY/7:;>800,.6@GJIFDBEHLORSRPNJHFHHHHGFHKONB@@369<=??AFGHFIMUfgfZX_P]FMXcrzwj\OBI=@O"''.6-"'7?7.0554442.+)+,->2)-2543NQUY]XO@++/24686>;?B>539379/+.1/44446666655451-(,++(&$&*022//,,.4&95gyic]he]ah]F#8:6?9-1'(1:EIJHCBCEHMPQPMJIGFHIGFGIKMNNC?B68;>>>>?>?BGR_n~|l`ZUPNOIPPSdr|qs]LAT1**('&(+.1.240('/500.+)*,/.4:<;4,&7BLSVRI:*(,./236>?????<<78;9656:4345553456443/,),*(&&%%&-/0.,+*,0.5@uqjciZ^gckW# '4<91//&%.8DKNJFB@BFJPQLHGHJIHGJIGGJHGC<=B46>=;?B.17:;<=<<=6+%&,/359<;==;:776757;<><;4545553267551/,())'%%$$%')*((()+2*6plh[l\dZbqR)*+'&)*()&4Td`SLGC?@@EJMNMHHGKKLJKJFGHGFBDEH*-47:;<<<=DObrĿp`YTQIFELY[\gklsvs~{a2)('&%&')*.*')..(!))()++*)-/0/1133<;934781').1567:9;;<<:::667;>?;84545553477652/,**((&&$$$%('((()+1.Jwh^_f[acle=!.'',.+$$$0Mr|mWJEC@ACJLOONIIHLLNMLJGHHIGDHIL'+169:===>DQeuhZTROHDBDRWYdjlqnhv{~`2(('''''()/.,++*)(++,+**,-002/0,-*754.012,%)0589;>>@?<<9752219:;9756667677776:::740-****((&(&""$%(*-16[oa_`fb_c`H34=761+".Pq}eQE@@DJPSUSNJGEJKNNKIIHJIHELNQ!%+.1456=fgd[g\h[oU-3?:961)&*?azeP@?>CJORTRNIFDIKNNKJGFHGGDLOR!"&(-13458@KYes}żzgXQMLKIHGF;AOYXT[`eP<0/1/+(&())*,,%),//-*')"J?#1/(+)('&&&&).20,-4;889987=<:75455789:;<<<;:::950,+)+))(*)#'#%36,egb\XYcioQ3,6<813.&(=_w~nRB?>ADILNONIDBBIKLJMNKHEEIJQRS"#'(,01247=GTakuȼp`SOKKKIHGEGCFLPSX_SE90/0,(&&())*,,')+-/-*().E<(-,&,+**)))(*,,)'(.5G>9:=;78765588789:;<<;:98885/+*****)+)$)%'/2=gd[W[`deL>2/02:=./5E[p}}x^E=B@@CHKLMMGCBDJLNMOMKGFEILQRS"#&)-//-017ALWaitſrcXQLKJJIHGEI?=DOSTS<741/.+(&$&')*,,(()+--+('=:5/(+&)))*))('-,**+/38=978<<@C;AKUUL>42222568878:;<<<;877774/,+++++)+)&*$$+'0Ti`UV]fda9620,)+/#,B_t{z{xmK58B?@DGIJLKDCDFKNONOOMJHHKMVWX&&)+-..+--39DNW]do~ÿpcZSNKJJJKJIFA;=FPPIA//10.+))$$&')*,-)'&(+-+)'I1,4%++('()))('*)),379:59;;:9=@VbjdQ<3/1112567889;<<<<<:87774/,**))+)*(',&'-"4gd\UX_d_ZA9210*#*Hfttsx}[:07?@@CFHGHJBBEHMOQRPNLJGGKOXZZ(*,.00/+--.4>FNRS]lĺ|l_XSOLLLLKLKKGA=AFH@83-//.,)(($$&')*,-+)%'+..,0T5+5$(+)*+,----*)+17:745>=;;9:::72/***)*())(*'*-)Cr^[Y[^]WU?941-'##.==:<9:::72/)))(('&()()**8Xp\]\[ZVRR795+%6T\edfkt|m\C0,1;=DBDFFFFGCFKMOOQRQOPLJJNQ^]\0369;;630--29?EDCDOaxxnaYSPOPNNNNNOOONMSE82-(),0/-,*(%%""$')*,--(!!(./-3IM95.(,+*)+.13=<;;;:85554:J[c_92.1=@;2534444779:;<>==::999961.))('(''&+%+)'Kmf^\WSSRQU87/$#=VoqhYYcd_C8-*,07>FCEFGFGGFINOONOQTSSPNNRU`_]369:;;953224;>DA>>HTh~xne^TPMLMOONOONONNLLHHFGGGGGGJMPPMKJLTUSQORUZ[[Z;;=====;<=>?@DEEHHLR[it{{rjieb^YUROOKKIGHFHOTJBJPLL=4,(-01-/....+))))))+++,+-( !*/.+-08>9,#F@<;?@>:47::7437>9/(&)/3037:;99::::9775501569::;>;9:=;61)+*(&%&&0-#&JooZNOMOORTS/)PoyxsaLCBB90,210302>BHKKGIKJPSSPMJJILMNPRUY^e\R????????@AACDEFGJIMOU]dhlprrmg_YVROKIHHGKIIHGFGIMTMFMOJE90,),020....--,++++++++,..( )..-*)0:BCC?;5478637898779:74,'&)-14678776::<:9755523568899;;==;62-+*+)(&%%')*5PeaMLMPQSSVQ/*3On|pbHB;7751-/442303>EHMLHHLKQTSQLHHHJJLQTXX^YSIEEEEEEEECDEFGHIGJHJLQUY[]^__\YSQMKHCBCCBGEFFHHJLMUPNUQE@71/++,//.--.-,,++++++++,0.( &,.0+(*09?D63027<<<<:7689::-+'%%(+.568744599997755334668998:<>=91+(,++)(&%&#%,=OTOFHLPSWWVPFVn{[<$+/20.0/.3413/3=GJONJJNNTUSPKIHILLNSX[WXJE>IIIIIIIIGHHIJKLJHGILOPRSWWWUTQPNMJFB@>@?AACDGJLMQUOQ\XD:860-)*./-,---,,++++++++,1.' ").-+**+./254248<8658751('&&&()*147855678886644422478879:<=;2+'(*))(&$#%*#':HGGLJLORVVWT_xtY8%.33245-2312/2:::<>@@CFHKQQJRc`MC=940+)+++)*++**)))))))),10(" &-*,,-.004<<988885<9::<61(((((((&&+/378867666443332257:<;=<<:5-((*))*(&%$%-"%:IFGNLLNNRUWWfzjH4&&*.34430-1201.170.+*(*()****)))))))),1/)$"*./,*(+08:<=>>>=<8:>>>6/'+***)('%%)0357877555444457:;>?=?:83-('(*()(&'%$%)!*ANGEJNMMMQTWWX^ZB,%*.2126960++11/0-0;ILQQNNSRQPOKJLORXZ]]WOEBMGBOOOOOOOOOOOPPPPOPOOOOONNNKKIIGGGLKID?:86669:;ACECA?26<;91.)-++,+(''%'+.049;7554444479<;=<;93/+('))()*)'(&%$#%2EKCDLMNQQTUVUE=4,*,3668;=<6/**01/0,0:HLQQNOSPONMLKNTX`a]ULGEIOIBPPPPPPPPOPPPPPQQUTRQPOMMNLLLIIGIKLKHD?<:44779:::>DA<:5>SOE:53/)")'(*****))))))),0.,+#'#)01./5=BDEC?70.,1662.,+-+,--+***(()+09>755454559:;9:653-('')*)&*+*)'%&&#*8CB=ESLNRTVVTQ;(&242.16=90+,.--++*,+,+,+,.5:7/##(/8?DFHAD>3/010120//..,**+,++,,.-,,+-0/225799986430/.,,.,,+***,*)))(''$'7C?>DIGJOOPXROT59BB6)*4GQTF7*#"(0112+.<98666655-13%'C`JZbSHHD6+*,*,))'+)+)+*,.-/-(" $27?FGFB@AA:1/14334200/..*+)*++**.-+*+-./.0033434,,-++,.//,-,+++,+*,*)()&10(#$'./13,/<:876534-30%9ON5L_^UOHA1-++-/0044445557;>>=<>@DHGGEB?==B?70.03643310..-,,+,,-+++))*,//0/./..,+*)()*+-/0.-,****+,,,**())8=?:<865311/1+-LS4+9UgeUNPA<646:=>AABBCCDERTROLLLNHFB@@@BDF@722134333010//....----**+*+-.//--,,+**))()*,---,+*)+++,--+*)++;<=;?FMOMQPQYW[dQ@0(0?NVE:.),--,+--04-.8FJPPNOTQMLPYa`XQAEIMMKJLPIBQQQQQQQQSSSSSSSUYYYVVRRQQQRTVXXXURQRRQPMGC?;963/.---:RJ+9;Rnvh^_QF@:=>A?CBDCFDGGHIHGDDBBABABB@>?G?6330032111011111311/1//--,,*+)..-/../.)(*+,+,+,+)())))*,,*))-0@<<=CHMNIORU\PFG-)(2EQK@7-&*140-,--04-,5BFNOMOTQLOU\`[QHBGMMJGGLNHAQQQQQQQQSSSSSSSSXVVRROOMMMOQRTVVUSSTUTQOKGA<963.+*+9LH<9E@I`ppe\ND?;?>>9?=@?A@CCDDFHHIIHCDEEA>::F<324101/0101344334331300..-,)**..-....-))**+*+**,*)((**),-+)*/3B?=@FIJIINOVZJ7109CJOL>/-$!*5963..-15-*2=BKMMOURPQWZYRJEHIKKJHFIMG@QQQQQQQQSSSSSSSSVTTRQOOMMOOQRTTTTSSSUTRPMIC>851.*(,GXA3NE>BB>7==@ABCEFCDEEGFC?DCA>>?@CB80463/2/001334522220000,-..--,,//.,***(**+--,,+,-,**)),(+-+)*06GB@DIJGGNNKMSD2,9ITQE=84&)587520.15-)1;CMNNQSRUX[ZUNHDNKHIJKEEMG@QQQRRSSSRRRRRRRRSSSSQQQQRRRRTTTTPQWWVTSTSQMC=82),$3WmeWOEEGHKKMMEEDEB=<<89>==??:300232232333120..-/...----////000....,,,,--,,,..--,+*+',)(+)-=HJGHHJKLMKNQH:7;YQHC@;51&##'0563--.//.,(;FRUQSSUZeeYKGHGIKMNMKHGLD;QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTTSRUVZZXVWYYTOH=40%)=GB=?VTQOMMJJTG>:@A;499=>BDEEFDDECDDDA@?>===??<600/0023433110.-,,-,,,----////00000000000///..//.-,,++&,)(+(,>ILJJLMNOGHKPPLQTMG?:::74-)')/2200010/.,*9DRRSRSV^eaTIFFEIJLNMKIILB9QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTTTPPRY\YVW`ijibVJ<.(./(*3015:BJPRYNE?BC@:;<>@CFFFDDDDEECCBB?>===>@?<51-,-21211110.,,,,,..--//////00000///1100////..--,+**&+)'*'+=IIJLMNPPOPONQUYUB:6369880-**.0/.2220/0-)5@MNQRUW``WLEEECHJKMLJHHJB8QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTTWTRSWZ[]]ix~rgN>210,,4+**)+/11BJOKDBCF>?>@CDDDDDDDDDBCBA>><<=>81,+-010/1//.-,,+,,----//////000////.1000////---,+**)&+(&)&*ILQTWZa[NECEECHIJKJIGJJ@7QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTTX\[YX]hpwkS?75225<950,+*(*8HKGIIEBBABAAAADFFFDDDCBA>====>:;=93-./0/.-/--.--,,,+--////111111100//.11000////..-,+++(-*(*'+;GHJLOPRQMOJBDHA3/.++.379652//.,,45540/-)1:GKRVY[`WICDGGFIJKKJIHIIB8QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTTUZ\Z\g|rT?8312332348:9(/6AO[VIJFFDBB?ADFFFCCCCAA@=<<==89:970/.//.----.,,,,++-,////11111100/...///...--..-,++**(,)')&*9GHJLONOQNLFBB?6,+*((*-1475422/-,35521.-*/7DMSYYYYOCAEFFGIIIIIHGJI@9QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTVVXZ^jȲz]I:1/675453303214H_dZSOKJGDABDFFEEDBBC@??<<==:::::4/+/.-,,,,-,,,+--..//1111111100/.--..---,,,--,,+*))',)&)%)8GHJLNOONNGA=:1+)+-,+)++-457751,-022120.)+5CLV[YVPI@BFFFHJJJJIIHJI@7QQQRRSSSRRRRRRRRSSSSSSSSTTTTTTTV^_ajƵbG7224577976571+6Rim\WSNKHDCFFFEEDBBCB?>><<==9:;:6-&/.-,,,*-,,,+-,..//111111110/..-,--,,,+++--,+**))',)&(%(8GIJMOOMLD:462+*20120.,-,359973,-.0101/.+*4AMV\XUIC>BFDDGJJIIIHHLIA7SSSSSSSSSSSSSSSSSSSTTUUUUUUUUUUWZ]nǵiF-/01530299:75FjpZQOLIHGKF>@JI@@@@>><;9>99985.*0/.-,+*,+--,.---0000111154321/..--------+/21-**+(.)#&%(6JKJJMQI>5520/00033410/.++-2664..+..-/./+&1CR]_WRDD@@CFGFJNNJHKLMKB7SSSSSSSSSSSSSSSSSSSTTUUUUUUUUUUY]jŲcK3/./23597?EPgϨ{]USMEFEHKF??E??@@>=<9<;9:;61-0/.-,+,,+--,.---0000122243210.----------.011/,**(*%$($&5ELROKD:/1000111345521/.,+.045421/.-+++-,(3EU`bYPDC@@BEEEGKKHGJJMJB7SSSSSSSSSSSSSSSSSSSTTUUUUUUUUVVZ_xĴlE7,.478:9K_v֟aDKYULBBEFDD?@??@?=::::<<72.00/.-,----/..-//11222244210/.-,,--------10000.+()'#&*#&>?>???==9:=?>95210/./,----/..-//223222440//.-,++,,,,,,,,2/-.//+'+($() (EVRG:3.-.)*./210043321/..+,,.146884.'%$&''8PdniXEA@??@ABBCGIHJKHID<0SSSSSSSSSSSSSSSSSSSTTUUUUUUVVWW]oŭbB57998Xzۢc@DNRI=;@=>?@???=;<@@>95312101./////.0///3332433300//.---........2/-.00-*++(((!-LRH8.,-.1-./00/-.021///.,++,-.25785/(%$%$%;WkrgQ=>>>>>>@@DHJJLLGE?9.SSSSSSSSSSSSSSSSSSSTTUUUUUVVWXX]m͹rO;:=BGsQ:FJ<7D>??@>>>=\ml_K9<;==;;<>CGJKLLCB83*SSSSSSSSSSSSSSSSSSSTTUUUUUVVWXY^kzï}[FCKZdːYDEFAA??@@>=<DHJLMK@;4/&SSSSSSSSSSSSSSSSSSUVVWUUUUVWZ\^erz˷bNLWn}qGHJ;@@>>=<;;>>>;523654543011//100///11210//.00/////.--------.14320485;22JZMA11250+,3+*)((*+,))******,+-,,,-+01443.'$*B[aXKA:;>==<:>?GKOPRN?6*.,VVVVVVVVVVVVVVVVVVYZ\[ZVQSW[_lïvUIUowFA??=846:77:762677875431322110/..-....,*+/11000//,,./11120101/1026=ASesr<.///...----,,+++......../.----./023666411>II@67:@?@><:;5-0.VVVVVVVVVVVVVVVVVVYZ\[ZVUTW[cwԿy`Zi:2-39@@B?=989DLSVTK8.-0.VVVVVVVVVVVVVVVVVVYZ\[ZVVUW]iм}ޭn?@K@8:6;?=946<;<:;998844433221000/.--.22111000320///11641235326@IVoz_,,.---,,,---,,+++----------,,,,--,,,-.1232571+)/4<=A@?;::ENVXSI4(,.,VVVVVVVVVVVVVVVVVVYZ\[ZVTTY`mпȉP;<@<7;?=;78;;<==<;;;66655554432110002221110043100012654556326?MWorL(,.---,,,---,,+++--------,,++++,,.-++,--/-/0-))-/58=@?=>?GQZZSG4%*,*VVVVVVVVVVVVVVVVVVYZ\[ZVTUYamĸٓWFE;:<>?>:99<==;<;;;8666655565421112322211110001245648:;86349?R[ne:*-...---,---,,+++,,,,,,,,,+****+,..+++,,+*+//.+-,/38:=>@@>:79:9::::<88888888:975455633222111/01345554U^kU(..///...----,,+++,,,,,,,,++*))*++--,,,,+,+,/1210.-.358:?BITZXPA0%,,*VVVVVVVVVVVVVVVVVVYZ\[ZVYWWZbx˖[D@>AB@<57687768888888888;:86556733322111234553214>GH?97:;;U^fI0.00///..---,,+++,,,,,,,,+**))**+++,-,-.,+-136441+-0257=?ITZWM@/#,,,VVVVVVVVWWWWWWWWWWZ[]\[W[WY`gviK:@GA:=223/.-145788::98:9998777223443323199-(';702>JD7?851.+.26DKTRK<2,,-,VVVVVVVVWWWWWWWWWWZ[]\[WXVYaiyЦiB2**-364349857>4444333356677655;17@3&(+,.*%%2AKETaS9%(3244433324433322243332221//.-,+**((((()*+0.++.4<@=:73-+*,=DMMH<4/..-UUVVVVWWWWWWWWWWWWZ[]\[WXVY`hwټy<6559;6-&@:8:80-133332222455554436/?SH403*-*&#,:FQ\^F.%+1355443335444444466655544220/.,++**))*+,,/-**.19:=;;61,('5;CEB;40//.UUUVVWWWWWWWWWWWWWZ[]\[WXWZ_et̿ҼaC559<73259:;;111111136666654332MfZ@43*+++(*/6[^V=.,.-35544333444444448887776654321/....-,,-..----116499<:6/,*.472-.-,TTUVVWXXWWWWWWWWWWZ[]\[WXWZ_cr̽нscKLC2(*,*222233337::9986659SgX?2,+++.,**.\WM;663-455544443344445599998887776543220/.-,,,,,-01222-137:7410-06:962---,TTUVVWXXWWWWWWWWWWZ[]\[WWVZ_dsǹдxG850222334468:::98767;LTC40+../2/,1:RKF@A>935777666544455666:::99888998877665320.-..//01332-*-277422/16:973..-,RRSTVWXXWWWWWWWWWWY[]\[WVWZ`guøw7)//334455687998765458A<,(.*./220.;NIECFGB;8455666775556677799:89787:9:9989989420.//11..+*)%!+165552356850--.-NOPQUVWXUUVVVWYXWX[]^[XUUVZ]gɽr53/-111122442556766564-'&*+)0/)(4CD>?BDFEB>;3100125666664444768576879787:9<=:9840..001/-)&''+,1489;967<;<;4,,+(MNPQSTXXVVWWWXZYXX[]^[ZVWV]bnĸp32.-//1122442256766551-'(+,++*3<@<:9=>ABBA=<643012466666442276655667777789:;?>;75336764-)*/1;;=>?=:89>?=:9555566666442277666677777789;;BA?;:89<>;71/3=BJJHE@:528=DGJF>5..+MNPRTVYZZZ[ZZZ\[YY[\][ZWUPU`tɾl0000./223232224466878320237><<88878666644228766667887788:;=9989==;71/5?EEFEA;4/,28BGKG>30/,MNPRTVZ[\[\[ZZ][YYZ[\ZZWVPT`tɿm1223./33422122446689:56677=DbsyoZA8653479;<:;8::9:666644228876678888889:;<=<;7768;:961/3;??@@=6/+*-4@EJF<1**'~|~yv}xwxz{}}|}{y|~}~~wxxy|||z{{|}~~~vwwxxwvvwwwwwwww}~~}}zywx~~~~}~~~~}~sv~yoiwwwvvvy{rruwz|~~zyxyz{zy|~~yxyvr~xvwz~zzzzzzzz}~~{}~}yxy{}~~}}}~|~||}} q%"s%"q# m# o$ tun||||||||{ywvsqom '!*%'#z%!x% |'!'"~'"~'"~'"~'"~'"~'"~'"~'&$$z$%u%'t"#uw|uz|}ywwy~{!y%$t))q,-n<=u;v<=u;AdIMjW\o\cmYadU\bT[cV\hV]gV]gV]gV]gV]gV]gV]gV]gJPJRyNWtR\uJSr9@n+/o%&v-1p37v9=z;?|:?y8=u9>v;@w65w66v99w>?uEHsNSqV]pZboijdhicghbhicijdjkeijdhic^aXdg\hl^fj\hkdijn_^lPNd^em_eqV[oFJg>@g>>p;:t42q"#"#"#"#"#"#"#"#~~g{pen~nztmzpy{x}! xv!yt.)JJ?Cf=:q@>pHIuTV|SWzMQvPTzX]etafnpfh}gdgc|eeocgfchbb]}fb{dcqabf_d`bhdage[ceSWRV|SW}77s3.~,(rKKo\ad`badfahkbik^hh^gfbjeilfpeeegggiiihhjeegdchfejihmfffffffffffffffeeeeeeeeedddddddddddddddddddddddda`edcifemaakZZdSV_TW`Y\eb`k\[afgihloZ^iTUqNO{?>wu}!}{{~~zy')v%'q!n!!y)'kq*+{:;~@@|;7t2*u+!x"w'$u54x@@~76z!r{~~}{|~'&()|$&s&*%30:921w!otz~zsp|~||}}}{~~~$"yyqv mu p 1.RVajs]gfaklLFB==n<>nBEx@B}.1xqq~~}j'*m>DxRYPX}=Dp,1h'+h23+/y/7eFR`]ie\fhHKj33i6@s3=n2?w.*~*$|~~~|}~ }|xq!p "y}ptp# {vo')s<@EF99+)|&!} !s)+v!$i!#`47n=@iGMeclujnzhkz_dwY]vUZzTX~OQFI|GNQUZ^y`cl`b_ab]dfcijlmqpY\e>?],*[)$g*&s&!un8+@8TQpZZdffrb^ufb{c`ugdkgdmgflhgmhhjgiffibfi^fffeeedddeegffhfejfejedifffffffffffffffeeeeeeeeeffffffffffffffffffffffffiiieeebbbcdfhimhkpcfm\_h=?uPS|V[yNVmY]W\X_g^ba^`mOMu3/l_y x {!86LNV\|Yco]_lbejgihkmjhhjhhjeeefgbhj_gjafibegbdfcegfdhgeihgggdddcccddfffhgfkedicbgfffffffffffffffeeeeeeeeeggggggggggggggggggggggggeecghcghcegbgiheil]`iSUbU\vEIv*,v~yy~u $nx+-wFMy]h|bmNU.1xr)$66:;./z~mllnnnosxn fdkuny !% ~&"y##~~}!,)42??DD??31%!%(#~wvvuz~~~|}}puyz|z{|~}{{|14yGOsQY~QSPRW]w_kaFHEG<<+'"89yLRr!}))<>CE=@sFJwY\BIwHL)*| k=?x<>q10rIEZ\q[\zOQz<AFJINHMCH>B:=>C;ADfKU_[c?Ft,1i.1t15~-1z26}>E;AuNT4:n')bCD>=*)o=<`jOdl]]dlLOn<>o<BqOViCGj//mKIzFCx>=y><{AB{EHuDIg?G\NHnLHaECY;7i/)!{~!oyx ! ~AB{WYpacbcb^gcdjckeeegggiiihhjeegdchfejihmfffffffffffffffeeeeeeeeeffffffffffffffffffffffffcbhggihhhdfcghjhjv^_tOOk"j)&wyzxruy{ywx|}~|~~y~~{ws"g@Em`gygjyQPo:7d!%~ur}!~}wvy~~~ |'+9?GNIQENGPNWIRIQHPGNGMHNIOHNBOCOEPEODMCMDNEPBK:C|5>w5={-4|$x~||~{y#%x(+x+/y28v05w,0y$'vwy "# !~~~~~{z~xxyy}~vq u #%y{z#$57PTJLGJ}ELzIP~PWJS8A=@8; e g(*t pw'&9AeUamXen17iv=@Q]iAEDE33,/vBJqS_oVcl\htBLp&'g"pA<~TUsOWdAGi17u8>zIPKR|CLmKQsMR|=@s--izs}r}vy*+DJ|Y`pdhggidgc`hgbghbdddcbheegegZbfKffffffffffffffffffffffffdlTemXeh]ac^abdcdiedlbaib_fddfcdhZ\sKL>=44/1{unpw&& o yv$!y h yxw { n}0$ ww wzs"7:PQOR;C)0 z}xw{}~#'(.+3 }!| y s %w)*63BAKK}2SDGVBRLz?Xw6WDLZFIKKKLOKMLNLSHNCJLHJMJIIGHPHOFLFPB<@}.1v'(x(){ILwciyY_mEIl@DFIJRV^S\LTyS[Y^RWJN{EK{).hiy|{zy""|!} {"#59vKPmY]i__ihgeiiagi^de_edigflfffbc[ffffffffffffffffffffffffcavedveeqcbheecijbjl_hj\rsklmr``xUVuPTwGKz*.u gw{ x$! $ #}1.k }"~{ ~~zxz}zx~!$(,;BNSXZEGz$'no#**7:CLLV5<!z((+)}')~+-.33:6>:E@NBSJOuEJDIHNKNFKDNDXy?TBNEUvDJHIJRwILDR_CMfDQWDNrELESpFPGLGQEQwEJGIJJILFJHGLHVMIKAJGIHC@@=HAWDWCM~KSfPUDQ~).v ~$uq|',7==DAI?E8<14/3/425)0t&u ~|y}~-0'*wu{  ()34'$}##}{{} | "m! tp!*-BK7>-2*./26;AFGMELzQXQXRYMTMSSYBH|RUNPCD21!~x17k8<{13~02}FITXBF*-px;?oX^tX^vMQJLMOLU|R[MUIOOVTYTZ~X^~bnlOYeFLpCE76+(# wovz}xorw,.yFI|X[~_^}ccoffhgi^eg\ggeihpgercalffffffffffffffffffffffffgflhglgggddbcccedical^\j[`LY[gPOwIKtRXpU_z:@|w !*$W(#{|q#dd!v#'}#m) s h!!{ "%zu|'}!}!|u k kx&)HEHGBE8:()|wu xvnz "-:ADKQLUIT3<}(0x;BAFGFIHIKDN>R7T~2S~1SQKHKDNGRKPHKDM@T7U{;Yd=Sk=OYBN\FNeET=AQ6AOXBROCPcCOwDQsEQFNGQKQHOHNJLJIKFNJ}TPuTKvFL~>MIKXEWECM2YBNCJJOuNSBP-7%+y)$~:D22.(.//4n.1~48=DCOEOIPJQKQIMHHEDLMAH4;(+!$ &|!&x#!"' %"&!{|{}}~}! #!~~xus$+',06;A@D=E?JEQ?H>G;D7@3:060312-8.5)/{pz!"!~oyv!| }#~%)+0'.!(y!(y%,}q!y}ztr,/HJMUKSHPKSBJ{FNV^GNEOsJRLRHN@G{:Aw5:|14%#%%&(;##{quv~'(?APQSTRQy[\qegfgi\hh`hhjgepddpffffffffffffffffffffffffddXfgYghXghZghbihnebs_[t^e]`ctWYJL|CHr=Cu.1~z||~{ytrz u!*y.=h;CqXhuMbOQdP^ikZ_s\[iNLMdhkku1=w$z p'" xwy{! w}#&#(i "u/77=/0"""p(k#*n"}*.xDMtFIPVFO6@{)2u4B@I9A>C8;%% !~&& vz{ # #xz#&#$"#"#"#~z|!!}}}$%,--93@AJLSPTLRFPBO{HTGTGREQDOBOAM@LLTQQ`ZDCIO:@LFK8z?://"!).:>~@@|?:|EA|FC|HH~JLGJ@E=B?D@BGL?H3=)3{&t$&{66DIDEM|KS?D+- q69DG69(+z36CGFK@It/3}"#~!(p;BvIR{FP@H28,--../59xDJ~CFNRZ^SZwMSkY]xbe[]=B#%| v |y~--7767p>=QP|cbpihcgg]fe`fheejfggggggggggggggggggggggggb_jebieeeghcknekqggleaf`ci\a~PTz?Az*+}v}q|~,kBZt,GXYzingdctkudSh-R`"ht,ct&dyA@JTHCaA0ZH4g?.e #!  s(U&d %*#)}~(vy""%-~$6v-4>FIO@D605+<0@5z:BFOIQFM5<06@I>HAGBGBIBLDQ}DTuATtASw0\7_G?XR@M=M=U;HQ&VCWLLOJQGPGtPM`PRiJPDHNINJLLKLIJIJHL|FMyJJKOKQsKNmJJbNIMPL)QM QJ OKHNLMRJ#ZFWH+GU44a9^AW)JPfMQGRBS~DLJJLOnJQJHQ==E=D>E?E:@28-3,2?D6:+/ #|z~vy~((9:EGN_RaP[yILwFEKGMMMPGKFICGFI~HN~JRHSFRIMzNHvaTJFxKU8DxNKzVAjQLRNHnKDIGGM[JP*SN8\Jd[HfXHcTH`QHcPJlMKzNMONCB{LOCJ~=J~KXIR?CBA8?18~,3{=C=C5;<@BE;=+.&*,0'*&.o9B}KT@H,115CHGMEHCKCM4=# $;CP[{IS>F)-(*}8:HM7957CEIKMRrW^h]faGSa8@e&)nw}|!!+-x35n79KM`auhgehe^ee]fi`fl`ggggggggggggggggggggggggopkkkmbblXYmSTpNRoFIhT1-Rj~7wLIGPDWF`Q(mu^HH~022?s(9gz%(/8(-"$"%*n/5gAEuNQ[MMQ~8Ox2F{:=C<@C7H~HDQNPSGMmFJmKLE@9/;K>MHTT[9>"}/5BI>M=M>N?OBPDRETBT1\m m%q!$b];UVHV CV;PGFSYLPiQGRDSF{TL}NO{GLMKXMJ]MMKNNPMGsMFyKKgLKmFU.KOhMGLCLDPJfSK>TI+l5 [D%HOGL OB JF1Zo8W@SHHbHJsDHBOyCIDFyJGfGN,EQEKAHFuHKFQ~FRDLHMKOMP}LNeJMRKKMJINPLCOJGMGILFHMHOMIZKI_IJ^MJSLHVQL`QMdKGbKHeQNiROjFOCLDLIQHPBJBJGOHREOGPMVOXJRDLAIFNGOIPEK6;#'~wv!"~zyvwz#%|)+~cynjxkRXVCC[JIqRVyP[oRIdRH`RJYWOZXU\TT^FLZPD*WMXZPuNHJC<K;^@&Z?W@R@PCMG'MKt-+v"}|48KQBHPU}_`rfdghdcgfdfhcbiagggggggggggggggggggggggghnb]`eJJl64s,(}&"w!"utsy}|tpsww&"yQ[~zxt|YU_:e\L=K6P6X5c8t=J$i`lm'jt5FQLPql2d^*MIwo$ZO=VUSitdU_! #&s`lzBGo)'f1,bQNalj^tr[snZTEz-j~qm{\H}REOOWLtSLxIIo>JX;UJ>^Y9\x1S>X}=Uy>PxDM15~#&u9\IKAQALYCjX>A]>gD]6\:\?ZFYK&SL;CB{MPo[bhhqp_dx:9sh}{|9=^eNZW^x^`ldbghcijgpghm`ffggggggggggggggggggggggggJJp>;t)$x~ }r$(+3t&,x~).r$*f4^XcA]_\`[r^UfUM6MELCRGhE ia[mIXF@SATLISUNTM3PO_EWa4`?#e%k/qI4Xf?\j8Nc1?d07n@DPT>E|=J9Rf5^@0d@)gR!jLrxy x {xr% q/cT#cH1m>X+JGdSHYQBcLM RI"RF.SMRMSCMRDQSK6SHBMJiONxNPHMuGN`MONOJDODB@V0(W3a.f LU@U?JClIY?>ZJ [LYBTUAdQH?YA)_J+VG QFWP$RN(LH+RP9BNvFQ~HRFOEMGOHPFNcpUbIUHTMYMXITFP02,.*,25>BHLJOIN07()KZy|{_uc^DGZHEs\u&H-],^f$f@\`!BYmJ_vn 4 #[ H ")'0U`[a#ji1TOUMe]ZG@&h_@`ZLNPCw{`RL>U@Qjq_NR-d`GjgTKO,CB.C6=ZGCjX(@4&.%85&;L40p\7\[%}UUXXc:ErDFKGSVAM7IFGLPHR?IKX3E;R@]}FL~IRGTCOCF}IGJNEUCN|EOLTGN7>5Cqszz}}~}|u'!wv.}!^{2=s~abYTzh*T;U@ `RF<!$*B,,l$<+*5 0-N5RE&%0-PD I4! p$}!V,]/S+nE? *>;:F8FspwM!!0/ (+=%Gim%#7>= _+Cl Lh+oYGYM)83M5P<GMU5 j+V'Aq5Nes7NV3G:blGz{fx`])[Pe}>(k?kxwy " /~%!e)mV;Q:#] v"q:g/\8Xf7fASMO JL$>M"A[+:X&RTG;P=KXFUI;US<7X-Fd0VU'%l(| tr 5^5g6=`8"f7b4LJW,AF(_CYzEJ73^OOIFKDFCEKSFNE7=-34:BIGN>D>C-0y~8=6EFNIRENAJLQKQ@Fx+/nlx#!y z+-;DJQ{bfrnmilibnjikjo^befahppnfjkAFd #jvse|sEKq|o|X]}Y_yU]pU`tU^?E!tr}~||"g!%$7MXc}bpNsN(%7)? 5'! 5;\+6bI3-.- -)%GG##78EQ[&%3PE)0Z :&7? "J*-& + @!3 &1/. %~<@26.- ,71GH &) '" IKDH.$0//,JqD?j2FsRlSUdE{yM;?H;MO1}?0~BF XS [,@V24~qowW Ebmym,\,ixrnpvt5]3T GVFH =X h yk o  b$$N0kFCEVh3Tw2Z~FtEGxJPDPDAAHKRoIJfLLpT[nHM@>OOBDtLMGVK9VMO<+S<_: mC \HIMKXBO|DQT\HMaPS|FHHW^HWl:Gs;IxHXzCQvGSy^ilN`@M;H}:HoIW|AL"p}|~~~} $,1),} #tj}"'$2s,9JlGYzomG4b(I>%J!;g7:+4T+5=`Ru_rHbA^p]|~5VM4TI &(#/O  ,'.=[C//79_GPm3GbMj|eDS<%/ "! +13:>;ZG&V<WBl`$ZbUl_̃qobow`mco^ggReGS}NS}OM~D;~UGLGCD?FKR?AzPRKUx@QkCI28%*~#|!|(,4849$)z4814$&~",1!k{x!u)/{:AGOKSJRBLgQY~LQ..|k~wv7xKLAB.2r%(k "mmv#!!|~}|(drgtXLdN]|Sg}t2,>. !B)0d +mLERX.G&F , : 6]YMg3n~biH D? $    " .L1# 4?V,.O:<&+!26 ,P8E N6 1 OYA8*<$Qqo0LExD4YyoSnCOHELDOODI;LxUiLa|ft}kWj{CHLQUkyIYzBP@NGU|YgPY'-wy|~HT|y{"M9KP>0;.5Yt/N_YF\Oqn_fVykg XKT?kP2zyEM>[]5x0o\!O@!U`(XʕH]rHUEM|E|/3z !~!"|~}+/yRWumsqlrhchd]bhW^hfkWMOf-*y||xtwywuz|{mo,/~-/ |y{y{#+l=Da)#OH@K^[8_e%IP1tVxQJI-%,+ *$Xs.X & !)("F lB/3%MWLOfFg0FKc1Y}3"R" 5 -535 -*&K:* A, %H) Gh.% $=lL, 4)2/f,/"Ln=sB_U`]PH69DO*-LjtBBN8FF<3V,&53Q W`'9L*J gsig q&{ 6n'`74 04 !WP?Co0I^`$ompw n#p} mr {xs|wt#w z)vgj ^Bs;Ki|hzjAO5AH[NNDIIKLJGI>HEM~ROJUKOOMHGI^@Jc=^A<`n;^t9PDUIW8FWdEPfEL9BF9?$(}~!$ vViwh̓ibEzkLxT[\"R]&ik~bfxVSRGPPoe`xkSLxPMlZYi7:CWW_ZX]pkg\VJT[:QS"XQ'B:'-+58 FDF;=*40 M_5b|UJUW.1(15/2'''/" 7:@=O=%960T2%P5"(\DfpR ]P mv}CMR_jti^dp:@NKRXYNTKLQCIkMQFEJI10}|),}w!#&)'+?EIPFNLTKR \$`&k18N 9 $  >*m(bE K$?6 ,KVQp"#F,E'7U~8:qJ>dW!7*]k:EIb1AN*M 7*<?]E&*iDTc8P=A /DEY1s*J 9V@=!l ejR&f9 x`^dot y | uq#oo{{|wuz|kfo wcw2` 42' tU@`KaHoFB}VA|HLUe~krMZcDBiONz>HTLBJUN2XNEPOKEF?M>N=RKN`'+wAGSit7Wb@e:n#M]3[t2^kGp>c~8_\W{mF`{/9)0%+#~ss}yz|}||} pn{{#$~3;N^}bgWՎfHn%x(RjFVr?lm9U`/\1:f1I[BKZ8?s3?i3Ban~WfQ\x.;3>2)PI-+7#3'  &< P6"&$$'2IL?),PEI38!/<^bZGU1\2 hTC,]EmV-WBgT*cN9ZB@]CN>MHUWNO))]` py!#!$){>ECKAKFOHQFNCI<@+.!&z$pnu!!zw(()*z02mLSphsyV[y46s|yw! z|"# yz  nz%%$$(b(E&h@GY7M92cI-.+";*@%5D$L9>~2U?)>[K)ys5acM?H%*..9):V0#Ac#PM3*y1-k<(r5O2_q?SKEB;E4D83J DLQfb#O? Y*FlG :%!=L@M[ M1}L.u)37Ki,taae^=Hx.PTs4N0^%?4& 3S";^ C}361/R"/ 2*N 2Q1% [zQ),;;^">9R^P$$:\o[ I UVf rsu in[Qa c "u'.:3L~! ~dh e|wzu~4}.#K:#*&X5g*[J@JOSZETJNWybbdv:AKC`7c.,]3[:U(>X+C]BG]PBH^83[yp&-E><,aM,ZZMxe5]]IG"Ga6t&I]@bc.rx u} !"|r$+y#e)#'?Q}M0s[}ks|izZK_j$2}DfM1Iav1*x#"|"|(#!&!&z$#eTNr[N_YM[qlhRV3II#9/#?37HV5!&$ ,89 Z77.* 3A. !0!% ,C(R"9/B/81Q1"uJDlXB*L/ L/Y;_AV4e@#O> K>PLLnFQSYd`//a~ ~{~ {q$)zIPQYFOGPFOFOJRGN4:#q n"'{6Q@T'6{t`0CR:bJ5hW.`_$TV@UR)QCAQ>K!s51%.n G69F@ut1R92K7<&_Jz>Uu%i;G7AUb w2;\e&([ .Q"C  (nc%'Y(? IGuj$9n3*Z>oN$.7 4;!-H% OSTr6O|*V;D?0Y!%&&4=,!* *1W:)\ j d/ N/6<("7#H': Te `p%Yt,p- X G 2K2.RF=PN#a8pC:m4W G d{| }pin{}q! {*u"MO'>!GMC@VD]aselyJY<0@#0F9.R&VEEe?HDF.e:e81FY")uHquOWRh(Ai)id e#k lv! $"{ ~"v `w7@wUit'5*Ca(C^Z~X}dQ\p;RZ1Ac(bl&}ys{"{a7:e25V@MUXlS]oW:BDJ0<13978 5# :+ [j/Hs> H8%L-([#'mYF9m/3'g6~^52^:->EAD1XYz~2KQ5<@HC N@P;V=^FG8A@4A #5 j{O`mOBHh|~|~|~{"}',}>E>FFMGNEMBKFPKUBL3=r.6t3j& x{t#"p|wpzyvxy~s|xz~{""w^sIeV.G}GnB[1LE|&%qod"-5D RX>gezTVU*&%E;/H;A7E@00$FHWH 8b2,K+l*.pS|".Q ;=$ @,(08NCVa9D= 03J9I3:/YCo9@30(42 $ IdzZL7^*W(a*w'|y"k|u0=IOgBJyAMHTKTJKgPF:ZH$`JJ;bUNxLGCEOW4=wks%! h .fIuEfwKmJnMb% r  + " y!#k.\[BE9')#-!, 0J-E*I=$KMa_dEPV\wOeGx?m4h6R<@)6>9<@0@^,b.}p9Zd?iJ6RT"Wl4, oL^$lW?e*M4W;w|:iu-u9]Fy%%w[7 t'Nv0-3t2:;A,D4c)1LwqOI/@370&a:7;:>$I>D1&QmJY7Gb-4^>X>C!JxeLKD4T7"]%>$ =YH-McT# *%A23GFX5U#)g(0`.SvXRMR?P~8N?MJLLHWKD*TT:HM-SYWIK?DIQ5<!ump{y&#n&- !/R[|M*iw-F\({'#$ j*h |m<1(ylA]*o?U#B_`vO@=.B)>1!Ug$| xg\ZmI/RIR:]+[;G$^=VQVpA4Go}.AY:HbKb;aVWP"P4UK> j`/mE!]Hyi5eJE{,R.IV+Z?o$u-F^$@(bSi*+/k(j58r%%-~-w:mMo2o$h%{!s6B+hA4PS\1Hr Sk;T^+:MJ;Ia?$E9R*;PA?cG n9Rf_PUJOE^p"0vy.Yh{)z5=E UX;U<:I^GHCGWV?I4f! |l4TN|:%p #u o#~}~%%h^l wm%xc_'+|~~ yrr!(n"*hESpqtl\qvIXu'/x!  "&mx|}q6)-PaYCP< 2 ..?!H^46kAMl&0x&G9+o F%6x \LI  '  '! %>E  ,$!$" 7)[:Z>ZBVCQ@L;E24?)@=.& sp%&1*@4vWIbTPgSUnGQt|p9f:pDH/UIIQH{U.0*AL.\H%NHJ8}|9]H0C~]=X%`l Q{P(Vo.?Up>fYyDZ2|>Xh.3%l1>q2T/9Q}{*0+z|)iz*{6s"9)'pJRNWVly1<)-$' n Q_ {~# xt~yuX !&&P&38I70C## 62 >"U9,2EC ?q*3'_}#v)m)d'aG53,[G*$( PM+' -:&+'# 91-$2.D0?,D2VDaMaG_AdCNHD5^&|9BK[_,`Q&W6-]P h[8j`i^X|RMvNHnPFhSEh`Mz\KoSDaRF^c\dkhYUT6A@!M;#>9+%S}n}t#,=3>yvW*YBPWE]Cy7b.^# ! "ue7K`]R~v8wvahf{xl+,bVpU[YzZgtGDe0Nd={OM0Y9Y%p~Cfk)kh94 }:2a\6hQ'lOuM%y$ha-:X@tIe:HZdX$u{1t@e=,nfV{9N*-:/e/(R9Bo;~>GIWQY=I3DWAj:D5~XBnYzN1N.K0Gy/TZ"U y+Z!\u|,,%q@bI5A{"!e!  rdhu$#$$vjz%((-~")oy |$"s$"v^ntwy||jYq%YK\_E,s-$KC2 &:1U F <&! /!-*-:3M; Z>a= c<N@K=22'cl3-YPI-YEU5a:iHr[)s_DeRTUEFRJ%ZV X>?X?:L6J8 TDQ?=,*e6"T><5&%Ei45+j`_WKCv6BjMQh_B{9k/S&g)'{)o?:cY^Gr;_2[@DžkoXs?huKh.xAltW-Ka5b;qf9Y&q&rKw3Ti0'.Us?r%U6%>mTl)hn0Z3R:w7gBfMEJnfm8_;N><}2/,Y6,mKQdeln|qvYj!b׀labhzvtRX@3,,, ~[13u*h=Sx+l(7h06pQ"8T(>&I +.F$Q1=6<5H#J3ZU<9!"=$+G!XA;U0`<&8V4"p6Ao'Ak)k]CAe QD ,E"U3S2V;V-O7\l)w*2J9C&^ca.3G)2W, Ab!N74P }~~~|!!p-z\|d#$'j }w"$y/2.1~!#z v+0-1),!zoghwy"{ {#u#!xzqot{ {!uC'10AR0&? %  9!?mI>1 oaVC[K 5lG\*eBtOX}HƂEO>u5e+{6_G,y)>C2?&V) # * '%#!<1I8D2;4:3-,#f c,#$E3 aEb9 ^:^DbPZNJBC>FEE7QCRCRHK@@4B47, \7Q7A4/)5 jxLAkHT{a`e&rVDZ^ZQ=J~CugUAK/zU+\@fB>x$~@T{iJzVCOMjoq9p~0+p92KdN&l#G3/ G+g 9Q7X9d8EB* 4E0=j,k3z.3WcB*FK3jD|3)GM).C"%oX8< IoKu6+\G a;Q" k~y}MnO8=Skx}~|12KNEH+,! vutuw  d| axox~}}~y++H%C\2/J)#=2+20%  #7SS9^NA*G1_3X`zyzֆtTRL|A{;u-w1w/F,>J&3U *))1>@YGSCJ=>9.2' )!'-. 12"38#!.+434*C4+F-*E"x}h$3mIDK0#?5t%*|%8YtrVG7h.fC_VO hB#oVWbF[]FKKi0qd/XA!7nG^6W5h:c>:Fno,͘JȦ_LfaA^]qI`:Jb9R3R$xPO^;X+qJH\cNuk^PrgnOՒ[pl\LJPpohtv|fdtxy[_q}pbq݇yS/Q67v?i.g& U'+*8;>Ifu"!\4q$Td&9l1 -MJEPI?C<,%b)E^6];O9;H5#x`0i$1R5H+H @"ENr*hW08I[ @= {!|#w}|!!JbLDTk#'t X(&gx!tqt|  }}Z{!nw|iys|}k#o !}/ %>2P6;%" *%&;E[*(" %A`'V:8Peesuhz?a0q0D?}0WV(  A'24./ -.+T:%H?'#''# 00 05 &  '! .!G#1L$@&Q,K`G/ c$0F'5!tm y#! ,2 }M5UNydd~m_n]?W^nK%ztXMi0^4o0t:b+fk+b8g2<ΣU:(i4}J+rJaKmPv2jyJ,L@|O:͜quiY}F(O0P'}C_s{**,-} |~j}~~~ o)V*E@ 2 $19&T#`  2 &I3k"?%Ih]kpoRUKeq4v55y : #& .069cU8&* X("B2 <@.Y,6M+&GI!(3%. &"LE=hu%`cH|jDi3d+k5w5ic\NZ&w7PObTx0R[oP㖭od]_zqIΌՂJrjrewrzskltlg}ׂupkjrrqxzdUxVԈku\zJrP\f2e[~HBfuufyvi]z}vsXJ#S9O+91CYN pt<[ 70 - $.Nl0ḱIvFMLf{yQ4;'* ~D{j$#014k;uH94'& H"ZXGQBf#YUKGAC\ fRR*8 o}vd/S )<;&J0) 2&,A.%E#92$*2%Q.JWWWAOfg_qxfEdS>-r6\:#29o3C <+E<+R-fH &?,aJ') UD)B'P17TS"O:/]6-q/o="Fj&eT(g.:r5F pk,=+=W3L"0*.0$e!~}&{G0dUj[\Cc>a7|7{ mSQz8Y[_f'YGBTnh_a®i[^`/siZ3Z$G4%|- .PR">p=qj8.w";B#j0 e$ [;P"NPN.:u,jEc2* &].R-AAJ*1l'$Y-#/c#%# n }--,;@3DK$4K$E*/$hz~|%|({2vD2Znzfy6f>_5KQRt9\+gAzVV[IH3{')I)891$heFo-_SВG2p=MC *lD^MiEÔFLD?Ss\ŏG{|vRzW2͕B@JaQ=/"'W=WabYnerj`~g^|lXtruiyqsp~ja^dZe]Qԁ_W[oNtaPSyhzzw|sqp3\`UqΘb†ieL_V}vOAvF`0s>|z/a$qDs/`&F*;-v)@E!3JYdi{okecj~̀pijrmՆtrsoxz^k{yZFQl>M_wsDkvZЂyt}9Il}|fZCC&,7=[MXP0TՂy]XɃHo09$z2@Icj3i9:L.*~&P;Bu2TZ5,NJ!Yt+'@rIE#.~&y}{z|x|}r u>=CQISB88E{d"[d1W8M>m(Gd`w^q'VV99>?;56yJ_-EPP!@LGP, 88>XR);r 33.R$\r#w"%mz%} n ! "y;2E\7w'b88_KISn)%G&pM-'oy? mFRL2WTf,S~e$gp-[mGh2vM)7Dx 6/b`AzHSqyb#2s H(txVwOa)f5={ybjrocEU[w?hY.QoX6.{%:C|d|ouzP`r^uk0@a=F|dLhl5\RXf{|bvfmMv[QmWmdp{mQaWqzVvkznuzKudT[iccZO99>#-9$AfaJex=B9e HV|dc7y=o@7a@C\[Df7<(zd.Hkn w\!@0iq#w'2P! }||||}{{h,kDHIBm&zE2P*J!ƒ)5 HfDjDI(]bS4dVWl؉T3rFsocOmTU;{$U7v5DK5LP#l(OEPbDQ;m.ikS&FjrcF4yM*l iMBr8H9U[;BG6>$'FS<`R*Nn9jWP4'e6-K$c|*"kywkp!s v | t |&@=GX$XNaF$k D54gB'HPDl0PKvk2W/n$jcJ]xmYO809$AY{7%t=Zv3TO}W30w 1 O3pSQ"5agրumHl@kKIV4rF|I|/!)j(~Bq WF%}pA*p,RiLzEQ8HigB~TkZiL3uZ?a??&<='9,BA`'Ei s~(s/Hp# "} xwV6Ga"2?00J8)T0!\4BsQ>mo=b_2J;Ur0WpHoA[k;I,0"@IX l~VCpo<0vI]+p7#zH\ZVp)! #zk(/b(ÇSdEz@i6o4D.v!nZd{+}*+m@NkI*`)tD[:aePT`+#p( %`Xupv؏sjMvpgm{|gftcm\d^NVZ@TgkqTW@/UTHSDk7q\KKosIQjaRwiU;Na`dPcE;^\Uz|d}z`f2>`Nadov_`Wx78E!DV z#oA$M^:DH"N3"GZ6U1gnMn^rU`wa5dyJ_?b4x8tF]#y#p,{Mgl"X2.Nc[TLa'_5nOwa`T>OcnTDm-ePO01E5SE8i&N, 7N }%"ks rw %#tmi^y(| `(XKb42=oc){Undt6YW.I;eZ-AZ gG8)pm*'t~#xSecWZq3mw2s)^*k "&@@6ZD /8&KW2n q]McgxpYwsr{q7k\πȈabcl[Ul[eQm>B^I0`̿WNafaK:ɨG2 u4+,G)ITJhjH.w'`$"+~!}#/Chfb'YdQ0IhX' pp h~~|tm) )HG_~.S5ieOs^{[u2aNs`BnkNqM4kCt9F[/_7r1{23 (#y%]4{G`He2S7zZg@cB9Q]=-#YEf1nFjTSwS;NT-3g"{}~~'u'^N;n9¢5̈7[.c=|e3s=ui_< Sg&m0(d5/I3oUHsA\i%p,jUT&+k,{QgaG :GQ.?MVW5iy1&EZ`tQ?;m-5v)^E '&8m>w=VA7\R+d!BS., c/"q@1c\aP8w{l1)t z;>s4_mjajpbW>.ycjS'T+"USfaj?&L3i.R]CyPmNsT-10G@H6 #p('"?gJM:"& !m ~|uo OHGS BFduIbwGUiX^5i?ĐVs3b;`.y3;'Ap*X8fIR7Y*]Es=fAQr w1H"l4JFq([|77LM&ar| }y}~~~0nTI+PH!y6a{AzR{fzV=FcL?Qu[dQyLU~seXA+okj+7>~DFGS\dwjnsD-CnZWcgkkG|~Yt|WepPhiWsw\mxPu_q}eZfPiwDHw9|]bTw\|d^oHDX~muW_bjwc|fP&+8ZaLftL^HQE9q{<eYSER^LOH*J<*-"7"r o ~j&}! h r}a"CxJ$m}}~w}}wt #6lJD0&'85E>$0Јr7=kFrF)kzd~"z!X>{e#iwr&:F8#pD2zrB(gF#x)r~V5T[E8! |2QSSXR4*|%*lG;^6RECY!**h`C;d$7r!'2V\\uZ;@JåoT7eqM}AiUqu~ r!$rvo{DBuzQ^Qo.2FL;1AXcvbjiRye|]vkIayJa]krdxrv]^Nfheqe}j_cbhr|Yp|VfoZd^gwaRWHnLjGhnblos|n~Q@2EEEd}bc'gFMnC|O{QS3t'ZFkniA/]@MoVxEH!U $z!wy!r'$s$""u t$$$|e&_?/{"(v!w~}zw%Gc/p/*kM0-"'KeCB:(76"tO0Qˇ@Kw5i*m>~C8|7i?MIy~,^,c:[%cA}u o~~&dZq5mWC)UXY2i? n&~w~Z@g0~Bz u(ك,t:M,_2}gx!'f&_@hZ=QYBLOJQ/;m ~y&T=gqIj$xY:,,^cnRD͇/՚6Ƒ+ƨ8Eofℐ.xhLNicTيNKvF<)~qg?@yvt]V9yM7CC4$.FQHUprizRkhjVL>dr?[WemaZT`noglofhh`mnft~clu~y[D~]mjcVf'|}s][ATPQv@;BHE|4Xx-vD0R~o,‚i:pG5v"0m-s y$ u)8JvFWv*-c`?5U>mFC1j0M{I^-zUGn18~Y=#b"p$kK0eka>3]Q*W"|A)M AgLUh>P3a.";:spa6bmk8^;GWhWbgSU(6KOZ57`.+X$gPZEGB?0!)Xu[0Iajmetur[c^]uVv~Ux`Z^Ovh`uVX[p|zq`Vjr]nupu[i`YeYGBOZKnpA5F|?c_"rCr8^3fLc3}ONa/L`9Z]B*!#z=Jwc}z:h6a.s!!d {- #k#.N"H/W4!<7iz~~ &(}E@-k ['6[+=AAN3^]>! +5V/'qZ΂NC}[GD 22>=(|w%U8lw)>o v;O@Mr 4m PM]lN3qRp;%&xv}#xrt~;'o(E-_G'P@Cf/1~$Nx s4~HH`mjq\P,?^bs/w.T:uA$o*1:2mx  ~ $ dJ;\9)r7y$Z+U]9CrD^@tJ8jHC(KiEIJd~:R]\KNImE=:Mx@`nTWWUW`1;1?UX&<`i`TC1=Hbv~[njmVXfIGa}ajpqfkkbgfu`ooeF8\zJMZ.v}SmͳB 8˴,=PPe\Q*`.Y+b9d6e(_8TBh $} o}iag5=#(| }~~~1!v, t!05HYH6cEGnZc""x^VIaTrlgaYQ2Ǿ_HLP&0| ~%y+)|#vo*f(},!/(x$4'l ~xd#*nZ]$k<-ªbh_^YsrSy\edPs^IP]{[M.L2E :$6JG(cɆh?5BIptDnv;0? 2X?`^Ek\wPegs;eycazuqp`[XZ;JeH1CTMd*Gc)S&m3cKlriq5nG@n a#_OlOZL`JTY8#~  n}uBKW|.B=Lt!kB#&I4(X*':/J+O.%9=F>LW"$o |{l u/`-#jL9;:9-|:UCff q4:ü-;Y.ēP4W~#n!oe82(<;hDm-v8fB\@A8kL2r/]n\lk]YNq`jinsgipM^;MxSA@7P.K]*X*GLK/0j{bX='Y&";WZOn}Lnw{nmvfևygmjf_WkTlr\wч[rFz%9l^/oy$l4\B^"M t>Vg9=\5^6b_%y?W7w"{+w+vz&"*6F4EO#xs)l(@\6)GCGH!*98B4KI3b, jP #~v$b!! yz.'@8aa\%dhMos\V}Mmp[c_vfff]\dgfnkkibdWijbecqF@f;/o2(q r|}${2&z2,tot "T% q { !w'zXM@t|Keaxe`~ik`hhfggeu~Ew[Z4Gs+_+tN[\^@I7e%& z vr#.J%11%0KR!_"l w {|w #`E=:|<U4Ⱦ!&ô=77)()7UKS-ǐo P84JX{CA{Ix6-0.*89^2KCJH1 ?` q$!%z*"nIJi&â123FUvyfvxkrwYhnLcd\gdwjkeeegihmhhfceXkm`nmr]Zo2AYaV./p~',}_dNmxQWg! d{} /( ( \7)dһ/P:HnsUacU^Zqe`~wze,=K='.:-;'629)C+)1'3'*B=͋=f7fe|`lZT]ـng`fqZhhNau5l+]S]j)^b:W'&")Tso0L0Ob"tcNK*A0X4\7QFPFZ8o7~%g:k_9Q/l"\uz }!-W'95kmqx{zww s*"^_[lD5zR#/Ľ';-/4,B3/)fQ$ RQ9&F!e,:c!:8lD p;z @L'#$  - r~!|~}>7Y14 0szPtx]tvinojde`]][bafkitegZijeiikdddcd\ik`lmgiiktlwolw`_mQSjDGp12s# y"ipyJcnClscdf{JHy==qGHv)&#~jG[l>X:&nC:SMJEsveeaziiklmggfncccBEU95-&FN296:,;4{YK}H^43,(%FVŰCÄAP5l9w+8/*^O^oKZ[PEKJP^XKpa-O|T-e{:DeEt&<O3(0M. @qUf4p4\(IQBD}Mi7e.f+a#[yFŐr$nXh`5,} `z{|#d#TR}}~ {ty73}-dyX,4.@ _Mnj P!˻'45ϡ)֚D4uVRU69^<||j 8N9Cx2+*0>_QoJ74B(OVz&twvvw{:,{C(D!?cd_eg\egZccacalfdrhgmhicabZiiggfkcbhfejggede_fg_^Vehblmkpoptnqx_bsOPlKNofeuefkegdfhggfngepggihj_Ycd[hV_c,]kpv|wZpIC?wQ`aehoPpzFkoa]\lf\ueaXXOR7)[*08 ^0†au(އ(`h8|Hi5Q \&p.|3o$j1{FdR rUW>EO%l$(~|t p p~~~tyvV<}ZfPgk8YlV1+i8':ڵ(ħ;|6Ԏ9Η#͜g'M;c)(nj?]V(.N&)x$s'!1T1X0&oegad7%kxd"vtx{ |)TXd$=CefyB_igrijefhZde_gepljxiiibeTccehgledjcalhfshgoeeeef`lp>prMjiWba_cafaaa_bWbjU\]bklnrrrhhj`]fb_jjdnmhnr``nq\sSX:h~>~c5~>lkyaowR\\dbdcfi^npojlgeblsRb`m`^iJFi0']lO#L7/-5*(&6;SzP=B&E,ơ 19…*QD%#"5I 9S;0C"3Ǩ3bEQ\ 0'w56:! @-IMN2'txutvy~~|!wK',)fMt5,51g;Ζ9ٹ*/J1:j/!%|{ ~ zyx*eo(4Xoy`8* ~)"|z ~.-yEFtQQi2LZWtabfenObjSpnqe\obc^dddggihhhde`ab\eeckkmhgmcd\koXnq\bc]cbgiikde`bg`hkdcb]`\Yhbbjeiebidck^^^ooqppr^_Z\^PkpZkpZ[`Ldg\k]]plc`_gPW_P(4ZOWYLgn^YZllsaelZotnt~\qzgOTZ_gPs{cRTiCA! "w`{*50D#,.20>"1‚+p3ECG8+ʼAک r&{/҃4v (e6b34Zv+W|g# 01#B/)$B(4X]4C[C7. LE8*(1 !'=FG 7.5]D5/\+dZ'n4y7x?hY.YS{=\S,,(/05<19*#`x nm"~|}~~xx'+h;5sWn"G!7 VKj'&,2+̏1|4Db#i'$i "Z%~% {pI>ih*2Cu{(wk}s13nY\kovfumnj_^bcdjjgddi@eeo`iXlmegfkfdqihphicdf[ddfhevkkkhkX|ZbknYefakki`a[biahmgggegcdrllurkmn`hmYjigbafb`khhpijl`dc`chfjuXuppcj^[T[;-"@b%%I]A7?wUmqtnwZuyhps^hid_Y}biHajUs ADwOTgPVHICoovf~pY$+B_D&<۲4$M8м72!#Ø2nj&ܐyl4րy+Ѓ/Um.r% Fj_^ahztnslchdbgcfkg_amJIi73e}!sMRhW\r*'t69|O^aS]_YeaTc`Zgpblx[dQu3DG/:$˦!Ϧ&аաҠΚ Éԑ͇}|$Ώ2ۗ(ڭHUŌ`{D2?-5d]AG72NJ*m -4+ 70527 ]` Z!lO85b/<& C=[31A9OF:008:*9$124/=3B =?hod!~~}|z} MJuOrp=X>8c:-HH=+a/˚Ϳ(ֳ%vJ/>cXx##{!jq"!|+w7r&sgDYj:9X&%g##kx {*'n{z99wafjfg_kdtffffffffffffffffffffffffffffffffffffffffffffffffeeefffhhhjjjjjjhhhfffeeeffffffffffffffffffffffffeeeggghhhiiiiiihhhgggeeefjiZ_[fkUliz\Sxem|U&$x  l4/oN/IػFݡ%݇0ޗםҚ)ԢA7t m~gϡݝ%&-R?D"B$52|i1;g61R7"QG!]9J.5=GXD,ON0!a?&V&c*WgA<44*LER6_#ndIH,UPM?5W(*sZ]R97f t~|zz}}{pn 06pz#+k320J^}T&B{`]c 1*:S#l vqxz ~#$"wp{6e<;ZnM*h2hr^1j'#p)!!z}{!$#y~~|||v&'wBDuimxfj[ddZlfpffffffffffffffffffffffffffffffffffffffffffffffffgggggggggffffffgggggggggffffffffffffffffffffffffffffffggghhhhhhgggfffffffin][smnhkmUcfSTLcLRh! bl{I-Zad[hlUvNszYmpehjgegdeh_gjahkdim^dgRgdka[wx}]F>[kDvz tl&/j:ƛ5'Ӷ LJ )&qt|ۏ-6w1ɪPb`e_AY92g>z'PVR"JD4i?aJ Z. 31;OAJWIP Ҟ1kvNPK\tY3=V\.w'tcq#a9<[}(*e~}{rqx t&l} z {. wPNSlIYs)o'xs1aD>A`$ 't #"*hA7@URMIJi$#oo x~ f<#vuKzJt{w} T>o¢5$}0ʭ%ؠ٠͍Ή!~ "46ʬ2Ņ$pbj74&]=l&+;|r#qBY 9D2|#J(RW WM82P^ [%QVI8Fg\sI3cla/LQZa;2s  u [!| ~~{z)+ zzz!"tr n% i2"GR4CGh\*cZ5cONziO,~^IYZTO2hh9s `w xF8B]w|  40c>@O( if6BrP:Q~S]J>@./fFm/8Y"&p$'t'*{(*'("#}{z~60^iglgdoso~ab]ffffffffffffffffffffffffffffffffffffffffffffffffeeeeeeffffffffffffeeeeeeffffffffffffffffffffffffffffffeeeeeeeeeeeeffffffihmc^tzyeonZSryMhhrB9z]<>y! [dc>lmekkihgleeecd\ceZffdhgmde]srz`]nmmy[]j P|$* | yc G9vK:ڠҍnz<žT;?~m! }#{w  %i0<<{Fs %^1,_>_t)]/`+(I@7V\50\;"r "k2:+B<^$ $vr"%h.4h %\y{}~#&u9D`L^NRUMHM@ _Rsknd^L[?)E80x8\t!s&!}/+&$$ t*%y\ p$u*%*&{53~'(i),qp{v##(*ojx!#6V[\cdhciGhlmyiljabeecYc[fsjWaXbe^nmhZqa]ja`ff`ek^gp^hqcgpifobn`\g_dpb`id[cebjl`fv_es`clcdhmnpgfk`]hkfmvqngcWkki^X\qbyoemgiTkksd\tqiRwlr`^adoi^v^m_r\mnga)+I$ M>G]\dWX]c]eNIycuMw{jwDip7G%wt~ qc$(;BPiA#'q||}x{!a"-K<6\GCQ75)(%ME8xp[og9HDXPC3I]##},/v#n3~px!|zpj%l%!k!w {}~~"#}%'z%'|!"~wtIDxzHwpfegYX]sRVUcgffljgkjmmmulqn_flXagfbiccpfgsijmhefbYg_Tl`Rkcpicge]lgackc`h`^hcOicShl^dgVfiVeg\cabecfgfbbbVjuWjjbmkVedP`clckmad]f]zVXJii_gc`d^`[YMX> ;)E.#*3xT]Z*H`^kyWT30~5:P``=J])1b #r z |w(utBMè581S/׵:Lp`c8=Z!o wbJdiK\AbwOiSn'^t3?W/W`'%1Ud=Bm%$d}wt||u#;DI?N;xz~~~xt|iq (L-0[*%u g9:NjsF(W-a 65WVIeNE?@H-7`?MvqnH~li_h|zwshpnbff^sskjl^rv_6B=@8t|@po]|xR2QludcmJC%ڲЊ+}<ݢ<1PR[bQ$Kcr[(# }$(k_|{u&tw N@aq.CӼ:`@ſGƽFZ*5.9/+ӡ Ց}ؚ 2$4LKkLYabqyvp!'*,ojx~yr#u9&hHȸw%ZC=k}%h# Y$#} "v0XRN!?)j^/C6N>Hb3DU5.l)V -g9M2!%oy}|&{ {%c +{.h1R)`!py~y~~wr zos#z, "Kgg]B:G.vt|}|" Ne$%{vyx{%zxw6=O53d.V$l{x~w!}|yr(."9N-@m$yz{y\Hc5j M\}WL,t*I9/5qU(W?D>MZ%ae2i%M/|VIar"t L pe-pc Q|@/*.b#k o}}~~}|x#yoWC^~c]:s|1X&zIp]p ȏ&ɍq̐ x_!I m!w'Ց.{#jȕ qeۥ+QUx đИ 5z=Ā&Ē}bq 2|,M+Bǡ>ܲ*(/?60D*MTn~|>1MVE|I:[M@T>>V!vu|y #b9I.HWD45e !%l+*l v||"u"vy{ %i5>gMc=4BK"f{z|wu %!nYNLNGN0-BCLW/&K:59eA+H `3y/]n+J`v6Yv@6UsTk['Z9F9 4T +^%qxw&#~x!" p5+giPpbY%XPVZ '{E xZtyG`S~,oS{(Tv]lNy ߐw=ua(bV|HjDoQhEZ>Y<V9fHgl_\ xVTDŽ5-DJbkWǛ<Č9eD~T4="?;)}Ce~|"$o"N@cJKEwjqw/-vHV<_cd n|#}}*#p( st~z(j,=h^{)@T9"*[|z  % x+y$6^apGcT?+?=SApsX9R<^m|R8D-;>)`[H<5at!zom 54nLV4'*a'5f)nu!#t~xvy~ 3[,cky{m+lBTF/;U mup}xx ~ s'Og|QT"f8mDe4ÉYpZN+O3 2>,@:JM6:PL%PF @7 ;@ ;R 9Z4U 5X5^,]wzw}x #}- 2$a.FH:m^#D9_ZT713#6DCO977-TGQB*NG-j!^q!n6@B~>_RJ%VWIg_8hr`y__!`NeJ^=W>_JtWsa]JcLv\pR bBgEuQHb^ ^YJ>#NTAII5ERI>&'W_b ~|{*ra"2#v-"ww"^'/Vt .403E75NK)xhs{u j $cC? :Q 'cvxz "uyyuv}&&k%_ z"jSd0~_)8Q3@ooj#O)5'C< L?>3=7KI>(3c)i7 SDB?I*dy||~} ]i>5xHJLt@8HH/MA{QJ[;H8C: G_<2;. ?7AL1B<0Mx3a,_LF>;=@EA>@8B<@?1M'fx||ts!f$&l"%js"/ #}$+{"}!o0]9P FKD>4AI?5a@$P,Y?t3SjNo*c7Qn0J0G8O#?[(Rq5v,o5$oEq_;/(WH+ZD BIN: D:IM?88MB>CYBAE0E7@FKV2'_kG%[C?267CHGIBA?C>G:@-]y| %x s!%gkw 9t c~%p+" v f( u$_CK@3?@IH:<@?@, O0T1DrCM>@%R4'ZI <@6E BK72)?($aT~}u,lO nۻ*$ +ö)03EQT,9o!uv~|%t{ eb!xn*\*=A!3K!i 9y N28< syq&l 0L :: >6@<@A 9F1ay xu |{tv~vl~}|"#%&nz|{$z$1+[YlYvQOb CHAE >B=?<=?>B@EB?@?@?@?@?@?@?@?@@A?@CD JK JKCD?@@AC2'GRy+0 ~{} }~ u|||y !}yxu:\67 FODD!D#$IQ87 9,V9pJi@9M BN89J?K;C4KDCCD5:I,bYPQcl_P_MK')%=˾16a8;$&{ry~}}}v)b1SJC,A 6a+kqm#~"v# ,i :H>96?8N?N=?C93`q)k3+Z""^wso|%b&e~pz|{w ls{||zz|,1s$'x}}|~p~--CH1ǩmMC <) BF @D?B>?=>@?A@BA?@?@?@?@?@?@?@?@?@=>?@CDCD?@=>?@ ?42W%1Y,+ym X$ ! q}|~zy{|%m0SYN>;<;N?>23 6B9Gd'FKS+I? JBG>E=@6:2876>:HR@:MT\M)U:7.nKR~:7-+Ǡ)ԧ0ֱI<;P@g&(wu|~}~~x&h.[ FD?AD0E6 3bv% r,-c%`%m&g"m|x"e$g}$o{z|}{unj!~xy s~}x~||{{|8@q+0pqru}+~jWImIw6@/86ACAB@A?@?@@@AAAA?@?@?@?@?@?@?@?@@A=><==>=><==>@A:=4O>VX/>S&6P7Fc! ~|wkc"hcy'$}~~| ly%6nG<T4E8==X^E}L)c; XUH$;GXB@ ZE NH KRJ[8P?[E24GDO1Kh"s6$bV+]PhcvhWBRCXuyx{~}~}~#q)e>=M9@:4=^ "h j-TBBH9?9?CCE?; @:/ht(m1c*\,a)_'nyxm!lx"t)g4I/_'s#z y~zywwx|wz~(.j!%ntxy|3 $m:48;ui/LJBB@@@@AA@A@A@A@A@A?@?@?@?@?@?@?@?@AB?@>?>?>?>??@AB>I C63YbD3 D:C\z,=[f w&#|w!ww~p /r -9#VC$`DG'A@rfo,Drq3R)AH HP>GFO3<679/A&M)AA?f+vM!9/Q"+vF[DMFQ@?@?A@AA@A@A@A?@?@?@?@?@?@?@?@?@?@@A@A@A@A@A@A?@FEB/ AK @::4=J"I71IK\lOGOQ>8dF8:+"|~{x~ y#!! vz'l6[m-_D/.MY^n,>>YtICRJKD G@D?A@OLF9"dIjCX5F /O/`z%w$v!z{"q#h!d=T1d&o&a3I?>;B /I -g'mu| z~}|~~x}!u*%hXaBb9,750MC@?@?A@AAAAAA?@?@?@?@?@?@?@?@?@?@<=?@@A?@?@@A?@<=E5DK<0>M?J L-/a<2_.s _[xi$k\3A7?\tu{{r#7vABYYYJd?;__,+XC-G, N1 [=?gLA -\.Z#/L0VT#sUpHy`Qxi(c{#t:y.]vN' %~~|~ j=CIQU:4>H0k&|#t'h&Z#0Z-<](M/V1e}qs"s!nv13/A.M4K!HG*UA$Q:C2E-3/(B,b)v{ }vt{{x~r`lncS1+MO 8'D)@@@@@@@@A@A@A@A@?@?@?@?@?@?@?@?@=>@A@A=>=>@A@A=>?:CQB5CJ NJ)n7M9h2jz1]^vDs=&E=G`GuKkm*\|Uv"J(95@A?@@@??@?@?@?A@?@?@?@?@?@?@?@?@?@BCAB=>=>ABBC?@=U82;F I7 L)].V1Wjc\lDKR} ErGM(,vp{xk w d)!&$x::^\K b`7`g3q\1V_&l jMC-x#T;a+x'b=[8lWmAV6+YDb;sAjDN3dXT\SXeb994J#'g{"x~}{}~y|~,h$zt7Z6;X6^,')w!y}"  h ,{>=_)'{ q$2_rxoryxr r,n7W9?A:TfPioCBQB$IB+7i!mq!e+Y,[%jux vz{{|~"jTFy~@d$+6:C=6C :DCEKBJ<A7=A>MC?@F?J=I=@?=A?CEDLDF>;<4D;92OK ::3> XBe*-eN[ qu!|1UV _Uc? e0vIvZ2OȺ=£$n1A y#v%ey[:EKR[ oe*f0grZo$wn)pv/*;o)b@b>a=c9`J=R>3`8][L \[y)U"LT#%51B!," jzx~F(h~PCq'Kss).DM-_fC,"k`-x'to""j k""#y tr!|&l&&Jw  "u[CL6WPE4n4!K''@=/H+A'X"f#k#pqsx$,' osy~~wo&rcDJ2TXG@0 @;<<9;99:4<7CCIOA?@B?E@D@?@:@;?>=BBC GD G@ D;>1E; ;0BsF?u9`t/]t5KsP Z<V@eHtNrP A)mYqȸ%E@v"l!lP)l_OZ{T+YLJ/W=h?SLOCePtXf!eB^:fBjPdC"T5M7cKcGv9U0N2SV+queoT"#&z}~|}~}~}+nF1R\@<#8ITB>^O#d,R)>7,=E"+dxvprtwy{}}~n=,zTxv+KF)D-E:BE >IB<?:<8:8;8 @<B9>1H4@&A$yZ-"lkwLN6\<W8gTXFgQ0x/z)${U3r{"g}r%jrjSxRlC DjA p;i=U;kOs+]<pM uRmL \;M?]9nKj_'g\eA`I0@DZa` sv XkM#}zxzx{|qtt||rc6 =u;aPCqSVu@A]70O86]0a!6cGB`GA] 2Z-X?4TF:D;0Z*!txn!is s9:j#_LP7K`4M !1J`l'6M-J$uyzpws o!n nrw|i~NMl}mHF+E8AGG?@B;D<DAAB@A => I<?6;1 :.@,2_> O!,[%K_{pgBw/qt'oA bBeSlwk#cCCTHWQ_w~"o }y$A{ilufIRB\< \XaBhId#`CnQ kP gOiS eTiLeL bVaQbBYF(-7_gl`oo Hc8-uxp| |nux  f$v rt(# x)#*&{#;2;0~ |u5%pWMDE7Z0"y%{('"mw15(w""j!  %#17O%6H,O ]p~zs"m"m qx~~wc},-}A577!8(:;@HEKFHEFDF=K@@C7C8@B?H@I@DTAO? H9 D3K/7C=?9988:>FC; I1F5>A:I>GCCE.R?Q@ J7O./[&.lw'-w:Ld*Tvuy|z~|~}~~}&$xt #g(wm{Jɶq{B?D+8,?, ?0=6B>C>M4&T-$O3B@9G=BE<7&N>J<F3!W5.OKRcYX?bPiJn@Q4Fpx+SBiR v0N1hYmS]Tg'{u5'twh7]2rV tP^GhKR>]K wh'_P WFS<V;uXhBZ=WBk|` kU,`W6]a$\B^3pMLW >Oa (&y oys*^'4a (s|~zyzt#"/ (un u x~}z!n( u } t+(kqS]b<ɞŹ)*&mVDq#uh_07?jw]$(N!#~~ r5" zEdf^1eTy]8oVhcO+J;<3I6.V1A_-@X4.GAZ=h<lH{nscw@m8&6cBj8h?x@QA~pnj&6O/AO$.k{tqzx 0# u ,|#o"x!x  r z9-6-rA7Rp%ˍy4Ѵ?ÐOnAX%v$u3KI2R3+B&q n~zurt{wz~~|hgHf@C`i:1AP5Q6D,8. ER9L<6.::KEgj?!R9O(9N/T^P3UaeM b:yd#fcd[tt.L[A\={x+svwRD7A#Rz|ovj17qYcd]T`OkV\EcBsFd>ULrdd[6u;nBXCnJW9[D%c^Q\}~_Q"UDaDoVwfXMH;D"p//g4..,4CI1&ta~}vpv!!mwyt(n`2#tvLNԛ0ɞ-nUAhUO5׎ז ǝ;riJ3h ! &yx\ٛ .aWbr&z{~eu|zxwz|~|||~?=|P6ս5]]KWIH37> AO8CKD6Q0K/C0 ZD]3@ xyQYN0hxK@>2O|ONAk,v:_j;_;WIgAD6ntHKJX[" ~vxoX UxOj%ūcC_=wTsSS0oFkBjG^=kT4iceH bJ h[ ^YNJY )!X#+Z`NNlRDT97m+~}}|}u!od-qr; &-̲!%őф؇ΐ ֮7hO;5#_  $& }R0$– 4+X "snyx x}zyz~~}}}{{xx%)iIJ\xtiaT#DId; 93F=]4/p84uWS[@kHaK W/> CQ0`n0[NPI_@Yk+?cT^@f@NAll}#IW6 h/}{tBH7ZΕhhҜѠ)'yevM{TaXrF]|JVyP}WpN v[ [?\LUM(93U,(|kmjhQa2u,yYo'HO u ~~v|uos ~ ^Ds`=Ō ؜ )0 ՕЈޙÈh͒0Œ?VBMj#1۠*?1 2%mt|u}}~~~}~}yus11oD2նAjNN4'<5ZlBjuk@{Ib 4=(P*3NGMlXz\;XzYugsTr+MsTM= jesf xrad7}ws:?6Ũ@-ҋ ޙ ғɈ Ӌݝu~l[o|OjP"*]LtO r?QCM:P3&v] o!%UW,=Q9L8)O%z!~lu~h!"*p.n v:*h~Fœ ؓ&$ڔؐ)@դ#‰%׍%ʦEzk*sI . M1"x!w| v~~}}!"zt"y  Pku\V#2М&i;9B9sRi^i ~,y1rCHxr$t.dbL_mjhO n]FV  t }q'*yP')Eژ ؝ɋˎȌԟ+ #o~ef,^9*$hTcD C84,n x 10t~uS #g#ys~~u t   }bPLݹ/0+!%(33N֠"ȎӢ)ԏѰ%ݚԄ ňr#eB"JD^$m|st~~}|~ !zus%nZnRL7RQ>Sa GJd@T4CKab?Xw1+Huv(vKY>#[>ba_n&lU =nb\V A`|x^@N29 Z! | ({~ruB@o)ڱ3ޫ6آ&ޢ0ۢ  0ŝ,ޡ"ڔˆyR@Kp9pd*OQ*!8"si!wr5P=wf)YS38Vfy0 ~}~~ ur  us*F8hYzJ535175%#+)#.C7ʹַ+Ɖ3ɍ\gRJRg/lx"{u ||}}~~}~}{}}z$!x bvA *Jɴ4CCYI`*_FlEM@~IHW;Vf>>OtFdEc0`p.q*ʜQe"tV w{'|aCO znr['M""z) s{v|y}[ 3ӥ+3Ѝɢ! -ָ>֡ϰV;NefTMM)1- |jh zZc`yt&47>l)! ~}|}p|y*#WWRYnja}l\J-! 7&4E?,+58A*$58:8ߡɋ$ʨ='ĕ-RiH56%Y w !tuwz~}}}u {"l!n_`rD 92bp%4F ]=s8qH}JQY knYosa#s5SJo`s-fw6q3^r(xS 57`Bt %5ix)xs|zLKSPȷA1޼ޣ 412ܳ#.*( դڧ4ϟ#nLxoC3k q""&m@SM3?C(N5#p{.!l~{z{}xuwVQXj7E)*:+7!1(2:33ݯT1 '2;*gPܣޖ̖|S@F p "orux}~p"a se-#1,+5BC[=gClQ`au[uc`t`v.dEAc*tw5^gn#RO5P1{)GHL$zmz25^.'7ݺC+=11#86Ϡڔ)Đ"С 19zI\ATuy!"cKXO}j0JsC1=okp!! t&jnl]*9&*2.(14*(-,*).22-$-H0A(AB.ǥ'ۤ&Ց{y]8@  'pc}}}}}}}}~xxapi-ZKZa+A?eE _9mUEFbaVhLvax ytF_(tz2UX!f[-{[ o(d207?.l:5o.'m nx~rg?Aq*&H'>?7@-,#+"Ф)4ǘF*/O;<yxjCL[R=Tf%B"$"#z!!~qsh=+Ӣٶ),),)*,++.664ЬХ 4Σ,,&6(%)5,ʊq {%cs;?Dd, {#{{~~~~~~~~v}#mbsm ELb\YVG?d; jBUA y:nX@5yF?Ts yV|);/@W7i8.BAN g#  }z~| l?AzgK?&9!8-)ݧ 1.7nS?@/jI;'but39kxAAO\.)W~ pz!"~~{ ]ZS-Ǹǿ%+)*+#+)((076197I>1?/)*('ˇ ZmMS(k =9 N9L"&e{#~~~~~~~~vs"nx\NPKP=XLZHj:g@ OCnA$"tLI@49~ai-p,fD h-TOPs u  |s"69|Y&2$4/7#-ģ:*;D%cL\GFB5>-c zv~&&~-[A;a*,]|t* o'hVT/*"&012,".*'',345*#@:I:,-5- !ߠi c@qA^|\YOpeG30eu~~~~~~~~up>2F;1wYiSS7h3\2ui/lU~"Sf FT!$M?I="pILR&C"ER:Bc t*%yowzngs%og<#$?'C/:6$<*ʍ:w&W { ltJB@ w|x{~w~xy# !~ x *T7e2֛'B2('&+-#+)(&&$)0%)& 5zb6*)-:5իѓ ޗq g{$n%6A1.#q% dw}|[ef:>B~%vNy\$mPv>|b Qd+gLNO dhx7n]2B,B'!5*+"M/ "n yvy! }&%ktH7F'*þ'-5ъ"kww_{&c$ w{tyrx|x{!$ t%"#} iwENw7KA2$'54)&&*+&&(227q4@(,96)ξ!ڮחԌ̄ y-uW!hG4H%@7Tp!v}{rO:0f5sY=z_u~!h76yadjTd:&0UX-6';921s }yuw|zpjrt!24A;*E':6<&(ϭl2 j7aa%Ah& 'W&v~p!sv#f)~$uO pS=>BA2#)2-.*+262,)5*;.%3O34* $&&ё'-hpR\%5I-A1Xi$#w2ͨ6q%$LKT*a4~N=QS7e4~Dh>nk*ʉ-@:'-DE2.$".3 ,-/4?&(*"י,z_%usaM)+7"qmr ut"nm+V08ݿ)ÜT^c3f>gN6B1ݣݖ،̈́Έ&ZQnKMC9)0d{#"d |*t&~M-/T)'їߗ1r-d6_9_;a:J![!c7nCg.wD#-9?.vy gp#".}]bP"wq.Ż?mXX72_6|l{|tzt~!jJ@Ao|PjFr-ItJR$~k?){l z ~  RSq@3wbGѰ/C<О#|zφ*Ă+w e(OX<'62M&s*}#w~!t $ v<(m^nKW0"Δ1q,a4\7^;bҪ'[bi=D;4,{nw}{~  se/ s v#* },rf:SV8bV&5B8+f |6?D6w5A}'D80@9%Βq][0w&Q0h&js}{$."+x z#$&sx|~ tn &#xX=P|g(`\,,.^~ j/Of`ELF&/4/ý!-Ͼ:`TT v, |  $\g0uF8I+-x x}$z!k*z+_T;3BXQ7DBP!&m!q-GH4uK[4,+'5ITSe' !l,h"!m !sy-%NL<%iKxQ (*tw|}~!|txx vl1,)0&$I'l{em(9L?^1)40+4L~K5( mu~z} tq1g"=h117A(,.E#q ~r*p!8JAE_/'8-G%?=%q- #!ruxz|y' c9,>B%eoy~y|}'{&g)@rv]rM >;B'tz!i~ -P21<@k=12=]efaV+t("| xvx}}z wwx{swz|!| 'OQN=M(w^hVL"!c obh 8;F/ TNoC'>C9A2w ' #}!ztn|xw||q'%mN$ m!B[q  {##n!$i-1:8ISaUJL+\,,vr!#p"hu~{~~##""~}|{zy%*dGLiUWpE>q-v$0#N]tWvgM30E!,/r""{h! ~z}|||}lqw{{k$$j('k#j q#}WX6`qH'IP`U$# ""&+|tlo z~~{{~!'a&+k%)suy{}yutFZXqkQ04L'7NV{ #$ }w,0w~! ""{s{z~~{|'-i/4v-1{ wxu|<89/v{}u$%&'y"*X_n}}o!#z"#{w~z{HAQ0~?P>*=%C_w|xv#&sNYkvRY+,{s~}{~}unp{=.nM3_j)JlD^_gj"$z} 11yu+1m!px}z~~~|}~~|{-C}k-1p"%v}||||||||{}~~{yvxxxxxxxx|}"}}}~}}j45nNOBBx$_zwzztw{{}}!xxxwvtts~~}~~joy~wtv *%/-nB>pdbwlpa^aXWUk!~!~}|z~~~~~~~~~rv}|totqrtusyrux|}z"!~)),(u.*w-*y(&yvuz}}}}}}}}~ {} !~pdv"|)$*$$}~&!u! f>?kabwlky\XoIBd?@lBDmEGpBCq98t,'y!$}.*~301-'"}  zxx%%&#t*%& & *%&#t+'~2.9764},)x!xvxyyxyxv~~ux||w!"|,.<=uGKf]]ieapgdkpom^Zu6,s}~wz~y!~}zuty| }&#z**r66rHJzVY[\p]^sYZvNPv<@p,0o"&p"s}v//u?mMNmdgpmnhcc[b]clcxdkdeldeldeki`dpUUwHE|?:}CBlFFhMPcW[d\agZ^iPRgHIe<;,+q%$j0/s;;{?@yFG}OQY]fX[jKLh::\::\KLhX[jY]fWZi[_h^cf]ccV[aMPcEEgA@lAB{;;w44t..t+*z#"~ztm{y$ -)DGjWZcsrnqlp`\[ghc\\x.*t{}}~~~}}}}}}}}} "~& z(#w67g?@nJLsPQpQTgWZ_af`jpbik]lnampihlo_bqUYtOQxLM{@@t@@t@@t@@t@@t@@t@@t@@t51}/+x$ tqt} $!z$"k//eIIoacznpfjihmiinhhmgfkgeijgjoils`cladmfglijdfiXdeWhdcnhvegdcf_cgYgkZlp_osempgjlgdgncgjdicgmaiocioefkebfecfoY\eUWc]`ifipgknhmijoigmaingdhg]ad]addhginggmaioehnbgn^gn^gm_fkedhkbenhlmcgh_bg]alZ\sORu@@r43l($y)%z%!xuvyx pv !s,,t.-q+(o)#mJGt_\mnimibifbagj_QYf05lpqswz~~~{{{{{{{{|||||||||xuty~}}}}}}}}u"{($x'%n+*l44t32t*)mplm)&s=:}PMYW~\Yxbfighljkojkmiigghbgg[ghXaaYddZgg]jkclmhmmomltljufibfibfibfibfibfibfibfibhf|^^xNNr<=m,,h hjja67pOQz[]v_anefkfejcbgcanb`ka`ha`fa`fcbjfdqgesmnhjjhddfaa_ef^kmbjjhedjjgnhfkecfcb`cc[ddXdeUefTigrhfqfdodbmdbmecnfemgfnik^hj_hj_hiahj_gi\dgVcfS_]hcaligrlkslksigrcal_]hedldckcbjcaldbmfdohfqhfqii_hh\gi[jl^jmdgih^^hUWfUVtVWvPPrFEmCApECu?dEF~<:~ "yuvy||zxw||}||}}}zxx}~}}|{}}|yvvw{ ""xz|}zuqnttng!&f*-r*+~%#35r45u12u**t oklowwx{|}!}tn.-s==sORq_bkgifjkfkinjgra_`cadhfiefaabZfhefes[Xw!suz|}~|}wvspl$#o32v>>~]^r`ascercfoaehaeddicglefekfekfekfekfekfekfekfekfekfekfekfekfekfekfekfekccceeeggghhhhhhgggeeecccihnedja`fa`ffekihnihngflffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffhideeggflffhab]efaihmcaoddlacbfl`dm\W`[PVn=?|s~{zy}~~}~wvtstuwx{y|wyyv!w)'z&$xw~}zxxxz }~~|&'zCF{X^xZakQX^]eh]dlZ`nTYoKNoEGpBCsBBtADq@Bs=>v88v31z-*{)%|&!{{w%"y55ABDG~BEx>>p68a>?]TUgbbja`f`_egdmcafebiiglfgbbdWgjajkobaszxz|~}y{}{{{}~~|{|~..n22p78p=>nCEkLMiUXi\`kfnVhpXhpYfm[biY`fXag[bh^ggiggiggiggiggiggiggiggiggiggiggiggiggiggiggiggieeeeeefffggggggfffeeeeeehidijejkfhidfgbefaghcijeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffddfcbhjinmniehWcfQfhZfgaolsljogh`ejSgpU`ek>9y |ruw{{zxx}}}~~zy z+(o*&r*&s0-r>>tJKyJK{CCw=:?@=<83/|+&x%u*%(#&!}'"|,(|64@?GG+. ;5YY}gm_hpGcjZek]flbejfdhicfmegsfhufkeejfdhk`cl\^mWWoRRnONm?=o?=lBBhKLjWZm`dmchkcig`bwSThQRda`njjtfekccegggnlmfdgechggghidgihZYgC@[|yypoqrwxwu}|}~|z|zzxxyyx s%$r'%n(%lNOmUWp`avgivklqjlihkbgk]adYcf]dg`dfccdfcdieemggqeeceeceeceeceeceeceeceeceeceeceeceeceeceeceeceecfffffffffeeeeeefffffffffcd_fgbhidfgbcd_ab]cd_efaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggibafgfklmhfhZcfUgh`ggicgjZYxID|A>wFDu>>t+'{}}}|zwutw{{zr +(w+)t/.t87y>>zABxEGxJL|VWuWWyVVzXYu^bndimdio`do^d`agcelegmieki`ehY]fUYdY\oWZmTWjTWfVZc[`cagceld[h^LRj63v*!z2)|HAw]Yrgdkcccdddeecffdfgbfgaghbhicfh]hj_ik`kmbkldjkcijbhiaijljlkjliikfgjaeh]fj\fj[molhjideifgkjiniiifgaceZmmeba_a_dfekhgmcbpOLk4.\||{{{|~yxt|~uj+/nIK{Y\WYrMNcghjgihgiffhcfgbfgahgbihcffrggsggsffpeeoeeoeeoeeoggeggeggeggeggeggeggeggeggeggeggeggeggeggeggeggegggfffeeeeeeeeeeeefffgggeegeegffhggiggiggiffheegffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffopkccc``bccacd_ggglizid>I].3jw}pn}}}||||||||x{|! !%!0/h54m;;q>>r>>p==o=>n>?oZ\kY[j[]iadkeileihhmglqkikhklpjjrghjfi^hl[gk]dg^gkZglXfkWfkUfkWfj[fi^fi`fkdglfhmginghnbfm]dlUckSjt\iqfcgjZZdWV^\[ad`ngbviguiguhfqhgmhhhghcgh`gi^eaoebmgdmhelhfigefgfdfeade`ghcjjhiiiggifejihnlkqacXfg_fgabc^bc^fgbef``aYgg[ba]fdiihpedlcbr]ZyQKy=Adv:?v:?w6:w03v)+v%&v^]e^]e^]e^]e^]e^]e^]e^]e?>w?>w?>w?>w?>w?>w?>w?>w^]b^]b``baaaccceecfgbghcggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffghcghcffddddbbbaac_^c_^c`_g`_g`_g`_g`_g`_g`_g`_gffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffiiiiiigggfffdddbbbaaa```fekfekfekfekfekfekfekfekcjbcjbcjbcjbcjbcjbcjbcjbdchddfeegeeefffggeggehidggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffghcffdffdeeedddddfccecbggflgflgflgflgflgflgflgflffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggfffeeeeeedddccccccggiggiggiggiggiggiggiggifj\fj\fj\fj\fj\fj\fj\fj\hhjhhjhhjhhhgggggeggeggeggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffdffdggggggggiggiggiggiggiggiggiggiggiggiggiffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdddeeeeeeeeeeeefffffffffeeceeceeceeceeceeceeceecd`nd`nd`nd`nd`nd`nd`nd`nggggggggggggffffffeeeeeeggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffgggggghhhhhhhhhddbddbddbddbddbddbddbddbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdddeeeeeeeeeffffffggggggggeggeggeggeggeggeggeggeihfihfihfihfihfihfihfihfeeeeeeeeeeeeeeefffffffffggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggffffffffffffffffffffdffdffdffdffdffdffdffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe`fe`fe`fe`fe`fe`fe`fe`eeceecffdfffgggggiggihhjggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggiggiffhfffeeeeeceecddbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffgggggggggfffffffffeeeeeeddfddfddfddfddfddfddfddffglfglfglfglfglfglfglfglfgbffdffdggggggggiggigfkggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffejffhffhffffffffdeecefaddfddfddfddfddfddfddfddfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggffffffffffffggiggiggiggiggiggiggiggidg`dg`dg`dg`dg`dg`dg`dg`fgbfgbffdfffeeeeegediediggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffejfejffhfffgggggeghcghcffhffhffhffhffhffhffhffhffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff A``A!4A`A1r A`A!4A`qA1r A`qA!4Aa/1A1r Aa/1A!4AasA1r AasA!4AaA1rAaA">AaqA1ZAaqA">AbB1A1ZAbB1A">AbA1ZAbA">Ab˱A1ZAb˱A">AcqA1ZAcqA">AcU1A1ZAcU1A">AcA1ZAcA">AcޱA1ZAcޱA">Ad#qA1ZAd#qA">Adh1A1ZAdh1A">AdA1ZAdA">AdA1ZAdA">Ae6qA1ZAe6qA">Ae{1A1ZAe{1A!4AeA1rAeA!4AfA1rAfA!4AfIqA1rAfIqA!4Af1A1r Af1A!+AfA1-!AfA!+AgA1-"AgA!+Ag\qA1-#Ag\qA 4Ag1A0$Ag1A 4AgA0%AgA 4Ah*A0&Ah*A AhoqA0Z'AhoqA Ah1A0Z(Ah1AhAhA0_)AhAhAi=A0_*Ai=A hAiqA0+AiqA hAi1A0,Ai1AhAj A/4-Aj AhAjPA/".AjPAhAjqA/"/AjqAhAj1A.40Aj1AhAkA.41AkAhAkcA.2AkcAhAkqA-43AkqAhAk1A-44Ak1AhAl1A,5Al1AhAlvA,s46AlvAshAlqA+7AlqAshAm1A+8Am1A`hAmDA+`49AmDAMhAmA*ִ:AmA:hAmqA*M4;AmqA'hAn1A)ô<An1A'hAnWA)ô=AnWAhAnA):4>AnAAnqA(?AnqA Ao&1A('4@Ao&1A AojA'AAojAAoA'4BAoAjAoqA&CAoqADApA&4DApAAp>A%wEAp>@ApaXA$4FApaX@ApA$dGAp@YApA#4HAp@ ApxA#QIApx@@ApA"4JAp@@Aq 8A">KAq 8@ЦAq/A!4LAq/0AqQA!+MAqQѹAqtXA 4NAqtXtAqA OAq AqAhPAqR`AqxA hQAqx`AqAhRAq`Ar 8AhSAr 86`ArBAhTArBA0ArdAhUArdg0ArXAhVArX0ArAhWAr 0ArAshXAr 0ArxA`hYArx%0AsAMhZAs%As38A:h[As388AsUA'h\AsUKAswAh]Asw^AsXA^AsXqAsA _AsAsA `AsAtxAaAtxAt#ADbAt#ИAtF8AcAtF8Ath@dAthAt@eAt AtX@YfAtXAtϸ@ gAtϸ/At@@hAt !LAux@@iAux Au6@ЦjAu6!4LAuY80kAuY8!Au{ѹlAu{"GLAutmAu"AuX nAuX#ZLAuR`oAu#Av`pAv$mLAv'x`qAv'x$AvI6`rAvI%LAvl8A0sAvl8& Avg0tAv&LAv0uAv'AvX0vAvX'LAv 0wAv(/Aw 0xAw(LAw:x%0yAw:x(LAw\%0zAw\)BAw8%{Aw8)LAw8|Aw*UAwK}Aw*LAwX^~AwX+hAxqAx+hAx+qAx++LAxMxAxMx,{AxoAxo-LAx8Ax8-LAxAx-AxAx.LAxXИAxX.LAyИAy.Ay>Ay>.Ay`xAy`x/+LAyAy/Ay8 Ay8/Ayǘ Ayǘ0&AyAy0&Az XAz X0cAz./Az.0cAzQ/AzQ0cAzsx/Azsx0Az !LAz0Az8 !LAz80fAzژ Azژ0fAz Az0fA{X A{X12&A{A!4LA{A12&A{d!4LA{d12&A{x!4LA{x12&A{!4L 8PAL_COLORMODELRGB @ PAL_TYPE DIRECTINDEX H PAL_MINMAXNUMERIC @INTERLACE_MODEINTERLACE_PIXEL H IMAGE_MINMAXRANGE 8IMAGE_SUBCLASSIMAGE_TRUECOLOR @INTERLACE_MODEINTERLACE_PLANE H IMAGE_MINMAXRANGE 8IMAGE_VERSION1.2 H IMAGE_MINMAXRANGE @IMAGE_SUBCLASSIMAGE_TRUECOLOR @INTERLACE_MODEINTERLACE_PIXELViTables-3.0.0/examples/misc/links_examples.h5000066400000000000000000000140601311223072700212470ustar00rootroot00000000000000HDF  0` TREEHEAPX arraystableslinks8 (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1TREE HEAPXpa1HSNODh 0P (TITLE (CLASSGROUP (VERSION1.0  *@(dU X2R (CLASSCARRAY (VERSION1.1SNODU 0TITLEA linked array(TREEHEAPX t1H (TITLE (CLASSGROUP (VERSION1.0x field1 ?@4 4field2 U 2R(SNOD (CLASSTABLE (VERSION2.7 0TITLEA linked table 0 NROWS@ 0 FIELD_0_NAMEfield1 0 FIELD_1_NAMEfield2 @ FIELD_0_FILL ?@4 4 8 FIELD_1_FILL  TREEX(HEAPXXht1@a1st1/tables/t1 (TITLE (CLASSGROUP (VERSION1.0SNOD(0 ht1st1 /tables/t1 @ea1external_file.h5/a1ViTables-3.0.0/examples/misc/nonalphanum.h5000066400000000000000000000125401311223072700205520ustar00rootroot00000000000000HDF  `HEAP0array_1array_sarray_farray_f_NumericTREEZdklZdklZlZl Z dk Tdk Tdk Tdk TdklZlZlZdklZdklZdklZlZd klZd klZlZlZd kl Z d k!l"Z"d k#l$Z$dk%l&Z&dk'l(Z(ddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^gOZ)d_SZ   \C (CLASSARRAY 0FLAVOR NumArray8pSNOD ( `\C (CLASSARRAY 0FLAVOR NumArray (VERSION2.3 (VERSION2.3 8TITLESigned short array?@@@@@@ @"@$@&@(@*@,@.@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@@@A@A@B@B@C@C@D@D@E@E@F@F@G@G@H@H@I@I@J@J@K@K@L@L@M@M@N@N@O@O@P@@P@P@P@Q@@Q@Q@Q@R@@R@R@R@S@@S@S@S@T@@T@T@T@U@@U@U@U@V@@V@V@V@W@@W@W@W@X@@X@X@X@Y@@Y@Y@Y@Z@@Z@Z@Z@[@@[@[@[@\@@\@\@\@]@@]@]@]@?@@@@@@ @"@$@&@(@*@,@.@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@@@A@A@B@B@C@C@D@D@E@E@F@F@G@G@H@H@I@I@J@J@K@K@L@L@M@M@N@N@O@O@P@@P@P@P@Q@@Q@Q@Q@R@@R@R@R@S@@S@S@S@T@@T@T@T@U@@U@U@U@V@@V@V@V@W@@W@W@W@X@@X@X@X@Y@@Y@Y@Y@Z@@Z@Z@Z@[@@[@[@[@\@@\@\@\@]@@]@]@]@ @  \C (CLASSARRAY 0FLAVOR NumArray    \C (CLASSARRAY (FLAVORNumeric` (TITLE (CLASSGROUP (VERSION1.0 FILTERSccopy_reg _reconstructor p1 (ctables.Leaf Filters p2 c__builtin__ object p3 NtRp4 (dp5 S'shuffle' p6 I0 sS'complevel' p7 I0 sS'fletcher32' p8 I0 sS'complib' p9 S'zlib' p10 sb. 8PYTABLES_FORMAT_VERSION1.5 @TITLEScalar signed short array ?@4 4 (VERSION2.3 0TITLE3-D float array ?@4 4 (VERSION2.3 @TITLE3-D float array, NumericViTables-3.0.0/examples/misc/objecttree.h5000066400000000000000000004304301311223072700203620ustar00rootroot00000000000000HDF  1` TREEHEAPX group1group2array18 (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1TREEHEAPXptable1array2@SNOD 0P (TITLE (CLASSGROUP (VERSION1.0x TREEHEAPX table2H (TITLE (CLASSGROUP (VERSION1.0 0H0 1R (CLASSARRAY (VERSION2.4 0TITLE Data arraystringarray (FLAVORpythonh( ?  ?identityidnumberspeed  8P $ 1RSNODx (CLASSTABLE (VERSION2.7 (TITLE 0 FIELD_0_NAMEidentity 0 FIELD_1_NAMEidnumber 0 FIELD_2_NAMEspeed 0 FIELD_0_FILL 8 FIELD_1_FILL @ FIELD_2_FILL  ? 0 NROWS@ h( ?  ?identityidnumberspeed  HP($ 1RSNOD (CLASSTABLE (VERSION2.7 (TITLE 0 FIELD_0_NAMEidentity 0 FIELD_1_NAMEidnumber 0 FIELD_2_NAMEspeed 0 FIELD_0_FILL 8 FIELD_1_FILL @ FIELD_2_FILL  ? 0 NROWS@  0 < 1R (CLASSARRAY (VERSION2.4 (TITLE (FLAVORpythonTREE)$ This is particle: 0This is particle: 1@This is particle: 2@This is particle: 3@This is particle: 4AThis is particle: 5 AThis is particle: 6@AThis is particle: 7`AThis is particle: 8AThis is particle: 9 A ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?TREE(1$ This is particle: 0This is particle: 1@This is particle: 2@This is particle: 3@This is particle: 4AThis is particle: 5 AThis is particle: 6@AThis is particle: 7`AThis is particle: 8AThis is particle: 9 A ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?ViTables-3.0.0/examples/misc/szip_compressor.h5000066400000000000000000013705431311223072700215060ustar00rootroot00000000000000HDF  cHEAPdatasetF32TREE `  X (szip  (dC@SNODTREE ''@ H U_!$B! UWBI!B!BI!B!Cx@j&>!B!U@jB!B5U!B!!oB?B!B0 U_5U!B!BU!B!|!oU!|@!B!`*"!B!B"B!B>D!DB7!B!!B!B?Ȅ!BB!BȄ!F>B!B!!B#!UU@UUT"""" UUPUU@H*zDDDDDDDPHH􈈈PXH TDDDDDDDDD@DDE􈈈?DDDDDDDDDDDCDD_DDDDD""""""""""""""!/"""""""">""""?"""!."""""""#UUUU$I8$IpUU I$H ĒI$pI'UUI$`I$I$*UUI$I$`U$I$N $O I$I$I$WI$I$0*I$I$II$$I$ $I$OI'I$I$I$?$I$I$G$O$I$I#I$I?I$$I$I$II$I$I#?$I$I$$II$HI$I'I$rI$I$I$$I$I$HO?$I$I$rI$I?I$9$I$I$I#I$I$I$r$I$I$9$I?I$II$I'I$I$I$I$I$I$I O?I$I$I?HI$I$II$I$I$I$$I$G$I$II#I$I$I&?9$I$I$G$$I$I#I$O$I$$I$I?II$I$I#I$I$I$$$I$HI$II$2I$I$I'?3c# '@ I$UUV $I# ?UU_I$$I$ HI$I8U_*I$I$I $I$pI$IUI$I$I$ UI$I$HOI$I$NI$$I$`I$I$II'I$I$I$r$I$I$9$I?I$II$I'I$I$I$I$I$I$IO$I$I$I$I??I$G$I$I$I$rI$I$I$$I$I$G$II$I#I$I'?I$$I$I$I$I$I#O$I$I$$I?I$HI$I$?I$rI$I$I$$I$I$HdI$I$II$OI$IdI$I$x<9$I$I$C$$I$I$I$OI$I,I$I$$9$I$I$H2I$I$I$I$I$I$Y$I$I$HI$I$C$I$I$I$I$I$K$I?$I$9$I$OI$$I$I$I$I$I$I'I$I$HI$$I$I$I$I?@ II$I$I$I$I$$OpI$II$I%h$P7DTDE?$I$ZI$K?h$DD@3II$I$IP?DDDDL ĈI$II$II$?DX$DDDDDEȗ?h$DDDDDD@3$I$RI')$S$RI')$I$V?ɑ?j?UUUUUTSUUUTUUOUTUUUUIB#;xGc? '@ -?$I$I$9$$I$II$II$I$I$I'HI$I$I$I$I$I$O$I$G$I$I?I!I$I$I$I$I$I,I$I$II$O?I$I I$I$|rI?j?UUUUUTSUUUTUUOUTUUUU?ꚪUUUUU5SUUUU5UUOUU5UUUU?ꦪ5UUUUUMSUUUUMUUOUUMUUUU?j_jjj}MUUUUUSSUUUUSUUOUUSUUUU?USUUUUUTjI?@#/gミc?~8??x?~>`ƃc~'@ $I$I$K$OI$I$rI$I'I$C$I$I$y$I$I$I$I0I$I$NdI$$I$i$I$K<?j?UUUUUTSUUUTUUOUTUUUU?ꚪUUUUU5SUUUU5UUOUU5UUUU?ꦪ5UUUUUMSUUUUMUUOUUMUUUU?j_jjj}MUUUUUSSUUUUSUUOUUSUUUU?USUUUUUTjI?D/?{c>|q񏟏q??G~d'@ $DDDDDDDDDX$E?I$I$KrI$TUUUUU4UUUUU5US?UUU5UUUOU5UUUUU8檪?U5UUUUULUUUUUMUSUUUMUUUO?UMUUUUU<骪jjj?UMUUUUURUUUUUSUSUUUSUUUOUSUUUUU>?j?UUUUUTSUUUTUUOUTUUUU?ꚪUUUUU5SUUUU5UUOUU5UUUU?ꦪ5UUUUUMSUUUUMUUOUUMUUUU?j_jjj}MUUUUUSSUUUUSUUOUUSUUUU?USUUUUUTj=SUUUUUTUUUUTUOUUTUUU?UTUUUUT?TUUUUU3?UUUUU5UOUUU5UUU?UU5UUUUT? U5UUUUUKUUUUUMUO?UUUMUUU?UUMUUUUTjj?jjUUUUUSUOUUUSUUU??UUSUUUUTI' A'@!' @`|| !@B|@o !|@????? ??????( [jjꪪjMUUUUUSOUUUUSUU?UUUSUUUTUSUUUUUSjꪪuSUUUUUTUUUUTU?UUUTUUTUTUUUUS~ꪪ5TUUUUU/UUUUU5U?UUUU5UUTUU5UUUUS>ꪪ`?UUUUUMU?UUUUMUUTUUMUUUUSi?jꪪjjpUUUUUSU??UUUUSUUTUUSUUUUSj?ꪪxUUUUUT?UUUUTUT?UUTUUUSꪪ?|UUUUU5?UUUUU5UTUUU5UUUS?U5UUUUULꪪ~?5UUUUUM?UUUUUMUTUUUMUUUSUMUUUUUN?jꪪjjMUUUUUS?UUUUUSUTUUUSUUUSUSUUUUUOjUUUTuUU?ꪪ D5UUUUDKUUUTDuU?UUDEUUSDCUUUTD>|MUUUDDGSJmUUUm&UUVm0""".mUU@mUU`#!'@ ?@|<<@B|7 ?>p ??????8@???????? ???????????????????????@ eUUUUUSUOUUUSUUU??UUSUUUUTj?ꪚUUUUUTOUUUTUU?UUTUUUT?ꪦ?UUUUU5OUUUU5UU?UUU5UUUTꪩ5UUUUUMOUUUUMUU?UUUMUUUTUMUUUUUSjjꪪjMUUUUUSOUUUUSUU?UUUSUUUTUSUUUUUSjꪪuSUUUUUTUUUUTU?UUUTUUTUTUUUUS~ꪪ5TUUUUU/UUUUU5U?UUUU5UUTUU5UUUUS:.UUUQ UU?ꪪUUUDD5TUTDDUUIm@uUUQ ??"""jlUUm @UU[m@8ƪmU[hI3332VmD 32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333"?@ '@p ? @B> ?> ?>> !>8@?????? ????????????????????????????????????????????????????????????????????????@@???TUUUUU4UUUUU5US?UUU5UUUOU5UUUUU8檪?U5UUUUULUUUUUMUSUUUMUUUO?UMUUUUU<骪jjj?UMUUUUURUUUUUSUSUUUSUUUOUSUUUUU>?j?UUUUUTSꪪ?UUUUUUT!"iꪪ#".6UUUU j"":UDDEUU&lm?qUUQUUh mm@&@mꨈfffffLəI3333M[mh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '@@ x  ?> !@|<@????? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<UUUUUMU?UUUUMUUTUUMUUUUSi?jꪪjjp~uUUUUT]TU5UUUU?? ꪪꪪj[lUUU[m@xUUDDD5O?[mUU@ uUQ UUm $32ffdI$̫ mT@ I3332ffffL@m`ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@ 33333ffd̀V m ffffff ə3332ff`ʠm`33332ffdmm @&fffffdə333&ff@Lʰmm33333ffL̀30ffffffPm 333&ff`̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? zU[m L$332ffffi[mhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd&fffd333333(mm@33332&ffd̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????? ???@@@@@@? D 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@L0mm33333ffd̀mmm ffffff ə3332ff`@m 33332ffd3 &fffffhmh 333&ff@L`m@33333ffL̀30ffffffmmm333&ff`6 mm 333332ffL33 &fffffml@332fff@L6 m 333333fd̀330fffffim` 332fff`ə333334mm[p33 L`m@ &fffff33323332ff333333Hm` ffffd330ffffd̀&fffff`33333233&fff`3333&fdɀfL333 30̀ AA/"Njy>'|????????????????????????????????????????????????????????????????????????????????????????????????@@???? ? ?????????@@@@@@?@@@@@@@ ? ???? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@32ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@33333ffd̀ffffe[6mP3333303333 fffd ̪m333323330 ̙3&fffffffL̀33333&`̀d33&fff@ffffgAAAA=x(AA8Ax0}8 x8AA8Ax@|@  @ $<H ?<(> IA ~e?   C\COq ?@ @@@@'<y`y8<<<<yO<y9y3y'x<'o#?<?|>>p#A'x??????????????????????????????????????????????????????????????<@@@@@ ??????? ? ? ????@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x < 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@`m@ d333&ffd&ffff` m @$̙fffd2fLəə333332fffffd 3333fffL̀fffffL333332&fffff339ACAA 2 R ACAA 2 0r  ! @AB?|@ @ p!@@@A @@Y@@A @@A@A?>8@^.  @@{xpxp ,| 7ys<o<yyyy`<O?8}Lc#'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp<?j?UUUUUTSUUUTUUOUTUUUU?ꚪUUUUU5SUUUU5UUOUU5UUUU?ꦪ5UUUUUMSUUUUMUUOUUMUUUU?j_jjj}MUUUUUSSUUUUSUUOUUSUUUU?USUUUUUTjI?D/?{c>|q񏟏q??G~d'@ $DDDDDDDDDX$E?I$I$KrI$TUUUUU4UUUUU5US?UUU5UUUOU5UUUUU8檪?U5UUUUULUUUUUMUSUUUMUUUO?UMUUUUU<骪jjj?UMUUUUURUUUUUSUSUUUSUUUOUSUUUUU>?j?UUUUUTSUUUTUUOUTUUUU?ꚪUUUUU5SUUUU5UUOUU5UUUU?ꦪ5UUUUUMSUUUUMUUOUUMUUUU?j_jjj}MUUUUUSSUUUUSUUOUUSUUUU?USUUUUUTj=SUUUUUTUUUUTUOUUTUUU?UTUUUUT?TUUUUU3?UUUUU5UOUUU5UUU?UU5UUUUT? U5UUUUUKUUUUUMUO?UUUMUUU?UUMUUUUTjj?jjUUUUUSUOUUUSUUU??UUSUUUUTI' A'@!' @`|| !@B|@o !|@????? ??????( [jjꪪjMUUUUUSOUUUUSUU?UUUSUUUTUSUUUUUSjꪪuSUUUUUTUUUUTU?UUUTUUTUTUUUUS~ꪪ5TUUUUU/UUUUU5U?UUUU5UUTUU5UUUUS>ꪪ`?UUUUUMU?UUUUMUUTUUMUUUUSi?jꪪjjpUUUUUSU??UUUUSUUTUUSUUUUSj?ꪪxUUUUUT?UUUUTUT?UUTUUUSꪪ?|UUUUU5?UUUUU5UTUUU5UUUS?U5UUUUULꪪ~?5UUUUUM?UUUUUMUTUUUMUUUSUMUUUUUN?jꪪjjMUUUUUS?UUUUUSUTUUUSUUUSUSUUUUUOjUUUTuUU?ꪪ D5UUUUDKUUUTDuU?UUDEUUSDCUUUTD>|MUUUDDGSJmUUUm&UUVm0""".mUU@mUU`#!'@ ?@|<<@B|7 ?>p ??????8@???????? ???????????????????????@ eUUUUUSUOUUUSUUU??UUSUUUUTj?ꪚUUUUUTOUUUTUU?UUTUUUT?ꪦ?UUUUU5OUUUU5UU?UUU5UUUTꪩ5UUUUUMOUUUUMUU?UUUMUUUTUMUUUUUSjjꪪjMUUUUUSOUUUUSUU?UUUSUUUTUSUUUUUSjꪪuSUUUUUTUUUUTU?UUUTUUTUTUUUUS~ꪪ5TUUUUU/UUUUU5U?UUUU5UUTUU5UUUUS:.UUUQ UU?ꪪUUUDD5TUTDDUUIm@uUUQ ??"""jlUUm @UU[m@8ƪmU[hI3332VmD 32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333"?@ '@p ? @B> ?> ?>> !>8@?????? ????????????????????????????????????????????????????????????????????????@@???TUUUUU4UUUUU5US?UUU5UUUOU5UUUUU8檪?U5UUUUULUUUUUMUSUUUMUUUO?UMUUUUU<骪jjj?UMUUUUURUUUUUSUSUUUSUUUOUSUUUUU>?j?UUUUUTSꪪ?UUUUUUT!"iꪪ#".6UUUU j"":UDDEUU&lm?qUUQUUh mm@&@mꨈfffffLəI3333M[mh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '@@ x  ?> !@|<@????? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<UUUUUMU?UUUUMUUTUUMUUUUSi?jꪪjjp~uUUUUT]TU5UUUU?? ꪪꪪj[lUUU[m@xUUDDD5O?[mUU@ uUQ UUm $32ffdI$̫ mT@ I3332ffffL@m`ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@ 33333ffd̀V m ffffff ə3332ff`ʠm`33332ffdmm @&fffffdə333&ff@Lʰmm33333ffL̀30ffffffPm 333&ff`̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? zU[m L$332ffffi[mhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd&fffd333333(mm@33332&ffd̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????? ???@@@@@@? D 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@L0mm33333ffd̀mmm ffffff ə3332ff`@m 33332ffd3 &fffffhmh 333&ff@L`m@33333ffL̀30ffffffmmm333&ff`6 mm 333332ffL33 &fffffml@332fff@L6 m 333333fd̀330fffffim` 332fff`ə333334mm[p33 L`m@ &fffff33323332ff333333Hm` ffffd330ffffd̀&fffff`33333233&fff`3333&fdɀfL333 30̀ AA/"Njy>'|????????????????????????????????????????????????????????????????????????????????????????????????@@???? ? ?????????@@@@@@?@@@@@@@ ? ???? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@32ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@33333ffd̀ffffe[6mP3333303333 fffd ̪m333323330 ̙3&fffffffL̀33333&`̀d33&fff@ffffgAAAA=x(AA8Ax0}8 x8AA8Ax@|@  @ $<H ?<(> IA ~e?   C\COq ?@ @@@@'<y`y8<<<<yO<y9y3y'x<'o#?<?|>>p#A'x??????????????????????????????????????????????????????????????<@@@@@ ??????? ? ? ????@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x < 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@`m@ d333&ffd&ffff` m @$̙fffd2fLəə333332fffffd 3333fffL̀fffffL333332&fffff339ACAA 2 R ACAA 2 0r  ! @AB?|@ @ p!@@@A @@Y@@A @@A@A?>8@^.  @@{xpxp ,| 7ys<o<yyyy`<O?8}Lc#'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp< ?> ?>> !>8@?????? ????????????????????????????????????????????????????????????????????????@@???TUUUUU4UUUUU5US?UUU5UUUOU5UUUUU8檪?U5UUUUULUUUUUMUSUUUMUUUO?UMUUUUU<骪jjj?UMUUUUURUUUUUSUSUUUSUUUOUSUUUUU>?j?UUUUUTSꪪ?UUUUUUT!"iꪪ#".6UUUU j"":UDDEUU&lm?qUUQUUh mm@&@mꨈfffffLəI3333M[mh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '@@ x  ?> !@|<@????? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<UUUUUMU?UUUUMUUTUUMUUUUSi?jꪪjjp~uUUUUT]TU5UUUU?? ꪪꪪj[lUUU[m@xUUDDD5O?[mUU@ uUQ UUm $32ffdI$̫ mT@ I3332ffffL@m`ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@ 33333ffd̀V m ffffff ə3332ff`ʠm`33332ffdmm @&fffffdə333&ff@Lʰmm33333ffL̀30ffffffPm 333&ff`̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? zU[m L$332ffffi[mhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff6m, 332fffd̙333334 mmh 333ffffi[ml32ffff ə333334 m d332ffffimm@I33&fffdə33333Mm6 L 333ffffL̀mmۀ@&ffff ̙33333 '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd 33fffffe mml332fff Ȃ'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 32ffff`ə33334ma333 &fffd[ml@ &ffff@Lə33333Mm`L̀3330ffffL mm[ &ffff`̙3333MmmL3333 &fffLhmfffff@L̙33332fdmm33330fffd lmhBfffff`ə3332ff -mm3333 &ffdmm&fffff@Lə3333&fd6m-33330fffL m&fffff`̙333&ff 4[ml؀A33333 &ffL32ffffff m n3332ffd6mmX@!333330ffd 33fffffim6 332fff hm33333 &fd32fffffimm 333&ffdlmh333330ffL 33fffff-ml@ 33&fff ̙333333@m@L332fffff"?@ '|????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????xx333333fL̀330fffffUm`33&fff`̙33333*mm[P 333 &ffffUmm32ffff@L̙333332m@̀3330ffffe[@m 32ffff`ə33332mh@ 333 &fffd-mmffff@Lə33333*mmB ̀3330ffffL 6m-ffff`̙3333*mA3333 &fffLT[ml@ fffff@L̙33332m`̀33330fffd VmmZ fffff`ə3332ff m63333 &ffdhmfffff@Lə3333&fdʀmm33330fffL lmhFfffff`̙333&ff ̪-mm 33333 &ffLVmmffffff@L̙3332ffd̫6m-333330ffd&fffd333333(mm@33332&ffd̈ a'x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????? ???@@@@@@? D 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@L0mm33333ffd̀mmm ffffff ə3332ff`@m 33332ffd3 &fffffhmh 333&ff@L`m@33333ffL̀30ffffffmmm333&ff`6 mm 333332ffL33 &fffffml@332fff@L6 m 333333fd̀330fffffim` 332fff`ə333334mm[p33 L`m@ &fffff33323332ff333333Hm` ffffd330ffffd̀&fffff`33333233&fff`3333&fdɀfL333 30̀ AA/"Njy>'|????????????????????????????????????????????????????????????????????????????????????????????????@@???? ? ?????????@@@@@@?@@@@@@@ ? ???? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@32ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@33333ffd̀ffffe[6mP3333303333 fffd ̪m333323330 ̙3&fffffffL̀33333&`̀d33&fff@ffffgAAAA=x(AA8Ax0}8 x8AA8Ax@|@  @ $<H ?<(> IA ~e?   C\COq ?@ @@@@'<y`y8<<<<yO<y9y3y'x<'o#?<?|>>p#A'x??????????????????????????????????????????????????????????????<@@@@@ ??????? ? ? ????@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x < 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@`m@ d333&ffd&ffff` m @$̙fffd2fLəə333332fffffd 3333fffL̀fffffL333332&fffff339ACAA 2 R ACAA 2 0r  ! @AB?|@ @ p!@@@A @@Y@@A @@A@A?>8@^.  @@{xpxp ,| 7ys<o<yyyy`<O?8}Lc#'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp<,) ,r ,r ,0r ,r ,,*r ,E6r ,^Br ,wjOr ,[r ,Nhr ,tr ,2r ,r , r ,&r ,?lE2Ka) dsr }r r r *r d7r Cr HPr ,\r E,ir ^ur wr r r fr سr J^  5 & ?OTREE9 8D!2 K%&td+}W15<; D N N[ h ,av E ^q wE0u) r r &"r ? tddzd2!<dK' dd,0 d}: dqG dT db d p d} dd,dEEd^Sdw) dr dr dEr dr d)r d r d& r d?) 5 v@ 26M KZ dIh }u Y hfr سr J^  5 & ?O'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp</"Njy>'|????????????????????????????????????????????????????????????????????????????????????????????????@@???? ? ?????????@@@@@@?@@@@@@@ ? ???? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@32ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@33333ffd̀ffffe[6mP3333303333 fffd ̪m333323330 ̙3&fffffffL̀33333&`̀d33&fff@ffffgAAAA=x(AA8Ax0}8 x8AA8Ax@|@  @ $<H ?<(> IA ~e?   C\COq ?@ @@@@'<y`y8<<<<yO<y9y3y'x<'o#?<?|>>p#A'x??????????????????????????????????????????????????????????????<@@@@@ ??????? ? ? ????@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x < 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@`m@ d333&ffd&ffff` m @$̙fffd2fLəə333332fffffd 3333fffL̀fffffL333332&fffff339ACAA 2 R ACAA 2 0r  ! @AB?|@ @ p!@@@A @@Y@@A @@A@A?>8@^.  @@{xpxp ,| 7ys<o<yyyy`<O?8}Lc#'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp</"Njy>'|????????????????????????????????????????????????????????????????????????????????????????????????@@???? ? ?????????@@@@@@?@@@@@@@ ? ???? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@32ffffd̙33332m4  3333fffd̀Pmmڀ@fffff ə33332mm3332fffd@m ffffdə3333*-m@L 3333fffL̀`m@fffff ̙3333&f`̠mmm@33332fffLV mmfffffd̙3332ff@L̨mm@33333ffd̀ffffe[6mP3333303333 fffd ̪m333323330 ̙3&fffffffL̀33333&`̀d33&fff@ffffgAAAA=x(AA8Ax0}8 x8AA8Ax@|@  @ $<H ?<(> IA ~e?   C\COq ?@ @@@@'<y`y8<<<<yO<y9y3y'x<'o#?<?|>>p#A'x??????????????????????????????????????????????????????????????<@@@@@ ??????? ? ? ????@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x < 3333fffL̀ m &fffff ̙3333&f` m`33332fffLmm0@"fffffd̙3332ff@`m@ d333&ffd&ffff` m @$̙fffd2fLəə333332fffffd 3333fffL̀fffffL333332&fffff339ACAA 2 R ACAA 2 0r  ! @AB?|@ @ p!@@@A @@Y@@A @@A@A?>8@^.  @@{xpxp ,| 7ys<o<yyyy`<O?8}Lc#'z@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@ ? ? ? ? ? ? ? ?@@@@@@@@@@@@@@@@@@@@@@@@yy yp<y<<?π<y`3Ϟ?g?x<`'|@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@@@@@@@@@@@@@@@@@@@@@@x ? ? ? ? ? ? ? ?<@@ @@@@@@@@@@@ @@@@@@x@A ? ? ??0? ? ?<@@ @@@@@ @@@@@@ @@@@  @@@@  t @@@~@?? ??:@ @@@@@@ @@@@@@ @@@@@@ @@@@     t@@@@????:@@ @@@@@@ @@@@@@ @@@@@@ @@@@     t@@@@????:@@ @@@@@@ @@@@@@ @@@@@@ @@@@     t l< s<yysy9y9?Gs'~qs~s|8??0|?3?~1?? @ '~@@@@@@@@@@@@@@@@@@@@@@@x? ? ? ? ? ? ? ? <@@@@@@@@@@@@@@@@@@@@@@@x? ? ? ? ? ? ? ? <@@@@@@@@@@@@@@@@@@@@@@@x @~? ? ? ? ? ? ? <@@@@ @@@@@@@@ `@@@@@@  _@x@@@?? ? ??: @@@@@@ @@@@@@ @ @@@@@    t@@@@????:@ @@@@@@ @@@@@@ @@@@@@ @@@@@    t@@@@????:@ @@@@@@ @@@@@@ @@@@@@ @@@@@    t@@@@????:@ @@@@@@ @@@@@@ @@@@@@ @@@@@    t@@@@????:@ @@@@@@ @@@@@@ @@@@@@ @@@@@    t@@@@????:@ @@@@@@ @@@@@@ @@@@@@ @@@@@    t y?<y???>'??p|?3>33'1??p|?> 'Ã>gp|gg?'33py??AViTables-3.0.0/examples/scripts/000077500000000000000000000000001311223072700165265ustar00rootroot00000000000000ViTables-3.0.0/examples/scripts/MDobjects.py000066400000000000000000000054641311223072700207630ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ This is meant to exercise ViTables capability to zoom into multidimensional cells. It also works to check views of multidimensional attributes. """ import tables import numpy class Particle(tables.IsDescription): """Description of a table record.""" name = tables.StringCol(16, pos=1) lati = tables.IntCol(pos=2) vector = tables.Int32Col(shape=(200,), pos=3) matrix1 = tables.Int32Col(shape=(2, 200), pos=4) matrix2 = tables.FloatCol(shape=(100, 2), pos=5) matrix3 = tables.FloatCol(shape=(10, 100, 2), pos=5) matrix4 = tables.FloatCol(shape=(2, 10, 100, 2), pos=5) # Open a file in "w"rite mode fileh = tables.open_file("MDobjects.h5", mode = "w") # Create the table with compression 'on' in order to reduce size as # much as possible table = fileh.create_table(fileh.root, 'table', Particle, "A table", filters=tables.Filters(complevel=1)) # Append several rows with default values for i in range(10): table.row.append() table.flush() # create new arrays atom1 = tables.IntAtom() shape1 = (2, 10, 10, 1) filters1 = tables.Filters(complevel=1) #(2, 10, 10, 3) array1 = fileh.create_carray(fileh.root, 'array1', atom1, shape1, filters=filters1) atom2 = tables.FloatAtom() shape2 = (2, 10, 10, 3, 1) filters2 = tables.Filters(complevel=1) #(2, 10, 10, 3, 200) array2 = fileh.create_carray(fileh.root, 'array2', atom2, shape2, filters=filters2) # Add multimensional attributes to the objects # Integers will go in /table table.attrs.MD1 = numpy.arange(5, dtype="int8") table.attrs.MD2 = numpy.arange(10, dtype="int64").reshape(2, 5) # Complex will go in /array1 array1.attrs.MD1 = numpy.arange(5, dtype="complex128") array1.attrs.MD2 = numpy.arange(10, dtype="complex128").reshape(2, 5) # Strings will go in /array2 array2.attrs.MD1 = numpy.array(['Hi', 'world!'], dtype='|S6') array2.attrs.MD2 = numpy.array([['Hi', 'world!'], ['Hola', 'mon!']], dtype='|S4') fileh.close() ViTables-3.0.0/examples/scripts/array_samples.py000066400000000000000000000052351311223072700217470ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a set of scripts by Francesc Alted. """Several simple Arrays.""" import numpy import tables # Open a new empty HDF5 file fileh = tables.open_file("array_samples.h5", mode = "w") # Get the root group root = fileh.root # Create an Array a = numpy.array([-1, 2, 4], numpy.int16) # Save it on the HDF5 file hdfarray = fileh.create_array(root, 'array_int16', a, "Signed short array") # Create a scalar Array a = numpy.array(4, numpy.int16) # Save it on the HDF5 file hdfarray = fileh.create_array(root, 'scalar_array', a, "Scalar signed short array") # Create a 3-d array of floats a = numpy.arange(120, dtype=numpy.float64).reshape(20, 3, 2) # Save it on the HDF5 file hdfarray = fileh.create_array(root, 'array_f3D', a, "3-D float array") # Create an array of floats a = numpy.array([1, 2.7182818284590451, 3.141592], numpy.float) # Save it on the HDF5 file hdfarray = fileh.create_array(root, 'array_f', a, "Float array") # Create a large array #a = reshape(array(range(2**16), "s"), (2,) * 16) a = numpy.ones((2,) * 8, numpy.int8) # Save it on the HDF5 file hdfarray = fileh.create_array(root, 'array_int8', a, "Large array") # Create a set of arrays and save them on the HDF5 file basedim = 4 group = root dtypes = [numpy.int8, numpy.uint8, numpy.int16, numpy.int, numpy.float32, numpy.float] i = 1 for dtype in dtypes: # Create an array of dtype, with incrementally bigger ranges a = numpy.ones((basedim,) * i, dtype) # Save it on the HDF5 file dsetname = 'array_' + a.dtype.char hdfarray = fileh.create_array(group, dsetname, a, "Large array") # Create a new group group = fileh.create_group(root, 'group' + str(i)) # increment the range for next iteration i += 1 # Close the file fileh.close() ViTables-3.0.0/examples/scripts/array_timeseries.py000066400000000000000000000040251311223072700224500ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """CArray with time fields. """ import os import time import tables output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass # Open a new empty HDF5 file hdf5_name = "carray_ts.h5" filepath_hdf5 = os.path.join(output_dir, hdf5_name) h5file = tables.open_file(filepath_hdf5, mode="w", title='Example CArray with time fields') # Create a CArray and fill it root = h5file.root shape = (300, 2) atom = tables.Time32Atom() filters = tables.Filters(complevel=5, complib='zlib') hdfarray = h5file.create_carray(root, 'test_carray_1', atom, shape, "Signed short array") now = time.time() seconds_by_day = 1*24*60*60 for index in range(0, 600, 2): seconds = now - seconds_by_day * index hdfarray[index/2, 0] = seconds hdfarray[299-index/2, 1] = seconds # Create other CArray and fill it shape = (300,) atom = tables.Time32Atom(shape=(2,)) filters = tables.Filters(complevel=5, complib='zlib') hdfarray = h5file.create_carray(root, 'test_carray_2', atom, shape, "Signed short array") now = time.time() seconds_by_day = 1*24*60*60 for index in range(0, 600, 2): seconds = now - seconds_by_day * index hdfarray[index/2] = [seconds, seconds] h5file.close() ViTables-3.0.0/examples/scripts/carray_samples.py000066400000000000000000000024701311223072700221100ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a script by Francesc Alted. """A simple CArray.""" import numpy import tables fileName = 'carray_sample.h5' shape = (200, 300) atom = tables.UInt8Atom() filters = tables.Filters(complevel=5, complib='zlib') h5f = tables.open_file(fileName, 'w') ca = h5f.create_carray(h5f.root, 'carray', atom, shape, filters=filters) ca[10:60, 20:70] = numpy.ones((50, 50)) h5f.close() ViTables-3.0.0/examples/scripts/create-large-table.py000066400000000000000000000050411311223072700225200ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """This program creates a potentially big table for tests purposes. The program is based on the tutorial programs included in the PyTables User's Guide. Modified to use buffers so that filling times are bettered by one order of magnitude. F. Altet 2006-02-27 """ import time from numpy import arange import tables t0 = time.time() # Describe a particle record class Particle(tables.IsDescription): """Description of a table record.""" lati = tables.IntCol(pos=0) longi = tables.IntCol(pos=1) temperature = tables.FloatCol(pos=2) pressure = tables.FloatCol(pos=3) # Open a file in "w"rite mode fileh = tables.open_file("large_table.h5", mode = "w") # Get the HDF5 root group root = fileh.root # Create a group group = fileh.create_group(root, "Particles") # Now, create and fill the tables in Particles group filters = tables.Filters(complevel=1, complib='lzo', shuffle=1) nrows = 10**7 table = fileh.create_table("/Particles", "TParticle", Particle, "Sample set of particles ", filters, expectedrows = nrows) # Number of rows in buffer nrowsbuf = 10000 # Fill the table with 10**N particles for i in range(0, nrows, nrowsbuf): if i + nrowsbuf > nrows: nrapp = nrows - i else: nrapp = nrowsbuf # First, assign the values to the Particle record lati = arange(i, i + nrapp) longi = 10 - lati temperature = lati + 0.5 pressure = 10.5 - lati # This injects the Record values table.append([lati, longi, temperature, pressure]) # Flush the table buffers and close the file fileh.close() tsec = round((time.time() - t0), 3) print('Last of the run: {0} s'.format(tsec)) ViTables-3.0.0/examples/scripts/earray_samples.py000066400000000000000000000047601311223072700221160ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a set of scripts by Francesc Alted. """Several simple EArrays.""" import tables import numpy fileh = tables.open_file('earray_samples.h5', mode='w') root = fileh.root a = tables.StringAtom(itemsize=8) # Use ``a`` as the object type for the enlargeable array. array_c = fileh.create_earray(root, 'array_c', a, (0,), "Chars") array_c.append(numpy.array(['a'*2, 'b'*4], dtype='S8')) array_c.append(numpy.array(['a'*6, 'b'*8, 'c'*10], dtype='S8')) # Create an string atom a = tables.StringAtom(itemsize=1) # Use it as a type for the enlargeable array hdfarray = fileh.create_earray(root, 'array_char', a, (0,), "Character array") hdfarray.append(numpy.array(['a', 'b', 'c'])) # The next is legal: hdfarray.append(numpy.array(['c', 'b', 'c', 'd'])) # but these are not: #hdfarray.append(array([['c', 'b'], ['c', 'd']])) #hdfarray.append(array([[1,2,3],[3,2,1]], dtype=uint8).reshape(2,1,3)) # Create an atom a = tables.UInt16Atom() hdfarray = fileh.create_earray(root, 'array_e', a, (2, 0, 3), "Unsigned short array") # Create an enlargeable array a = tables.UInt8Atom() hdfarray = fileh.create_earray(root, 'array_b', a, (2, 0, 3), "Unsigned byte array", tables.Filters(complevel = 1)) # Append an array to this table hdfarray.append(numpy.array([[1, 2, 3], [3, 2, 1]], dtype=numpy.uint8).reshape(2, 1, 3)) hdfarray.append(numpy.array([[1, 2, 3], [3, 2, 1], [2, 4, 6], [6, 4, 2]], dtype=numpy.uint8).reshape(2,2,3)*2) # The next should give a type error: #hdfarray.append(array([[1,0,1],[0,0,1]], dtype=Bool).reshape(2,1,3)) # Close the file. fileh.close() ViTables-3.0.0/examples/scripts/filenode_sample.py000066400000000000000000000034731311223072700222350ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a script by Ivan Vilata. """How to use the filenode module.""" from tables.nodes import filenode import tables h5file = tables.open_file('fnode.h5', 'w') fnode = filenode.new_node(h5file, where='/', name='fnode_test') print >> fnode, "This is a test text line." print >> fnode, "And this is another one." print >> fnode fnode.write("Of course, file methods can also be used.") fnode.close() node = h5file.root.fnode_test fnode = filenode.open_node(node, 'a+') print >> fnode, "This is a new line." fnode.attrs.content_type = 'text/plain; charset=us-ascii' fnode.attrs.author = "Ivan Vilata i Balaguer" fnode.attrs.creation_date = '2004-10-20T13:25:25+0200' fnode.attrs.keywords_en = ["FileNode", "test", "metadata"] fnode.attrs.keywords_ca = ["FileNode", "prova", "metadades"] fnode.attrs.owner = 'ivan' fnode.attrs.acl = {'ivan': 'rw', '@users': 'r'} fnode.close() h5file.close() ViTables-3.0.0/examples/scripts/large_number_of_objects.py000066400000000000000000000041151311223072700237400ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org "This creates an HDF5 file with a potentially large number of objects" import sys import numpy import tables filename = 'large_number_of_objects.h5' # Open a new empty HDF5 file fileh = tables.open_file(filename, mode = "w") # nlevels -- Number of levels in hierarchy # ngroups -- Number of groups on each level # ndatasets -- Number of arrays on each group # LR: Low ratio groups/datasets #nlevels, ngroups, ndatasets = (3, 1, 1000) # MR: Medium ratio groups/datasets nlevels, ngroups, ndatasets = (3, 10, 100) # HR: High ratio groups/datasets #nlevels, ngroups, ndatasets = (30, 10, 10) # Create an Array to save on disk a = numpy.array([-1, 2, 4], dtype=numpy.int16) group = fileh.root group2 = fileh.root for k in range(nlevels): for j in range(ngroups): for i in range(ndatasets): # Save the array on the HDF5 file fileh.create_array(group2, 'array'+str(i), a, "Signed short array") # Create a new group group2 = fileh.create_group(group, 'group'+str(j)) # Create a new group group3 = fileh.create_group(group, 'ngroup'+str(k)) # Iterate over this new group (group3) group = group3 group2 = group3 fileh.close() ViTables-3.0.0/examples/scripts/linked_nodes.py000066400000000000000000000053741311223072700215470ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org "This creates an HDF5 file that contains soft and external links" import os import tables as tb output_dir = '../misc' try: os.mkdir(output_dir) except OSError: pass # Open a new empty HDF5 file hdf5_name = 'links_examples.h5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) fileh = tb.open_file(filepath_hdf5, mode = "w") # Create some groups and add datasets to them garrays = fileh.create_group('/', 'arrays') a1 = fileh.create_carray(garrays, 'a1', tb.Int64Atom(shape=(2,)), shape=(100, 3), title='A linked array') gtables = fileh.create_group('/', 'tables') t1 = fileh.create_table(gtables, 't1', {'field1': tb.FloatCol(), 'field2': tb.IntCol()}, title='A linked table') # Create a group and put some links there glinks = fileh.create_group('/', 'links') # Hard link to table t1. If we remove t1 it will still be accessible via ht1. # Hard links are not a subclass of tables.link.Link so they don't have a # target attribute. Because hard links behave like regular nodes one can't # infer if ht1 is a hard link by calling its __str__ method ht1 = fileh.create_hard_link(glinks, 'ht1', '/tables/t1') t1.remove() # Soft link to array a1 sa1 = fileh.create_soft_link(glinks, 'sa1', '/arrays/a1') # Soft link to table t1. This is a dangling link because it points to a # non-existing node. In order to get the pointed node the soft links are # callable >>> psa1 = sa1() st1 = fileh.create_soft_link(glinks, 'st1', '/tables/t1') # Recreate the pointed table so the link is not dangling hht1 = fileh.create_hard_link(gtables, 't1', '/links/ht1') # External links. They behave like soft links but point to nodes living in # a different file hdf5_name = 'external_file.h5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) fileh2 = tb.open_file(filepath_hdf5, mode = "w") new_a1 = a1.copy(fileh2.root, 'a1') fileh2.close() sa1.remove() ea1 = fileh.create_external_link(glinks, 'ea1', 'external_file.h5:/a1') fileh.close() ViTables-3.0.0/examples/scripts/nested_samples.py000066400000000000000000000057461311223072700221220ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a set of scripts by Francesc Alted. """A Table with nested records.""" import random import tables fileout = "nested_samples.h5" # An example of enumerated structure colors = tables.Enum(['red', 'green', 'blue']) def write(h5file, desc, indexed): fileh = tables.open_file(h5file, "w") table = fileh.create_table(fileh.root, 'table', desc) #for colname in indexed: # table.colinstances[colname].create_index() row = table.row for i in range(10): row['x'] = i row['y'] = 10.2-i row['z'] = i row['color'] = colors[random.choice(['red', 'green', 'blue'])] row['extra_info/name'] = "name%s" % i row['extra_info/info2/info3/z4'] = i # All the rest will be filled with defaults row.append() fileh.close() # The sample nested class description class Info(tables.IsDescription): _v_pos = 2 Name = tables.StringCol(16, dflt='sample string') Value = tables.Float64Col() class Test(tables.IsDescription): """A description that has several columns""" x = tables.Int32Col(shape=2, dflt=0, pos=0) y = tables.Float64Col(dflt=1.2, shape=(2, 3)) z = tables.UInt8Col(dflt=1) color = tables.EnumCol(colors, 'red', base='uint32', shape=(2,)) Info = Info() class extra_info(tables.IsDescription): _v_pos = 1 name = tables.StringCol(10) value = tables.Float64Col(pos=0) y2 = tables.Float64Col(dflt=1, shape=(2, 3), pos=1) z2 = tables.UInt8Col(dflt=1) class info2(tables.IsDescription): y3 = tables.Float64Col(dflt=1, shape=(2, 3)) z3 = tables.UInt8Col(dflt=1) name = tables.StringCol(10) value = tables.EnumCol(colors, 'blue', base='uint32', shape=(1,)) class info3(tables.IsDescription): name = tables.StringCol(10) value = tables.Time64Col() y4 = tables.Float64Col(dflt=1, shape=(2, 3)) z4 = tables.UInt8Col(dflt=1) # Write the file and read it write(fileout, Test, ['info/info2/z3']) ViTables-3.0.0/examples/scripts/objecttree.py000066400000000000000000000047401311223072700212330ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a set of scripts by Francesc Alted. """Sample of a typical object tree.""" import tables class Particle(tables.IsDescription): identity = tables.StringCol(itemsize=22, dflt=" ", pos=0) # character String idnumber = tables.Int16Col(dflt=1, pos = 1) # short integer speed = tables.Float32Col(dflt=1, pos = 1) # single-precision # Open a file in "w"rite mode fileh = tables.open_file("objecttree.h5", mode = "w") # Get the HDF5 root group root = fileh.root # Create the groups: group1 = fileh.create_group(root, "group1") group2 = fileh.create_group(root, "group2") # Now, create an array in root group array1 = fileh.create_array(root, "array1", [bytes("string", encoding="utf-8"), bytes("array", encoding="utf-8")], "Data array") # Create 2 new tables in group1 table1 = fileh.create_table(group1, "table1", Particle) table2 = fileh.create_table("/group2", "table2", Particle) # Create the last table in group2 array2 = fileh.create_array("/group1", "array2", [1,2,3,4]) # Now, fill the tables: for table in (table1, table2): # Get the record object associated with the table: row = table.row # Fill the table with 10 records for i in range(10): # First, assign the values to the Particle record row['identity'] = 'This is particle: %2d' % (i) row['idnumber'] = i row['speed'] = i * 2. # This injects the Record values row.append() # Flush the table buffers table.flush() # Finally, close the file (this also will flush all the remaining buffers!) fileh.close() ViTables-3.0.0/examples/scripts/pandas_timeseries1.py000066400000000000000000000036321311223072700226640ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with Pandas in PyTables. Example 1. """ import os import numpy as np import pandas as pd ## A test series, the deprecated way (not supported by timeseries plugin) #startdate = pd.Period(freq='D', year=2009, month=1, day=1) #rng = pd.period_range(startdate, periods=365) #ts = pd.Series(np.arange(1, 366), index=rng) ## A test series, the recommended way dti = pd.DatetimeIndex(start='1/1/2009', freq='D', periods=365) ts = pd.Series(np.arange(1, 366), index=dti) # Saving this time series in a HDFStore will add two arrays to the h5 file # one array with the index and other with the data # So we create a data frame in order to store all the information in a table df = pd.DataFrame(ts) # Write to a PyTables file output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass hdf5_name = 'pandas_test1.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) store = pd.HDFStore(filepath_hdf5) # The following code create a group with 1 leaf (Table instance) # df # |_ table store.append('one_column_ts', df) store.close() ViTables-3.0.0/examples/scripts/pandas_timeseries2.py000066400000000000000000000034521311223072700226650ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with Pandas in PyTables. Example 2. """ import os import datetime import pandas import pandas_datareader.data as web startdate = datetime.date(2002, 1, 5) enddate = datetime.date(2003, 12, 1) # Retrieve data from Google Finance # Data format is [(d, [open, high, low, close], volume), ...] google_f = web.DataReader('F', 'google', startdate, enddate) # Write to a PyTables file output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass hdf5_name = 'pandas_test2.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) store = pandas.HDFStore(filepath_hdf5) # The following code stores the information in a Table instance # intc # |_ table (field index contains the dates range used as index, field # values_block0 contains [open, high, low, close, adj close], # field values_block1 contains volume # shape is (480,)) store.append('google_f', google_f) store.close() ViTables-3.0.0/examples/scripts/pandas_timeseries3.py000066400000000000000000000037501311223072700226670ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with Pandas in PyTables. Example 3. """ import os import numpy.random as nr import pandas ## a test data frame with 3 column and 365 rows index = pandas.date_range('1/1/2009', periods=365, freq='D') df = pandas.DataFrame(nr.randn(365, 3), index=index, columns=['A', 'B', 'C']) # Write to a PyTables file output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass hdf5_name = 'pandas_test3.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) store = pandas.HDFStore(filepath_hdf5) # The following code create a group with 4 leaves (Array instances) # df # |_ axis1 (the row index, a range of dates, shape is (365,)) # |_ axis0 (the column index, shape is (3,)) # |_ block0_values (the random array of values, shape is (365,3)) # |_ block0_items (identical to axis0) store['df'] = df # The following code stores the same information in a Table instance # df_table # |_ table (field index contains the range of dates used as index, field # values_block0 contains the random array of values, # shape is (365,)) store.append('df_table', df) store.close() ViTables-3.0.0/examples/scripts/scikits_timeseries1.py000066400000000000000000000036321311223072700230670ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with scikits.timeseries module in PyTables. Example 1. """ import os import numpy as np import scikits.timeseries as ts import scikits.timeseries.lib.tstables as tstab import scikits.timeseries.lib.reportlib as rl ## a test series data = np.arange(1, 366) startdate = ts.Date(freq='D', year=2009, month=1, day=1) test_series = ts.time_series(data, start_date=startdate, freq='D') output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass ## write to csv file csv_file = os.path.abspath(os.path.join(output_dir, 'test_series.csv')) mycsv = open(csv_file, 'w') csvReport = rl.Report(test_series, delim=';', fixed_width=True) csvReport(output=mycsv) mycsv.close() # Write to a PyTables file hdf5_name = 'scikits_test1.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) h5file = tstab.open_file(filepath_hdf5, mode="w", title='Example table with csikits time series') group_doc = h5file.create_group("/", 'examples', 'Test Data') table = h5file.createTimeSeriesTable(group_doc, 'Example_1', test_series) h5file.close() ViTables-3.0.0/examples/scripts/scikits_timeseries2.py000066400000000000000000000052271311223072700230720ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with scikits.timeseries module in PyTables. Example 2. Notes: -The dates from the yahoo quotes module get returned as integers, which happen to correspond to the integer representation of 'DAILY' frequency dates in the scikits.timeseries module. -`fill_missing_dates` will insert masked values for any missing data points. Note that you could plot the series without doing this, but it would cause missing values to be linearly interpolated rather than left empty in the plot """ import os import datetime from matplotlib.finance import quotes_historical_yahoo import scikits.timeseries as ts import scikits.timeseries.lib.tstables as tstab startdate = datetime.date(2002, 1, 5) enddate = datetime.date(2003, 12, 1) # retrieve data from yahoo. # Data format is [(d, open, close, high, low, volume), ...] where d is # a floating point representation of the number of days since 01-01-01 UTC quotes = quotes_historical_yahoo('INTC', startdate, enddate) # Create a DateArray of daily dates and convert it to business day frequency dates = ts.date_array([q[0] for q in quotes], freq='DAILY').asfreq('BUSINESS') opens = [q[1] for q in quotes] # opens: the data portion of the timeserie # dates: the date portion of the timeserie raw_series = ts.time_series(opens, dates) test_series = raw_series #test_series = ts.fill_missing_dates(raw_series, fill_value=-1) # Write to a PyTables file output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass hdf5_name = 'scikits_test2.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) h5file = tstab.open_file(filepath_hdf5, mode="w", title='Example table with csikits time series') group_doc = h5file.create_group("/", 'examples', 'Test Data') table = h5file.createTimeSeriesTable(group_doc, 'Example_2', test_series) h5file.close() ViTables-3.0.0/examples/scripts/scikits_timeseries3.py000066400000000000000000000031771311223072700230750ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Storing time series created with scikits.timeseries module in PyTables. Example 3. """ import os import numpy as np import scikits.timeseries as ts import scikits.timeseries.lib.tstables as tstab # Generate random data data = np.cumprod(1 + np.random.normal(0, 1, 300)/100) series = ts.time_series(data, start_date=ts.Date(freq='M', year=1982, month=1)) # Write to a PyTables file output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass hdf5_name = 'scikits_test3.hdf5' filepath_hdf5 = os.path.join(output_dir, hdf5_name) h5file = tstab.open_file(filepath_hdf5, mode="w", title='Example table with csikits time series') group_doc = h5file.create_group("/", 'examples', 'Test Data') table = h5file.createTimeSeriesTable(group_doc, 'Example_3', series) h5file.close() ViTables-3.0.0/examples/scripts/table_samples.py000066400000000000000000000165741311223072700217300ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org # # This script is based on a set of scripts by Francesc Alted. """Several simple Tables.""" import sys import numpy import tables class Particle(tables.IsDescription): """Description of a table record. """ name = tables.StringCol(16, pos=1) # 16-character String lati = tables.Int32Col(pos=2) # integer longi = tables.Int32Col(pos=3) # integer pressure = tables.Float32Col(pos=4) # float (single-precision) temperature = tables.Float64Col(pos=5) # double (double-precision) # Open a file in "w"rite mode fileh = tables.open_file("table_samples.h5", mode = "w") root = fileh.root # Create a new group group = fileh.create_group(root, "newgroup") # Create a new table in newgroup group table = fileh.create_table(group, 'table', Particle, "A table", tables.Filters(1)) particle = table.row # Fill the table with 10 particles for i in range(10): # First, assign the values to the Particle record particle['name'] = 'Particle: %6d' % (i) particle['lati'] = i particle['longi'] = 10 - i particle['pressure'] = float(i*i) particle['temperature'] = float(i**2) # This injects the row values. particle.append() # We need to flush the buffers in table in order to get an # accurate number of records on it. table.flush() # Add a couple of user attrs table.attrs.user_attr1 = 1.023 table.attrs.user_attr2 = "This is the second user attr" # Append several rows in only one call table.append([("Particle: 10", 10, 0, 10*10, 10**2), ("Particle: 11", 11, -1, 11*11, 11**2), ("Particle: 12", 12, -2, 12*12, 12**2)]) table.flush() class Particle2(tables.IsDescription): """Description of a table record. """ name = tables.StringCol(16, pos=1) # 16-character String lati = tables.ComplexCol(itemsize=16, pos=2) longi = tables.ComplexCol(itemsize=8, pos=3) vector = tables.ComplexCol(itemsize=8, shape=(2,), pos=4) matrix2D = tables.ComplexCol(itemsize=16, shape=(2, 2), pos=5) # Open a file in "w"rite mode table1 = fileh.create_table(root, 'table1', Particle2, "A table") # Append several rows in only one call table1.append([("Particle: 10", 10j, 0, (10*9+1j, 1), [[10**2j, 11*3]]*2), ("Particle: 11", 11j, -1, (11*10+2j, 2), [[11**2j, 10*3]]*2), ("Particle: 12", 12j, -2, (12*11+3j, 3), [[12**2j, 9*3]]*2), ("Particle: 13", 13j, -3, (13*11+4j, 4), [[13**2j, 8*3]]*2), ("Particle: 14", 14j, -4, (14*11+5j, 5), [[14**2j, 7*3]]*2)]) table1.flush() ###### class Particle3(tables.IsDescription): ADCcount = tables.Int16Col() # signed short integer TDCcount = tables.UInt8Col() # unsigned byte grid_i = tables.Int32Col() # integer grid_j = tables.Int32Col() # integer idnumber = tables.Int64Col() # signed long long name = tables.StringCol(16, dflt="") # 16-character String pressure = tables.Float32Col(shape=2) # float (single-precision) temperature = tables.Float64Col() # double (double-precision) Particle4 = { # You can also use any of the atom factories, i.e. the one which # accepts a PyTables type. "ADCcount" : tables.Col.from_type("int16"), # signed short integer "TDCcount" : tables.Col.from_type("uint8"), # unsigned byte "grid_i" : tables.Col.from_type("int32"), # integer "grid_j" : tables.Col.from_type("int32"), # integer "idnumber" : tables.Col.from_type("int64"), # signed long long "name" : tables.Col.from_kind("string", 16), # 16-character String "pressure" : tables.Col.from_type("float32", (2,)), # float (single-precision) "temperature" : tables.Col.from_type("float64"), # double (double-precision) } # Create a new group under "/" (root) group = fileh.create_group("/", 'detector') # Create one table on it #table = h5file.create_table(group, 'table', Particle, "Title example") # You can choose creating a Table from a description dictionary if you wish table2 = fileh.create_table(group, 'table', Particle4, "Title example") # Create a shortcut to the table record object particle = table2.row # Fill the table with 10 particles for i in range(10): # First, assign the values to the Particle record particle['name'] = 'Particle: %6d' % (i) particle['TDCcount'] = i % 256 particle['ADCcount'] = (i * 256) % (1 << 16) particle['grid_i'] = i particle['grid_j'] = 10 - i particle['pressure'] = [float(i*i), float(i*2)] particle['temperature'] = float(i**2) particle['idnumber'] = i * (2 ** 34) # This exceeds integer range # This injects the Record values. particle.append() # Flush the buffers for table table2.flush() # Create a new group to hold new arrays gcolumns = fileh.create_group("/", "columns") pressure = [ p['pressure'] for p in table2.iterrows() ] # Create an array with this info under '/columns' having a 'list' flavor fileh.create_array(gcolumns, 'pressure', pressure, "Pressure column") # Do the same with TDCcount, but with a numpy object TDC = [ p['TDCcount'] for p in table2.iterrows() ] fileh.create_array('/columns', 'TDC', numpy.array(TDC), "TDCcount column") # Do the same with name column names = [ p['name'] for p in table2.iterrows() ] fileh.create_array('/columns', 'name', names, "Name column") # Save a recarray object under detector r = numpy.rec.array("a"*300, formats='f4,3i4,a5,i2', shape=3) recarrt = fileh.create_table("/detector", 'recarray', r, "RecArray example") r2 = r[0:3:2] # Change the byteorder property recarrt = fileh.create_table("/detector", 'recarray2', r2, "Non-contiguous recarray") # Finally, append some new records to table table3 = fileh.root.detector.table # Append 5 new particles to table (yes, tables can be enlarged!) particle = table3.row for i in range(10, 15): # First, assign the values to the Particle record particle['name'] = 'Particle: %6d' % (i) particle['TDCcount'] = i % 256 particle['ADCcount'] = (i * 256) % (1 << 16) particle['grid_i'] = i particle['grid_j'] = 10 - i particle['pressure'] = [float(i*i), float(i*2)] particle['temperature'] = float(i**2) particle['idnumber'] = i * (2 ** 34) # This exceeds integer range # This injects the Row values. particle.append() # Flush this table table3.flush() # Finally, close the file fileh.close() ViTables-3.0.0/examples/scripts/table_timeseries.py000066400000000000000000000051721311223072700224250ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Table with time fields.""" import os import time import numpy import tables # Describe a particle record class Particle(tables.IsDescription): """This class defines a table record. """ lati = tables.IntCol(pos=0) # longi = IntCol(pos=1) Time = tables.Time64Col(pos=2) pressure = tables.FloatCol(pos=3) ID = tables.StringCol(itemsize=10, pos=4) Int16 = tables.UIntCol(itemsize=4, pos=5) Int64 = tables.IntCol(itemsize=8, pos=6) Bool = tables.BoolCol(pos=7) output_dir = '../timeseries' try: os.mkdir(output_dir) except OSError: pass # Open a new empty HDF5 file hdf5_name = "table_ts.h5" filepath_hdf5 = os.path.join(output_dir, hdf5_name) h5file = tables.open_file(filepath_hdf5, mode="w", title='Example Table with time series') # Get the HDF5 root group root = h5file.root group = h5file.create_group(root, "Particles") filters = tables.Filters(complevel=1, complib='lzo', shuffle=1) nrows = 6000 table = h5file.create_table("/Particles", "TParticle", Particle, "Sample set of particles ", filters, expectedrows = nrows) # Number of rows in buffer nrowsbuf = 1000 # Fill the table with 10**N particles for i in numpy.arange(0, nrows, nrowsbuf, dtype=numpy.int64): if i+nrowsbuf > nrows: nrapp = nrows-i else: nrapp = nrowsbuf # First, assign the values to the Particle record Int64 = numpy.arange(i, i+nrapp) Time = Int64 + time.time() lati = Int64 pressure = lati - 10.4 ID = (i + Int64).astype('S10') Int16 = lati - 50 Bool = lati % 3 > 1 # This injects the Record values table.append([lati, Time, pressure, ID, Int16, Int64, Bool]) # Flush the table buffers and close the file h5file.close() ViTables-3.0.0/examples/scripts/vlarray_samples.py000066400000000000000000000100511311223072700223010ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """Several simple VLArrays.""" import pickle import tables import numpy # Create a VLArray: fileh = tables.open_file('vlarray_samples.h5', mode='w') root = fileh.root vlarray = fileh.create_vlarray(root, 'vlarray1', tables.Int32Atom(), "ragged array of ints", filters=tables.Filters(1)) # Append some (variable length) rows: vlarray.append(numpy.array([5, 6])) vlarray.append(numpy.array([5, 6, 7])) vlarray.append([5, 6, 9, 8]) # Now, do the same with native Python strings. vlarray2 = fileh.create_vlarray(root, 'vlarray2', tables.StringAtom(itemsize=2), "ragged array of strings", filters=tables.Filters(1)) vlarray2.flavor = 'python' # Append some (variable length) rows: vlarray2.append(['5', '66']) vlarray2.append(['5', '6', '77']) vlarray2.append(['5', '6', '9', '88']) # Test with lists of bidimensional vectors vlarray3 = fileh.create_vlarray(root, 'vlarray3', tables.Int64Atom(shape=(2,)), "Ragged array of vectors") a = numpy.array([[1, 2], [1, 2]], dtype=numpy.int64) vlarray3.append(a) vlarray3.append(numpy.array([[1, 2], [3, 4]], dtype=numpy.int64)) vlarray3.append(numpy.zeros(dtype=numpy.int64, shape=(0, 2))) vlarray3.append(numpy.array([[5, 6]], dtype=numpy.int64)) # This makes an error (shape) #vlarray.append(array([[5], [6]], dtype=int64)) # This makes an error (type) #vlarray.append(array([[5, 6]], dtype=uint64)) # Tests with strings # Python flavor vlarray5 = fileh.create_vlarray(root, 'vlarray5', tables.StringAtom(itemsize=3), "Ragged array of strings") vlarray5.flavor = "python" vlarray5.append(["123", "456", "3"]) vlarray5.append(["456", "3"]) # Binary strings vlarray6 = fileh.create_vlarray(root, 'vlarray6', tables.UInt8Atom(), "pickled bytes") data = pickle.dumps((["123", "456"], "3")) vlarray6.append(numpy.ndarray(buffer=data, dtype=numpy.uint8, shape=len(data))) # The next is a way of doing the same than before vlarray7 = fileh.create_vlarray(root, 'vlarray7', tables.ObjectAtom(), "pickled object") vlarray7.append([["123", "456"], "3"]) # Boolean arrays are supported as well vlarray8 = fileh.create_vlarray(root, 'vlarray8', tables.BoolAtom(), "Boolean atoms") # The next lines are equivalent... vlarray8.append([1, 0]) vlarray8.append([1, 0, 3, 0]) # This will be converted to a boolean # This gives a TypeError #vlarray.append([1,0,1]) # Variable length strings vlarray9 = fileh.create_vlarray(root, 'vlarray9', tables.VLStringAtom(), "Variable Length String") vlarray9.append("asd") vlarray9.append("aaana") # Unicode variable length strings vlarray10 = fileh.create_vlarray(root, 'vlarray10', tables.VLUnicodeAtom(), "Variable Length Unicode String") vlarray10.append("aaana") vlarray10.append("") # The empty string vlarray10.append("asd") vlarray10.append("para\u0140lel") # Still more vlarrays... N = 100 shape = (3,3) numpy.random.seed(10) # For reproductible results vlarray11 = fileh.create_vlarray(root, 'vlarray11', tables.Float64Atom(shape=shape), "ragged array of arrays") k = 0 for i in range(N): l = [] for j in range(numpy.random.randint(N)): l.append(numpy.random.randn(*shape)) k += 1 vlarray11.append(l) # Close the file. fileh.close() ViTables-3.0.0/examples/tables/000077500000000000000000000000001311223072700163115ustar00rootroot00000000000000ViTables-3.0.0/examples/tables/nested_samples.h5000066400000000000000000002151561311223072700215670ustar00rootroot00000000000000HDF  n` TREE@ HEAPXtableH (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1$((??????????????????sample string333333?333333?333333?333333?333333?333333?(??????????????????sample string333333?333333?333333?333333?333333?333333?p&x* extra_info&value ?@4 4y2*0 ?@4 4info28&info3&Cname value @y4*0 ?@4 4z4BnameC valueM* bluegreenredy3Q*0 ?@4 4z3name z2InfoNameValue ?@4 4color* bluegreenredy*0 ?@4 4z h2RSNOD (CLASSTABLE (VERSION2.7 (TITLE 0 FIELD_0_NAMEx 8 FIELD_1_NAME extra_info 0 FIELD_2_NAMEInfo 0 FIELD_3_NAMEcolor 0 FIELD_4_NAMEy 0 FIELD_5_NAMEz 8 FIELD_0_FILL  8 FIELD_1_FILL  @ FIELD_2_FILL ?@4 4333333? 8 FIELD_3_FILL @ FIELD_4_FILL ?@4 4 @ FIELD_5_FILL ?@4 4? 0 FIELD_6_FILL 8 FIELD_7_FILL 8 FIELD_8_FILL sample string @ FIELD_9_FILL ?@4 4 0FIELD_10_FILL 8 FIELD_11_FILL  @FIELD_12_FILL ?@4 4? 8 FIELD_13_FILL 0FIELD_14_FILL @FIELD_15_FILL ?@4 4 @FIELD_16_FILL ?@4 4? 8 FIELD_17_FILL 0 NROWS@ TREE??????????????????name0sample stringffffff$@ffffff$@ffffff$@ffffff$@ffffff$@ffffff$@??????????????????name1sample stringffffff"@ffffff"@ffffff"@ffffff"@ffffff"@ffffff"@??????????????????name2sample stringffffff @ffffff @ffffff @ffffff @ffffff @ffffff @??????????????????name3sample string@@@@@@??????????????????name4sample string@@@@@@??????????????????name5sample string@@@@@@??????????????????name6sample string@@@@@@??????????????????name7sample string @ @ @ @ @ @??????????????????name8sample string@@@@@@ ???????????? ??????name9sample string033333?033333?033333?033333?033333?033333? ??????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333???????????????????sample string333333?333333?333333?333333?333333?333333?ViTables-3.0.0/examples/tables/table_samples.h5000066400000000000000000010634051311223072700213730ustar00rootroot00000000000000HDF  g` TREEHEAPX8newgrouptable1detectorcolumns  (TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1TREE HEAPXptableHSNOD07= h0P (TITLE (CLASSGROUP (VERSION1.0($namelati longi pressure  temperature ?@4 4 X 8shuffle$deflate8$ISNOD (CLASSTABLE (VERSION2.7 (TITLEA table 0 FIELD_0_NAMEname 0 FIELD_1_NAMElati 0 FIELD_2_NAMElongi 8 FIELD_3_NAME pressure 8 FIELD_4_NAME temperature 0 FIELD_0_FILL 8 FIELD_1_FILL  8 FIELD_2_FILL  @ FIELD_3_FILL   @ FIELD_4_FILL ?@4 4`7R TREE!$#"x`7R (CLASSTABLE (VERSION2.7 (TITLEA table 0 FIELD_0_NAMEname 0 FIELD_1_NAMElati 0 FIELD_2_NAMElongi?uNGZؔimA @? 8 @ user_attr1 ?@4 4|?5^? H user_attr2This is the second user attr 0 NROWS@ &xnamelati&r ?@4 4i ?@4 4longi &r  i  vector(*&r  i  matrix2D8*@r ?@4 4i ?@4 4 0 FIELD_3_NAMEvector 8 FIELD_4_NAME matrix2D 0 FIELD_0_FILL  FIELD_1_FILLr ?@4 4i ?@4 4  FIELD_2_FILLr  i    FIELD_3_FILLr  i    FIELD_4_FILLr ?@4 4i ?@4 4 0 NROWS@Y HEAPX0 tablerecarrayrecarray2(+ (TITLE (CLASSGROUP (VERSION1.0 (CLASSTABLE (VERSION2.7 0TITLETitle examplex9N@}G8A,PPADD8irMF)RD)n<h7<% !@ @=  @ > @5  @ @-  @ ^ @*  @ zix @zo 9C PFf$7n1GeX`PF5 @5r|[3$@TkFtK h @ @ @vڭf^Vb& @b ,ŬKU @`[q[9 @zcQoV] @ @N ϳ|lwډhBD|eGvvwăWA/*R TREE+"xParticle: 10$@B??T@|xS?]>@Particle: 12(@C@@@@;T6K?g뚘;@;T6K?g뚘;@Particle: 13*@@C@@x?VQ@8@x?VQ@8@Particle: 14,@C@@he%'?*oa5@he%'?*oa5@TREE/x&3ADCcountTDCcountgrid_i grid_j idnumber @namepressure#*  temperature+ ?@4 4!5308SNODN Z.`7R 8 FIELD_0_NAME ADCcount 8 FIELD_1_NAME TDCcount 0 FIELD_2_NAMEgrid_i 0 FIELD_3_NAMEgrid_j 8 FIELD_4_NAME idnumber 0 FIELD_5_NAMEname 8 FIELD_6_NAME pressure 8 FIELD_7_NAME temperature 8 FIELD_0_FILL 8 FIELD_1_FILL 8 FIELD_2_FILL  8 FIELD_3_FILL  8 FIELD_4_FILL@ 0 FIELD_5_FILL @ FIELD_6_FILL   @ FIELD_7_FILL ?@4 4 0 NROWS@TREE8=3 Particle: 0 Particle: 1?@?Particle: 2@@@ Particle: 3A@"@Particle: 4AA0@Particle: 5A A9@Particle: 6B@AB@Particle: 7DB`AH@ Particle: 8BAP@ $Particle: 9BA@T@ (Particle: 10BAY@ ,Particle: 11BA@^@ 0Particle: 12CAb@ 4Particle: 13)CA e@8Particle: 14DCAh@?TREEAHEAPX(?pressureTDCname0_=? (TITLE (CLASSGROUP (VERSION1.0    EP`7R (CLASSARRAY (VERSION2.4BhSNOD_C M@ 0TITLEPressure column (FLAVORpython 8  E(`7R (CLASSARRAY (VERSION2.4 0TITLETDCcount column (FLAVORnumpyParticle: 0Particle: 1Particle: 2Particle: 3Particle: 4Particle: 5Particle: 6Particle: 7Particle: 8Particle: 9 (CLASSTABLE?@@@A@AAA AB@ADB`ABABA  0 D`7R (CLASSARRAY (VERSION2.4 0TITLE Name column (FLAVORpython&f0  f1*  f2f3XO! `7RGE0TREEg!  (VERSION2.7 8TITLERecArray example 0 NROWS@ 0 FIELD_0_NAMEf0 0 FIELD_1_NAMEf1 0 FIELD_2_NAMEf2 0 FIELD_3_NAMEf3 @ FIELD_0_FILL   8 FIELD_1_FILL  0 FIELD_2_FILL 8 FIELD_3_FILL (FLAVORnumpy&f0  f1*  f2f3[! `7R/dTREEg!  (CLASSTABLE (VERSION2.7 8TITLENon-contiguous recarray 0 NROWS@ 0 FIELD_0_NAMEf0 0 FIELD_1_NAMEf1 0 FIELD_2_NAMEf2 0 FIELD_3_NAMEf3 @ FIELD_0_FILL   8 FIELD_1_FILL  0 FIELD_2_FILL 8 FIELD_3_FILL (FLAVORnumpyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaViTables-3.0.0/examples/timeseries/000077500000000000000000000000001311223072700172105ustar00rootroot00000000000000ViTables-3.0.0/examples/timeseries/carray_ts.h5000066400000000000000000002110501311223072700214340ustar00rootroot00000000000000HDF  (` TREE0HEAPX(test_carray_1test_carray_20 @TITLEExample CArray with time fields (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1  (,  1R (CLASSCARRAY (VERSION1.1x@SNOD  8TITLESigned short arrayTREE( ( * ,  1R (CLASSCARRAY (VERSION1.1 8TITLESigned short array1ROG/R, O,R"O*Rr%O^'R(O$R*O"R[-OuR/OR2O/RD5OR7OR:OFR-=OR?O RsBO] REORGOR\JOtRLOQOO.QEROQTOQWOEQ.ZOQ\OQt_O\QbOQdOQ]gOsQjOQlO-QFoOQqOQtODQ/wOQyOQu|O[QOQOQ^OrQOQO,QGOQOQOCQ0OQӖOQvOZQOQOQ_OqQOΨQO+QHOQOQOBQ1OQԳOQwOYQOQOQ`OpQO͋QO*QIOQOQOAQ2O~QO{QxOXyQOvQOtQaOoqQOnQO)lQJOiQOfQO@dQ3OaQO^QyOW\QOYQOWQbOnTQOQQO(OQKPLQPIQP?GQ4PDQ PAQz PV?QP*Q5%P'Q'P$Q{*PU"Q-PQ/PQd2PlQ5PQ7P&QM:PQ*Q"P,QP/QLP'2QP4QPm7QcP:QP '?\c'@6(A(BIG(C!)D9pp)E6)F\ *G-\*H#ª*IrW*JG+K3+L_+MU3,N=,OLx,P g-Qm-R9,-S$ .TNY.U&M.Vuq.WwE/X /Yb%/Z410[H0\O]0]j1^k1_<1`2aگDW2b)A٥2cxm2dcC3e3fe+3g.4hT}4iR:4j}5k\i5l?5m;6nT6o,d6p{36qč@7rV"7sh7txK,8u z8vUt8w, 9xf9yBO29z:{q[R:|/:}~:~%>;;kHB;)< kkx<X<=)d=E=AR>O>2d{>>І;?9?n?:b'@ u@[]@AaAHIAA3rMB5BVB/9C"yćCq YC$D-sD^DOE?_EKrԭEiEJF8&F&FH6G%OGtkGx"H qHaH6IA\IN_IdIHJ;JJ٩F4K(;ۂKwoK] LnLd-L MVZMQ4MMVFN>訔Ny=N 1O+fOz-OɾPP$lPgḺPrM QWQTvQ& QCRAI4RRk]/S.}S}STiTjBDTUemUUWUU+AVDV;TV,W1^}{WWπX;gXmϵX4dY RYZWY!Yy>ZG KZZ-t*[4y[P[1\!sd\p[\]'P]]]I]A<^Jl֊^j^'_7 v_(_B`$Qb`se`z`Na`a8a;9bMab^b%c:tccأHd'5_dvqdWdKecz/e  e X7f P.f f P#g=qgs?gh*h]hy'hȸhJ&IifۺilOi4jSxj j k@C6okʽke_ l-Zl|l l!Fm"i !-v?\|v@CvACwBIfgwClwDxE6SxF*xG /_v[`0&LPR!kU- ^N˅w@߲UѤ.BM1/63)Gߖ7kQ֐j6>rRO"@yf}DH%WZQ:vlynB'u놨/?Oյ۷~a1={9ΚzW:K?3#p\<7'2}'p\;<SziO#o}-ygprPx_~1~#uiӹ?v;/wlR-ls,.g!j Wfb\cvG3s,dk y|$R.jv#<&`Jli?}'Y諒O+Lu؍)6WuxRU{2mDPz([R3y)dbT= Gwu2Vz(k#_y)d=btA G:'|i?b9'/KWyr+]K0c-VC!_rP ft>Y %c*VC_r32M]&~EGnZzZTIv[`-`D}PY(ּ>Y8Y6ױ?z/d6X oanHT]>j;v\'Ϲ4:`z![OO#;J=ħky'E+|2Q/Yߋ5ܧW*ٿU=h0 (RIy$QeXQhCԒC НS }̖o,vSgRSiw]D6_2ktMs֘ Qj{Tk>Qo>tl ʛ$+FsZlF.}%= @y2Q2c\p`ɡnRWM}Uiw)Y<-wܽ&k& 4%I~ UB j (`ݧ@6_@3XKO@kAxE<Mh@HtVCUg&;6*@<3ph-@8] ( r{GTdH4h`VE:4aׄ!;AG3ovfrg_ D!tc1DLL?( ]!l.@zZ2<@@\^`ߓr3 Tů,D"Q(zfffff0@fffff&1@(\0@\(1@\Gp333330@fffff&1@)\0@)\0@Wi_g{G0@Gz1@{G0@Gz0@&vLb%1@QE1@ףp= 0@R1@sQ(\51@= ףp=1@q= ף0@Gz.1@IJLNHz1@Gz1@)\h0@0@^9 ףp=0@fffff0@L0@333330@ w=fffff0@(\0@ffffff0@Q0@Qu[5)Q0@Hz0@Q0@ 0@[w 0@(\u0@{G/@ףp= 0@lB~^zG!0@3333330@0@0@[dbGz.0@Gz0@fffff&0@= ףp}0@VTEOR/@\(/@Q8/@(\u/@2ٝ= ףp=/@\(\/@)\.@= ףp.@X[G.fffff1@{G:2@Q1@q= ף02@rE/fffff&2@Q+2@333331@Gz2@xi/Gz.2@Gz.2@)\1@= ףp1@D.G5Y01@(\1@̌1@ףp= 1@+W@1Hz1@ ףp=1@= ףp}1@{G1@cтk1fffff1@= ףp1@(\1@ףp= 1@Xt"c1(\1@ףp= 1@Qx1@fffff1@ `ե2333331@ףp= 1@3333331@(\O1@de^i2@1@@1@0@Q0@9B3Q0@Gz1@0@333330@ k[ʒ31@\(1@(\0@0@^XK\'3333330@333330@)\h0@̌0@e84333330@(\0@̌0@ ףp=0@s=y5p= 0@\(\1@Q0@R0@]2i5R0@Gz0@0@Gz0@4:d%Ģ5̌0@Q0@(\O0@{Gz0@[tU76p= #0@q= ף00@= ףp=/@Hz/@ta 6R0@ffffff0@Q0@\(\0@ m@7Y0@ 1@Q80@Q0@tY+7 ףp=0@{G0@(\u0@{Gz0@cN7Hz0@ ףp= 0@zGa/@(\u/@`<NG,8R.@\(\/@Q.@ ףp= /@9Q/@ףp= /@(\.@33333/@Hk~ٓf90@ ףp=0@R/@ 0@~(%.9= ףp=/@zG/@ ףp= /@/@qw: ףp=/@0@.@ ףp=/@GWR:Gz/@{Gz0@ ףp=/@0@d3h>;0@= ףp=0@/@ ףp= /@]a;(\/@{G/@.@Q/@XQ>;zG.@= ףp=/@.@.@p@gx<.@{Gz/@.@zGa/@8$d=p= #/@ףp= W/@(\.@L.@ q+=Q.@(\.@Q.@Q8.@ PgzN> ףp= .@(\.@fffff+@{G+@ɨO>+@Q+@zG)@\(\*@18:w>ffffff*@(\*@Q)@Q8)@L4?333333)@q= ף)@Qk(@)@T?ffffff)@p= ף+@Q(@)@D^'@(\)@Q+@)\(@ ףp= )@u@)@L*@fffff(@Q)@$A3@Q)@{G)@(\u(@Hz(@Q.DAfffff(@R)@fffff'@ ףp=(@u}xAQ(@Q(@Q(@333333(@ nMB(@33333)@ ףp= '@HzG)@خB ףp= )@)@Q8(@Q)@j,B)@{Gz)@ ףp=(@333333)@ZWTCfffff)@*@(@(\B*@tq$Dףp= W*@Q*@Q*@ffffff*@ئl~sDffffff*@q= ף*@*@q= ף*@iDD= ףp*@ ףp= +@Q*@*@i%E333333*@333333*@ffffff(@fffff(@XEvdE)@)@RQ'@Q'@jJF)\((@(@(@RQ(@{aF)@)@(\'@(\(@\mm"F(@(@L'@ףp= '@]6G(\'@{G'@Q8'@Gz'@dt"H'@q= ף'@'@HzG'@c qHHzG'@33333'@Gz&@zG&@ kGHzG&@Q'@L%@33333&@(2I'@Q'@(\%@Q8'@\I333333'@RQ'@33333&@Hz&@`k˄HJ)\('@ffffff(@R&@(\B(@L!]J(\(@(\u(@Q'@R'@h1pJ(@q= ףp(@33333'@fffff'@B4K(\(@{Gz(@Hz'@ףp= W(@ 9tׂKGz.(@(\B(@(\u'@(\'@fĔnL(\'@zGa(@p= ף'@)\((@peWJV)Lffffff(@ףp= (@Gz'@Hz'@߉ MHz'@ףp= '@Gz'@(\B'@׆xRZMQ'@'@ ףp= '@(\B'@d7 M(\B'@(\'@'@ ףp='@YNsO9N'@Q'@\(%@zG%@1O{G%@Q8&@= ףp=%@&@\rbOfffff%@Q%@{G$@zGa%@4H`O&@&@RQ$@ffffff$@ MPffffff$@&@RQ$@%@HI QR%@{Gz&@ffffff%@%@lWQfffff&@fffff&@(\u%@RQ&@:krQzG%@333333&@%@Hz%@Q%@ףp= %@\($@L%@DvRL%@p= ף%@%@zGa%@@}AY/Sq= ף%@Q&@Q$@q= ף$@,|}S$@fffff$@ףp= #@Q$@|cdS$@(\B$@Qk#@= ףp#@pT= ףp#@q= ף#@(\#@ ףp=#@U$@$@(\"@RQ#@HZ:iUU= ףp"@(\B#@{Gz"@Gz"@=U#@L$@333333#@q= ף#@ ]Up= #$@Q$@(\#@Q8$@@&AVp= ף#@(\#@#@(\B#@`}Ȣ,W(\B#@q= ף#@"@#@4y{W\(\#@{G#@Gz"@#@'f W(\#@(\#@"@)\"@̍VX"@)\"@ ףp= "@RQ"@6gXRQ"@(\u"@!@RQ!@RYRQ!@!@ @!@9@-Y!@Q!@ ףp= @@XRYQ@)\(@@@(O>Z333333@@ffffff@ffffff@@-FZ333333@!@333333@p= ף @y[)\ @)\ @q= ףp@Q@i&[!@!@33333 @= ףp!@L>-\"@"@ ףp= @Q @LId\ffffff!@fffff!@ @{G @VV\ @{G @ @Q @9C](\ @#@ @#@,0R]Gz#@q= ף#@Q"@"@|!=<^= ףp"@"@= ףp!@ףp= W"@0BҊ^"@Hz"@{Gz!@Q!@Bf^)\!@Gz!@Hz @q= ףp!@wl$_R!@)\("@!@(\!@{`(\!@33333!@33333 @33333 @^ Mb` @Gz!@Q @ףp= @pY;`fffff @HzG!@= ףp @Q @v`\( @Gz.!@Q @\( @4ez4a!@q= ף!@!@Q!@j9bp= #!@(\!@Q!@!@:3]b333333"@#@Q!@33333"@p4bQ"@"@!@!@ņ%c(\!@"@!@{Gz!@RxyDd333333!@zGa!@zG @!@_ _dQ!@Q!@Q!@(\B!@m\mdGz.!@ffffff!@R @ ףp= !@خ-dq= ףp!@fffff!@ףp= W!@!@GxKe333333!@!@(\!@L!@؏trT7f(\!@Hz!@ffffff!@!@,h6fQ!@ ףp=!@Q!@!@ċ}f)\(!@ ףp= "@!@\(!@8?&#g"@\($@(\!@p= ף$@a#qg33333$@zG$@Gz#@Qk$@0ld]h%@Hz%@33333$@(\%@G_h%@&@q= ףp%@p= ף%@Kh&@Qk&@(\%@(\&@Li(\B&@'@Q8&@(\&@hs9etjL'@R'@Q&@fffff&@LKjfffff&@fffff&@R#@Q#@ׇ kfffff#@Q$@ffffff#@L$@5 &2okQ$@(\$@\(#@ ףp= $@uƽkq= ףp#@R#@L#@(\#@,b^l33333#@33333#@)\"@fffff"@l#@#@fffff"@= ףp=#@![= ףp=@@@Q@`!= ףp=@p= ף@Q@@ŢC @(\ @(\@ ףp= @l sffffff@ ףp= @ףp= @= ףp=@11&@zG%@L%@)\%@ܝ%@&@ ףp=%@{G%@,Wk)\%@%@%@%@|jffffff%@%@\($@)\(%@ HzG%@RQ%@fffff$@Gz.%@Co7AWL%@= ףp%@= ףp=%@\(\%@$jե= ףp%@{G%@ףp= W%@q= ף%@\%e|L&@{G%@%@33333%@w (Gz%@Hz%@Q%@)\%@aI.(\%@Gz%@333333%@L%@ܤo0Q}ffffff%@L&@{Gz%@Q&@F˴)\(&@'@ ףp=%@%@,au%@ffffff&@ffffff%@Gz%@lZR#8 ףp=%@Gz%@ ףp= %@ ףp= %@qrT333333%@(\u%@fffff$@L%@Į)a(\B%@{Gz%@Gz%@q= ףp%@}GQ%@)\%@L%@Qk%@KnݷQ8%@%@333333%@Qk%@3LH,zGa%@(\%@(\B%@(\u%@Hz ףp=%@Hz%@p= #%@Q%@"qɸffffff%@= ףp%@%@Q%@ 9ffffff%@33333%@Q8%@ ףp=%@ E&hQ%@q= ף%@%@%@FuWRR%@HzG&@(\%@p= #&@(xĊ젺p= #&@&@fffff%@q= ףp&@0knQk&@{G&@ffffff&@R&@b>R&@(\'@zGa&@(\u&@}Oa)L&@ffffff&@{G%@)\(&@̲IgxGz&@\(&@Gz&@R&@qƼ{G&@\(\'@&@HzG'@<'@)\('@ffffff&@zG&@#z%d&@RQ'@(\&@Q'@hw333333'@Q(@)\('@Q(@D' } p= ף(@(\)@HzG'@zG'@[e;Q'@Q(@{Gz'@= ףp'@ϗ5Hz'@= ףp'@Q8'@(\u'@HSuQk'@= ףp'@ffffff'@)\'@ܲ\'@'@p= #'@(\B'@`l?v(\B'@(\B'@Q&@(\&@yaQk&@'@Qk&@zG&@4LݘEzG&@L'@(\&@333333'@HvL= ףp='@333333'@Q&@= ףp&@ޗ'@L'@R&@(\B'@+ho,9p= #'@ףp= W'@fffff&@{G&@}<(\u'@(\u'@(\u'@(\u'@U'@\(\'@{G&@Q'@%`EQ'@)\('@&@q= ף&@l0rBקq= ף&@p= #'@zG&@ ףp= '@Y\h<_(\&@(\'@(\u&@Q&@_ЭL&@L&@L&@L&@/eGz.&@(\B&@ףp= %@&@?#&@Q&@\(\%@\(%@]kз6%@%@L%@ ףp=%@aL ףp=%@&@R$@333333&@l  ףp= &@ ףp= &@ ףp= &@ ףp= &@Xu" ףp= &@)\('@ ףp= &@R&@E83= ףp&@zG&@Gz&@Hz&@P I\&@fffff&@L&@ףp= &@4+sZ\33333&@'@p= ף&@'@M2Qk'@Qk'@Qk'@Qk'@}HQk'@'@L'@ffffff'@dbn1C4'@(@Qk'@q= ף'@ _ׂ(\'@fffff'@(\'@fffff'@xW Tl333333(@Qk(@Q'@HzG(@L[ Gz(@Gz(@Gz(@Gz(@vnGz(@Hz(@(@(\B(@*SZzGa(@fffff(@(\B(@Hz(@uHz(@Hz(@HzG(@ףp= W(@ 5M|33333'@33333'@33333'@33333'@F\(\'@(\B(@Q'@Gz.(@̥oGz.(@ ףp= (@ףp= W'@'@؇#c(@HzG(@fffff'@ ףp= (@PfL(@(@ ףp= (@(@4^F(@fffff(@Qk(@\((@} lL(@L(@L(@L(@h\(\(@Q(@(\B(@(\B(@ cs(\u(@Gz(@(\B(@q= ףp(@8\(\(@= ףp(@RQ(@p= ף(@>n?Cq= ףp(@)\(@Q(@ףp= W(@y0Q8(@Q8(@Q8(@Q8(@%b(\u(@(\(@Q8(@zGa(@(\u(@Q(@\(\(@q= ףp(@X}a= ףp=(@(@= ףp=(@Q(@@58i)@Q8*@)@Q*@@HzG*@HzG*@HzG*@HzG*@N[L*@HzG*@Hz)@Q)@;)@Gz)@Gz.)@Qk)@苩'AQ)@R)@Q8)@Q8)@@;p1zGa)@HzG)@fffff(@)\()@(Pףp= (@ףp= (@ףp= (@ףp= (@wT,ףp= (@{G(@(@33333(@bd(\B)@(\B)@(\B)@(\B)@7g\(\)@*@Q8)@*@L+̵fffff)@Gz*@(\)@ףp= )@hWmMRzG)@q= ףp*@\()@ffffff*@S> ףp=*@Gz*@fffff)@= ףp=*@ TREE8!HEAPXPindexH0 PTITLE+Indexes container for table /google_f/table (CLASSTINDEX (VERSION1.0"pTREE&@48HEAPhp7 8P (VERSION1.1SNODx IP 8TITLEIndex for index column (CLASSINDEX (VERSION2.1 0 FILTERS@ 8 superblocksize@ 8 blocksize@ 8 slicesize  8 chunksize  8 optlevel  8 reduction  (H' 8shuffledeflate!Y 0CLASS INDEXARRAYSNOD0.(-(X`6@1@ (VERSION1.1 0TITLE Sorted Values 0 EXTDIM  (  8shuffledeflate!Y 0CLASS INDEXARRAY (VERSION1.1 8TITLENumber of chunk in table 0 EXTDIM  (@ 8shuffledeflate!Y 0CLASS CACHEARRAY (VERSION1.1 0TITLE Range Values 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Median ranges 0 EXTDIM  (@ 8shuffledeflate!Y 0CLASS CACHEARRAY (VERSION1.1 0TITLEBoundary Values 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Start bounds 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE End bounds 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Median bounds 0 EXTDIM  5 8shuffledeflate 9!Y 0CLASS LASTROWARRAYSNOD h+)$Hx38H0p8X (VERSION1.1 @TITLELast Row sorted values + bounds H 8shuffledeflatePA!Y 0CLASS LASTROWARRAYsortedindicesrangesmrangesboundsaboundszboundsmboundssortedLRindicesLRH8X 0TITLELast Row indices@ 8 nelements  8 nelements TREE ITREE)fS  0 DIRTY xSU]ptwwwttĥ$[AACDAw?/w}>sf3_.>oK׮7fv.ꂔ{[j}=N\#ԭ_,4eqլjxBh'aP2A%_\ܖ]}˛w,RvAaRxVO0jd.}I&A߉;d lzxbs6j[^cgRuX]ǷxpUK/%3vi٤48&X@YEV/֧W&6kӦՋw4Bv1U :-k8Zj)KsHpҼQq 2`=`.~<^>OLt֚M+g4\f 1E:-k(Jj1SsHp6w t|瑤rHiXӴnByFL~,;!hc[^Q6{fsVI.&1t>-l oo7~XqﭺUJߣrƸVh$PAoE)<7J"=zq4,;ͪo0M*nxBf( @uV,Z!f%iFcՀ}Dя} ??[b.oK#mS<; 뫏DZ?}GEcVp-~Zy^[E7_is])N藲_9HPށ6nj:(#y'kCx9߄=p^f Dj]:\7(;<3 KrM:Kj^x :(!C`1B5HW}?6 7`5%oq9~@/Ndo~fI &:rEb0>\~^}w>OeRy ɯPr)9Ab9zJd۬%!/}@A@ hhh>| clll'xx DOI@H)((()ihhiiAAXXYY988yxxxEDDD%$$%%edeeUTTU544ihikk=bnaaaibmccckkggg򥛛' {$8$$44,,,<<""222**:::&$.>>[w III))iiYY9yyEEWTTVVVWW7444665558>>>1199955==333;;777vn4"~vx6oׯx  Om( 0` 0`ViTables-3.0.0/examples/timeseries/pandas_test3.hdf5000066400000000000000000003071101311223072700223520ustar00rootroot00000000000000HDF  H` TREEHEAPX dfdf_table8 TITLE (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1TREE HEAPX8haxis0axis1block0_valuesblock0_items SNOD(HxJJLP TITLE (CLASSGROUP (VERSION1.0 0 pandas_typeframe 0pandas_version0.15.2 0 encodingUTF-8 0 ndim  0axis0_varietyregular !Y (CLASSARRAY (VERSION2.4 TITLESNOD X(ABCABCx?ljZG i̐+׸ƘqL&wf9njT$M:Ė&RrT"PV}x_O> /_v[`0&LPR!kU- ^N˅w@߲UѤ.BM1/63)Gߖ7kQ֐j6>rRO"@yf}DH%WZQ:vlynB'u놨/?Oյ۷~a1={9ΚzW:K?3#p\<7'2}'p\;<SziO#o}-ygprPx_~1~#uiӹ?v;/wlR-ls,.g!j Wfb\cvG3s,dk y|$R.jv#<&`Jli?}'Y諒O+Lu؍)6WuxRU{2mDPz([R3y)dbT= Gwu2Vz(k#_y)d=btA G:'|i?b9'/KWyr+]K0c-VC!_rP ft>Y %c*VC_r32M]&~EGnZzZTIv[`-`D}PY(ּ>Y8Y6ױ?z/d6X oanHT]>j;v\'Ϲ4:`z![OO#;J=ħky'E+|2Q/Yߋ5ܧW*ٿU=h0 (RIy$QeXQhCԒC НS }̖o,vSgRSiw]D6_2ktMs֘ Qj{Tk>Qo>tl ʛ$+FsZlF.}%= @y2Q2c\p`ɡnRWM}Uiw)Y<-wܽ&k& 4%I~ UB j (`ݧ@6_@3XKO@kAxE<Mh@HtVCUg&;6*@<3ph-@8] ( r{GTdH4h`VE:4aׄ!;AG3ovfrg_ D!tc1DLL?( ]!l.@zZ2<@@\^`ߓr3 Tů,D"Q(;;kHB;)< kkx<X<=)d=E=AR>O>2d{>>І;?9?n?:b'@ u@[]@AaAHIAA3rMB5BVB/9C"yćCq YC$D-sD^DOE?_EKrԭEiEJF8&F&FH6G%OGtkGx"H qHaH6IA\IN_IdIHJ;JJ٩F4K(;ۂKwoK] LnLd-L MVZMQ4MMVFN>訔Ny=N 1O+fOz-OɾPP$lPgḺPrM QWQTvQ& QCRAI4RRk]/S.}S}STiTjBDTUemUUWUU+AVDV;TV,W1^}{WWπX;gXmϵX4dY RYZWY!Yy>ZG KZZ-t*[4y[P[1\!sd\p[\]'P]]]I]A<^Jl֊^j^'_7 v_(_B`$Qb`se`z`Na`a8a;9bMab^b%c:tccأHd'5_dvqdWdKecz/e eX7fP.ffP#g=qgs?gh*h]hy'hȸhJ&IifۺilOi4jSxj j k@C6okʽke_ l-Zl|llFmiQ?7*?c_?iu?tG ?&?l? ~*ՋٿRj9ؿ{a)y&?(?5Կ?Ho x#?LA@?Y?2Fܿ@ɵkN4\eK([?Όꞡ(\:?T J?33 Sjoqʿ-Ccؾ@狺TW ?XCJ5?B1V)? F?3`$ı?{,?2(~-濢pwZ? TR?L濞i!vd?f6?>?2"Rc?}1W{l?-*?-늅:?"lF?t=$?i>?A?d-e?Q=¿n4 +ٿyB?JxnǿU ?ָֻ6Zo ?_ϧ˿Fy;|۩?{\xN?BzHaŘ{S.?ɥ?W?e =z??n?_PzPXt|R+?!Q?MvdݿiB7rk!>m?G5N7{َ㿆 տĹ+?Ԗ|T[WpyG?"z/?RP?KG#mؿ4z?QIX?`? <7ٿ,׿10w7?3s[?e?&b_L ´~?" YO 7&ug?1Ο-Ӱmq?^&h deտʺ>l3ÿKq?XV Z-ۧ?ӮM??1t&f?Bi}l?80[}V̚,~v׿ Ζ? iV?/`/f$mj?N Xir) 觲{?}K쿽6JmBH?CxO??q"8?ʰ@۴+̿i#ү /?OPnwMĥ?뭄v'T|2vgYbĊ#?-%Q.@n?W]ܿ;/] +?K|$5 {?aY?rr=o?% >%mo%?E?^ߜ{d?kS~ ?QO%?Ykѿ VZuU59ٿǚw?)N5Hg?UoV:f?xz;SZտ Ⱦ??bXt3?CM&[꿁u? bLmmH!?߄ ?"?8ݠ?%shՁ?v͵_V?qߘu2ڿ{?~Y?p!DT?뤟?`us?L/?;m??e,n ?1IS2࿇i 4g/Q&KBwZUEglm?4G?8!? tX2?8ȯP?*/MqjuaG9N[)@IJpTIɿ.cH8R?Mjl?ji?:gO ?+~t??K'\߿C;Et?Ǔ2,\?#7?]5Ȼ- ?!ز ֨?D՟9\LJlQݿ֌!?_sMy?+<ǿ,]ѻ?6%J[Dgqz_?d?lW,\m?k?U6ڕ; ho?. J?{Z”#⿦_<ob0.?D%??$ ?)4,|?3M3f?5:翴23?0̳ S?\?J:Ֆ?0}No?٨vYXA~0?Ѽw @TzGƿRxs?-\oTm?1~s2Bÿа]C?#/)"|e5?i)VraF?ft $k {?ғ 5w~뿍 _?tQd @dӿk`(Edܾ='I?6@ҖFsֿ}8?\ ?O˅9?̒Ґmſ׉?*S'phۿ]LWܿzbL򿃄?m6)ؿ;MX?RM\ˡn?ji:J^B?:"ȿ@ֽ?% `*?7AI? s\kXQP!@H^UY?eT?|&Gg ??!#N%M{?cΖ翘Kʊ?Y[?-.H?|=a5P Nǿ |?lz=?m+\?|dP3nT yb<ݿr܆i⬁ <߿.["?W!߿K-^V?0 W,M\ @Nt)>BZڿ)N_RͿ#9b?uX8i!?Lflg?#$aIf@ulᐟ^?80?sޟ?e}mԴ>X?ƾt{Y ;?/V?}ScƿF˿+Kʿ$e*\?~?)pZL?p \@=\~?5#_t@A?K桥rz?*M< ?w\d?w^ū?MNpݡ`уeӿR*֥?m2 ?*_;db$8S&|a{=q?鸒?fF"?-!ge?ŬTr@V-?+׿>ғ?>? Qvir>\:?ّ 6OC?et?/>Lg?k 힁?/єI?ձ>l?pnQYuڟ)"?#޷?嵺迸N)˿ڬ0C?]Y?CX? WOs)?-[??y H?qԟ>p?>0CDS?`?$MH?z<\,c]K@?rÞR?;j>?OA?"z)ɿ+j2!?-?z&/>?D 0aɿ??jhpſnY)2w)ܿh ?ʊ}Egܿ5B?Zx?]Iuxh?Y޺3fM?ٯ?Fpl?I2Ѧb5߿G?឵?0i?h?dohI?iL]r5 :^ҹc?@SAP37΋۹? =?::ÿv?;?:H̿Ն,|?BȷpB @?Vjrb#ӿ϶ܿv|xM鿲>ῠ?F[ "϶?=ºʿ|^?XV̓K?ؿQu)pֿ%fޘ?㱷c` rP"| d?$? 껿wJq?12 ?-ϙ??Cgr [s?6g?vm ?~̿H#)?:Ӫaw ِ?zTFz]ԿvQ cK#?|M?o׈{P?m"?u6O %6? aeiNY ?i)??Aڹ˔ᅴy=f^?O2Կ<,YyFKm{ĿeXv?'`<¿b Q??x:%I9п6~64UY?_9o&J?T2Rʜ~?'6)"?3TľH*=?Sүl.AR2|,?)uR?aH^w?G4b? χٿ:/?at ?v^?|[?tAm|? EF??=3࿮7[T?'?d!?/ k??` ʀݿqV?Y 3e(XA}迯9yJ? HXſPZ^?*!DB??_ /1?lՍv?ËLJ;Կ[N~JХ)޿kv ?9E{S̿GW? ? B hrmq k޿,e???Csc뿳 ?Aӿܮ?ɼ5?J?Ҝtm+ x ?u^ZA..vܿv]Vw{?89D꿈ĊgUܿQƕÿ6Օ[? KE?ZS,7f?0EDseVWi>u4Z/|w??Yq?.nT1= b?7Ï4~"f?:i32 2LTdv@<hw~B?Jjox[^?C.m@$ ^87F?Ƞ@SX?OIֿpk?pT?%i?D[ z?ϫ1?260z?^?A}k?x1Cm⿞iv?^_տ\%Q|o п47 Eſ6[࿍4m?u~?d`OÙF?zM>? 0 SV"5&6H?epj[E?׿֞{-ÿCX, ?? 8 transposed (kindstring (nameN.8MTREE SHEAPX Ltable_i_table8JL TITLE (CLASSGROUP (VERSION1.0 8 pandas_type frame_table 0pandas_version0.15.2 8 table_typeappendable_frame H index_cols(lp0 (L0L Vindex p1 tp2 a. H values_cols(lp0 Vvalues_block_0 p1 a. Xnon_index_axes*(lp0 (L1L (lp1 VA p2 aVB p3 aVC p4 atp5 a. 0 data_columns(lp0 . (nan_repnan 0 encodingUTF-8 0 levels  0 metadata(lp0 . hinfoB(dp0 L1L (dp1 Vnames p2 (lp3 NasVtype p4 VIndex p5 ssVindex p6 (dp7 Vfreq p8 ccopy_reg _reconstructor p9 (cpandas.tseries.offsets Day p10 c__builtin__ object p11 Ntp12 Rp13 (dp14 Vn p15 L1L sVnormalize p16 I00 sVkwds p17 (dp18 sV_offset p19 cdatetime timedelta p20 (L1L L0L L0L tp21 Rp22 sV_use_relativedelta p23 I00 sbss.hT`& index@values_block_0* ?@4 40W !Y (CLASSTABLESNOD`__aRm (VERSION2.7 TITLE 0 FIELD_0_NAMEindex 8 FIELD_1_NAMEvalues_block_0 8 FIELD_0_FILL@ @ FIELD_1_FILL ?@4 4 8 index_kind datetime64 Pvalues_block_0_kind(lp0 VA p1 aVB p2 aVC p3 a. 8values_block_0_metaN. 8values_block_0_dtypefloat64 0 NROWS@mTREE`_ vK~L{?hȇv:2wӒԿҹ"#G{l?".3(GP?6eQWؿT|Cg*p?fH6?d'K hH?{ȷ2?vwq5+yXGuh ڳ>Q?7*?c_? iu?tG ?&?c+l? ~*2TՋٿRj9ؿ{aNǢ)y&?(?P[5Կ?Ho x#?p?LA@?Y?2Fܿ@ɵkN4\=eK([?Όꞡ$+(\:?T J?33۵Bz Sjoqʿ-Ccؾ@*G狺TW ?XCJ5?ykB1V)? F?if3`$ı?{,?2(~-濢pwZ? TR?f)L濞i!vdQ?f6?>?2"Rc?R}1W{l?-*?-늅:?S@"lF?t=$?i>?{=A?d-e?Q=¿bn4 +ٿyB?Jxnǿ@U ?ָֻ6Zo ?9)_ϧ˿Fy;|۩?w{wYu!\xN?BzHa0 !Ř{S.?ɥ?W?"e =z??n?_Pz+a"PXt|R+?!Q?Mvdݿ"iB7rk!>m?lN@"G5N7{َ㿆 տL#Ĺ+?Ԗ|T[WpyG? qi#"z/?RP?KG#mؿY#4z?QIX?`?8$ <7ٿ,׿10w7?$'$3s[?e?&bF$_L ´~?" YGP$%O 7&ug?1Ο-Ӱmq?r%^&h deտ3jy%ʺ>l3ÿKq?XV Z &-ۧ?ӮM??ь^&1t&f?Bi}l?80[}V 7&̚,~v׿ Ζ?o& iV?/`/@`J'f$mj?N  'Xir) 觲{?}K\c'6JmBH?CxO??6(q"8?ʰ@۴+̿(i#ү /?OPnIG(wMĥ?뭄v'!)T|29pp)vgYbĊ#?-%6)Q.@n?W]ܿ\ *;/] +?K|$-\*5 {?aY?rr=#ª*o?% >%morW*%?E?^ߜ{G+d?kS~ ?Q3+O%?Ykѿ V_+ZuU59ٿU3,ǚw?)N5Hg?=,UoV:f?Lx,xz;SZտ Ⱦ?? g-bXt3?CM&[m-u? bLmmH!?9,-߄ ?"?8ݠ?$ .%shՁ?v͵_V?qߘu2ڿNY.{?~Y?p!&M.DT?뤟?`uq.us?L/?;m??wE/e,n ?1IS2࿇i 4 /g/Q&KBwZUEglm?b%/4G?8!? tX2?4108ȯP?*/MqjH0uaG9N[)@IJpO]0TIɿ.cH8R?j1Mjl?ji?:k1gO ?+~t??K'\߿<1C;Et?Ǔ2,\?#7?2]5Ȼ- ?!ز ֨?D՟گDW29\LJlQݿ֌!?)A٥2_sMy?+<ǿxm2,]ѻ?6%J[Dgqz_?cC3d?lW,\m?k?3U6ڕ; ho?e+3. J?{Z”#.4_<ob0.?D%?T}4?$ ?)4R:4,|?3M3f?5:}523?0̳ S?\i5\?J:Ֆ?0}No??5٨vYXA~;60?Ѽw @TzGƿT6Rxs?-\oTm?1~s2Bÿ,d6а]C?#/)"|{36e5?i)VraF?č@7ft $k {?ғ 5V"7w~뿍 _?tQd @h7dӿk`(EdxK,8ܾ='I?6 z8@ҖFsֿ}8?\ ?Ut8O˅9?̒Ґmſ, 9׉?*S'phۿ]LWܿf9zbL򿃄?m6)ؿBO29;MX?RM\ˡn?:ji;#D?a;4?B ?;v0? eB?7~N?kHB;ST ??PA?)<olݟ@pOӿ b]b9? kkx<U39?>:J^B?:"ȿX<@ֽ?% `*?7=AI? s\k)d=XQP!@E=H^UY?eT?|&AR> ĕ@ѿdk?ea& ?2d{>Kt?I_?Sk0P>3տ"/6DO?~ԿІ;?5:?deLl-ſH?9?ͿǤWdvʒsn?Ec"棽Thi?:b'@&"?gٓQX? u@ J@^cO?OS?[]@ifL?mELa?:UA,/ <ؿ(? +WE?aAK ?/D߿m|eHIA_#z@e"w.bAÀۿߵ'?3rMB($ۿ9tbr5BrhcKޯ w]dzVBGg ??8&F!#N%M{?cΖ&FKʊ?Y[?-.H?H6G|=a5P Nǿ%OG |?lz=?m+\?tkG|dP3nT yb<ݿx"Hr܆i⬁ <߿.["? qHW!߿K-^V?0 W,d-LM\ @Nt)>BZڿ)N M_RͿ#9b?uXVZM8i!?Lflg?Q4M#$aIf@ulᐟ^?M80?sޟ?e}VFNmԴ>X?ƾt{Y ;?>訔N/V?}ScƿF˿y=N+Kʿ$e*\?~? 1O)pZL?p \@+fO=\~?5#_tz-O@A?K桥rz?*M< ?ɾPw\d?w^ū?MNpݡP$lP`уeӿR*֥?m2 ?gḺP*_;db$8S&|rM Qa{=q?鸒?fF"?WQ-!ge?ŬTr@V-?TvQ+׿>ғ?& Q>? Qvir>\:?CRّ 6OC?et?AI4R/>Lg?k 힁?R/єI?ձ>l?pnk]/SQYuڟ)"?#޷?.}S嵺}SN)˿ڬ0C?]Y?TCX? WOs)?-[?iT?y H?qԟ>p?jBDT>0CDS?`?U$MH?z<\,c]emUUK@?rÞR?WU;j>?OA?"z)ɿU+jZMCܿb俌x~?G KZ,jU"?_Z|BBw?Yf1v?j?-t*[f7iB)O?[4y[_6_? 俛pĕJ2?P[yd V?aӿ"Sɒ1\ohĎyʿd4)?!sd\kZ9=&6dp[\^?w?Z"*~࿲KD]sʣ?&\??'P]ǝja?M7?K6s<}]]4횡ı,Evc޿zG+I]!gEw?G?p?~tGu?A<^*m3OĿ?{i?Jl֊^WNt?!*?Kn@j^5ϳS鿖Uo$8Ҽ'_n;˙V?P??7 v_;0Ν Y?'y߰?(_@Z%??B`Ԕ?qw ?!͕$Qb`\C.[?%FF޿g?se`J1it?@qz`#? [鿴E5Q?NaMOk]hQ2,.?`aN6?fM?su?8a<߶gV7%5?;9bښ"h?h9 _q 3?MabQ? b^׿Z?^bbCW?aWԸ%cS?ڀ޿:^k?:tcu{?F?Psc8e?K|Q#`l?أHd\AD2)?Wjl'5_d~?cawAL?X\ؿvqdf9ҿh?([ۊ?Wd~+oc+?O?~#.?Ke95xY\]޿CZTm?cz/eu@?p. \mο e;zE? Q'C()<Ý?X7fJ&%?]DEݶDCҿP.f Q 翈h?3"?f=w??ҿP#g@:?2!?*h]h-?z&/>?D 0aɿy'h??jhpſnY)ȸh2w)ܿh ?ʊ}EgܿJ&Ii5B?Zx?]Ifۺiuxh?Y޺3fM?lOiٯ?Fpl?I2Ѧ4jb5߿G?឵?Sxj0i?h?d johI?iL]r5 k:^ҹc?@SAP3@C6ok7΋۹? =?::ÿʽkv?;?:H̿e_ lՆ,|?BȷpB @?-ZlVjrb#ӿ϶ܿ|lv|xM鿲>l?F[ "϶?=ºʿFm|^?XV̓K?il'vt.AR2|,?)uR?3 VtaH^w?G4b? χٿJt:/?at ?3tv^?|[?tAm|? mAu EF??=3o\u7[T?'?d!?u/ k??` ʀݿqV? !-vY 3e(XA}迯9yJ?\|v HXſPZ^?*!DB?Cv?_ /1?CwlՍv?ËLJ;ԿIfgw[N~JХ)޿kv ?lw9E{S̿GW?x ? B h6Sxrmq k޿,e?*x??Csc뿳 ??~ KE?ZS,7f?Z0EDseVWi>O(bu4Z/|w??Yq?.nT1=J b?7Ï4~"f?<ܬN:i32 2LTdv@<hmAw~B?Jjox[^?C.m@$ ^)j:87F?Ƞ@SX?x!OIֿpk?pT?Dzׁ%i?D[ z?ϫ1?D(&260z?^?A}k?eռtx1Cm⿞iv?^_տfQÂ\%Q|o п47 Eſ6[࿍4m?u~?Rz`d`OÙF?zM>? 0 SV"5&6H?epj[E?׿֞{-ÿ?=8LCX, ?? bTREEeHEAPXaindexH_a PTITLE+Indexes container for table /df_table/table (CLASSTINDEX (VERSION1.0fpTREExj@y8HEAPh{|P (VERSION1.1SNODbc8eP 8TITLEIndex for index column (CLASSINDEX (VERSION2.1 0 FILTERS@ 8 superblocksize@ 8 blocksize@ 8 slicesize  8 chunksize  8 optlevel  8 reduction  (k 8shuffledeflate!Y 0CLASS INDEXARRAYSNOD0(s(xqxlXz@Xv@ (VERSION1.1 0TITLE Sorted Values 0 EXTDIM  (  8shuffledeflate!Y 0CLASS INDEXARRAY (VERSION1.1 8TITLENumber of chunk in table 0 EXTDIM  (@ 8shuffledeflate!Y 0CLASS CACHEARRAY (VERSION1.1 0TITLE Range Values 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Median ranges 0 EXTDIM  (@ 8shuffledeflate!Y 0CLASS CACHEARRAY (VERSION1.1 0TITLEBoundary Values 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Start bounds 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE End bounds 0 EXTDIM  @ 8shuffledeflate !Y (CLASSEARRAY (VERSION1.1 0TITLE Median bounds 0 EXTDIM  Hz 8shuffledeflate}!Y 0CLASS LASTROWARRAYSNOD o0nhiHw8t|X (VERSION1.1 @TITLELast Row sorted values + boundsXeH 8shuffledeflateȅ!Y 0CLASS LASTROWARRAYsortedindicesrangesmrangesboundsaboundszboundsmboundssortedLRindicesLRH@}X 0TITLELast Row indices@ 8 nelements m 8 nelements mTREE TREE)c8e 0 DIRTY ViTables-3.0.0/examples/timeseries/scikits_test1.hdf5000066400000000000000000000333361311223072700225610ustar00rootroot00000000000000HDF  6` TREEHEAPXexamples@ HTITLE&Example table with csikits time series (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.00TREE( HEAPXExample_1@SNOD(Pp 0TITLE Test Data (CLASSGROUP (VERSION1.08 @ _dates _data _maskmp  JSNODTREE  0CLASSTimeSeriesTable (VERSION2.6 (TITLE 0 NROWS@m 0 FIELD_0_NAME_dates 0 FIELD_1_NAME_data 0 FIELD_2_NAME_mask 8 FIELD_0_FILL  8 FIELD_1_FILL  8 FIELD_2_FILL (FLAVORnumpy special_attrs(dp1 S'recshape' p2 (tsS'_baseclass' p3 cnumpy ndarray p4 sS'_hardmask' p5 I00 sS'_optinfo' p6 (dp7 sS'freq' p8 I6000 sS'_fill_value' p9 Ns.0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 !1 "1 #1 $1 %1 &1 '1 (1 ) 1 * 1 + 1 , 1 - 1 .1 /1 01 11 21 31 41 51 61 71 81 91 :1 ;1 <1 =1 >1 ?1 @ 1 A!1 B"1 C#1 D$1 E%1 F&1 G'1 H(1 I)1 J*1 K+1 L,1 M-1 N.1 O/1 P01 Q11 R21 S31 T41 U51 V61 W71 X81 Y91 Z:1 [;1 \<1 ]=1 ^>1 _?1 `@1 aA1 bB1 cC1 dD1 eE1 fF1 gG1 hH1 iI1 jJ1 kK1 lL1 mM1 nN1 oO1 pP1 qQ1 rR1 sS1 tT1 uU1 vV1 wW1 xX1 yY1 zZ1 {[1 |\1 }]1 ~^1 _1 `1 a1 b1 c1 d1 e1 f1 g1 h1 i1 j1 k1 l1 m1 n1 o1 p1 q1 r1 s1 t1 u1 v1 w1 x1 y1 z1 {1 |1 }1 ~1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 !2 "2 #2 $2 %2 &2 '2 (2 ) 2 * 2 + 2 , 2 - 2 .2 /2 02 12 22 32 42 52 62 72 82 92 :2 ;2 <2 =2 >2 ?2 @ 2 A!2 B"2 C#2 D$2 E%2 F&2 G'2 H(2 I)2 J*2 K+2 L,2 M-2 N.2 O/2 P02 Q12 R22 S32 T42 U52 V62 W72 X82 Y92 Z:2 [;2 \<2 ]=2 ^>2 _?2 `@2 aA2 bB2 cC2 dD2 eE2 fF2 gG2 hH2 iI2 jJ2 kK2 lL2 mViTables-3.0.0/examples/timeseries/scikits_test2.hdf5000066400000000000000000000333761311223072700225660ustar00rootroot00000000000000HDF  6` TREEHEAPXexamples@ HTITLE&Example table with csikits time series (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.00TREE8 HEAPXExample_2@SNOD(Pp 0TITLE Test Data (CLASSGROUP (VERSION1.0HP  _dates _data ?@4 4_mask  v JSNODTREEv  0CLASSTimeSeriesTable (VERSION2.6 (TITLE 0 NROWS@ 0 FIELD_0_NAME_dates 0 FIELD_1_NAME_data 0 FIELD_2_NAME_mask 8 FIELD_0_FILL  @ FIELD_1_FILL ?@4 4 8 FIELD_2_FILL (FLAVORnumpy special_attrs(dp1 S'recshape' p2 (tsS'_baseclass' p3 cnumpy ndarray p4 sS'_hardmask' p5 I00 sS'_optinfo' p6 (dp7 sS'freq' p8 I5000 sS'_fill_value' p9 Ns.9=0?@:9]?@;<`?@<4q?@=99L>@>yp>@?@A&Ǚ6>@B!=@DA=@E&cN<@F.'6=@G;l+=@H6'>@I{V>@JJ+=@K@>@LkN3>@MlI>@N(\>@O=@P$f =@Q }ج<@RB <@Sׅ @g=@TZOFz=@U/W=@V}^=@XUi/<@Y_ );@Z`:@[e)3:@\|k:@]И;@^PkC ;@_Sv>2:@``9@aK{;@buJ <@cV)=@dGUC=@egBGx=@fr@ >@g[ <@hJgJl<@i;@jg/Wh;@kZ'Z<@l?)<@m3';@n[*);@ok;@p47B;@q9,:@ra; ;@snZ;@u2wa:@v]u(;@wAٴ:@x=cx8:@yTE=;@zUB$9@{5˗:@|2]9p9@}ѯS19@~},9@Y} 9@ w9@yP;@';@ȏB^;@.]:@O:@DV:@?[Fyr9@E":@ 9@48@q(]9@.Q9@e@ 8@Yٌ7@= ףp=7@o548@(|Jt9@`YI9@W@^*8@:@]V_:@bo:@JԊ;@*1;@:@99@6NY:@CdAQ9@E_h`9@$8@Zo8@#y8@u^8@ mO7@w!M8@d+o8@՛%3@*3@5 3@ѯ1@}O43@]B2@D@3@*=83@{]|2@V1@!q0@Mn_0@>j1@Ż/_/@#^'>0@Z0@=tXO0@qq/@sR,@Qt0@I1@U>0@d:0@-F0-@lH0@K0@|0@4;G%1@x1@ISJ0@_Gԩj0@vuZ0@+X.@4Ѡ90@Wm/@;J0@KrW&0@=0@"j0@@'5/@:w~-@'Fx-@I%80@CdK/@@o/@} Wל.@-AV\)@z%6(@7lF*@Y^NDk)@3.)@䏖p(@jQ(@"$'@L{(@Xpsm)@2I1*@A,'^,@3 (@bi]M)@W$T)@O)@m۶mk*@*@ (;-@ O&+@ F.T}.@ kQ-@ uN-@#q.@Lml.@~ 0@`QY0@ x0@D:0@GK[0@/@&2/@-QmLc/@ÃB0@W*t0@ʡE0@umM0@`(+?0@rSPG1@eOn1@fffff1@ 5afD2@!WDJP2@#(TK2@$C}3@%s 2@&OG1@'h1@(&8*0@)7o0@*˨/@+HF/@,3[e0@-w</@. /@/=r"Fw20@0@/@1t>.@23.@3͙U .@4KN.@6~.@7sk-@8UJ-@9-K+@;g,@<1F -@=-@>}//@?Lgӗ.@@3u8.@Ax_IqW.@BO/@CBeXY:E/@D1f/@Eʐk/@FY.@Hu1,@Ib[Ag,@JMXs-@KiJ-@LgHu+@MB=ގI,@N2+e,@O1-@PRAk+@QwNV+@R;=+@S^eh,@Tmf+@U=.+@VU*@WV^r+@X"y@+@Y41W+@Z:wL<+@\DzD-@]RC`K.@^y%6t.@_Ib.@`JJ0-@a!-@b\u-@c@Y5-@d'WNG.@el.@fd-@gML-@hg).@iB/J,@jҥJe,@k4o+Uy,@ls2,@m}B0a-@nsI /@oU3T.@pj20@q\3 0@r/@sq>80@tNÊ00@u /@v) 0@w|$i/@xC̨/@y13333-@z:k5-@{P.@|$m/@}m7v#o/@~ x40@F j/@g.@<[x.@0 .@DL!c-@(\.@0@zo/6 0@+s0@,N0@ 0=>0@A7A1@V6'n0@ɷdBZ0@Z"0@zj0@a`0@ْ 彊0@Аi(-1@pwk0@)g61@$1ן0@rlA1@Te1@6V1@c&e1@S1@#1@2<1@>0@ ~0@[>"0@<0@Ǧӯ0@=c۷1@K#%1@x2@YM2@8-2@(By 2@I$I2@J}4@?BD3@0s3@X=M73@ۤ3@})v 3@;03@>3@V@ 53@oXT3@ӱ+dL 3@{2@U1@-vS2@c+ 2@3IoMy2@ 92@g" HŠ2@L;V3@t3@6b3@9`b4@(H$4@×4@(l4@pĩ5@>5@W 6@AeA 6@Dug6@Y"K5@v!5@LA05@C~t6@ٍ'N5@{Y(>6@-{O&6@¤;06@_e#6@\. 6@m;6@I!eup6@.N*ň5@ZYb5@#fN5@]_5@*b5@"q5@'6@tmj6@=m6@[ 7@{Z7@U47@l(9@=8@Qy8@j8@~O9@j)z,9@W:9@ Ék9@VL9@@9@C*N9@uX9@$h9@NTay8@X9в8@s(IUP9@9@*9@)SO9@,-:@O-9@`ƀy9@yu9@% +8@?8@o8@^E+9@,m58@@qň9@Lr%:@4h:@d O):@:Ib:@ n%:@8%:@/İp;@ƂXɂ;@VE=@0eN#<@ v1.<@ r=<@  /{<@ >#b<@ jEN;;@;@TD ;@o E<@'a{ =@v᪺=@gl=@/=@nU֤K>@3$L>@gçM>@^]>@F~g>@Bp=@hL>@uN>@(1?>@?C<@Qe!y=@ I|S<@!sM<@"d<@#J@ViTables-3.0.0/examples/timeseries/scikits_test3.hdf5000066400000000000000000000333761311223072700225670ustar00rootroot00000000000000HDF  6` TREEHEAPXexamples@ HTITLE&Example table with csikits time series (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.00TREE8 HEAPXExample_3@SNOD(Pp 0TITLE Test Data (CLASSGROUP (VERSION1.0HP  _dates _data ?@4 4_mask , v JSNODTREEv  0CLASSTimeSeriesTable (VERSION2.6 (TITLE 0 NROWS@, 0 FIELD_0_NAME_dates 0 FIELD_1_NAME_data 0 FIELD_2_NAME_mask 8 FIELD_0_FILL  @ FIELD_1_FILL ?@4 4 8 FIELD_2_FILL (FLAVORnumpy special_attrs(dp1 S'recshape' p2 (tsS'_baseclass' p3 cnumpy ndarray p4 sS'_hardmask' p5 I00 sS'_optinfo' p6 (dp7 sS'freq' p8 I3000 sS'_fill_value' p9 Ns.\6m?\d\5>?\9!2?\<>M?\Qu?\?\#~M?\?\}no?\";?\ӫLu?\xNM?\G: 0?\MќQ?\cF?\G?\F~C?\ %^,?\,bpf?\f]_?\K!?\,R2?\gjV?\AbS?\6Hh?\ E?\ gR!?\_C8?\6٪?\䛇Q?\@Y?\{zQ?\sS?\öiQt?\hX?]ʶ7?]?{ܪ!U?]%2U?]a]?]}T?]6T?]^D,?]m~I;?]/HL? ]1T? ]զe? ]wY? ] ? ]r ?]$?]/V?]w}?]&r?]u?]F+&)?]0?]笘?]4ri$?]M/?]T,v?]`߃?]QOŠ?]#GF?]o?]X|L?]&te. ?]c<_(5? ]?']hT-/?(]8N?)]V4Nh?*]&?+]?,]=V?-]~ֳ?.] =p?/]ۡBG?0]\,?1]?2]PL?3]A?4] ?/?5]Z ?6]LA?7]??8]7U?9]^?:]'6?;]>oq?<]s?=]9#?>]Fr??]'89?@]j L.|?A])  q?B]TZjo?C]TXo?D]y/!Q)?E]NE?F].Fy?G]J4[?H]xc?I]Rǎ?J]*:q"?K]=g?L]u@f?M];h?N].X?O]Q?P] 9 ?Q]FFG?R]1?S]EX_J?T]i'?U]F(#}?V] {-?W]xF?X]5z?Y]&x?Z]yjX?[]}7\?\]5Oo?]]Vu?^]vnL?_]A?`] ?a]ԇY???b]Jc/ ?c]#,_c?d]эc }?e]X[ ?f]Ul3E?g]K: ?h]\'^?i]fM!?j]9#(?k]Vv?l]n?m]u?n]XP?o] L?p]Ԟ&?q]wj?r]fܑo?s]" /S?t]X?u]p>?v].c?w]S?x]DX/[?y]L?z]?{]~S?|]񔼄?}]{O˩?~]\?]Gϓ?]23%ǻ?]H'f_?]K?]u={?]l=+h?]:uK?]̰?]i?]!}?]l0رh?]B?] }z?]C87?] g?]?] !ʋ?]n|?]7R -?]< :?]e[?]h,E¦?]x>}?][@?]Ў?]/_x?]k8ő?]4~ ?]fa!?]T;?]?]X3$Z?]~4d?] _.?]$3O?]Pg1[?]ZQC!=?]|l?]3%?]*?]я?t?]"r.?] A|n?]ۀɛ?],?U?]G_?]06p?]yJ?]^CN ?]Ʒ>y?]4)SҞ?]B_?]@?]tB8k?]hhV?].\?]?]y7?]z,@?])*:&?]D`?]9RU?]qL1G?]nٹe?]kş?],Ztѱ?]JB?](I?]TvB?] Fdʲ?]/ϥ?]/]=?]?],2?]O?]=qS?]wW#?]R:?]0q8j?]JU '?]9pf?^A?^37F?^?^>)?^m M?^2S?^?^gs5?^n ?ViTables-3.0.0/examples/timeseries/table_ts.h5000066400000000000000000000271601311223072700212510ustar00rootroot00000000000000HDF  p.` TREEHEAPXParticles@ @TITLEExample Table with time series (CLASSGROUP (VERSION1.0 8PYTABLES_FORMAT_VERSION2.1(TREE HEAPXTParticle@SNOD Hh (TITLE (CLASSGROUP (VERSION1.0(+lati Time@pressure  ?@4 4ID Int16 Int64"@Bool*P H 8shuffle+deflate+I1RSNODp (CLASSTABLE (VERSION2.7 8TITLESample set of particles 0 FIELD_0_NAMElati 0 FIELD_1_NAMETime 0 FIELD_2_NAMEpressure 0 FIELD_3_NAMEID 0 FIELD_4_NAMEInt16 0 FIELD_5_NAMEInt64 0 FIELD_6_NAMEBool 8 FIELD_0_FILL  @ FIELD_1_FILL ?@4 4 @ FIELD_2_FILL ?@4 4 0 FIELD_3_FILL 8 FIELD_4_FILL  8 FIELD_5_FILL@ 8 FIELD_6_FILL 0 NROWS@pTREELM $!O)+xXf "*"Sܸ ƽq{ZkUkjTDQEEqahCL <\r|Br3042V)[Ԭy*WZz,j[ױ[m;4iج'N.jn-=Z}ںM[O/o_?аȨv;tԹKטn{ջO~?8aaG8zq'L4yiӓf̜5{y,\xeW\:ugk?_/7|M|yw[Ï?m߱]{o{߷<9r_Mڱ'N:}&.^|7nʺ}'y?z/^z]dccScH9FcL9*1#͇E`o k  (@gEF z\V*pY .粢yrrr)'rPC3ƀ_ p0ZZePho/sWhqKwXݸxb.救FʠVǦS|a.=nXݸxb/旉'k VӘ۬PCIba5@vzn@l`~@#ٝ}gڧ߀L )d~F},1?UG-qQi6t7>9u#م2fm/C f_v֝{iN_%+ۏQ5ll4wqk' $"SLϾCG0%iv¥+׬۰i˶;xg/xğm:ի7.ȼQ2n 6rh  bhǠ}MP{ Y}w. ]b1tgГCo>,}Yg{2%%e0K,Xc$Q<y1Xx1DxL1T.@3),f 0G$ "< @,`HdHdHVdHV/t``l|- ͅ;֭vhђÝÃ,Y[e bC,am@ kHXpN‚@pX`23@bWN:HM$?Ȋ0"A6~d W..WdtEFt *sHIW}"/]U!.jn-=d8@?xVC1cQQ/zW69@a+aa` 㙳f2k{`~d/j_Y6~in~ؽg?9z'Nz!#GFEv/_ǵ1޸yw}=OH|$5-iFfֳy/ _*}]W𦱩O'/&O؄!|,[b5oܴevw#ǎ<}bnܺ}ރqI)Yٹy%eյu ͭ=}>1h @ ",b!"*b\ sbsQb.z(sA @ h/`+dԏ)Ȏ)ȒaT\bՠ&O`)vLs{aI0RpKp$^l[+aoør1?^%66<[%sWB| @ @ @ @ @@lܣI)ORҟfdf=}_𢰨eIi٫ʪu o[Z;:1$$FH3Y2lH9yQJʣUTƨkh?hD3s {B'9MvvqusIG^H???8?ibdMx“Q[ @ZgquWgpu Wȹ:t>'癄g~r^lOsAC: @ @ @ @H@ !؜,x}XMw̌ݚaffffv3ü 33Y30o3#fffI$I$I$I*I^쏝}r}O<{>==snF7snλBeXk>Qulǧ>]~g>7yi-Z/ymN:bzk^ܥݺ}րΐw7ᨏ>ɘO8iO~6_rW͜o~7o.Zd+VZÚn?oe[~?<{g~{p `С!GB ?q"dԩ1gbƝ?p!bҥ)WR]K`@m% ZO#xT  #:=V'F).l  z.+ .+q.+*TVEW,x%W*xeW i @@A @6*<IYi@ e-xl{@VI 0@*9A!aQ1q I)iY9yE%e65j֪m8֭נaM6o٪u:ԱSzݷ 6|(cM4e3fΚ=g /]r7nڼe6O/o_>Qop;,i-. cv B 8X !`qrU=! ɱ(eiPO3ɐ<e@ii_4. diHBZ%'AzVȸ&k brv_f`8}q%B@@@@@@@@?@CC ;~BŤKɗS^My=F͜[-(,*.)-+VL Wg[m ZO#xh5ɂWD@@G-yNpvSde?8o'y?8༃7>}@@@@@@@@/@!xUPGPF݅*PwwoO͙molrp&ow첻q\v[ܽwG<}W߼}OtNI&K"eiҦKMopϘ)sٲș+w(XpŊ5K*]l*V\j5j֪]n 6jܤi-ZjݦmA:v ܥk=zݧo?˟_CqUG@@깬*jsYL&A^u>}xl57,Ob^lO@v@P ٝB@4#@kfQF@ttbfhF̢ dw>)<> <>IvD(Hc3 FO≵Fdw~AЌ7 \ dwhY!(u+ă +zQ q os|;:??mJ,%-o$!y#)q XKĶ*o$Z@H􋼑hGy#ٝk3{x2ҼE&Hؚ6' gA$i)RJ&m]\2gɚ-{rɛ/ )Zx qhR˔-PBJTVFZԭW?AF4mּEV۴m>CNtֽG^A 6|Qnj7~IL6}Y̝7ECB,]!  sUiUqԪ{氖U_ǀ߀ǟb&ÿبsȷű粒|rŶ´򷘆XðٿÚu )̷ԻȹʴW-%.{߲]J4 -40d鼫ՙӺ] ,6633NbӒ_YFZ jo;470 g,Va(ek(Xt753" c#y}H&zQק@52$ hH3r0<{9LY62"H[k/A]- p60&Kw{Frk' !n8) }ܞ>(h$9Q3 `˰s%?;# 4>(ۺN:ղm6Yfa~KʫʐH+XtwUt㧤зuPŴr3ǹnZG5+7²vgZK7 EpxjU>! Ǒ ǯU?ϴɩ̀ Ժ̿׿ƫU|ʯu0б׻sÕ(5˴n>e_jK4.|\ͼQ  ]?QLadYMB+# Kc  Tk#^Ep[ 3yaN wF>/B{`p4}E",uI zٺT.R\t~,+ y H(sGƃ& &9ـm]݃ qGmeM  Lɠsh% ڞf[ځP }Ąx4_7gʀŲM& DY 0]YӶ~2 *_!ūn7ɨ ȚkIWv* ŗ ¯fhټ֡…övD܀ ﭿҽ ~[̀õqWC2&zϼueN1mkXB-  _taM3<% mm ms?wq}U۾!ԥ: ܪp  峟 𿠛vM Τz ߀ߣ ᯙ~Ug̀ﭻݱ뻜kMĢn#1ƭΤx$Ͱޯר{U|߰ݹRᯡj`֨Φӂȩـ뵓v2" 2ݧӨɱhD+"2/ Ā鯸Ӂ_]I2 -5313 fȡ ɣ,/5544/3MԳe@@'7453-4/iz+(|D I453+3RxoBp~JUv"7̒J5/"!t{~0o#!ve {~>4560KaY X4|FO֬N4561M9 y @ Io"we8460t# z!c` 6@360 Lowl:a-~L gH37/.U\F= H|B %N47$ m"}{&az<;؀H50Нmpx8 M>6*r̤%y9 Sb84Lʡ˪z; VH5$۞K Kf9*~Ąx +m8DM"hˀƴM' 8صi9T]YӶ~2 #\FGʬn:ɩ ȚjNlx* ǘ fiٽ֢ÅĶvD܀ ﮿Ӿ ~[̀ĶqXC3&{ϼveN2nkXC.  _uaN3 =% ‘ ½ʽ ̀π¢ŪDZN˼  ç Ɵa Ɯ Ƣwɫbۀζ$@ο3$ ğUԀ ʹzӼC?h DɱuW8`m߀l^I2=|f .;|fbɶ^:Vo^QC%bHĺՎ+CXLC6.'"   2xuf LK:72 7wzw  IZ"tL ^D`$<C ea @&+8 \g">ɼpbP4$ɾ~pbTF5) ȸ~q^PC5)  ^ź}l_PA4) 2pvj[N?4& it320H-_ewU2Ufㄝ{xfUńJ܄mj? ӄX넝vݞЈUǬ䁝י̄;}ƚђㄝgU~"ЁЉё䁝Ńs܄OQ֚p$ňϿ̊ґ⁝Ёô҃uɱÃӄ*R҅ꄝ]%ҁ̊⁝ ǸyՈ遝˄xĈŶ̃S˽߁ㄝD'iöxÐăUЁщ܃*そU„ǁ͏sy Ѣāߋ偝UӁЋӃ-䁝؏Ёщꂝu ӈځそjK3yÉ꼏f?W zQ, ,ЁŏjЁӌϊ{߁č  X҈ƁЎu /ˆそJ|nGWYY ؎,82O߰Rr8uт }t M:"'  $l`` HX1b8 ]݆"ѕ@n)ρޓ& =vv$KŠ+nN* !ŒՓr7v҉2kI5AT*Ó.߉Î}ב’&#Bq\Žv+t }F`A?1DO/{N IǑjH<Ā͂ߑ>kɑ,3}:3Y!d$Zn(Y5ݒݑ ̈ƂՊX흝؁dS<#8, R[,܈Ɂ܃䈭0,fˈ؁̔Ґ?聝 睝:uj gø9 |-Bڈāߓl ~XˈՁЏʴnՇ ~|䁝¬S"} iйa.&ނFZ.BDZa)郝bֿw+N{ڈCCiʆ̨R'y܂귂Cŧږ^-jK꽠Ѿn݊ͻjʷCـ꿁ƴ ɀӁ̘ð[遝ҿvlϼE˸zeRC,ǵ}hO7؎űmU<$ llj¯rYA)FѾx`H/ͻ}fN4kS;# npY@(Hw_G.|eL3jQ: npX?'Kv^E-H-_hyU5Ufㄞ}xfUńL܄mj? Մ[넞xޟшUɭ䁞י̈́;}ǚҒㄞgU"сщґ䁞Ńt⁞܄OQךp$ƈϿ̊ґ⁞сĵ҃vʱăՄ*U҅²넞]%Ӂ͊⁞ ǹyֈ遞̄xňŷ̃T̽ㄞD'köyĐŃVЁщ܃*䁞UÄɁϏsy ѤŁ偞WՁыՃ-䁞Œ؏Ё҉ꂞu 23ӈځぞjL3,531zÉ꼏f? 52*W zQ, 530,сŏk450сՌЋ.51|ō ,50Y҈ƁЎu5*/ˆ䁞J 452Ĺ~ *50}nߨ1H-5&ZY ؀ ɼqj%Y5/2O Ϙ+;Ӏ65 ֶHot[q85. ~<(!҂952Uvqnp} 7pSK5!2Qo`y2 <o5)30SJ5/l FJ^![53lszʉ\5==e'F}5R9(RJ5W~gz}ot5D[F>Ɍ57&F!FP5fD{t ݀5peMyө5 e_";YoĈ50e>b<Ŋ>52Af%2U!5U5+"FiO) fi5#$Ilh6e52f~kXt͋]52S K|i$V5)~;).\R؀L5\ nͮ.Q6526ބˬOGә5# ͈͓gnGˍn52퀞GJD5 d6 M ׂ51>#Q߀R5 RZ޾T%Ӧ5&݈Ɂ܃䈭ܼ](R5/f̈؁̍ٹm 5?遞ÉӾ;5 螞[5*`z5; gù9 ʊ5;-B܈Łߓli659YˈՁЏʵo85A|䁞­S"˅65Jiлb/ b57{.BDza mә>5Vꃞbw+Z@5M}ڈC/5ljʆͩR55T뷂CŨږ^-¯K뾡Ѿn݊ͻkʷDـ뿁Ƶ ɀՁ̘ı[遞xmнF̹{fUC,ɶ~iP7؎ŲnU<$ mlj¯sZB)GѾy`H/ͼ~gN6lT;# orYB(Hx_G/}fM3kS: pqX?'Kw_F-mǁȆƋ<ǐǕǚȟȤFȩȟȜ˃ǘӃȕ߄bǒȐōЃlj܃-ȆvÇˀ̃kՒ܉؃́щN݁сmؚՒ܁-Ϛ́Ӄ݁܉߃Ցщfh́с.݁܁Ѓ׈Ҋ֑܃ωс́Շ߃6j܁݁͌׃z1 ˒σ̃؊́˖׃߈ˀͅЛàk׉Ձ̖܉X3͉݁ϖщ˖сӃ͘Ձߐځ߃nϒА6֌ҁ܉mޅЁъЃ ߁Րс܃óځ8݌܁Ռڏ܈ӆaB$ z_މ̀̌ˀт꼏f?Yzr։Ձց ƦzQ, ,9͉݁ߏʈ Џ  }ߍс)lr׍w@x>ވˀύJՏWՉӁʶռt^I6"ṗѲ_AqtY عdH0 `@O ƗiSF6 :]„࿞s"} ɲ~fM6&'^Krr]r<k2*6Q \PiRvSfyUQcLUG1|E3]ʲCeoKLpCw ɮ֋GD EЄB t%_ ǂe08KڈǛh8zZ҈t #Nс#2jEǂف RXj+j䈭d&fKj ^!/+QڈڑFZ TɁ҈Ғ_sπAׁ?-;T߁qrǁˍ&ʞڈ݋҃k,6ĀшՆ͊~< Wɂ=T̀̂ˍa%~Ձюw+0~̂ށˎC~ׂЎZ?؂ VقЍږ^-˅dр̌ҋАϕYЁ̛݁,ˠxـؓ˥Јˀ͎ѫ[ӀϫjX:ͩgF'̧«mN/˥ŲtU6[؄ҥ|]>УfE$ˡlL-ǯsU3^{\;"dC#kK* ŬqR2b{Z:t8mk@5jf(]Q Dy" 7l]*` S! F|( 9oL,b} U H~% ;q0/d]"W J!  >s'1f>Hp  s#E+ 3Q&C *L )L%$Fo4 >ed 5[ -R" %Hq( >fB 6\u .R &Ir$ ?g- 6]V.R &Is  @g& 7]8.Ri&Is  @g"  7^(.SA'Iu @h6 7^o.S'Ju @h 7^[/T#'Jw  @h\ 7^ /TG &(Jwp !Ai# lrd  1' 08?(D"2G$:I%>I%?gJ%94.*%! 4Zƻ|vpjd^WQKF@:50+&" +Ov|wqke_XRLFA<61,'# #Cg~ysmgaZTNHC=72-($   4Smytnhb[UOIC>94.)%! $:O[^[VQKE@:4/+&"  #/6741+'"   ViTables-3.0.0/macosxapp/ViTables.png000066400000000000000000000235451311223072700174440ustar00rootroot00000000000000PNG  IHDR>abKGD pHYs B(xtIME(M- IDATx}yt[^e{cg#BCPt -KKiC.Я=27ҁi) B)$$$MN8 my-K^dZv{}vɺslw~WOJoo r=aR3=L&uJJ6^aV_˒3ΔϟI/gu2T2K <"8,8/D+y~{A u$aqYl?<DJuƍU@/1hD ZY:mI#D 4iJ!T4 aJ)jIxyɊn#p8(9qCIr C67z{M ,xB.߶@1-P== ,_͗ FPd*PqqU@7 b4< <VdIÉ25oڶС/A`&p`uؑ-, p|\R(|7AQ^oj2{T$(--{PTe p(/˾dL$UT^spTp#%Y"NV.uy KU9M\eP@&p< D>:~ÂBAA$M g? k>7FS|Ʌ hlZ$IZmRF\B(Z,I=z@0g1(1z(R!I !.TNVN'gZ "41:'gNI^}ᙲ|;v|_'F6PU".d VX-5:"e :I ##h4@EK6-^1L@8y@w( 労}_P@DQx}!|!//?7Z2z𔠵Zy\F _p4!Lz%&RL)+U<[$ Yflv{%pO^&R)#jkKvMMB<9/&:%b%u{7+(׀¢_~Y A / 3vPjP%48PfR'Ō!Z;w+g *?';mm{DPO˔ uJhY1GZ-CqOZEL;۽l_]@hy@sP(NdQYMZr\.0TWh^!3*,:fYU.am/b1 k  8Nttt$]]]QگEq*P| Jӵkíق m ܅ SH ~8-KDLFSH$Q_RM6DQfvtw'ގiOZ{͐|$HUG4;{̷+ U|zL\NXxy0р EvOaD"ʡl4 HӚhzᨳ#f<|}s8J )"S@(yAs?}ۢ _o(1S6_QVw<A|@n e&zEB+7ESs@>=NQ/H YUױ&HwijdO}}fg*Lg shk;6u RfӟM|-dGZͅMbiJ>wތ^z w>ݍ3^W4"XsCiQd '&h=~//>݈L&V!8s8H4!O< s'ŢE_pwQԿG{B!q/]r?H"MdİyBQN<Ãs  |>8pmmXb{F\So$5ﯾ sg|sS?$=1aє%Nȶ6|v~U@$ESᩧ‘#Gp94{-) (b}YXƁ7x־Jה;sh~W&/Cf.Po| g%RkӬ:h/7*uM+rl\>tGcJr%? ڥHm߯[4+~ ȱk C"7#O*w-ApUk7٣"Y~wUvVwߝq$+r+-=ѨR2IOޛ*Pro %"o>,LpeZ]Ij|ι#\אO(B,$k ^U}39qu v }'~Z?(oȼNo{K%g,/y-y\,zwߜ߹bq=Sd$-AL)~T(Q#oSk/1==v 2FP />[&hSյӀ?R})q3?M:w4kܹd>It&."VǶ˜>q]44ӜҎss=@p+9.^ ->^LC7q"3~Xc}~F \v'K pgQfG' eͿ0n*(w0Y'Ƚm Y0mgQ yHb岪1ǖ_+nҜz,;bޡVSPX^``wU,ҘPJfd^^:K'` ;@L N3@,l”eˁM!_/TK9Kk1@d:4 2p@fߨ~XmW`P{i{7pMð}FcsT?üc/,bYMd%>p 18Ӣ^bXHrp^qxȡ@몫>8(+BYY6n+Q9Y@fde1"Q@a?T =4N'zk?ѐq@EllT,́ ~92:I*g<|ʙ.'ھ7pd VKdFW|guQk z$ K{!Q64U RMY=5{wďF! 8`JnV+"i?i?*Y>@,F+]A`NUU:^]Y+O \WG'oL)n^uKFXX8?\ p ӝmBirڵsp:[׵/.w6\2 u&5Vڨg?|ºb 8qc< f…a>҃}\))/O9~j#n?!$uSS{6y~ V|'K b18cFcqZ@pP1N%Mxpa-:73>iw]TBkaH%B`(J bv;2qz} GX,;d2 :B$òͅ@^9q0Ȩx: tظ N|bO Gna`>@V-D<ӄ[ۦW-4-Lә.su'?ίE\:Wc|/EG+@t 00hT'YelٲO>$:::o>۷͈F3[=_َ[0M\zA޽ݾR XDB&Az Lm6R\[|J Ch>_x%i}-_i+ODNTCO dRCWf?C B믿}ރϗL"By sS:Y2a/ qu_Hl\[|a4\\ٔpN+15+Űb\6`kS6ԇK (֚s\TohXWܸ*rPdQRDM5:t O]|1G,F r;k(+1H 7rۅbAI ߍ25#j`۷R*  ab"{@AB͛oX~g*"X,{)`l>oszTd<\զ sIwEpT hӋPQU]<@P, ``˲|yT>=c/)Q%$\@  $8P좐x@,@B| "LC"!+rx4 ?JR>'p|cc#}lj۾pk<4-@,FCS@W-(1GB&>1Ⱥ8[F0:vnlC@7sA;4 .){߬˭|" ѧdnw`RNM'TccQ+5ll>wXNc.e]3&-Vħ4۝!M:F,ngpttl~jGY,f`F ǽϜ ,z1(,z/ qiR~&-zݡ1dx|CC}e}XܑLȜG(si 1N:~JfiRVCeTFF԰}7dt:|n3DXG#<v0`^aӃτW+rB?qrv;n1G89cQ+ő/ /PmNw[Hk$Y a`ad:1cBivƂVjxJlߐ귘}^,r:F(N4ǿG49Lsd|b r8)/[z. P9Y:SәPOiu}7F~/p##xy4L&9^8JH!ž …Aj9ob#+J {Nؘ-ˋ8$:D8m.g -˖iH/;5lgeX>OӱXMbr:LᓓTˎf%E>Bm$onVbIBO_.Ae_IENDB`ViTables-3.0.0/macosxapp/ViTables.xcf000066400000000000000000000540351311223072700174360ustar00rootroot00000000000000gimp xcf fileBB$gimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) ?k}z SVG composat     8}zP?_}zl"2I84 /+&!   " *  ѹ  ʬ   ˬ   ˬ     Ȭ ˬ ڬ    µ Ȼ ʬ ¶    ̬õ Ѭ ٱά  ۬   Ȭ           ˬ ج ج     Ь     %[m/c*f aM7 ttCvKq'84 /+&!   " *  Һ  ˭   ˭   ˭     ɭ ̭ ۭ   ® ö ȼ ʭ ·    ͭĶ ҭ ٲϭ  ܭ   ɭ           ˭ ٭ ٭     Э     & 嶣Cm/Ǽc*ר <\O 9- n JgDetD 'E, BY^r84/+&!    " *                                                          . ٿs'm/ūw\B(c*Ч|gYH.ʭ*ҿyaI6 38E{38n/+a+T &G}! :p.c!V I% =r* 0e.G36j6+655l5-544o4043 3 q3 23 2 2 s2 42 1 1 v1 71 0 0 x0 90 / / {/ ;/ ..}.>.---@-&,o~,hj,;<(<1-( !! "" ϬȬ۬  㭬   ¬  լ   Ȭ  ج   Ϭ     Ȭ جȬҾ۬˿ ķ¬ լ    Ǭ άج    ȬǬ ۬ ج   }_E+  ǠyR+  e>  Ǭ} כ /  ^   $ '   k   >K   K     28    \l  2 S 1-( !! "" ϭɭܭ  䮭   í  ֭   ɭ  ٭   ϭ     ȭ ٭ɭӾܭ̿ Ÿ­ խ    ȭ ϭح    ɭȭ ܭ ح FG  }`E+@GG ǠyR+ 3GGe>GGȭ~ FGG؜AG G/=G G,G G^ FGG$ż;GG\ ?*GG }5mGGN , ےHGG oKGG 1LGG _GG OG G g ^G G 1o G G1-( !! ""                                  %  Ʀ%  ۗuU4 ǠyR+ qдe>Cә : S ^ ܠ#$Dzr]H2#T't&M*2$-+8,_ ! -+ 4ie0'\,P'Cx !6kD)_{R !"!Y!!!"6"m"""#J###$($_$$$ %<%s%%&&P&&&'.'e''' (B(y(( )q@ ,+3+l**67T788P89699 :K::::64_<b JD~]G@ 6 Up<   Zt  ,cA}~MEm19m   𬬭 g& 3K Ĭf"o Ҭ険 ߬       ά  ܬ    Ų Ѿ ʷ ˬ նϵȯ   ʬ ɭ۬       Ͼ ̼ ɹƶǯ #*0"  PPx8f#L9fkzWoY,(J7*Zy&Wxa xs2NBxQ#v  5Di c:&{ Iy~lg_N:@ֻ "@Թc ֣z [ H 3- ŭf"nɯ ҭ険Ǭ ߭     ­  ϭ  ܭ    Ƴ ѿ ˸ ̭ ַ϶ɰ   ʭ ʮܭ       ³Ͽ ̼ ɺǷȰ #*0=X":ӿV9_+`3һݜ[/ؖU+xB( Ѫ{K$ ȇ! 3 f"l}< 険w6                               #*0======H=<;5: 0,e: I,O(Z('''N'&&&Q&%%%S%$$$U$###X##""Z""!!\!!  _  a"cœv$˥Z4" Ԯb=)ܷkF /etO)  P  ;/ 1   Th; ! 3     TRC  !b  \   Q  =E  w4      l   '    ->  >  B>      묬 M   }  8L       ̹g2,  0 u@ 6Y  n u'   :؊< b  . V   Vf# 8ìr?}˻"ɹ ƶó ͽ"ʺ'Ƿ-Ĵ21 +%+ 2.  pG G Y G G #( ^G G G GQ G G1ZdG G G G, ۷G Gm G GO QGG1G iGGy |GG xGG qGG|4 jGGpf `GGe HGG[ ۩GG[ہGG^WGGa GGe& fGGh5 ۴GGq9 fGGŪ GG NGG쭭 oGGt GGNcL GGN| IGGL KGGT̺g2&HGG^ vA /vGGJ u' ۩QGGj؊< nSGGa V AGGf#&GGhír?̼"ɹ ƶô ξ"˻'ȸ-ŵ21 +%* 2.  q .!  /O  0~ +D;H +e& +pd +|f*gy+ie+`i+Eq+*x+ +W +'5.K,_1+/3*D}+)$y_}r1 AZ"n "s$!TR ?)Ԟ7~=H ɐO k u'5؊< B V n'Rr?#"  "'--1 #%+2.a:::g999j887$777w655O43 323E3}334#4Z444575n5566K661ƠzU(*ϩ^8 #زfAổoJ$ĞxS- ͧ\6$ְd?*߹mH"1Q+->=Drop-Shadow y:0,x:4,r:5,o:75%     @-@IXX@yEKkKQVWWW?84 / !'.6* %-5=GQ[f% $+2;DNYdo{! ")19BLValx !'/7@JT^iu &-5>GQ\gr~ $+3;EOYdo{ #)19CLWbmx  !(/7@JT_ju  &-5>HR\gs~ (2o% 4b% +U%  #I}%  >o$ 4c$ +V$ #J~$ ?p#4c#+V# #J~# ?p"5c",W"   'N" %+-+&*L|!+=LVZXOC7/.;W!_3  -  ' %,4;AA:, ! #*2:CMXblrqcK. ")08AKV`kwjC"   '.6?IS]htǮU, %,4=FP[fq}Ød6 $+2;DNXcnzЦq@ ")09BLValwٲ~J# ?IS^iu༉T*r}ŕ_1짲 Ρk: իvC  ܶN% X, əc4 ѥo= ذ{G! ߺQ(!Ò\/!̞g8!өsA "۳K# "ὋU*"Ɨ`2"Ϣl;"֭xE #ݷO&#Y-#ʛe5#Ҧp> $ٱ|H" $߻S) $Ĕ^0 $͟i9 $ԪuB  %ܵL$  %⾌W+ %Șb3 %Уm<  &׮yF  &޸P' &‘[. &˜f6 &ӧrA '۴Q- 'hF3+'" 'Эk[UPH;+'ǬzhQ9$ 'üaD, 'ĬnN2'ѹxU6'~Y8'ƦX5 (Ȧ}S0)ŠtI') ܾg=) ԱV) ɠp)۸5ˡ6ڴz  /B X/n? P( 6QjueYU]s! 9Z}" 3XǾ"&Jw"5a" Ct"%M"(S")T1&P0 !Fx & 9g"*P 9`#Ad&?[v!4GXchgc^\`ht"-47730/18AMYgw %-8FYv "4Qz 7a(O Bt7g.Z&N Bt8g.Z&N Cu8h/[&N Cv8h/[&O Cv9i/\'P Dw9i0\'P Dw:j0]'P Ex:j0](Q Ex:k1^(Q Ex:iüvn/YĽxph`YQJC<#FozrjbZSLE>71,'" 0Niy}zsld\UMF?93-(# /?HJFA:4.)$  7788999::::::9998877߼6ԫ6Ř5س4ǜj4ֱR3g<2ͧzL(2ֵ\42i@!2ʤvK)2׳X2 2ȝl? 2༌X/2ݷP'2޸P'2⾌V+2Ɩ`22Ρk:2֬vC 2ݶN%2X-2ɚd52ѥo= 3ذ{G! 3ߺR(0Ò\/)ɛe6"Ȟj; ӻg: ƾ}W2»pY>$ýwog_WNC4$ žyqiaYRKD=71+& {skc[TLE>82,(# »}ume]UNG@93.)$ üwnf^WPIB;5/*%  žyph`YRJC<60+&"  {rjb[SLE>82,'# ޝ}tld]UNG@93.)$ f^WPHA;4/*%  !60+&! ( /6=a4q@ K# T)Ē[-ȗ_0˚a1̛b2̛c2̛c2̛c2̛b2˚a1ɘ_0œ[-U*M$ uC g8W,xG" e7Q)= +  fX! "#  & .QCB!!ViTables-3.0.0/macosxapp/make.sh000077500000000000000000000044741311223072700165010ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org set -e VER=$(cat ../VERSION) PYVERS="$(ls /System/Library/Frameworks/Python.framework/Versions | grep -v Current)" if [ ! "$PYVERS" ]; then echo "No available Python installs." > /dev/stderr exit 1 fi if [ "$1" = "clean" ]; then cleaning=true fi if [ $cleaning ]; then rm -f vitables-app.py else cp ../scripts/vitables vitables-app.py fi for PYVER in $PYVERS; do if ! python$PYVER -c 'import tables' 2> /dev/null; then continue fi rm -rf ../dist/ViTables.app if [ ! $cleaning ]; then echo "Creating application bundle for Python $PYVER..." (cd .. && python$PYVER setup.py py2app) fi DMGDIR="ViTables $VER (py$PYVER)" DMG="ViTables-${VER}.macosxppc-py${PYVER}.dmg" RESOURCES="$DMGDIR/ViTables.app/Contents/Resources" if [ $cleaning ]; then rm -rf "$DMGDIR" "$DMG" continue fi echo -n "Building $DMG..." echo -n " app" mkdir -p "$DMGDIR" cp -R ../dist/ViTables.app "$DMGDIR" echo -n " examples" mv "$RESOURCES/examples" "$DMGDIR/Examples" echo -n " license" cp ../LICENSE.* "$RESOURCES" cp ../LICENSE.txt "$DMGDIR/License.txt" echo -n " readme" cp ../README.txt "$DMGDIR/ReadMe.txt" sed -e "s/@VER@/$VER/g" -e "s/@PYVER@/$PYVER/g" < ReadMe-MacOSX.rtf > "$DMGDIR/ReadMe-MacOSX.rtf" echo -n " guide" cp ../doc/UsersGuide.pdf "$DMGDIR/User's Guide.pdf" cp -R ../vitables/htmldocs "$DMGDIR/User's Guide (HTML)" echo "." hdiutil create -srcfolder "$DMGDIR" -anyowners -format UDZO -imagekey zlib-level=9 "$DMG" done echo "Done" ViTables-3.0.0/mswindows/000077500000000000000000000000001311223072700152535ustar00rootroot00000000000000ViTables-3.0.0/mswindows/Makefile000066400000000000000000000046671311223072700167300ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # Author: Vicent Mas - vmas@vitables.org # # This Makefile is intended to create the ViTables installer for Windows. # It is not intended for distribution. VERSIONFILE=..\VERSION #VERSION=$(shell type ..\VERSION) (syntax not supported by nmake) VERSION=2.2.2 PYTHONVERSION=26 DOTPYTHONVERSION=2.6 ROOT=.. LICENSEFILE=$(ROOT)\LICENSE.txt LICENSEFILENAME=LICENSE.txt WINDOWS32=C:\\Windows\\system32 # The NSIS intstaller script VTNSIS=vitables-py$(DOTPYTHONVERSION).nsi # ViTables executable script PYTHON=C:\Python$(PYTHONVERSION)\python SIB="$(USERPROFILE)\VendorID-1.0.0\sib\sib.py" ICON=$(ROOT)\vitables\icons\vitables.ico # Documentation in HTML and PDF formats INDEX=$(ROOT)\doc\index.rst HTML_INDEX=$(ROOT)\doc\index_html.txt PDF_INDEX=$(ROOT)\doc\index_pdf.txt HTML_OUTDIR=$(ROOT)\vitables\htmldocs PDF_OUTDIR=$(ROOT)\doc clean: del $(VTNSIS) del ViTables*.win32-py$(DOTPYTHONVERSION).exe del $(ROOT)\vitables.py del $(INDEX) del $(ROOT)\doc\UsersGuide.pdf rmdir /q /s $(HTML_OUTDIR) rmdir /q /s $(ROOT)\doc\_build vitables.exe: copy $(ROOT)\scripts\vitables .\vitables.py $(PYTHON) $(SIB) -u -i $(ICON) ./vitables.py # $(MAKE) -C build_vitables (syntax not supported by nmake) cd build_vitables && $(MAKE) copy build_vitables\vitables.exe . copy build_vitables\vitables.exe.manifest . rmdir /q /s build_vitables del .\vitables.py vtdoc: htmldoc pdfdoc htmldoc: del $(INDEX) copy $(HTML_INDEX) $(INDEX) cd $(ROOT)\doc && make.bat html mkdir $(HTML_OUTDIR) xcopy $(ROOT)\doc\_build\html\*.* /E $(HTML_OUTDIR) rmdir /q /s $(HTML_OUTDIR)\_sources copy $(ROOT)\vitables\LICENSE.html $(HTML_OUTDIR) rmdir /q /s $(ROOT)\doc\_build pdfdoc: del $(INDEX) copy $(PDF_INDEX) /Y $(INDEX) cd $(ROOT)\doc && make.bat pdf xcopy $(ROOT)\doc\_build\pdf\*.* $(ROOT)\doc rmdir /q /s $(ROOT)\doc\_build installer: vitables.nsi.in $(VERSIONFILE) $(LICENSEFILE) vtdoc vitables.exe copy ..\vitables\LICENSE.html LICENSE.html type vitables.nsi.in | sed -e "s/@VERSION@/$(VERSION)/g" \ -e "s/@PYTHONVERSION@/$(PYTHONVERSION)/g" \ -e "s/@DOTPYTHONVERSION@/$(DOTPYTHONVERSION)/g" \ -e "s/@ROOT@/$(ROOT)/g" \ -e "s/@WINDOWS32@/$(WINDOWS32)/g" \ -e "s/@LICENSE@/$(LICENSE)/g" \ -e "s/@LICENSEFILENAME@/$(LICENSEFILENAME)/g" \ > $(VTNSIS) makensis $(VTNSIS) del LICENSE.html del vitables.exe del vitables.exe.manifest ViTables-3.0.0/mswindows/vitables.nsi.in000066400000000000000000000272241311223072700202130ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # Author: Vicent Mas - vmas@vitables.org # # This script is intended to generate a binary installer for sources # imported from a ViTables repository. It is not intended for distribution. # INCLUDES !include MUI2.nsh !include Library.nsh !include Sections.nsh !include LogicLib.nsh !include fileassoc.nsh !include UAC.nsh # INIT # Admin privileges are needed for writing in HKLM and HKCR root keys # of the registry and also for installing into system folders (Program Files). # But the UAC plugin requires user privileges RequestExecutionLevel user SetCompressor /SOLID lzma Name "ViTables @VERSION@" OutFile "ViTables-@VERSION@.win32-py@DOTPYTHONVERSION@.exe" XPStyle on # CONSTANTS !define APPNAME "ViTables" !define APPFOLDER "ViTables @VERSION@ for Python@DOTPYTHONVERSION@" !define S_DEFINSTDIR_USER "$LocalAppData\${APPNAME}" !define S_DEFINSTDIR_ADMIN "$ProgramFiles\${APPNAME}" !define INICIOFOLDER "$SMPROGRAMS\${APPFOLDER}" !define INICIOFOLDER_RUN "${INICIOFOLDER}\ViTables.lnk" !define INICIOFOLDER_UNINSTALLER "${INICIOFOLDER}\Uninstall.lnk" !define INICIOFOLDER_EXAMPLES "${INICIOFOLDER}\Examples.lnk" !define INICIOFOLDER_GUIDE "${INICIOFOLDER}\User's Guide (PDF).lnk" !define DESKTOPFOLDER_RUN "$DESKTOP\ViTables.lnk" # The installer icons as used by MUI (see NSIS FAQ) !define MUI_ICON "@ROOT@\vitables\icons\vtinstaller.ico" !define MUI_UNICON "@ROOT@\vitables\icons\vtinstaller.ico" # Variables declaration Var VITABLES_KEY Var PYTHONDIR ########################################################### # PART I: INSTALLER ########################################################### # -------------------------------- # FUNCTIONS # -------------------------------- Function .onInit # The registry key where application settings will be stored StrCpy $VITABLES_KEY "SOFTWARE\ViTables\@VERSION@" # Check the python installation ExecWait "pythonw -c $\"import sys; (sys.version_info[0:3] > (2, 6)) or 0/0$\"" $R0 ${If} $R0 == "1" MessageBox MB_OK|MB_ICONEXCLAMATION "It seems that Python 2.6 is not \ installed. Aborting the ViTables installation process." Abort ${EndIf} # Check the tables installation ExecWait "pythonw -c $\"import tables$\"" IfErrors 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "It seems that PyTables is not \ installed. Aborting the ViTables installation process." Abort # Check the PyQt4.QtGui installation ExecWait "pythonw -c $\"from PyQt4.QtGui import *$\"" IfErrors 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "It seems that PyQt4.QtGui is not \ installed. Aborting the ViTables installation process." Abort # Check the PyQt4.QtCore installation ExecWait "pythonw -c $\"from PyQt4.QtCore import *$\"" IfErrors 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "It seems that PyQt4.QtCore is not \ installed. Aborting the ViTables installation process." Abort FunctionEnd Function preInstallDir # The installation directory depends on the user privileges # admin user returns 1, regular user returns 0. The result is stored in $0 !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin StrCpy $INSTDIR "${S_DEFINSTDIR_USER}\${APPFOLDER}" ${Else} StrCpy $INSTDIR "${S_DEFINSTDIR_ADMIN}\${APPFOLDER}" ${EndIf} FunctionEnd Function prePythonDir # The registry key where python install path is stored ReadRegStr $PYTHONDIR HKLM "SOFTWARE\Python\PythonCore\@DOTPYTHONVERSION@\InstallPath" "" ClearErrors FunctionEnd Function postPythonDir IfFileExists $PYTHONDIR\pythonw.exe +3 0 MessageBox MB_YESNO "Cannot find a valid Python@DOTPYTHONVERSION@ interpreter in \ $PYTHONDIR.$\r$\nYou can install ViTables there, but it will not run \ without Python@DOTPYTHONVERSION@ installed in the same directory tree.$\r$\nContinue \ anyway?" IDYES +2 IDNO 0 Abort FunctionEnd # -------------------------------- # PAGES # -------------------------------- # Page: Welcome !insertmacro MUI_PAGE_WELCOME # Page: License !insertmacro MUI_PAGE_LICENSE @ROOT@\@LICENSEFILENAME@ # Page: Components selection #!insertmacro MUI_PAGE_COMPONENTS # Page: Installation directory for ViTables data files !define MUI_PAGE_CUSTOMFUNCTION_PRE preInstallDir !define MUI_DIRECTORYPAGE_TEXT_TOP "Setup will install ViTables @VERSION@ data \ files in the following folder. To install in a different folder, click \ Browse and select another folder. Click Next to Continue." !insertmacro MUI_PAGE_DIRECTORY # Page: Installation directory for ViTables modules and scripts !define MUI_PAGE_CUSTOMFUNCTION_PRE prePythonDir !define MUI_PAGE_CUSTOMFUNCTION_LEAVE postPythonDir !define MUI_PAGE_HEADER_TEXT "Choose the Python-@DOTPYTHONVERSION@ interpreter" !define MUI_PAGE_HEADER_SUBTEXT "Choose the folder in which the Python-@DOTPYTHONVERSION@ \ interpreter is located." !define MUI_DIRECTORYPAGE_TEXT_TOP "Setup will install ViTables @VERSION@ modules and \ scripts under the following folder. To install in a different folder, click \ Browse and select another folder. Click Next to Continue." !define MUI_DIRECTORYPAGE_VARIABLE $PYTHONDIR !insertmacro MUI_PAGE_DIRECTORY # Page: Install selected components !insertmacro MUI_PAGE_INSTFILES # ------------------------------------------ # CALLBACKS # ------------------------------------------ Function CreateShortcuts # If we install as admin make sure that Start menu folders will be created # for regular users too, not only for the admin user !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin SetShellVarContext current ${Else} SetShellVarContext all ${EndIf} # Create shortcuts CreateDirectory "${INICIOFOLDER}" CreateShortCut "${INICIOFOLDER_RUN}" "$PYTHONDIR\Scripts\vitables.exe" CreateShortCut "${INICIOFOLDER_UNINSTALLER}" "$INSTDIR\Uninstall.exe" CreateShortCut "${INICIOFOLDER_EXAMPLES}" "$INSTDIR\examples" CreateShortCut "${INICIOFOLDER_GUIDE}" "$INSTDIR\doc\UsersGuide.pdf" CreateShortCut "${DESKTOPFOLDER_RUN}" "$PYTHONDIR\Scripts\vitables.exe" FunctionEnd Function SaveToRegistry !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin # Update the registry WriteRegStr HKCU $VITABLES_KEY "INSTDIR" $INSTDIR WriteRegStr HKCU $VITABLES_KEY "PYTHONDIR" $PYTHONDIR ${Else} # Update the registry and associate the .h5 extension to ViTables WriteRegStr HKLM $VITABLES_KEY "INSTDIR" $INSTDIR WriteRegStr HKLM $VITABLES_KEY "PYTHONDIR" $PYTHONDIR !insertmacro APP_ASSOCIATE "h5" "ViTables.HDF5file" "ViTables document" \ "$PYTHONDIR\Lib\site-packages\vitables\icons\vitables_file.ico" \ "Open with ViTables" "$PYTHONDIR\Scripts\vitables.exe $\"%1$\"" ${EndIf} FunctionEnd # ------------------------------------------ # SECTIONS (STUFF TO BE INSTALLED) # ------------------------------------------ Section "ViTables @VERSION@" VT # Copy the ViTables script in the Python Scripts directory SetOutPath $PYTHONDIR\Scripts File vitables.exe File vitables.exe.manifest # Copy the ViTables sources in the Python site-packages directory SetOutPath $PYTHONDIR\Lib\site-packages\vitables File /r /x images /x plotter /x .leo_shadow @ROOT@\vitables\*.py File /r /x images /x plotter @ROOT@\vitables\*.ui File /r /x images /x plotter @ROOT@\vitables\*.ini SetOutPath $PYTHONDIR\Lib\site-packages\vitables\plugins\csv\icons File /r @ROOT@\vitables\plugins\csv\icons\* SetOutPath $PYTHONDIR\Lib\site-packages\vitables\icons File /r @ROOT@\vitables\icons\* SetOutPath $PYTHONDIR\Lib\site-packages\vitables\htmldocs File /r @ROOT@\vitables\htmldocs\* # Populate the installation directory with: # -text files (TODO.txt, LICENSE.html...) # - users guide (sources and PDF) # - examples directory # - uninstaller SetOutPath $INSTDIR File @ROOT@\*.txt File ..\vitables\LICENSE.html SetOutPath $INSTDIR\doc File @ROOT@\doc\UsersGuide.pdf File @ROOT@\doc\usersguide-*.rst File @ROOT@\doc\index_*.txt File @ROOT@\doc\make.bat File @ROOT@\doc\conf.py SetOutPath $INSTDIR\doc\images File /r @ROOT@\doc\images\* SetOutPath $INSTDIR\examples File /r @ROOT@\examples\*.* WriteUninstaller "$INSTDIR\Uninstall.exe" # To ensure that everybody can accesses the examples folder in read/write # mode on Windows Vista even if we install as admin !insertmacro UAC_IsAdmin ${If} $0 = 1 ; We are executing as admin AccessControl::GrantOnFile "$INSTDIR\examples" "(BU)" "GenericRead|GenericWrite" ${EndIf} # Create shortcuts in the Start Menu and in the desktop Call CreateShortcuts # Update the registry Call SaveToRegistry SectionEnd ########################################################### # PART II: UNINSTALLER ########################################################### # -------------------------------- # FUNCTIONS # -------------------------------- Function un.onInit # Variables set in installer functions are not available here so we must set # them again StrCpy $VITABLES_KEY "SOFTWARE\ViTables\@VERSION@" FunctionEnd # -------------------------------- # PAGES # -------------------------------- # Page: Welcome !insertmacro MUI_UNPAGE_CONFIRM # Uninstall page: execute uninstall sections !define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation complete" !define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "ViTables deletion completed \ succesfully." !define MUI_UNFINSIHPAGE_NOAUTOCLOSE 1 !insertmacro MUI_UNPAGE_INSTFILES # ------------------------------------------ # CALLBACKS # ------------------------------------------ Function un.RetrieveFromRegistry !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin # Update the registry ReadRegStr $PYTHONDIR HKCU $VITABLES_KEY "PYTHONDIR" ReadRegStr $INSTDIR HKCU $VITABLES_KEY "INSTDIR" ${Else} # Update the registry ReadRegStr $PYTHONDIR HKLM $VITABLES_KEY "PYTHONDIR" ReadRegStr $INSTDIR HKLM $VITABLES_KEY "INSTDIR" ${EndIf} FunctionEnd Function un.RemoveShortcuts # Make sure that Start menu folders will be removed for regular users too !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin SetShellVarContext current ${Else} SetShellVarContext all ${EndIf} # Remove the application entry in the Start Menu RMDir /r "${INICIOFOLDER}" Delete "${DESKTOPFOLDER_RUN}" FunctionEnd Function un.CleanRegistry # Delete the ViTables key from the registry, unassociate the .h5 # extension from ViTables and restore the previous association !insertmacro UAC_IsAdmin ${If} $0 <> 1 ; We are not executing as admin DeleteRegKey HKCU $VITABLES_KEY ${Else} DeleteRegKey HKLM $VITABLES_KEY DeleteRegKey HKCU $VITABLES_KEY !insertmacro APP_UNASSOCIATE "h5" "ViTables.HDF5file" ${EndIf} FunctionEnd # ---------------------------------- # SECTIONS (STUFF TO BE UNINSTALLED) # ---------------------------------- Section "Un.Vitables uninstall" UVT # Read the INSTDIR and PYTHONDIR values from the registry Call un.RetrieveFromRegistry # Remove the application directory and the vitables package # Note that a regular user can't remove a system wide installation # because she will try to retrieve PYTHONDIR and INSTDIR from # the HKCU key root of registry RMDir /r $INSTDIR RMDir /r "$PYTHONDIR\Lib\site-packages\vitables" Delete "$PYTHONDIR\Scripts\vitables.exe" Delete "$PYTHONDIR\Scripts\vitables.exe.manifest" # Remove shortcuts from the Start Menu and desktop # Note that a regular user can't remove a system wide installation # because she has no write permissions to the All Users folder Call un.RemoveShortcuts # Delete ViTables key and file associations from the registry Call un.CleanRegistry SectionEnd # Eventually the LANGUAGE macro must be inserted !insertmacro MUI_LANGUAGE "English" ViTables-3.0.0/mswindows/vitables_setup.iss000066400000000000000000000025511311223072700210270ustar00rootroot00000000000000; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define name "ViTables" #define version "2.2a1" #define pydir "WinPython-32bit-2.7.6.4\python-2.7.6" [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{200AF704-AD3A-4108-900F-DDBBFB7F36A1} AppName={#name} AppVersion={#version} DefaultDirName={pf}\{#name} DefaultGroupName={#name} OutputBaseFilename={#name}-{#version} Compression=lzma2 SolidCompression=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl" [Icons] Name: "{group}\{#name}"; Filename: "{app}\{#pydir}\pythonw.exe"; WorkingDir: "{app}"; \ Parameters: """{app}\{#pydir}\Scripts\vitables-script.pyw"""; IconFilename: "{app}\{#pydir}\Lib\site-packages\vitables\icons\vitables.ico" Name: "{commondesktop}\{#name}"; Filename: "{app}\{#pydir}\pythonw.exe"; WorkingDir: "{app}"; \ Parameters: """{app}\{#pydir}\Scripts\vitables-script.pyw"""; IconFilename: "{app}\{#pydir}\Lib\site-packages\vitables\icons\vitables.ico" [Files] Source: "{#SourcePath}{#name}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs ViTables-3.0.0/requirements.txt000066400000000000000000000000471311223072700165060ustar00rootroot00000000000000Cython numexpr numpy tables PyQt5 QtPy ViTables-3.0.0/setup.py000066400000000000000000000065201311223072700147360ustar00rootroot00000000000000# Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved # Copyright (C) 2008-2017 Vicent Mas. All rights reserved # # 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 . # # Author: Vicent Mas - vmas@vitables.org """ Setup script for the vitables package. """ import os from setuptools import setup, find_packages # Utility function to read the README file. def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup(name='ViTables', version=read('VERSION'), description='A viewer for PyTables package', long_description=read('README.txt'), author='Vicent Mas', author_email='vmas@vitables.org', maintainer='Vicent Mas', maintainer_email='vmas@vitables.org', url='http://vitables.org', license='GPLv3, see the LICENSE.txt file for detailed info', keywords='HDF5 PyTables', platforms='Unix, MacOSX, Windows', classifiers=[ 'Development Status :: 5 - Stable', 'Environment :: X11 Applications', 'Environment :: MacOS X', 'Environment :: Win32 (MS Windows)', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'Operating System :: POSIX', 'Programming Language :: Python', 'Topic :: Scientific/Engineering' ], install_requires=['qtpy (>=1.2.1)', 'PyQt5 (>=5.5.1)', 'numpy (>=1.4.1)', 'numexpr (>=2.0)', 'tables (>=3.0)'], entry_points={ 'gui_scripts': ['vitables = vitables.start:gui'], 'vitables.plugins': [('columnar_org = ' 'vitables.plugins.columnorg.columnar_org:ArrayColsOrganizer'), ('import_csv = ' 'vitables.plugins.csv.import_csv:ImportCSV'), ('export_csv = ' 'vitables.plugins.csv.export_csv:ExportToCSV'), ('dbs_tree_sort = ' 'vitables.plugins.dbstreesort.dbs_tree_sort:DBsTreeSort'), ('time_series = ' 'vitables.plugins.timeseries.time_series:TSFormatter')] }, packages=find_packages(), # Include data files that belong to the vitables package package_data={ 'vitables': ['LICENSE.html', 'htmldocs/*', 'htmldocs/*/*', 'icons/*', 'icons/*/*', '*/*.ui', 'plugins/*/*.ui', 'plugins/*/*.ini', 'i18n/*.qm' ] }, # In order to include files that do not belong to any package we have to # add them to MANIFEST.in AND set the include_package_data keyword to True #include_package_data=True, ) ViTables-3.0.0/unixapp/000077500000000000000000000000001311223072700147055ustar00rootroot00000000000000ViTables-3.0.0/unixapp/vitables.desktop000066400000000000000000000007221311223072700201120ustar00rootroot00000000000000[Desktop Entry] Type=Application Version=3.0.0 Name=ViTables GenericName=PyTables & HDF5 Files Visualizer GenericName[ca]=Visualitzador de fitxers PyTables i HDF5 GenericName[es]=Visualizador de ficheros PyTables y HDF5 Exec=vitables %U Icon=vitables #There is not mime-type yet for HDF5 #MimeType=application/x-hdf5 #Set this to the vitables documentation files #DocPath=vitables/index.html Terminal=false Categories=Qt;Database;DataVisualization;Science;Education ViTables-3.0.0/unixapp/vitables.svg000066400000000000000000000210071311223072700172370ustar00rootroot00000000000000 image/svg+xml ViTables icon 2006-02-21 Domenec Morera Carabos Coop. V. ViTables-3.0.0/unixapp/vitables_128x128.png000066400000000000000000000203741311223072700202470ustar00rootroot00000000000000PNG  IHDR>asBIT|dtEXtSoftwarewww.inkscape.org< IDATxy\U￧Ʈ̄$H1*C@@RpKhW*^W}*\bC 40t汻驪kqzs;O9gkNyS ˭VS=TN{0ܶxNu8]n p>G+9|JK;-`paqTro/+} \FS .սʯ]0=p܋޷ S<CS¿Kp ?^4OD, N[f3a:ǕIaN 8G}`A)qۦꅧ4˙iTfEch_ 0sesWvl Ԏ5[_AmzzF3.w+{9P7ch,f$<>zt:4hZ%R.w :>m*PSÒ3'Fg V0-r/!{uNVȚTq''ZTY5-t K r7"W VwLk^3M6S1XΩHN[K :&ggj=ԭr`k9r@Yt瓽o_H:9GزX+h944hRהi@]K} ЮzV"dMH&=L4U[_є/ž=ly ˮz.NyU} ǢPM$)pw;#`0wTݤ(ECC-#(ASaeF %bϔ_Z mmƖ t%L*JxHj3G'U]rgcH {|Ӵ j|(*%VQ;b%kj U7%}xOi%Z[嶁sA7Jڽuۀ 45v]h&st sfK޾oEAyjPJө Ξ]'CxX"V D BIAKKE^ aP^,4U:^}8ؽhh4*!|((H}V+gժq̙]@ ^KT6쿾F Ib~ ?b\,9QGm@ /*P_ݎ\iqg noGsx$D$hPH"lK& a6P9]}!B/ Sɍ>_f)+968))ˋ&z|,:IuP?:FsQh^k9z[hˁgՍ\"LzjjtD"?j,$Q[xޜ9RKd@0n;#L~WRApz a?tO[*dk#PI0{vo}"mh(Leh?J(сQ]NC"ت&U$%05'J۟35t:ͦ ;+VրΈֈj^5C5U6@$ Oiar@_T!`(O:-\K/}Y 7hRbΒ1+zV)+$( Jl>\&?Jcykf2B'jkO =,/W]D{j J+v MN,%JXlM&OT\,"pK0U{3`e衡lY)K q(@:]nc^RS  jk &7 l ?_mhIX=@ŧjA>'ny7ZW~%r=t_C<;~UPhrP;?ymk$i_<ȄFMM&8=DOaz{sD"'2ϻ=m㒳|թʉF$)UW  Z@2SY & Wzò|ٳ={=wRUgܺ߰Ǿo:*w9ZrZ -͵̞~V&[0%'nJ1BA,.;˺z]Ngn!EJ0ńMPd2XC{ Y2 ݻ(>_ŃRS5Xo_y_JNᰏoOmp H@: `r@.0Tdc4hz~[d߾w1]7k+oZWAͪT=\ʁjAo*X A}6>_^snhw¢[TU7N^8@s]Fv^xqJ[[? wJ@ ǟ}~D7_J(T4ֹI ~X 0- U TA jmG8_@@37,D=ȝgPc"f?xC%`;B7|:p[ne֭q,Oڙz?~dYeC8soxob^ K}TF]央g|Zh*([L@8@A y;577sW}x٦U?*@2ɉ J&`$:@e{E<$+ ǵOӷO=ess?*.rn%FFF;w.d}wѫǔ\Vi5—.Oexgb)ҶQ#Q@ ^_U̵|bEQrl~%LRcm6 \Z]l ~ĞL8hqbvXI a7,5탷{+7L,޼h7(EZSPl._T 7\ۓʈO]sk<֮!ǝS` :}2PQ}U;=ݦug:-(k~AuUCN\_.kr 1xSTj>rd!k3[JJB鴔W'ߖ"o~=c%<$XAm,ai')#PxCZ쳫Rn"f/喉rRIkrfSn]i:}I+*s8G HaQި]).~tac("Z15ŧHӿ+l]M12LWI6꼵59)ܜ25api@/\we8[T`6`Fp rѪ R_Bd$7&L.Webd?;X |rR$RVZ-\7%LQlT_{yk2͵p:xSm Ptsz/eB> \r>Ta[E>awATK2fꍓbUuMJI Z(]F\-Ջ薶AVVWfKMf* Kԇ]#pO:9U |qkbo[b+u4[&?J!KDsp{,[u%p h3\II=S1LX,BͶ㥼 S>LzSY3K ?.c$'  ?XY) ]{7y'X$Gʂ77gS鸬bp0fO'#]F*wu*rrtz~ۗ <C_&߻z6Cf}]rB% ջ181)d@+_t8}N 0 F{ln)p 9I'CBy !9P*(P$0K[]yHю@u9ۀDǓx hP\H8׍>K[n4ȇM_=4$`n| K'_>D9qMLGQ{5w'gѦBw&0V|`9%fϋJ$1lSΝ0@~_93+6ij[g3+xhXXI*CR4HIPw;WgVlt5:l.4jeajWѕ77*J)BkX6Y~*FדdȨk$2x΀LZ =b%pُ`Wo}[@'`1L tuz'[?6Rdj5JL }}G__6mgO ~R 5aXSQ*/*|>4=|{}9G 9<܅" J)2m%i2ٳYn֭˾AoB" 'v< AGӛ )&!q gB* Vwq*]`d5P*ɣt&w1P t8䑒" *HˡAođKzVN~:& ᰧYAqK/;!^G;şS#=Vc0󉦗,S?wun.tTgPFZ mmDm~}2-NlR ڃ׋3U f$X:!m^Yge$'|WrxH޺uZoYwu]SE#VBIidW ϲrsXw+SfnxJw};رEzRkO U{9}ȴL6XzBߗo߾kgβ,,Zۘ*2@H>z lqf+S[`?5l۩tܿQ^ ]6yL-.wQTꪌVQC  I?fֻYWW7sdyƁT2l`0$R37 襹rY&00^i,k,,UJF 24bx8FaY|/s~v^% >v"׏g~w'ss[,|PpW0SF{r%Nʼ')FFB +|d$UThL4,\4>EpQq{1vA2\~9K3OA<?rTp5-_\s0ulxXL}E MV$UR8]Mz^g e;b!hCá ߌF6fBCCMъCCClذM6rɔ 抅|S˙Q򥗏/:8[r@<`%ҋ=dրfp0뮻lڴ 6qFNfJfe:bēMOY9qY9I^qxxa՟|XL!1l' t]^Kdgb1^Ē3ư c_WX4jZgjTd؉D{70909$d@ (֨8G~#ɕ=>:7 AI))HEn]p5g$"Nj*)_@&.I`"uy̝[8X℟"3cޱsS6m:ƿCx-Nhit8UWt62 !3h[\Gs`J1`>z{Ue*Dfc!,F[0ImwIDATa-ੌi. S4p*86LtsJU W8۩@' FFpU{L |QC `;S~;S02~:5 ~B:Ǣ?IENDB`ViTables-3.0.0/unixapp/vitables_16x16.png000066400000000000000000000015431311223072700200740ustar00rootroot00000000000000PNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<IDAT8u_hw?y&ĄPԤ&QF%mQ,J !}+-X[K BBA@EԂK٤ 9[ޟ|'<|;3̌$E66n@лC=$ԮzeYݺj v@8 .gܹcs+躊 m$B!<_Tl/V76ƍ4M% N.W wXzU\.qsnV(MMȒAQeJ%A"KEŖ,,h/,kg=TVj ~]uUlmXVGJga!֭wO9 'h;P3۱O?rM$7n'Ȣ9OgsDUU8';V|Dqa}r,. #g Sv̴"ZIxfN6#\@@ib[3 $l쳵  [PL| p){{mre߼u koܐO/qOk%͖,G& VW&\S3_apJno3S|~>zc!g7GnhhxM:'0i2#Wu,:;},-d<d2,e@ȭ0''#G,B+>5|̏;IENDB`ViTables-3.0.0/unixapp/vitables_22x22.png000066400000000000000000000023211311223072700200610ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|dtEXtSoftwarewww.inkscape.org<cIDAT8[lUt.F!t[r(L|@ D㣈 }7%l Ѳ@\ڋe{vvC?r23w9s7iA +DPk^`J@%R)  dY\pmCʏOǯf` ҥnO=*f`k'&"I"UL%-=;zijj^Q5Ž$FgrHw:[au [bՊe& N`o ՍOh8Ma0 .bK&muXj|;*}/ʙi(+?>j]kÀ'O.2=X+#rHf)Q:W AӒ<4pjCl* G[ ]|PVpoNAt!^pAӷ^z`nx`@4A`VF?#!har_)F99{Z oN|Z+$gc ZG7(*/NPXoxs$Nv (w5_B[Y_q5EF?-? 9T՛ uv4/?vѱ򸕩HH$Iղ-8pWhg;eŧ;Zp B5{j8/OImVՔr"d fuHN6DӹyVmWnT7= c46֒b)c)bic),`< Uh>bD:O 25  ω5-??|@5Ȼ#)cIENDB`ViTables-3.0.0/unixapp/vitables_32x32.png000066400000000000000000000035701311223072700200720ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org< IDATX{lS?ھ}~;n-PDl4u]lju/N6iӄi4mMcT{ m 1Axӵ0!m$WlH;;ROqwy\NG0ؔ43k^ȇppwy y`k1Nl6 dD" r:&J-wgV#6Yfm9@YXŋB:J,K1m:L&JˢHd,0RVh_`NȮ'WuDt,*\GZ4P[#g\NGbB(}I$sGfkiAsr.дHg vǵ"gUUVjh4A8h4PYiuwyߋL#uOoQIat̏ǘ }w"K\veȯTUYL26@"hZP(ȈA%L]aCu,_^&P#344eSY.chZKFEcRQŌY~7R( Y>N'|?ͫ񥆁ϲ'.AAқ/l1܀_,f&μ,홤1|Ӽ>0RzX;~`W1rN3 g;s Yp}o|w¥e OgEioS#,۽mIo1^-'Žd3y {b813GD`ü#GE8(v7~vۉȓ[B91.^EϜv7TjjG?3:M5FH Pin oXBm¸BDL"^(^7-{ފ~;_RnQA0p:o)f5 f+T觙_EҥF+@M* fhFܲsN\ t`0BE% jdj*,![c ׮ٳ'pF|_㷗_ mlhnhb}`nhe ~8CE1SW+S[gVf+Lԩ|rs5ϧ:`!"mx^" "hT*ҥJiCs@.c<^K ,K`C.#Vj|9ԗӡB_!ᦘ EIENDB`ViTables-3.0.0/unixapp/vitables_48x48.png000066400000000000000000000056351311223072700201140ustar00rootroot00000000000000PNG  IHDR00WsBIT|dtEXtSoftwarewww.inkscape.org< /IDAThŚ{pT?ww{BD0VGgDZqFQ:Z1:8v(ӱ:٪H %(&YH3Bs7fa;sys90O4Xk>0Μ1W- !B!<#6R kDWˁ,]Z@Ś|DNyJ ͚l!  X@ut ZFmKG/E̖K`z99j 9BT@(FGA̾ɸ@Ūn"Ѻ3!ފVI;B(*ed #u6&^UHi!k+f ILƄbCTDѤTqΉf.,Q㧵뙁!6]/= 3{NMh4jzztu^*DQ&'XMts|)e/ 'GEYY`x؝naݛk0b`~ŚP$#IA㧫'lje>}W;-*e6i"dDOظ\>PBC>m)MG `K\l^s|YONelXOˢy$SX8E~RGp|Q+rIx uaA:_d9^3I^AtzbLd$ɇ?~ 9.:q-ߘZ=1 ժ߰Ǣ )9 ˇ叭2gLZEaQիNrssXzM EQQ.cc>/qFrvT5Xuk ̸딼B000DF@<?3g1mZ0zx.^H ^6{CTDFa_:)יh1/*oaܹa> A+z`~Fq{(L81$jhj$IUL&#~7`P޿D[Ѵ/MɂqYKuiיd" bO`Ųy}e 8P'̼[i*Uh6d>5N3<__zyj|'New?#ww?ABpÚ'! <zCo2%tb)zd.@f6Di !7Sj>Ι I>F3u ]\8R3TMO6A %/֚hAx{1יD.Q p4󴵵ܟÃ#P8$5 n~ .ZԸK> |Gu $!9n+r};u'𯴝޹zeO>{? OiGd3 rBS†XYsS{_:{.qsG UL/1- ߓ&cr0Jd:y\qpt?-͗T{Q]@}MHw1R'SQO`kkkgPQ>a)Ͽ?d2rJG܌ qr% ^Ci~C߿&\Xm[Tͷm+ יoD.`g -ie^u('m4*,sЇG|Hi|jU cUaKFfי5;L8 _L /b2cu-;tlp֭rmfQlnASV BħRYahE LC"v݃f ' ޾.ufb=%I3c>a!6GQ@ `{"b~fmC=?Ѹ)"zb@ÃM EL[$۽ƭ1t#d8r1u_Jn@@ n^ؤq=J$lء(,V+Jp:ܝ:$ÍC@K5;3*4ylAIENDB`ViTables-3.0.0/unixapp/vitables_64x64.png000066400000000000000000000105301311223072700200760ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|dtEXtSoftwarewww.inkscape.org<IDATx՛kt\uΌfF3#i4-?-A5vjBm&MJڒf! % ,8Ic6IQ0*'`{@6h$eYK};hte5=gs}gs'z3p8EslB ߟL{k=kM 4Mn!hA@(5ɤ&H - kWJQDҸH()i),pI1i#) %ת}MU\K}--YJ͍n,sfETV*~]] 3r:e~eSKUihRn)q+IP6f.Xe8AMX&Dvh);t0n҄+IC 3 sE{JHP0pVf݋Iځj0T(BiHb`ي3j;SqC0)`KZa(R%4+I4:vx5F2ia&K~@ wߒ崑,|ⶹSEMd* (/ ^|(]@YdyvL#RrKtv]-HD\v`2Zm MLj\(KߗCXG)h m;MgUcpdU`2q8TTy k~:Wb,4@>@5,fͪJ+O--gl9\G3;7̉gj5֕rП$>_nrts*; ׯO"@~TU+=;4k p _$`` sS3LjygΚPhD!MkC2 ijb1&z#p}fͪ>/  t H&'6` gJ;l  r@B&Zg%Wz gDBՅL h0(F{{?Nw)a7SUeP]mIk b W *G-Rʒūi]g ;C0l,,e L 3Y:lx# sU V\|kd׮n,b|QÄBqFF Fi)8 !b1\'spX oIj- wG΍NԐ@f E]g0=3vE7 P@}mDBcd$VS;@J !Yư; v֮_O}؋J6XlzOsO_B=H> f(5iZ= $Q.ƽ[qC#:+?]7LEz vk20 @H 9nkBnnŖ+k~ ѲP(^0㰛CH Y!RAU/k9EOy._>'B!`żIKOh[`yфiHݜpeP)eݣlF dnzzhm%:;; n^PbS ױzgR{5ׁkX3=U@W@gr4~6_nWC(6N`A@,N?6X8F}' v&?;4+?f&wLIF|6X`=[ic/w,N75xsW6[p S .M0} ffϞ_X/<_"SwPcwb6l'uVXC0Ǔa 384`7m?N+g~ġ}tw;pDr_+|Vcq*|Z1>{<7֍XsL &I a]]ni 8C~B-#uu6֬Ku3ghmmic⃓4]{nóQ#qNՙ }+}R κx*@VȪU::8sfh¶3uJ\u6\yfo6}20 W'iXp#jZȽ+R73P)I0ilqbI\`p(LvXK rU]>Pgg'oz?wo}j+^_79BYI.M’QW8y7/o}7S[[yMUK) *U7pNE M:GI ӊU̜YɓQFiGJ:In?e4!!N"ڒE dƬ Yk=ؐI& >_Mv5IXryi֭˻_~ d 0UU#vg̬/mMNhRxFF*p  17ɼyNTUKr%#QœL&<ͫfr[HU5(^@a_VwAH£ GNU General Public License - GNU Project - Free Software Foundation (FSF) Copyright Notice and License Agreement for ViTables Application Software